Skip to content

Commit

Permalink
Vulkan support in the Embedder API (#29391)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdero authored Feb 2, 2022
1 parent e3877ce commit 57cb85a
Show file tree
Hide file tree
Showing 44 changed files with 1,873 additions and 170 deletions.
4 changes: 4 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,8 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_surface_metal.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_metal.mm
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.h
FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_task_runner.h
FILE: ../../../flutter/shell/platform/embedder/embedder_thread_host.cc
Expand All @@ -1387,6 +1389,8 @@ FILE: ../../../flutter/shell/platform/embedder/fixtures/scene_without_custom_com
FILE: ../../../flutter/shell/platform/embedder/fixtures/snapshot_large_scene.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/verifyb143464703.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/verifyb143464703_soft_noxform.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/vk_dpr_noxform.png
FILE: ../../../flutter/shell/platform/embedder/fixtures/vk_gradient.png
FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.cc
FILE: ../../../flutter/shell/platform/embedder/platform_view_embedder.h
FILE: ../../../flutter/shell/platform/embedder/test_utils/key_codes.h
Expand Down
5 changes: 3 additions & 2 deletions shell/gpu/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ source_set("gpu_surface_vulkan") {
"gpu_surface_vulkan_delegate.cc",
"gpu_surface_vulkan_delegate.h",
]

deps = gpu_common_deps + [ "//flutter/vulkan" ]
deps = [ "//flutter/shell/platform/embedder:embedder_headers" ]
deps += gpu_common_deps
public_deps = [ "//flutter/vulkan" ]
}

source_set("gpu_surface_metal") {
Expand Down
4 changes: 2 additions & 2 deletions shell/gpu/gpu_surface_metal_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ class GPUSurfaceMetalDelegate {

//------------------------------------------------------------------------------
/// @brief Returns the handle to the MTLTexture to render to. This is only
/// called when the specefied render target type is `kMTLTexture`.
/// called when the specified render target type is `kMTLTexture`.
///
virtual GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_info) const = 0;

//------------------------------------------------------------------------------
/// @brief Presents the texture with `texture_id` to the "screen".
/// `texture_id` corresponds to a texture that has been obtained by an earlier
/// call to `GetMTLTexture`. This is only called when the specefied render
/// call to `GetMTLTexture`. This is only called when the specified render
/// target type is `kMTLTexture`.
///
/// @see |GPUSurfaceMetalDelegate::GetMTLTexture|
Expand Down
128 changes: 92 additions & 36 deletions shell/gpu/gpu_surface_vulkan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,68 +5,77 @@
#include "flutter/shell/gpu/gpu_surface_vulkan.h"

#include "flutter/fml/logging.h"
#include "fml/trace_event.h"
#include "include/core/SkSize.h"
#include "third_party/swiftshader/include/vulkan/vulkan_core.h"

namespace flutter {

GPUSurfaceVulkan::GPUSurfaceVulkan(
GPUSurfaceVulkanDelegate* delegate,
std::unique_ptr<vulkan::VulkanNativeSurface> native_surface,
bool render_to_surface)
: GPUSurfaceVulkan(/*context=*/nullptr,
delegate,
std::move(native_surface),
render_to_surface) {}

GPUSurfaceVulkan::GPUSurfaceVulkan(
const sk_sp<GrDirectContext>& context,
GPUSurfaceVulkanDelegate* delegate,
std::unique_ptr<vulkan::VulkanNativeSurface> native_surface,
bool render_to_surface)
: window_(context,
delegate->vk(),
std::move(native_surface),
render_to_surface),
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 window_.IsValid();
return skia_context_ != nullptr;
}

std::unique_ptr<SurfaceFrame> GPUSurfaceVulkan::AcquireFrame(
const SkISize& size) {
SurfaceFrame::FramebufferInfo framebuffer_info;
framebuffer_info.supports_readback = true;
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;
}

// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface.
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, std::move(framebuffer_info),
nullptr, SurfaceFrame::FramebufferInfo(),
[](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
});
}

auto surface = window_.AcquireSurface();
FlutterVulkanImage image = delegate_->AcquireImage(frame_size);
if (!image.image) {
FML_LOG(ERROR) << "Invalid VkImage given by the embedder.";
return nullptr;
}

if (surface == 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 =
[weak_this = weak_factory_.GetWeakPtr()](const SurfaceFrame&,
SkCanvas* canvas) -> bool {
// Frames are only ever acquired on the raster thread. This is also the
// thread on which the weak pointer factory is collected (as this instance
// is owned by the rasterizer). So this use of weak pointers is safe.
if (canvas == nullptr || !weak_this) {
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;
}
return weak_this->window_.SwapBuffers();

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), std::move(framebuffer_info), std::move(callback));
}
Expand All @@ -80,7 +89,54 @@ SkMatrix GPUSurfaceVulkan::GetRootTransformation() const {
}

