blob: ba8383c1343cf63020cb05440406d3b285fe206a [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/gpu/gpu_surface_vulkan.h"
#include "flutter/fml/logging.h"
#include "fml/trace_event.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkSize.h"
#include "vulkan/vulkan_core.h"
namespace flutter {
GPUSurfaceVulkan::GPUSurfaceVulkan(GPUSurfaceVulkanDelegate* delegate,
const sk_sp<GrDirectContext>& skia_context,
bool render_to_surface)
: delegate_(delegate),
skia_context_(skia_context),
render_to_surface_(render_to_surface),
weak_factory_(this) {}
GPUSurfaceVulkan::~GPUSurfaceVulkan() = default;
bool GPUSurfaceVulkan::IsValid() {
return skia_context_ != nullptr;
}
std::unique_ptr<SurfaceFrame> GPUSurfaceVulkan::AcquireFrame(
const SkISize& frame_size) {
if (!IsValid()) {
FML_LOG(ERROR) << "Vulkan surface was invalid.";
return nullptr;
}
if (frame_size.isEmpty()) {
FML_LOG(ERROR) << "Vulkan surface was asked for an empty frame.";
return nullptr;
}
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, SurfaceFrame::FramebufferInfo(),
[](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
},
frame_size);
}
FlutterVulkanImage image = delegate_->AcquireImage(frame_size);
if (!image.image) {
FML_LOG(ERROR) << "Invalid VkImage given by the embedder.";
return nullptr;
}
sk_sp<SkSurface> surface = CreateSurfaceFromVulkanImage(
reinterpret_cast<VkImage>(image.image),
static_cast<VkFormat>(image.format), frame_size);
if (!surface) {
FML_LOG(ERROR) << "Could not create the SkSurface from the Vulkan image.";
return nullptr;
}
SurfaceFrame::SubmitCallback callback = [image = image, delegate = delegate_](
const SurfaceFrame&,
SkCanvas* canvas) -> bool {
TRACE_EVENT0("flutter", "GPUSurfaceVulkan::PresentImage");
if (canvas == nullptr) {
FML_DLOG(ERROR) << "Canvas not available.";
return false;
}
canvas->flush();
return delegate->PresentImage(reinterpret_cast<VkImage>(image.image),
static_cast<VkFormat>(image.format));
};
SurfaceFrame::FramebufferInfo framebuffer_info{.supports_readback = true};
return std::make_unique<SurfaceFrame>(std::move(surface), framebuffer_info,
std::move(callback), frame_size);
}
SkMatrix GPUSurfaceVulkan::GetRootTransformation() const {
// This backend does not support delegating to the underlying platform to
// query for root surface transformations. Just return identity.
SkMatrix matrix;
matrix.reset();
return matrix;
}
GrDirectContext* GPUSurfaceVulkan::GetContext() {
return skia_context_.get();
}
sk_sp<SkSurface> GPUSurfaceVulkan::CreateSurfaceFromVulkanImage(
const VkImage image,
const VkFormat format,
const SkISize& size) {
GrVkImageInfo image_info = {
.fImage = image,
.fImageTiling = VK_IMAGE_TILING_OPTIMAL,
.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.fFormat = format,
.fImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT,
.fSampleCount = 1,
.fLevelCount = 1,
};
GrBackendTexture backend_texture(size.width(), //
size.height(), //
image_info //
);
SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
return SkSurface::MakeFromBackendTexture(
skia_context_.get(), // context
backend_texture, // back-end texture
kTopLeft_GrSurfaceOrigin, // surface origin
1, // sample count
ColorTypeFromFormat(format), // color type
SkColorSpace::MakeSRGB(), // color space
&surface_properties // surface properties
);
}
SkColorType GPUSurfaceVulkan::ColorTypeFromFormat(const VkFormat format) {
switch (format) {
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SRGB:
return SkColorType::kRGBA_8888_SkColorType;
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_B8G8R8A8_SRGB:
return SkColorType::kBGRA_8888_SkColorType;
default:
return SkColorType::kUnknown_SkColorType;
}
}
} // namespace flutter