// 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 "flutter/fml/trace_event.h" #include "third_party/skia/include/core/SkColorSpace.h" #include "third_party/skia/include/core/SkSize.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrDirectContext.h" #include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h" #include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSurface.h" #include "vulkan/vulkan_core.h" namespace flutter { GPUSurfaceVulkan::GPUSurfaceVulkan(GPUSurfaceVulkanDelegate* delegate, const sk_sp& 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 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( nullptr, SurfaceFrame::FramebufferInfo(), [](const SurfaceFrame& surface_frame, DlCanvas* 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 surface = CreateSurfaceFromVulkanImage( reinterpret_cast(image.image), static_cast(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&, DlCanvas* 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(image.image), static_cast(image.format)); }; SurfaceFrame::FramebufferInfo framebuffer_info{.supports_readback = true}; return std::make_unique(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 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, }; auto backend_texture = GrBackendTextures::MakeVk(size.width(), size.height(), image_info); SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry); return SkSurfaces::WrapBackendTexture( 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