GrDirectContext* GPUSurfaceVulkan::GetContext() {
return window_.GetSkiaGrContext();
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
30 changes: 17 additions & 13 deletions shell/gpu/gpu_surface_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,25 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h"
#include "flutter/vulkan/vulkan_backbuffer.h"
#include "flutter/vulkan/vulkan_native_surface.h"
#include "flutter/vulkan/vulkan_window.h"
#include "include/core/SkRefCnt.h"

namespace flutter {

//------------------------------------------------------------------------------
/// @brief A GPU surface backed by VkImages provided by a
/// GPUSurfaceVulkanDelegate.
///
class GPUSurfaceVulkan : public Surface {
public:
//------------------------------------------------------------------------------
/// @brief Create a GPUSurfaceVulkan which implicitly creates its own
/// GrDirectContext for Skia.
///
GPUSurfaceVulkan(GPUSurfaceVulkanDelegate* delegate,
std::unique_ptr<vulkan::VulkanNativeSurface> native_surface,
bool render_to_surface);

//------------------------------------------------------------------------------
/// @brief Create a GPUSurfaceVulkan while letting it reuse an existing
/// GrDirectContext.
///
GPUSurfaceVulkan(const sk_sp<GrDirectContext>& context,
GPUSurfaceVulkanDelegate* delegate,
std::unique_ptr<vulkan::VulkanNativeSurface> native_surface,
GPUSurfaceVulkan(GPUSurfaceVulkanDelegate* delegate,
const sk_sp<GrDirectContext>& context,
bool render_to_surface);

~GPUSurfaceVulkan() override;
Expand All @@ -50,11 +46,19 @@ class GPUSurfaceVulkan : public Surface {
// |Surface|
GrDirectContext* GetContext() override;

static SkColorType ColorTypeFromFormat(const VkFormat format);

private:
vulkan::VulkanWindow window_;
const bool render_to_surface_;
GPUSurfaceVulkanDelegate* delegate_;
sk_sp<GrDirectContext> skia_context_;
bool render_to_surface_;

fml::WeakPtrFactory<GPUSurfaceVulkan> weak_factory_;

sk_sp<SkSurface> CreateSurfaceFromVulkanImage(const VkImage image,
const VkFormat format,
const SkISize& size);

FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceVulkan);
};

Expand Down
33 changes: 30 additions & 3 deletions shell/gpu/gpu_surface_vulkan_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,43 @@
#define FLUTTER_SHELL_GPU_GPU_SURFACE_VULKAN_DELEGATE_H_

#include "flutter/fml/memory/ref_ptr.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/vulkan/vulkan_device.h"
#include "flutter/vulkan/vulkan_image.h"
#include "flutter/vulkan/vulkan_proc_table.h"
#include "third_party/skia/include/core/SkSize.h"

namespace flutter {

//------------------------------------------------------------------------------
/// @brief Interface implemented by all platform surfaces that can present
/// a Vulkan backing store to the "screen". The GPU surface
/// abstraction (which abstracts the client rendering API) uses this
/// delegation pattern to tell the platform surface (which abstracts
/// how backing stores fulfilled by the selected client rendering
/// API end up on the "screen" on a particular platform) when the
/// rasterizer needs to allocate and present the Vulkan backing
/// store.
///
/// @see |EmbedderSurfaceVulkan|.
///
class GPUSurfaceVulkanDelegate {
public:
~GPUSurfaceVulkanDelegate();
virtual ~GPUSurfaceVulkanDelegate();

// Obtain a reference to the Vulkan implementation's proc table.
virtual fml::RefPtr<vulkan::VulkanProcTable> vk() = 0;
/// @brief Obtain a reference to the Vulkan implementation's proc table.
///
virtual const vulkan::VulkanProcTable& vk() = 0;

/// @brief Called by the engine to fetch a VkImage for writing the next
/// frame.
///
virtual FlutterVulkanImage AcquireImage(const SkISize& size) = 0;

/// @brief Called by the engine once a frame has been rendered to the image
/// and it's ready to be bound for further reading/writing.
///
virtual bool PresentImage(VkImage image, VkFormat format) = 0;
};

} // namespace flutter
Expand Down
16 changes: 16 additions & 0 deletions shell/platform/embedder/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ template("embedder_source_set") {
deps += [ "//flutter/shell/platform/darwin/graphics" ]
}

if (embedder_enable_vulkan) {
sources += [
"embedder_surface_vulkan.cc",
"embedder_surface_vulkan.h",
]
}

public_deps = [ ":embedder_headers" ]

public_configs += [
Expand Down Expand Up @@ -168,6 +175,8 @@ test_fixtures("fixtures") {
"fixtures/dpr_noxform.png",
"fixtures/dpr_xform.png",
"fixtures/gradient.png",
"fixtures/vk_dpr_noxform.png",
"fixtures/vk_gradient.png",
"fixtures/gradient_metal.png",
"fixtures/external_texture_metal.png",
"fixtures/gradient_xform.png",
Expand Down Expand Up @@ -250,6 +259,13 @@ if (enable_unittests) {
}

if (test_enable_vulkan) {
sources += [
"tests/embedder_test_compositor_vulkan.cc",
"tests/embedder_test_compositor_vulkan.h",
"tests/embedder_test_context_vulkan.cc",
"tests/embedder_test_context_vulkan.h",
]

deps += [
"//flutter/testing:vulkan",
"//flutter/vulkan",
Expand Down
Loading

0 comments on commit 57cb85a

Please sign in to comment.