[Impeller] Reland: Add Impeller Metal support in the embedder API (#42411) (flutter/engine#42545)

This reverts commit
45dd178414.

Original PR: https://github.com/flutter/engine/pull/42411

Part of https://github.com/flutter/flutter/issues/112230.
This commit is contained in:
Brandon DeRosier 2023-06-05 14:51:43 -07:00 committed by GitHub
parent cd6f44c544
commit fba5e2b514
51 changed files with 1154 additions and 240 deletions

View File

@ -1485,6 +1485,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.h + ../../.
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/texture_wrapper_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/texture_wrapper_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.cc + ../../../flutter/LICENSE
@ -2804,6 +2806,10 @@ ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target.cc + ../
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_impeller.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_impeller.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_skia.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_render_target_skia.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_struct_macros.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface.h + ../../../flutter/LICENSE
@ -2811,6 +2817,8 @@ ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc + ../../
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_gl.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_metal.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_metal.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_metal_impeller.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_metal_impeller.mm + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_software.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_software.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/shell/platform/embedder/embedder_surface_vulkan.cc + ../../../flutter/LICENSE
@ -4154,6 +4162,8 @@ FILE: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/surface_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/texture_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/texture_wrapper_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/texture_wrapper_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.h
FILE: ../../../flutter/impeller/renderer/backend/metal/vertex_descriptor_mtl.mm
FILE: ../../../flutter/impeller/renderer/backend/vulkan/allocator_vk.cc
@ -5489,6 +5499,10 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_render_target.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_render_target.h
FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_cache.h
FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_impeller.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_impeller.h
FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_skia.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_render_target_skia.h
FILE: ../../../flutter/shell/platform/embedder/embedder_struct_macros.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h
@ -5496,6 +5510,8 @@ FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.h
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_metal_impeller.h
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_metal_impeller.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

View File

@ -4,6 +4,7 @@
import("//build/fuchsia/sdk.gni")
import("//flutter/common/config.gni")
import("//flutter/impeller/tools/impeller.gni")
import("//flutter/shell/config.gni")
import("//flutter/testing/testing.gni")
@ -96,6 +97,10 @@ source_set("flow") {
"//third_party/skia",
]
if (impeller_supports_rendering) {
deps += [ "//flutter/impeller" ]
}
public_deps = [ "//flutter/display_list" ]
}

View File

@ -42,8 +42,10 @@ bool DisplayListEmbedderViewSlice::recording_ended() {
return builder_ == nullptr;
}
void ExternalViewEmbedder::SubmitFrame(GrDirectContext* context,
std::unique_ptr<SurfaceFrame> frame) {
void ExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) {
frame->Submit();
};

View File

@ -5,6 +5,7 @@
#ifndef FLUTTER_FLOW_EMBEDDED_VIEWS_H_
#define FLUTTER_FLOW_EMBEDDED_VIEWS_H_
#include <memory>
#include <vector>
#include "flutter/display_list/dl_builder.h"
@ -22,6 +23,16 @@
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkSurface.h"
#if IMPELLER_SUPPORTS_RENDERING
#include "flutter/impeller/aiks/aiks_context.h" // nogncheck
#include "flutter/impeller/renderer/context.h" // nogncheck
#else // IMPELLER_SUPPORTS_RENDERING
namespace impeller {
class Context;
class AiksContext;
} // namespace impeller
#endif // !IMPELLER_SUPPORTS_RENDERING
class GrDirectContext;
namespace flutter {
@ -414,8 +425,10 @@ class ExternalViewEmbedder {
// This method can mutate the root Skia canvas before submitting the frame.
//
// It can also allocate frames for overlay surfaces to compose hybrid views.
virtual void SubmitFrame(GrDirectContext* context,
std::unique_ptr<SurfaceFrame> frame);
virtual void SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame);
// This method provides the embedder a way to do additional tasks after
// |SubmitFrame|. For example, merge task runners if `should_resubmit_frame`

View File

@ -121,7 +121,7 @@ std::unique_ptr<Surface> PlaygroundImplMTL::AcquireSurfaceFrame(
auto drawable =
SurfaceMTL::GetMetalDrawableAndValidate(context, data_->metal_layer);
return SurfaceMTL::WrapCurrentMetalLayerDrawable(context, drawable);
return SurfaceMTL::MakeFromMetalLayerDrawable(context, drawable);
}
} // namespace impeller

View File

@ -42,6 +42,8 @@ impeller_component("metal") {
"surface_mtl.mm",
"texture_mtl.h",
"texture_mtl.mm",
"texture_wrapper_mtl.h",
"texture_wrapper_mtl.mm",
"vertex_descriptor_mtl.h",
"vertex_descriptor_mtl.mm",
]

View File

@ -21,6 +21,12 @@
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/context.h"
#if TARGET_OS_SIMULATOR
#define IMPELLER_CA_METAL_LAYER_AVAILABLE API_AVAILABLE(macos(10.11), ios(13.0))
#else // TARGET_OS_SIMULATOR
#define IMPELLER_CA_METAL_LAYER_AVAILABLE API_AVAILABLE(macos(10.11), ios(8.0))
#endif // TARGET_OS_SIMULATOR
namespace impeller {
class ContextMTL final : public Context,
@ -38,6 +44,14 @@ class ContextMTL final : public Context,
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
const std::string& label);
static std::shared_ptr<ContextMTL> Create(
id<MTLDevice> device,
id<MTLCommandQueue> command_queue,
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
const std::string& label);
// |Context|
~ContextMTL() override;
@ -90,6 +104,7 @@ class ContextMTL final : public Context,
ContextMTL(
id<MTLDevice> device,
id<MTLCommandQueue> command_queue,
NSArray<id<MTLLibrary>>* shader_libraries,
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch);

View File

@ -6,9 +6,11 @@
#include <Foundation/Foundation.h>
#include "flutter/fml/concurrent_message_loop.h"
#include "flutter/fml/file.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/synchronization/sync_switch.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/renderer/backend/metal/sampler_library_mtl.h"
#include "impeller/renderer/capabilities.h"
@ -67,10 +69,12 @@ static std::unique_ptr<Capabilities> InferMetalCapabilities(
ContextMTL::ContextMTL(
id<MTLDevice> device,
id<MTLCommandQueue> command_queue,
NSArray<id<MTLLibrary>>* shader_libraries,
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch)
: device_(device),
command_queue_(command_queue),
worker_task_runner_(std::move(worker_task_runner)),
is_gpu_disabled_sync_switch_(std::move(is_gpu_disabled_sync_switch)) {
// Validate device.
@ -96,16 +100,6 @@ ContextMTL::ContextMTL(
shader_library_ = std::move(library);
}
// Setup command queue.
{
command_queue_ = device_.newCommandQueue;
if (!command_queue_) {
VALIDATION_LOG << "Could not setup the command queue.";
return;
}
command_queue_.label = @"Impeller Command Queue";
}
// Setup the pipeline library.
{
pipeline_library_ =
@ -204,13 +198,28 @@ static id<MTLDevice> CreateMetalDevice() {
return ::MTLCreateSystemDefaultDevice();
}
static id<MTLCommandQueue> CreateMetalCommandQueue(id<MTLDevice> device) {
auto command_queue = device.newCommandQueue;
if (!command_queue) {
VALIDATION_LOG << "Could not setup the command queue.";
return nullptr;
}
command_queue.label = @"Impeller Command Queue";
return command_queue;
}
std::shared_ptr<ContextMTL> ContextMTL::Create(
const std::vector<std::string>& shader_library_paths,
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch) {
auto device = CreateMetalDevice();
auto command_queue = CreateMetalCommandQueue(device);
if (!command_queue) {
return nullptr;
}
auto context = std::shared_ptr<ContextMTL>(new ContextMTL(
device, MTLShaderLibraryFromFilePaths(device, shader_library_paths),
device, command_queue,
MTLShaderLibraryFromFilePaths(device, shader_library_paths),
std::move(worker_task_runner), std::move(is_gpu_disabled_sync_switch)));
if (!context->IsValid()) {
FML_LOG(ERROR) << "Could not create Metal context.";
@ -223,11 +232,35 @@ std::shared_ptr<ContextMTL> ContextMTL::Create(
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
const std::string& label) {
const std::string& library_label) {
auto device = CreateMetalDevice();
auto command_queue = CreateMetalCommandQueue(device);
if (!command_queue) {
return nullptr;
}
auto context = std::shared_ptr<ContextMTL>(new ContextMTL(
device,
MTLShaderLibraryFromFileData(device, shader_libraries_data, label),
device, command_queue,
MTLShaderLibraryFromFileData(device, shader_libraries_data,
library_label),
std::move(worker_task_runner), std::move(is_gpu_disabled_sync_switch)));
if (!context->IsValid()) {
FML_LOG(ERROR) << "Could not create Metal context.";
return nullptr;
}
return context;
}
std::shared_ptr<ContextMTL> ContextMTL::Create(
id<MTLDevice> device,
id<MTLCommandQueue> command_queue,
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_data,
std::shared_ptr<fml::ConcurrentTaskRunner> worker_task_runner,
std::shared_ptr<const fml::SyncSwitch> is_gpu_disabled_sync_switch,
const std::string& library_label) {
auto context = std::shared_ptr<ContextMTL>(new ContextMTL(
device, command_queue,
MTLShaderLibraryFromFileData(device, shader_libraries_data,
library_label),
std::move(worker_task_runner), std::move(is_gpu_disabled_sync_switch)));
if (!context->IsValid()) {
FML_LOG(ERROR) << "Could not create Metal context.";

View File

@ -5,6 +5,7 @@
#pragma once
#include <QuartzCore/CAMetalLayer.h>
#include <memory>
#include "flutter/fml/macros.h"
#include "impeller/geometry/rect.h"
@ -37,10 +38,15 @@ class SurfaceMTL final : public Surface {
const std::shared_ptr<Context>& context,
CAMetalLayer* layer);
static std::unique_ptr<SurfaceMTL> WrapCurrentMetalLayerDrawable(
static std::unique_ptr<SurfaceMTL> MakeFromMetalLayerDrawable(
const std::shared_ptr<Context>& context,
id<CAMetalDrawable> drawable,
std::optional<IRect> clip_rect = std::nullopt);
static std::unique_ptr<SurfaceMTL> MakeFromTexture(
const std::shared_ptr<Context>& context,
id<MTLTexture> texture,
std::optional<IRect> clip_rect);
#pragma GCC diagnostic pop
// |Surface|
@ -58,6 +64,8 @@ class SurfaceMTL final : public Surface {
std::weak_ptr<Context> context_;
std::shared_ptr<Texture> resolve_texture_;
id<CAMetalDrawable> drawable_ = nil;
std::shared_ptr<Texture> source_texture_;
std::shared_ptr<Texture> destination_texture_;
bool requires_blit_ = false;
std::optional<IRect> clip_rect_;
@ -67,6 +75,8 @@ class SurfaceMTL final : public Surface {
const RenderTarget& target,
std::shared_ptr<Texture> resolve_texture,
id<CAMetalDrawable> drawable,
std::shared_ptr<Texture> source_texture,
std::shared_ptr<Texture> destination_texture,
bool requires_blit,
std::optional<IRect> clip_rect);

View File

@ -7,6 +7,7 @@
#include "flutter/fml/trace_event.h"
#include "flutter/impeller/renderer/command_buffer.h"
#include "impeller/base/validation.h"
#include "impeller/core/texture_descriptor.h"
#include "impeller/renderer/backend/metal/context_mtl.h"
#include "impeller/renderer/backend/metal/formats_mtl.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"
@ -39,98 +40,142 @@ id<CAMetalDrawable> SurfaceMTL::GetMetalDrawableAndValidate(
return current_drawable;
}
std::unique_ptr<SurfaceMTL> SurfaceMTL::WrapCurrentMetalLayerDrawable(
const std::shared_ptr<Context>& context,
id<CAMetalDrawable> drawable,
static std::optional<RenderTarget> WrapTextureWithRenderTarget(
Allocator& allocator,
id<MTLTexture> texture,
bool requires_blit,
std::optional<IRect> clip_rect) {
bool requires_blit = ShouldPerformPartialRepaint(clip_rect);
const auto color_format = FromMTLPixelFormat(drawable.texture.pixelFormat);
if (color_format == PixelFormat::kUnknown) {
VALIDATION_LOG << "Unknown drawable color format.";
return nullptr;
}
// compositor_context.cc will offset the rendering by the clip origin. Here we
// shrink to the size of the clip. This has the same effect as clipping the
// rendering but also creates smaller intermediate passes.
ISize root_size;
if (requires_blit) {
if (!clip_rect.has_value()) {
VALIDATION_LOG << "Missing clip rectangle.";
return nullptr;
}
root_size = ISize(clip_rect->size.width, clip_rect->size.height);
} else {
root_size = {static_cast<ISize::Type>(drawable.texture.width),
static_cast<ISize::Type>(drawable.texture.height)};
}
TextureDescriptor msaa_tex_desc;
msaa_tex_desc.storage_mode = StorageMode::kDeviceTransient;
msaa_tex_desc.type = TextureType::kTexture2DMultisample;
msaa_tex_desc.sample_count = SampleCount::kCount4;
msaa_tex_desc.format = color_format;
msaa_tex_desc.size = root_size;
msaa_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);
auto msaa_tex = context->GetResourceAllocator()->CreateTexture(msaa_tex_desc);
if (!msaa_tex) {
VALIDATION_LOG << "Could not allocate MSAA color texture.";
return nullptr;
}
msaa_tex->SetLabel("ImpellerOnscreenColorMSAA");
TextureDescriptor resolve_tex_desc;
resolve_tex_desc.format = color_format;
resolve_tex_desc.size = msaa_tex_desc.size;
resolve_tex_desc.format = FromMTLPixelFormat(texture.pixelFormat);
resolve_tex_desc.size = {static_cast<ISize::Type>(texture.width),
static_cast<ISize::Type>(texture.height)};
resolve_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget) |
static_cast<uint64_t>(TextureUsage::kShaderRead);
resolve_tex_desc.sample_count = SampleCount::kCount1;
resolve_tex_desc.storage_mode = StorageMode::kDevicePrivate;
if (resolve_tex_desc.format == PixelFormat::kUnknown) {
VALIDATION_LOG << "Unknown drawable color format.";
return std::nullopt;
}
// Create color resolve texture.
std::shared_ptr<Texture> resolve_tex;
if (requires_blit) {
resolve_tex_desc.compression_type = CompressionType::kLossy;
resolve_tex =
context->GetResourceAllocator()->CreateTexture(resolve_tex_desc);
resolve_tex = allocator.CreateTexture(resolve_tex_desc);
} else {
resolve_tex =
std::make_shared<TextureMTL>(resolve_tex_desc, drawable.texture);
resolve_tex = std::make_shared<TextureMTL>(resolve_tex_desc, texture);
}
if (!resolve_tex) {
VALIDATION_LOG << "Could not wrap resolve texture.";
return nullptr;
return std::nullopt;
}
resolve_tex->SetLabel("ImpellerOnscreenResolve");
TextureDescriptor msaa_tex_desc;
msaa_tex_desc.storage_mode = StorageMode::kDeviceTransient;
msaa_tex_desc.type = TextureType::kTexture2DMultisample;
msaa_tex_desc.sample_count = SampleCount::kCount4;
msaa_tex_desc.format = resolve_tex->GetTextureDescriptor().format;
msaa_tex_desc.size = resolve_tex->GetSize();
msaa_tex_desc.usage = static_cast<uint64_t>(TextureUsage::kRenderTarget);
auto msaa_tex = allocator.CreateTexture(msaa_tex_desc);
if (!msaa_tex) {
VALIDATION_LOG << "Could not allocate MSAA color texture.";
return std::nullopt;
}
msaa_tex->SetLabel("ImpellerOnscreenColorMSAA");
ColorAttachment color0;
color0.texture = msaa_tex;
color0.clear_color = Color::DarkSlateGray();
color0.load_action = LoadAction::kClear;
color0.store_action = StoreAction::kMultisampleResolve;
color0.resolve_texture = resolve_tex;
color0.resolve_texture = std::move(resolve_tex);
RenderTarget render_target_desc;
render_target_desc.SetColorAttachment(color0, 0u);
auto render_target_desc = std::make_optional<RenderTarget>();
render_target_desc->SetColorAttachment(color0, 0u);
// The constructor is private. So make_unique may not be used.
return std::unique_ptr<SurfaceMTL>(new SurfaceMTL(context, render_target_desc,
resolve_tex, drawable,
requires_blit, clip_rect));
return render_target_desc;
}
std::unique_ptr<SurfaceMTL> SurfaceMTL::MakeFromMetalLayerDrawable(
const std::shared_ptr<Context>& context,
id<CAMetalDrawable> drawable,
std::optional<IRect> clip_rect) {
bool requires_blit = ShouldPerformPartialRepaint(clip_rect);
auto render_target =
WrapTextureWithRenderTarget(*context->GetResourceAllocator(),
drawable.texture, requires_blit, clip_rect);
if (!render_target) {
return nullptr;
}
auto source_texture =
requires_blit ? render_target->GetRenderTargetTexture() : nullptr;
auto destination_texture = TextureMTL::Wrapper(
render_target->GetRenderTargetTexture()->GetTextureDescriptor(),
drawable.texture);
return std::unique_ptr<SurfaceMTL>(new SurfaceMTL(
context, // context
*render_target, // target
render_target->GetRenderTargetTexture(), // resolve_texture
drawable, // drawable
source_texture, // source_texture
destination_texture, // destination_texture
requires_blit, // requires_blit
clip_rect // clip_rect
));
}
std::unique_ptr<SurfaceMTL> SurfaceMTL::MakeFromTexture(
const std::shared_ptr<Context>& context,
id<MTLTexture> texture,
std::optional<IRect> clip_rect) {
bool requires_blit = ShouldPerformPartialRepaint(clip_rect);
auto render_target = WrapTextureWithRenderTarget(
*context->GetResourceAllocator(), texture, requires_blit, clip_rect);
if (!render_target) {
return nullptr;
}
auto source_texture =
requires_blit ? render_target->GetRenderTargetTexture() : nullptr;
auto destination_texture = TextureMTL::Wrapper(
render_target->GetRenderTargetTexture()->GetTextureDescriptor(), texture);
return std::unique_ptr<SurfaceMTL>(new SurfaceMTL(
context, // context
*render_target, // target
render_target->GetRenderTargetTexture(), // resolve_texture
nil, // drawable
source_texture, // source_texture
destination_texture, // destination_texture
requires_blit, // requires_blit
clip_rect // clip_rect
));
}
SurfaceMTL::SurfaceMTL(const std::weak_ptr<Context>& context,
const RenderTarget& target,
std::shared_ptr<Texture> resolve_texture,
id<CAMetalDrawable> drawable,
std::shared_ptr<Texture> source_texture,
std::shared_ptr<Texture> destination_texture,
bool requires_blit,
std::optional<IRect> clip_rect)
: Surface(target),
context_(context),
resolve_texture_(std::move(resolve_texture)),
drawable_(drawable),
source_texture_(std::move(source_texture)),
destination_texture_(std::move(destination_texture)),
requires_blit_(requires_blit),
clip_rect_(clip_rect) {}
@ -173,16 +218,16 @@ static bool ShouldWaitForCommandBuffer() {
// |Surface|
bool SurfaceMTL::Present() const {
if (drawable_ == nil) {
return false;
}
auto context = context_.lock();
if (!context) {
return false;
}
if (requires_blit_) {
if (!(source_texture_ && destination_texture_)) {
return false;
}
auto blit_command_buffer = context->CreateCommandBuffer();
if (!blit_command_buffer) {
return false;
@ -192,8 +237,7 @@ bool SurfaceMTL::Present() const {
VALIDATION_LOG << "Missing clip rectangle.";
return false;
}
auto current = TextureMTL::Wrapper({}, drawable_.texture);
blit_pass->AddCopy(resolve_texture_, current, std::nullopt,
blit_pass->AddCopy(source_texture_, destination_texture_, std::nullopt,
clip_rect_->origin);
blit_pass->EncodeCommands(context->GetResourceAllocator());
if (!blit_command_buffer->SubmitCommands()) {
@ -201,13 +245,15 @@ bool SurfaceMTL::Present() const {
}
}
if (ShouldWaitForCommandBuffer()) {
id<MTLCommandBuffer> command_buffer =
ContextMTL::Cast(context.get())->CreateMTLCommandBuffer();
[command_buffer commit];
[command_buffer waitUntilScheduled];
if (drawable_) {
if (ShouldWaitForCommandBuffer()) {
id<MTLCommandBuffer> command_buffer =
ContextMTL::Cast(context.get())->CreateMTLCommandBuffer();
[command_buffer commit];
[command_buffer waitUntilScheduled];
}
[drawable_ present];
}
[drawable_ present];
return true;
}

View File

@ -19,8 +19,10 @@ class TextureMTL final : public Texture,
id<MTLTexture> texture,
bool wrapped = false);
static std::shared_ptr<TextureMTL> Wrapper(TextureDescriptor desc,
id<MTLTexture> texture);
static std::shared_ptr<TextureMTL> Wrapper(
TextureDescriptor desc,
id<MTLTexture> texture,
std::function<void()> deletion_proc = nullptr);
// |Texture|
~TextureMTL() override;

View File

@ -9,6 +9,13 @@
namespace impeller {
std::shared_ptr<Texture> WrapperMTL(TextureDescriptor desc,
const void* mtl_texture,
std::function<void()> deletion_proc) {
return TextureMTL::Wrapper(desc, (__bridge id<MTLTexture>)mtl_texture,
std::move(deletion_proc));
}
TextureMTL::TextureMTL(TextureDescriptor p_desc,
id<MTLTexture> texture,
bool wrapped)
@ -28,9 +35,18 @@ TextureMTL::TextureMTL(TextureDescriptor p_desc,
is_valid_ = true;
}
std::shared_ptr<TextureMTL> TextureMTL::Wrapper(TextureDescriptor desc,
id<MTLTexture> texture) {
return std::make_shared<TextureMTL>(desc, texture, true);
std::shared_ptr<TextureMTL> TextureMTL::Wrapper(
TextureDescriptor desc,
id<MTLTexture> texture,
std::function<void()> deletion_proc) {
if (deletion_proc) {
return std::shared_ptr<TextureMTL>(
new TextureMTL(desc, texture, true),
[deletion_proc = std::move(deletion_proc)](TextureMTL* t) {
deletion_proc();
});
}
return std::shared_ptr<TextureMTL>(new TextureMTL(desc, texture, true));
}
TextureMTL::~TextureMTL() = default;

View File

@ -0,0 +1,16 @@
// 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.
#pragma once
#include "impeller/core/texture.h"
namespace impeller {
std::shared_ptr<Texture> WrapTextureMTL(
TextureDescriptor desc,
const void* mtl_texture,
std::function<void()> deletion_proc = nullptr);
} // namespace impeller

View File

@ -0,0 +1,22 @@
// 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 "impeller/renderer/backend/metal/texture_wrapper_mtl.h"
#include <Metal/Metal.h>
#include "impeller/renderer/backend/metal/formats_mtl.h"
#include "impeller/renderer/backend/metal/texture_mtl.h"
namespace impeller {
std::shared_ptr<Texture> WrapTextureMTL(TextureDescriptor desc,
const void* mtl_texture,
std::function<void()> deletion_proc) {
auto texture = (__bridge id<MTLTexture>)mtl_texture;
desc.format = FromMTLPixelFormat(texture.pixelFormat);
return TextureMTL::Wrapper(desc, texture, std::move(deletion_proc));
}
} // namespace impeller

View File

@ -627,8 +627,8 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe(
if (external_view_embedder_ &&
(!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
FML_DCHECK(!frame->IsSubmitted());
external_view_embedder_->SubmitFrame(surface_->GetContext(),
std::move(frame));
external_view_embedder_->SubmitFrame(
surface_->GetContext(), surface_->GetAiksContext(), std::move(frame));
} else {
frame->Submit();
}

View File

@ -74,8 +74,9 @@ class MockExternalViewEmbedder : public ExternalViewEmbedder {
PostPrerollResult(
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger));
MOCK_METHOD1(CompositeEmbeddedView, DlCanvas*(int64_t view_id));
MOCK_METHOD2(SubmitFrame,
MOCK_METHOD3(SubmitFrame,
void(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame));
MOCK_METHOD2(EndFrame,
void(bool should_resubmit_frame,

View File

@ -91,6 +91,7 @@ DlCanvas* ShellTestExternalViewEmbedder::CompositeEmbeddedView(
// |ExternalViewEmbedder|
void ShellTestExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) {
if (!frame) {
return;

View File

@ -75,6 +75,7 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder {
// |ExternalViewEmbedder|
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) override;
// |ExternalViewEmbedder|

View File

@ -5,22 +5,25 @@
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_IMPELLER_H_
#define FLUTTER_SHELL_GPU_GPU_SURFACE_METAL_IMPELLER_H_
#include <QuartzCore/CAMetalLayer.h>
#include <Metal/Metal.h>
#include "flutter/flow/surface.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/impeller/aiks/aiks_context.h"
#include "flutter/impeller/renderer/backend/metal/context_mtl.h"
#include "flutter/impeller/renderer/renderer.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
#include "third_party/skia/include/gpu/mtl/GrMtlTypes.h"
namespace flutter {
class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalImpeller : public Surface {
class IMPELLER_CA_METAL_LAYER_AVAILABLE GPUSurfaceMetalImpeller
: public Surface {
public:
GPUSurfaceMetalImpeller(GPUSurfaceMetalDelegate* delegate,
const std::shared_ptr<impeller::Context>& context);
const std::shared_ptr<impeller::Context>& context,
bool render_to_surface = true);
// |Surface|
~GPUSurfaceMetalImpeller();
@ -32,16 +35,29 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalImpeller : public Surface {
private:
const GPUSurfaceMetalDelegate* delegate_;
const MTLRenderTargetType render_target_type_;
std::shared_ptr<impeller::Renderer> impeller_renderer_;
std::shared_ptr<impeller::AiksContext> aiks_context_;
fml::scoped_nsprotocol<id<MTLDrawable>> last_drawable_;
fml::scoped_nsprotocol<id<MTLTexture>> last_texture_;
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface. This is a
// hack to make avoid allocating resources for the root surface when an
// external view embedder is present.
bool render_to_surface_ = true;
bool disable_partial_repaint_ = false;
// Accumulated damage for each framebuffer; Key is address of underlying
// MTLTexture for each drawable
std::map<uintptr_t, SkIRect> damage_;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
std::unique_ptr<SurfaceFrame> AcquireFrame(
const SkISize& frame_size) override;
std::unique_ptr<SurfaceFrame> AcquireFrameFromCAMetalLayer(
const SkISize& frame_size);
std::unique_ptr<SurfaceFrame> AcquireFrameFromMTLTexture(
const SkISize& frame_size);
// |Surface|
SkMatrix GetRootTransformation() const override;

View File

@ -29,11 +29,14 @@ static std::shared_ptr<impeller::Renderer> CreateImpellerRenderer(
}
GPUSurfaceMetalImpeller::GPUSurfaceMetalImpeller(GPUSurfaceMetalDelegate* delegate,
const std::shared_ptr<impeller::Context>& context)
const std::shared_ptr<impeller::Context>& context,
bool render_to_surface)
: delegate_(delegate),
render_target_type_(delegate->GetRenderTargetType()),
impeller_renderer_(CreateImpellerRenderer(context)),
aiks_context_(
std::make_shared<impeller::AiksContext>(impeller_renderer_ ? context : nullptr)) {
std::make_shared<impeller::AiksContext>(impeller_renderer_ ? context : nullptr)),
render_to_surface_(render_to_surface) {
// If this preference is explicitly set, we allow for disabling partial repaint.
NSNumber* disablePartialRepaint =
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTDisablePartialRepaint"];
@ -50,7 +53,7 @@ bool GPUSurfaceMetalImpeller::IsValid() {
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISize& frame_info) {
std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISize& frame_size) {
TRACE_EVENT0("impeller", "GPUSurfaceMetalImpeller::AcquireFrame");
if (!IsValid()) {
@ -58,7 +61,33 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISiz
return nullptr;
}
auto layer = delegate_->GetCAMetalLayer(frame_info);
if (frame_size.isEmpty()) {
FML_LOG(ERROR) << "Metal 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, DlCanvas* canvas) { return true; }, frame_size);
}
switch (render_target_type_) {
case MTLRenderTargetType::kCAMetalLayer:
return AcquireFrameFromCAMetalLayer(frame_size);
case MTLRenderTargetType::kMTLTexture:
return AcquireFrameFromMTLTexture(frame_size);
default:
FML_CHECK(false) << "Unknown MTLRenderTargetType type.";
}
return nullptr;
}
std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLayer(
const SkISize& frame_size) {
auto layer = delegate_->GetCAMetalLayer(frame_size);
if (!layer) {
FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder.";
return nullptr;
@ -69,15 +98,16 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISiz
auto drawable = impeller::SurfaceMTL::GetMetalDrawableAndValidate(
impeller_renderer_->GetContext(), mtl_layer);
if (Settings::kSurfaceDataAccessible) {
last_drawable_.reset([drawable retain]);
last_texture_.reset([drawable.texture retain]);
}
id<CAMetalDrawable> metal_drawable = static_cast<id<CAMetalDrawable>>(last_drawable_);
id<MTLTexture> last_texture = static_cast<id<MTLTexture>>(last_texture_);
SurfaceFrame::SubmitCallback submit_callback =
fml::MakeCopyable([this, //
renderer = impeller_renderer_, //
aiks_context = aiks_context_, //
metal_drawable //
drawable, //
last_texture //
](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool {
if (!aiks_context) {
return false;
@ -90,7 +120,7 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISiz
}
if (!disable_partial_repaint_) {
uintptr_t texture = reinterpret_cast<uintptr_t>(metal_drawable.texture);
uintptr_t texture = reinterpret_cast<uintptr_t>(last_texture);
for (auto& entry : damage_) {
if (entry.first != texture) {
@ -111,8 +141,8 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISiz
buffer_damage->width(), buffer_damage->height());
}
auto surface = impeller::SurfaceMTL::WrapCurrentMetalLayerDrawable(
impeller_renderer_->GetContext(), metal_drawable, clip_rect);
auto surface = impeller::SurfaceMTL::MakeFromMetalLayerDrawable(
impeller_renderer_->GetContext(), drawable, clip_rect);
if (clip_rect && (clip_rect->size.width == 0 || clip_rect->size.height == 0)) {
return surface->Present();
@ -138,7 +168,7 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISiz
if (!disable_partial_repaint_) {
// Provide accumulated damage to rasterizer (area in current framebuffer that lags behind
// front buffer)
uintptr_t texture = reinterpret_cast<uintptr_t>(metal_drawable.texture);
uintptr_t texture = reinterpret_cast<uintptr_t>(drawable.texture);
auto i = damage_.find(texture);
if (i != damage_.end()) {
framebuffer_info.existing_damage = i->second;
@ -149,7 +179,107 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrame(const SkISiz
return std::make_unique<SurfaceFrame>(nullptr, // surface
framebuffer_info, // framebuffer info
submit_callback, // submit callback
frame_info, // frame size
frame_size, // frame size
nullptr, // context result
true // display list fallback
);
}
std::unique_ptr<SurfaceFrame> GPUSurfaceMetalImpeller::AcquireFrameFromMTLTexture(
const SkISize& frame_size) {
GPUMTLTextureInfo texture_info = delegate_->GetMTLTexture(frame_size);
id<MTLTexture> mtl_texture = (id<MTLTexture>)(texture_info.texture);
if (!mtl_texture) {
FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder.";
return nullptr;
}
if (Settings::kSurfaceDataAccessible) {
last_texture_.reset([mtl_texture retain]);
}
SurfaceFrame::SubmitCallback submit_callback =
fml::MakeCopyable([this, //
renderer = impeller_renderer_, //
aiks_context = aiks_context_, //
texture_info, //
mtl_texture, //
delegate = delegate_ //
](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool {
if (!aiks_context) {
return false;
}
auto display_list = surface_frame.BuildDisplayList();
if (!display_list) {
FML_LOG(ERROR) << "Could not build display list for surface frame.";
return false;
}
if (!disable_partial_repaint_) {
uintptr_t texture_ptr = reinterpret_cast<uintptr_t>(mtl_texture);
for (auto& entry : damage_) {
if (entry.first != texture_ptr) {
// Accumulate damage for other framebuffers
if (surface_frame.submit_info().frame_damage) {
entry.second.join(*surface_frame.submit_info().frame_damage);
}
}
}
// Reset accumulated damage for current framebuffer
damage_[texture_ptr] = SkIRect::MakeEmpty();
}
std::optional<impeller::IRect> clip_rect;
if (surface_frame.submit_info().buffer_damage.has_value()) {
auto buffer_damage = surface_frame.submit_info().buffer_damage;
clip_rect = impeller::IRect::MakeXYWH(buffer_damage->x(), buffer_damage->y(),
buffer_damage->width(), buffer_damage->height());
}
auto surface =
impeller::SurfaceMTL::MakeFromTexture(renderer->GetContext(), mtl_texture, clip_rect);
if (clip_rect && (clip_rect->size.width == 0 || clip_rect->size.height == 0)) {
return surface->Present();
}
impeller::IRect cull_rect = surface->coverage();
SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.size.width, cull_rect.size.height);
impeller::DlDispatcher impeller_dispatcher(cull_rect);
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
auto picture = impeller_dispatcher.EndRecordingAsPicture();
return renderer->Render(
std::move(surface),
fml::MakeCopyable([aiks_context, picture = std::move(picture)](
impeller::RenderTarget& render_target) -> bool {
return aiks_context->Render(picture, render_target);
}));
delegate->PresentTexture(texture_info);
});
SurfaceFrame::FramebufferInfo framebuffer_info;
framebuffer_info.supports_readback = true;
if (!disable_partial_repaint_) {
// Provide accumulated damage to rasterizer (area in current framebuffer that lags behind
// front buffer)
uintptr_t texture = reinterpret_cast<uintptr_t>(mtl_texture);
auto i = damage_.find(texture);
if (i != damage_.end()) {
framebuffer_info.existing_damage = i->second;
}
framebuffer_info.supports_partial_repaint = true;
}
return std::make_unique<SurfaceFrame>(nullptr, // surface
framebuffer_info, // framebuffer info
submit_callback, // submit callback
frame_size, // frame size
nullptr, // context result
true // display list fallback
);
@ -188,11 +318,10 @@ std::shared_ptr<impeller::AiksContext> GPUSurfaceMetalImpeller::GetAiksContext()
}
Surface::SurfaceData GPUSurfaceMetalImpeller::GetSurfaceData() const {
if (!(last_drawable_ && [last_drawable_ conformsToProtocol:@protocol(CAMetalDrawable)])) {
if (!(last_texture_ && [last_texture_ conformsToProtocol:@protocol(MTLTexture)])) {
return {};
}
id<CAMetalDrawable> metal_drawable = static_cast<id<CAMetalDrawable>>(last_drawable_);
id<MTLTexture> texture = metal_drawable.texture;
id<MTLTexture> texture = last_texture_.get();
int bytesPerPixel = 0;
std::string pixel_format;
switch (texture.pixelFormat) {

View File

@ -64,6 +64,7 @@ SkRect AndroidExternalViewEmbedder::GetViewRect(int64_t view_id) const {
// |ExternalViewEmbedder|
void AndroidExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) {
TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::SubmitFrame");

View File

@ -46,6 +46,7 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder {
// |ExternalViewEmbedder|
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) override;
// |ExternalViewEmbedder|

View File

@ -313,7 +313,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) {
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
// Submits frame if no Android view in the current frame.
EXPECT_TRUE(did_submit_frame);
// Doesn't resubmit frame.
@ -381,7 +381,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) {
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
// Doesn't submit frame if there aren't Android views in the previous frame.
EXPECT_FALSE(did_submit_frame);
// Resubmits frame.
@ -446,7 +446,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) {
return true;
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
// Submits frame if there are Android views in the previous frame.
EXPECT_TRUE(did_submit_frame);
// Doesn't resubmit frame.
@ -553,7 +553,7 @@ TEST(AndroidExternalViewEmbedder, OverlayCoverTwoPlatformViews) {
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
@ -656,7 +656,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrameOverlayComposition) {
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
@ -724,7 +724,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFramePlatformViewWithoutAnyOverlay) {
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
@ -825,7 +825,7 @@ TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) {
return true;
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
@ -912,7 +912,7 @@ TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) {
return true;
},
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
EXPECT_CALL(*jni_mock, FlutterViewEndFrame());
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);
@ -1023,7 +1023,7 @@ TEST(AndroidExternalViewEmbedder, Teardown) {
SkSurfaces::Null(1000, 1000), framebuffer_info,
[](const SurfaceFrame& surface_frame, DlCanvas* canvas) { return true; },
/*frame_size=*/SkISize::Make(800, 600));
embedder->SubmitFrame(gr_context.get(), std::move(surface_frame));
embedder->SubmitFrame(gr_context.get(), nullptr, std::move(surface_frame));
embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger);

View File

@ -51,6 +51,7 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder {
// |ExternalViewEmbedder|
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) override;
// |ExternalViewEmbedder|

View File

@ -66,8 +66,10 @@ DlCanvas* IOSExternalViewEmbedder::CompositeEmbeddedView(int64_t view_id) {
}
// |ExternalViewEmbedder|
void IOSExternalViewEmbedder::SubmitFrame(GrDirectContext* context,
std::unique_ptr<SurfaceFrame> frame) {
void IOSExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) {
TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::SubmitFrame");
FML_CHECK(platform_views_controller_);
platform_views_controller_->SubmitFrame(context, ios_context_, std::move(frame));

View File

@ -5,6 +5,7 @@
import("//build/toolchain/clang.gni")
import("//flutter/build/zip_bundle.gni")
import("//flutter/common/config.gni")
import("//flutter/impeller/tools/impeller.gni")
import("//flutter/shell/gpu/gpu.gni")
import("//flutter/shell/platform/embedder/embedder.gni")
import("//flutter/testing/testing.gni")
@ -75,6 +76,8 @@ template("embedder_source_set") {
"embedder_render_target.h",
"embedder_render_target_cache.cc",
"embedder_render_target_cache.h",
"embedder_render_target_skia.cc",
"embedder_render_target_skia.h",
"embedder_struct_macros.h",
"embedder_surface.cc",
"embedder_surface.h",
@ -91,6 +94,8 @@ template("embedder_source_set") {
"vsync_waiter_embedder.h",
]
public_deps = [ ":embedder_headers" ]
if (embedder_enable_gl) {
sources += [
"embedder_external_texture_gl.cc",
@ -116,6 +121,15 @@ template("embedder_source_set") {
"//third_party/skia",
]
if (impeller_supports_rendering) {
sources += [
"embedder_render_target_impeller.cc",
"embedder_render_target_impeller.h",
]
deps += [ "//flutter/impeller" ]
}
if (embedder_enable_metal) {
sources += [
"embedder_external_texture_metal.h",
@ -124,6 +138,13 @@ template("embedder_source_set") {
"embedder_surface_metal.mm",
]
if (impeller_supports_rendering) {
sources += [
"embedder_surface_metal_impeller.h",
"embedder_surface_metal_impeller.mm",
]
}
cflags_objc = flutter_cflags_objc
cflags_objcc = flutter_cflags_objcc
@ -142,12 +163,11 @@ template("embedder_source_set") {
]
}
public_deps = [ ":embedder_headers" ]
public_configs += [
":embedder_gpu_configuration_config",
":embedder_header_config",
"//flutter:config",
"//flutter/impeller:impeller_public_config",
]
}
}

View File

@ -55,6 +55,7 @@ extern const intptr_t kPlatformStrongDillSize;
#include "flutter/shell/platform/embedder/embedder_external_texture_resolver.h"
#include "flutter/shell/platform/embedder/embedder_platform_message_response.h"
#include "flutter/shell/platform/embedder/embedder_render_target.h"
#include "flutter/shell/platform/embedder/embedder_render_target_skia.h"
#include "flutter/shell/platform/embedder/embedder_struct_macros.h"
#include "flutter/shell/platform/embedder/embedder_task_runner.h"
#include "flutter/shell/platform/embedder/embedder_thread_host.h"
@ -70,7 +71,14 @@ extern const intptr_t kPlatformStrongDillSize;
#ifdef SHELL_ENABLE_METAL
#include "flutter/shell/platform/embedder/embedder_surface_metal.h"
#include "third_party/skia/include/ports/SkCFObject.h"
#endif
#ifdef IMPELLER_SUPPORTS_RENDERING
#include "flutter/shell/platform/embedder/embedder_render_target_impeller.h" // nogncheck
#include "flutter/shell/platform/embedder/embedder_surface_metal_impeller.h" // nogncheck
#include "impeller/core/texture.h" // nogncheck
#include "impeller/renderer/backend/metal/texture_wrapper_mtl.h" // nogncheck
#include "impeller/renderer/render_target.h" // nogncheck
#endif // IMPELLER_SUPPORTS_RENDERING
#endif // SHELL_ENABLE_METAL
const int32_t kFlutterSemanticsNodeIdBatchEnd = -1;
const int32_t kFlutterSemanticsCustomActionIdBatchEnd = -1;
@ -454,7 +462,8 @@ InferMetalPlatformViewCreationCallback(
const flutter::PlatformViewEmbedder::PlatformDispatchTable&
platform_dispatch_table,
std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
external_view_embedder) {
external_view_embedder,
bool enable_impeller) {
if (config->type != kMetal) {
return nullptr;
}
@ -488,20 +497,33 @@ InferMetalPlatformViewCreationCallback(
return texture_info;
};
flutter::EmbedderSurfaceMetal::MetalDispatchTable metal_dispatch_table = {
.present = metal_present,
.get_texture = metal_get_texture,
};
std::shared_ptr<flutter::EmbedderExternalViewEmbedder> view_embedder =
std::move(external_view_embedder);
std::unique_ptr<flutter::EmbedderSurfaceMetal> embedder_surface =
std::make_unique<flutter::EmbedderSurfaceMetal>(
const_cast<flutter::GPUMTLDeviceHandle>(config->metal.device),
const_cast<flutter::GPUMTLCommandQueueHandle>(
config->metal.present_command_queue),
metal_dispatch_table, view_embedder);
std::unique_ptr<flutter::EmbedderSurface> embedder_surface;
if (enable_impeller) {
flutter::EmbedderSurfaceMetalImpeller::MetalDispatchTable
metal_dispatch_table = {
.present = metal_present,
.get_texture = metal_get_texture,
};
embedder_surface = std::make_unique<flutter::EmbedderSurfaceMetalImpeller>(
const_cast<flutter::GPUMTLDeviceHandle>(config->metal.device),
const_cast<flutter::GPUMTLCommandQueueHandle>(
config->metal.present_command_queue),
metal_dispatch_table, view_embedder);
} else {
flutter::EmbedderSurfaceMetal::MetalDispatchTable metal_dispatch_table = {
.present = metal_present,
.get_texture = metal_get_texture,
};
embedder_surface = std::make_unique<flutter::EmbedderSurfaceMetal>(
const_cast<flutter::GPUMTLDeviceHandle>(config->metal.device),
const_cast<flutter::GPUMTLCommandQueueHandle>(
config->metal.present_command_queue),
metal_dispatch_table, view_embedder);
}
// The static leak checker gets confused by the use of fml::MakeCopyable.
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
@ -652,7 +674,8 @@ InferPlatformViewCreationCallback(
const flutter::PlatformViewEmbedder::PlatformDispatchTable&
platform_dispatch_table,
std::unique_ptr<flutter::EmbedderExternalViewEmbedder>
external_view_embedder) {
external_view_embedder,
bool enable_impeller) {
if (config == nullptr) {
return nullptr;
}
@ -669,7 +692,7 @@ InferPlatformViewCreationCallback(
case kMetal:
return InferMetalPlatformViewCreationCallback(
config, user_data, platform_dispatch_table,
std::move(external_view_embedder));
std::move(external_view_embedder), enable_impeller);
case kVulkan:
return InferVulkanPlatformViewCreationCallback(
config, user_data, platform_dispatch_table,
@ -899,6 +922,76 @@ static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
#endif
}
static std::unique_ptr<flutter::EmbedderRenderTarget>
MakeRenderTargetFromBackingStoreImpeller(
FlutterBackingStore backing_store,
const fml::closure& on_release,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
const FlutterBackingStoreConfig& config,
const FlutterMetalBackingStore* metal) {
#if defined(SHELL_ENABLE_METAL) && defined(IMPELLER_SUPPORTS_RENDERING)
if (!metal->texture.texture) {
FML_LOG(ERROR) << "Embedder supplied null Metal texture.";
return nullptr;
}
const auto size = impeller::ISize(config.size.width, config.size.height);
impeller::TextureDescriptor resolve_tex_desc;
resolve_tex_desc.size = size;
resolve_tex_desc.sample_count = impeller::SampleCount::kCount1;
resolve_tex_desc.storage_mode = impeller::StorageMode::kDevicePrivate;
resolve_tex_desc.usage =
static_cast<uint64_t>(impeller::TextureUsage::kRenderTarget) |
static_cast<uint64_t>(impeller::TextureUsage::kShaderRead);
auto resolve_tex = impeller::WrapTextureMTL(
resolve_tex_desc, metal->texture.texture,
[callback = metal->texture.destruction_callback,
user_data = metal->texture.user_data]() { callback(user_data); });
if (!resolve_tex) {
FML_LOG(ERROR) << "Could not wrap embedder supplied Metal render texture.";
return nullptr;
}
resolve_tex->SetLabel("ImpellerBackingStoreResolve");
impeller::TextureDescriptor msaa_tex_desc;
msaa_tex_desc.storage_mode = impeller::StorageMode::kDeviceTransient;
msaa_tex_desc.type = impeller::TextureType::kTexture2DMultisample;
msaa_tex_desc.sample_count = impeller::SampleCount::kCount4;
msaa_tex_desc.format = resolve_tex->GetTextureDescriptor().format;
msaa_tex_desc.size = size;
msaa_tex_desc.usage =
static_cast<uint64_t>(impeller::TextureUsage::kRenderTarget);
auto msaa_tex =
aiks_context->GetContext()->GetResourceAllocator()->CreateTexture(
msaa_tex_desc);
if (!msaa_tex) {
FML_LOG(ERROR) << "Could not allocate MSAA color texture.";
return nullptr;
}
msaa_tex->SetLabel("ImpellerBackingStoreColorMSAA");
impeller::ColorAttachment color0;
color0.texture = msaa_tex;
color0.clear_color = impeller::Color::DarkSlateGray();
color0.load_action = impeller::LoadAction::kClear;
color0.store_action = impeller::StoreAction::kMultisampleResolve;
color0.resolve_texture = resolve_tex;
impeller::RenderTarget render_target_desc;
render_target_desc.SetColorAttachment(color0, 0u);
return std::make_unique<flutter::EmbedderRenderTargetImpeller>(
backing_store, aiks_context,
std::make_unique<impeller::RenderTarget>(std::move(render_target_desc)),
on_release);
#else
return nullptr;
#endif
}
static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
GrDirectContext* context,
const FlutterBackingStoreConfig& config,
@ -953,9 +1046,23 @@ static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
}
static std::unique_ptr<flutter::EmbedderRenderTarget>
CreateEmbedderRenderTarget(const FlutterCompositor* compositor,
const FlutterBackingStoreConfig& config,
GrDirectContext* context) {
MakeRenderTargetFromSkSurface(FlutterBackingStore backing_store,
sk_sp<SkSurface> skia_surface,
fml::closure on_release) {
if (!skia_surface) {
return nullptr;
}
return std::make_unique<flutter::EmbedderRenderTargetSkia>(
backing_store, std::move(skia_surface), std::move(on_release));
}
static std::unique_ptr<flutter::EmbedderRenderTarget>
CreateEmbedderRenderTarget(
const FlutterCompositor* compositor,
const FlutterBackingStoreConfig& config,
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
bool enable_impeller) {
FlutterBackingStore backing_store = {};
backing_store.struct_size = sizeof(backing_store);
@ -990,53 +1097,77 @@ CreateEmbedderRenderTarget(const FlutterCompositor* compositor,
// No safe access checks on the renderer are necessary since we allocated
// the struct.
sk_sp<SkSurface> render_surface;
std::unique_ptr<flutter::EmbedderRenderTarget> render_target;
switch (backing_store.type) {
case kFlutterBackingStoreTypeOpenGL:
case kFlutterBackingStoreTypeOpenGL: {
switch (backing_store.open_gl.type) {
case kFlutterOpenGLTargetTypeTexture:
render_surface = MakeSkSurfaceFromBackingStore(
case kFlutterOpenGLTargetTypeTexture: {
auto skia_surface = MakeSkSurfaceFromBackingStore(
context, config, &backing_store.open_gl.texture);
render_target = MakeRenderTargetFromSkSurface(
backing_store, std::move(skia_surface),
collect_callback.Release());
break;
case kFlutterOpenGLTargetTypeFramebuffer:
render_surface = MakeSkSurfaceFromBackingStore(
}
case kFlutterOpenGLTargetTypeFramebuffer: {
auto skia_surface = MakeSkSurfaceFromBackingStore(
context, config, &backing_store.open_gl.framebuffer);
render_target = MakeRenderTargetFromSkSurface(
backing_store, std::move(skia_surface),
collect_callback.Release());
break;
}
}
break;
case kFlutterBackingStoreTypeSoftware:
render_surface = MakeSkSurfaceFromBackingStore(context, config,
&backing_store.software);
}
case kFlutterBackingStoreTypeSoftware: {
auto skia_surface = MakeSkSurfaceFromBackingStore(
context, config, &backing_store.software);
render_target = MakeRenderTargetFromSkSurface(
backing_store, std::move(skia_surface), collect_callback.Release());
break;
case kFlutterBackingStoreTypeSoftware2:
render_surface = MakeSkSurfaceFromBackingStore(context, config,
&backing_store.software2);
}
case kFlutterBackingStoreTypeSoftware2: {
auto skia_surface = MakeSkSurfaceFromBackingStore(
context, config, &backing_store.software2);
render_target = MakeRenderTargetFromSkSurface(
backing_store, std::move(skia_surface), collect_callback.Release());
break;
case kFlutterBackingStoreTypeMetal:
render_surface =
MakeSkSurfaceFromBackingStore(context, config, &backing_store.metal);
}
case kFlutterBackingStoreTypeMetal: {
if (enable_impeller) {
auto impeller_target = MakeRenderTargetFromBackingStoreImpeller(
backing_store, collect_callback.Release(), aiks_context, config,
&backing_store.metal);
} else {
auto skia_surface = MakeSkSurfaceFromBackingStore(context, config,
&backing_store.metal);
render_target = MakeRenderTargetFromSkSurface(
backing_store, std::move(skia_surface), collect_callback.Release());
}
break;
case kFlutterBackingStoreTypeVulkan:
render_surface =
}
case kFlutterBackingStoreTypeVulkan: {
auto skia_surface =
MakeSkSurfaceFromBackingStore(context, config, &backing_store.vulkan);
render_target = MakeRenderTargetFromSkSurface(
backing_store, std::move(skia_surface), collect_callback.Release());
break;
}
};
if (!render_surface) {
if (!render_target) {
FML_LOG(ERROR) << "Could not create a surface from an embedder provided "
"render target.";
return nullptr;
}
return std::make_unique<flutter::EmbedderRenderTarget>(
backing_store, std::move(render_surface), collect_callback.Release());
return render_target;
}
static std::pair<std::unique_ptr<flutter::EmbedderExternalViewEmbedder>,
bool /* halt engine launch if true */>
InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor) {
InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
bool enable_impeller) {
if (compositor == nullptr) {
return {nullptr, false};
}
@ -1060,9 +1191,13 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor) {
flutter::EmbedderExternalViewEmbedder::CreateRenderTargetCallback
create_render_target_callback =
[captured_compositor](GrDirectContext* context, const auto& config) {
[captured_compositor, enable_impeller](
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
const auto& config) {
return CreateEmbedderRenderTarget(&captured_compositor, config,
context);
context, aiks_context,
enable_impeller);
};
flutter::EmbedderExternalViewEmbedder::PresentCallback present_callback =
@ -1814,8 +1949,8 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
user_data]() { return ptr(user_data); };
}
auto external_view_embedder_result =
InferExternalViewEmbedderFromArgs(SAFE_ACCESS(args, compositor, nullptr));
auto external_view_embedder_result = InferExternalViewEmbedderFromArgs(
SAFE_ACCESS(args, compositor, nullptr), settings.enable_impeller);
if (external_view_embedder_result.second) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Compositor arguments were invalid.");
@ -1832,7 +1967,7 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
auto on_create_platform_view = InferPlatformViewCreationCallback(
config, user_data, platform_dispatch_table,
std::move(external_view_embedder_result.first));
std::move(external_view_embedder_result.first), settings.enable_impeller);
if (!on_create_platform_view) {
return LOG_EMBEDDER_ERROR(

View File

@ -3,9 +3,15 @@
// found in the LICENSE file.
#include "flutter/shell/platform/embedder/embedder_external_view.h"
#include "flutter/display_list/dl_builder.h"
#include "flutter/fml/trace_event.h"
#include "flutter/shell/common/dl_op_spy.h"
#ifdef IMPELLER_SUPPORTS_RENDERING
#include "impeller/display_list/dl_dispatcher.h"
#endif // IMPELLER_SUPPORTS_RENDERING
namespace flutter {
static SkISize TransformedSurfaceSize(const SkISize& size,
@ -83,15 +89,30 @@ bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target) {
<< "Unnecessarily asked to render into a render target when there was "
"nothing to render.";
auto surface = render_target.GetRenderSurface();
if (!surface) {
#ifdef IMPELLER_SUPPORTS_RENDERING
auto* impeller_target = render_target.GetImpellerRenderTarget();
if (impeller_target) {
auto aiks_context = render_target.GetAiksContext();
auto dl_builder = DisplayListBuilder();
dl_builder.SetTransform(&surface_transformation_);
slice_->render_into(&dl_builder);
auto dispatcher = impeller::DlDispatcher();
dispatcher.drawDisplayList(dl_builder.Build(), 1);
return aiks_context->Render(dispatcher.EndRecordingAsPicture(),
*impeller_target);
}
#endif // IMPELLER_SUPPORTS_RENDERING
auto skia_surface = render_target.GetSkiaSurface();
if (!skia_surface) {
return false;
}
FML_DCHECK(SkISize::Make(surface->width(), surface->height()) ==
render_surface_size_);
FML_DCHECK(render_target.GetRenderTargetSize() == render_surface_size_);
auto canvas = surface->getCanvas();
auto canvas = skia_surface->getCanvas();
if (!canvas) {
return false;
}

View File

@ -125,6 +125,7 @@ static FlutterBackingStoreConfig MakeBackingStoreConfig(
// |ExternalViewEmbedder|
void EmbedderExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) {
auto [matched_render_targets, pending_keys] =
render_target_cache_.GetExistingTargetsInCache(pending_views_);
@ -172,8 +173,8 @@ void EmbedderExternalViewEmbedder::SubmitFrame(
// the context must be reset.
//
// @warning: Embedder may trample on our OpenGL context here.
auto render_target =
create_render_target_callback_(context, backing_store_config);
auto render_target = create_render_target_callback_(context, aiks_context,
backing_store_config);
if (!render_target) {
FML_LOG(ERROR) << "Embedder did not return a valid render target.";

View File

@ -6,6 +6,7 @@
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_VIEW_EMBEDDER_H_
#include <map>
#include <memory>
#include <unordered_map>
#include "flutter/flow/embedded_views.h"
@ -31,6 +32,7 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder {
using CreateRenderTargetCallback =
std::function<std::unique_ptr<EmbedderRenderTarget>(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
const FlutterBackingStoreConfig& config)>;
using PresentCallback =
std::function<bool(const std::vector<const FlutterLayer*>& layers)>;
@ -95,6 +97,7 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder {
// |ExternalViewEmbedder|
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<SurfaceFrame> frame) override;
// |ExternalViewEmbedder|

View File

@ -4,24 +4,17 @@
#include "flutter/shell/platform/embedder/embedder_render_target.h"
#include <optional>
#include <utility>
#include "flutter/fml/logging.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace flutter {
EmbedderRenderTarget::EmbedderRenderTarget(FlutterBackingStore backing_store,
sk_sp<SkSurface> render_surface,
fml::closure on_release)
: backing_store_(backing_store),
render_surface_(std::move(render_surface)),
on_release_(std::move(on_release)) {
: backing_store_(backing_store), on_release_(std::move(on_release)) {
// TODO(38468): The optimization to elide backing store updates between frames
// has not been implemented yet.
backing_store_.did_update = true;
FML_DCHECK(render_surface_);
}
EmbedderRenderTarget::~EmbedderRenderTarget() {
@ -34,8 +27,4 @@ const FlutterBackingStore* EmbedderRenderTarget::GetBackingStore() const {
return &backing_store_;
}
sk_sp<SkSurface> EmbedderRenderTarget::GetRenderSurface() const {
return render_surface_;
}
} // namespace flutter

View File

@ -5,12 +5,18 @@
#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_H_
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_H_
#include <memory>
#include "flutter/fml/closure.h"
#include "flutter/fml/macros.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace impeller {
class RenderTarget;
class AiksContext;
} // namespace impeller
namespace flutter {
//------------------------------------------------------------------------------
@ -21,29 +27,12 @@ namespace flutter {
///
class EmbedderRenderTarget {
public:
//----------------------------------------------------------------------------
/// @brief Creates a render target whose backing store is managed by the
/// embedder. The way this render target is exposed to the engine
/// is via an SkSurface and a callback that is invoked by this
/// object in its destructor.
///
/// @param[in] backing_store The backing store describing this render
/// target.
/// @param[in] render_surface The surface for this target.
/// @param[in] on_release The callback to invoke (eventually forwarded
/// to the embedder) when the backing store is no
/// longer required by the engine.
///
EmbedderRenderTarget(FlutterBackingStore backing_store,
sk_sp<SkSurface> render_surface,
fml::closure on_release);
//----------------------------------------------------------------------------
/// @brief Destroys this instance of the render target and invokes the
/// callback for the embedder to release its resource associated
/// with the particular backing store.
///
~EmbedderRenderTarget();
virtual ~EmbedderRenderTarget();
//----------------------------------------------------------------------------
/// @brief A render surface the rasterizer can use to draw into the
@ -51,7 +40,30 @@ class EmbedderRenderTarget {
///
/// @return The render surface.
///
sk_sp<SkSurface> GetRenderSurface() const;
virtual sk_sp<SkSurface> GetSkiaSurface() const = 0;
//----------------------------------------------------------------------------
/// @brief An impeller render target the rasterizer can use to draw into
/// the backing store.
///
/// @return The Impeller render target.
///
virtual impeller::RenderTarget* GetImpellerRenderTarget() const = 0;
//----------------------------------------------------------------------------
/// @brief Returns the AiksContext that should be used for rendering, if
/// this render target is backed by Impeller.
///
/// @return The Impeller Aiks context.
///
virtual std::shared_ptr<impeller::AiksContext> GetAiksContext() const = 0;
//----------------------------------------------------------------------------
/// @brief Returns the size of the render target.
///
/// @return The size of the render target.
///
virtual SkISize GetRenderTargetSize() const = 0;
//----------------------------------------------------------------------------
/// @brief The embedder backing store descriptor. This is the descriptor
@ -65,9 +77,25 @@ class EmbedderRenderTarget {
///
const FlutterBackingStore* GetBackingStore() const;
protected:
//----------------------------------------------------------------------------
/// @brief Creates a render target whose backing store is managed by the
/// embedder. The way this render target is exposed to the engine
/// is via an SkSurface and a callback that is invoked by this
/// object in its destructor.
///
/// @param[in] backing_store The backing store describing this render
/// target.
/// @param[in] on_release The callback to invoke (eventually forwarded
/// to the embedder) when the backing store is no
/// longer required by the engine.
///
EmbedderRenderTarget(FlutterBackingStore backing_store,
fml::closure on_release);
private:
FlutterBackingStore backing_store_;
sk_sp<SkSurface> render_surface_;
fml::closure on_release_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTarget);

View File

@ -56,9 +56,8 @@ void EmbedderRenderTargetCache::CacheRenderTarget(
if (target == nullptr) {
return;
}
auto surface = target->GetRenderSurface();
auto desc = EmbedderExternalView::RenderTargetDescriptor{
view_identifier, SkISize::Make(surface->width(), surface->height())};
view_identifier, target->GetRenderTargetSize()};
cached_render_targets_[desc].push(std::move(target));
}

View File

@ -0,0 +1,45 @@
// 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/platform/embedder/embedder_render_target_impeller.h"
#include "flutter/fml/logging.h"
#include "flutter/impeller/renderer/render_target.h"
namespace flutter {
EmbedderRenderTargetImpeller::EmbedderRenderTargetImpeller(
FlutterBackingStore backing_store,
std::shared_ptr<impeller::AiksContext> aiks_context,
std::unique_ptr<impeller::RenderTarget> impeller_target,
fml::closure on_release)
: EmbedderRenderTarget(backing_store, std::move(on_release)),
aiks_context_(std::move(aiks_context)),
impeller_target_(std::move(impeller_target)) {
FML_DCHECK(aiks_context_);
FML_DCHECK(impeller_target_);
}
EmbedderRenderTargetImpeller::~EmbedderRenderTargetImpeller() = default;
sk_sp<SkSurface> EmbedderRenderTargetImpeller::GetSkiaSurface() const {
return nullptr;
}
impeller::RenderTarget* EmbedderRenderTargetImpeller::GetImpellerRenderTarget()
const {
return impeller_target_.get();
}
std::shared_ptr<impeller::AiksContext>
EmbedderRenderTargetImpeller::GetAiksContext() const {
return aiks_context_;
}
SkISize EmbedderRenderTargetImpeller::GetRenderTargetSize() const {
auto size = impeller_target_->GetRenderTargetSize();
return SkISize::Make(size.width, size.height);
}
} // namespace flutter

View File

@ -0,0 +1,44 @@
// 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.
#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_IMPELLER_H_
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_IMPELLER_H_
#include "flutter/shell/platform/embedder/embedder_render_target.h"
namespace flutter {
class EmbedderRenderTargetImpeller final : public EmbedderRenderTarget {
public:
EmbedderRenderTargetImpeller(
FlutterBackingStore backing_store,
std::shared_ptr<impeller::AiksContext> aiks_context,
std::unique_ptr<impeller::RenderTarget> impeller_target,
fml::closure on_release);
// |EmbedderRenderTarget|
~EmbedderRenderTargetImpeller() override;
// |EmbedderRenderTarget|
sk_sp<SkSurface> GetSkiaSurface() const override;
// |EmbedderRenderTarget|
impeller::RenderTarget* GetImpellerRenderTarget() const override;
// |EmbedderRenderTarget|
std::shared_ptr<impeller::AiksContext> GetAiksContext() const override;
// |EmbedderRenderTarget|
SkISize GetRenderTargetSize() const override;
private:
std::shared_ptr<impeller::AiksContext> aiks_context_;
std::unique_ptr<impeller::RenderTarget> impeller_target_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTargetImpeller);
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_IMPELLER_H_

View File

@ -0,0 +1,40 @@
// 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/platform/embedder/embedder_render_target_skia.h"
#include "flutter/fml/logging.h"
namespace flutter {
EmbedderRenderTargetSkia::EmbedderRenderTargetSkia(
FlutterBackingStore backing_store,
sk_sp<SkSurface> render_surface,
fml::closure on_release)
: EmbedderRenderTarget(backing_store, std::move(on_release)),
render_surface_(std::move(render_surface)) {
FML_DCHECK(render_surface_);
}
EmbedderRenderTargetSkia::~EmbedderRenderTargetSkia() = default;
sk_sp<SkSurface> EmbedderRenderTargetSkia::GetSkiaSurface() const {
return render_surface_;
}
impeller::RenderTarget* EmbedderRenderTargetSkia::GetImpellerRenderTarget()
const {
return nullptr;
}
std::shared_ptr<impeller::AiksContext>
EmbedderRenderTargetSkia::GetAiksContext() const {
return nullptr;
}
SkISize EmbedderRenderTargetSkia::GetRenderTargetSize() const {
return SkISize::Make(render_surface_->width(), render_surface_->height());
}
} // namespace flutter

View File

@ -0,0 +1,41 @@
// 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.
#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_SKIA_H_
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_SKIA_H_
#include "flutter/shell/platform/embedder/embedder_render_target.h"
namespace flutter {
class EmbedderRenderTargetSkia final : public EmbedderRenderTarget {
public:
EmbedderRenderTargetSkia(FlutterBackingStore backing_store,
sk_sp<SkSurface> render_surface,
fml::closure on_release);
// |EmbedderRenderTarget|
~EmbedderRenderTargetSkia() override;
// |EmbedderRenderTarget|
sk_sp<SkSurface> GetSkiaSurface() const override;
// |EmbedderRenderTarget|
impeller::RenderTarget* GetImpellerRenderTarget() const override;
// |EmbedderRenderTarget|
std::shared_ptr<impeller::AiksContext> GetAiksContext() const override;
// |EmbedderRenderTarget|
SkISize GetRenderTargetSize() const override;
private:
sk_sp<SkSurface> render_surface_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTargetSkia);
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_RENDER_TARGET_SKIA_H_

View File

@ -10,4 +10,13 @@ EmbedderSurface::EmbedderSurface() = default;
EmbedderSurface::~EmbedderSurface() = default;
std::shared_ptr<impeller::Context> EmbedderSurface::CreateImpellerContext()
const {
return nullptr;
}
sk_sp<GrDirectContext> EmbedderSurface::CreateResourceContext() const {
return nullptr;
}
} // namespace flutter

View File

@ -5,6 +5,7 @@
#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_H_
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_H_
#include <memory>
#include "flutter/flow/embedded_views.h"
#include "flutter/flow/surface.h"
#include "flutter/fml/macros.h"
@ -21,7 +22,9 @@ class EmbedderSurface {
virtual std::unique_ptr<Surface> CreateGPUSurface() = 0;
virtual sk_sp<GrDirectContext> CreateResourceContext() const = 0;
virtual std::shared_ptr<impeller::Context> CreateImpellerContext() const;
virtual sk_sp<GrDirectContext> CreateResourceContext() const;
private:
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurface);

View File

@ -0,0 +1,70 @@
// 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.
#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_METAL_IMPELLER_H_
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_METAL_IMPELLER_H_
#include <memory>
#include "flutter/fml/macros.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
#include "flutter/shell/gpu/gpu_surface_metal_skia.h"
#include "flutter/shell/platform/embedder/embedder_external_view_embedder.h"
#include "flutter/shell/platform/embedder/embedder_surface.h"
#include "fml/concurrent_message_loop.h"
namespace impeller {
class Context;
}
namespace flutter {
class EmbedderSurfaceMetalImpeller final : public EmbedderSurface,
public GPUSurfaceMetalDelegate {
public:
struct MetalDispatchTable {
std::function<bool(GPUMTLTextureInfo texture)> present; // required
std::function<GPUMTLTextureInfo(const SkISize& frame_size)>
get_texture; // required
};
EmbedderSurfaceMetalImpeller(
GPUMTLDeviceHandle device,
GPUMTLCommandQueueHandle command_queue,
MetalDispatchTable dispatch_table,
std::shared_ptr<EmbedderExternalViewEmbedder> external_view_embedder);
~EmbedderSurfaceMetalImpeller() override;
private:
bool valid_ = false;
MetalDispatchTable metal_dispatch_table_;
std::shared_ptr<EmbedderExternalViewEmbedder> external_view_embedder_;
std::shared_ptr<impeller::Context> context_;
std::shared_ptr<fml::ConcurrentMessageLoop> concurrent_loop_;
// |EmbedderSurface|
bool IsValid() const override;
// |EmbedderSurface|
std::unique_ptr<Surface> CreateGPUSurface() override;
// |GPUSurfaceMetalDelegate|
GPUCAMetalLayerHandle GetCAMetalLayer(
const SkISize& frame_size) const override;
// |GPUSurfaceMetalDelegate|
bool PresentDrawable(GrMTLHandle drawable) const override;
// |GPUSurfaceMetalDelegate|
GPUMTLTextureInfo GetMTLTexture(const SkISize& frame_size) const override;
// |GPUSurfaceMetalDelegate|
bool PresentTexture(GPUMTLTextureInfo texture) const override;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceMetalImpeller);
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_SURFACE_METAL_IMPELLER_H_

View File

@ -0,0 +1,97 @@
// 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 <memory>
#include <utility>
#include "flutter/shell/platform/embedder/embedder_surface_metal_impeller.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/synchronization/sync_switch.h"
#include "flutter/shell/gpu/gpu_surface_metal_delegate.h"
#include "flutter/shell/gpu/gpu_surface_metal_impeller.h"
#import "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h"
#include "impeller/entity/mtl/entity_shaders.h"
#include "impeller/entity/mtl/framebuffer_blend_shaders.h"
#include "impeller/entity/mtl/modern_shaders.h"
#include "impeller/renderer/backend/metal/context_mtl.h"
#include "impeller/scene/shaders/mtl/scene_shaders.h"
FLUTTER_ASSERT_NOT_ARC
namespace flutter {
EmbedderSurfaceMetalImpeller::EmbedderSurfaceMetalImpeller(
GPUMTLDeviceHandle device,
GPUMTLCommandQueueHandle command_queue,
MetalDispatchTable metal_dispatch_table,
std::shared_ptr<EmbedderExternalViewEmbedder> external_view_embedder)
: GPUSurfaceMetalDelegate(MTLRenderTargetType::kMTLTexture),
metal_dispatch_table_(std::move(metal_dispatch_table)),
external_view_embedder_(std::move(external_view_embedder)),
concurrent_loop_(fml::ConcurrentMessageLoop::Create()) {
std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_data,
impeller_entity_shaders_length),
std::make_shared<fml::NonOwnedMapping>(impeller_scene_shaders_data,
impeller_scene_shaders_length),
std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_data,
impeller_modern_shaders_length),
std::make_shared<fml::NonOwnedMapping>(impeller_framebuffer_blend_shaders_data,
impeller_framebuffer_blend_shaders_length),
};
context_ = impeller::ContextMTL::Create(
(id<MTLDevice>)device, // device
(id<MTLCommandQueue>)command_queue, // command_queue
shader_mappings, // shader_libraries_data
concurrent_loop_->GetTaskRunner(), // worker_task_runner
std::make_shared<fml::SyncSwitch>(false), // is_gpu_disabled_sync_switch
"Impeller Library" // library_label
);
valid_ = !!context_;
}
EmbedderSurfaceMetalImpeller::~EmbedderSurfaceMetalImpeller() = default;
bool EmbedderSurfaceMetalImpeller::IsValid() const {
return valid_;
}
std::unique_ptr<Surface> EmbedderSurfaceMetalImpeller::CreateGPUSurface()
IMPELLER_CA_METAL_LAYER_AVAILABLE {
if (!IsValid()) {
return nullptr;
}
const bool render_to_surface = !external_view_embedder_;
auto surface = std::make_unique<GPUSurfaceMetalImpeller>(this, context_, render_to_surface);
if (!surface->IsValid()) {
return nullptr;
}
return surface;
}
GPUCAMetalLayerHandle EmbedderSurfaceMetalImpeller::GetCAMetalLayer(
const SkISize& frame_info) const {
FML_CHECK(false) << "Only rendering to MTLTexture is supported.";
return nullptr;
}
bool EmbedderSurfaceMetalImpeller::PresentDrawable(GrMTLHandle drawable) const {
FML_CHECK(false) << "Only rendering to MTLTexture is supported.";
return false;
}
GPUMTLTextureInfo EmbedderSurfaceMetalImpeller::GetMTLTexture(const SkISize& frame_info) const {
return metal_dispatch_table_.get_texture(frame_info);
}
bool EmbedderSurfaceMetalImpeller::PresentTexture(GPUMTLTextureInfo texture) const {
return metal_dispatch_table_.present(texture);
}
} // namespace flutter

View File

@ -86,7 +86,7 @@ PlatformViewEmbedder::PlatformViewEmbedder(
PlatformViewEmbedder::PlatformViewEmbedder(
PlatformView::Delegate& delegate,
const flutter::TaskRunners& task_runners,
std::unique_ptr<EmbedderSurfaceMetal> embedder_surface,
std::unique_ptr<EmbedderSurface> embedder_surface,
PlatformDispatchTable platform_dispatch_table,
std::shared_ptr<EmbedderExternalViewEmbedder> external_view_embedder)
: PlatformView(delegate, task_runners),
@ -157,6 +157,11 @@ PlatformViewEmbedder::CreateExternalViewEmbedder() {
return external_view_embedder_;
}
std::shared_ptr<impeller::Context> PlatformViewEmbedder::GetImpellerContext()
const {
return embedder_surface_->CreateImpellerContext();
}
// |PlatformView|
sk_sp<GrDirectContext> PlatformViewEmbedder::CreateResourceContext() const {
if (embedder_surface_ == nullptr) {

View File

@ -76,7 +76,7 @@ class PlatformViewEmbedder final : public PlatformView {
PlatformViewEmbedder(
PlatformView::Delegate& delegate,
const flutter::TaskRunners& task_runners,
std::unique_ptr<EmbedderSurfaceMetal> embedder_surface,
std::unique_ptr<EmbedderSurface> embedder_surface,
PlatformDispatchTable platform_dispatch_table,
std::shared_ptr<EmbedderExternalViewEmbedder> external_view_embedder);
#endif
@ -118,6 +118,9 @@ class PlatformViewEmbedder final : public PlatformView {
// |PlatformView|
std::shared_ptr<ExternalViewEmbedder> CreateExternalViewEmbedder() override;
// |PlatformView|
std::shared_ptr<impeller::Context> GetImpellerContext() const override;
// |PlatformView|
sk_sp<GrDirectContext> CreateResourceContext() const override;

View File

@ -132,6 +132,7 @@ void FlatlandExternalViewEmbedder::EndFrame(
void FlatlandExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<flutter::SurfaceFrame> frame) {
TRACE_EVENT0("flutter", "FlatlandExternalViewEmbedder::SubmitFrame");
std::vector<std::unique_ptr<SurfaceProducerSurface>> frame_surfaces;

View File

@ -87,6 +87,7 @@ class FlatlandExternalViewEmbedder final
// |ExternalViewEmbedder|
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<flutter::SurfaceFrame> frame) override;
// |ExternalViewEmbedder|

View File

@ -231,6 +231,7 @@ void GfxExternalViewEmbedder::EndFrame(
void GfxExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<flutter::SurfaceFrame> frame) {
TRACE_EVENT0("flutter", "GfxExternalViewEmbedder::SubmitFrame");
std::vector<std::unique_ptr<SurfaceProducerSurface>> frame_surfaces;

View File

@ -110,6 +110,7 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
// |ExternalViewEmbedder|
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<flutter::SurfaceFrame> frame) override;
// |ExternalViewEmbedder|

View File

@ -54,6 +54,7 @@ class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder {
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override {}
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<flutter::SurfaceFrame> frame) override {}
void PrerollCompositeEmbeddedView(

View File

@ -335,11 +335,12 @@ void DrawSimpleFrame(FlatlandExternalViewEmbedder& external_view_embedder,
flutter::SurfaceFrame::FramebufferInfo framebuffer_info;
framebuffer_info.supports_readback = true;
external_view_embedder.SubmitFrame(
nullptr, std::make_unique<flutter::SurfaceFrame>(
nullptr, std::move(framebuffer_info),
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
nullptr, nullptr,
std::make_unique<flutter::SurfaceFrame>(
nullptr, std::move(framebuffer_info),
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
}
void DrawFrameWithView(
@ -365,11 +366,12 @@ void DrawFrameWithView(
flutter::SurfaceFrame::FramebufferInfo framebuffer_info;
framebuffer_info.supports_readback = true;
external_view_embedder.SubmitFrame(
nullptr, std::make_unique<flutter::SurfaceFrame>(
nullptr, std::move(framebuffer_info),
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
nullptr, nullptr,
std::make_unique<flutter::SurfaceFrame>(
nullptr, std::move(framebuffer_info),
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
}
}; // namespace

View File

@ -53,6 +53,7 @@ class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder {
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override {}
void SubmitFrame(GrDirectContext* context,
const std::shared_ptr<impeller::AiksContext>& aiks_context,
std::unique_ptr<flutter::SurfaceFrame> frame) override {}
void PrerollCompositeEmbeddedView(

View File

@ -458,11 +458,12 @@ void DrawSimpleFrame(GfxExternalViewEmbedder& external_view_embedder,
external_view_embedder.EndFrame(false, nullptr);
flutter::SurfaceFrame::FramebufferInfo framebuffer_info;
external_view_embedder.SubmitFrame(
nullptr, std::make_unique<flutter::SurfaceFrame>(
nullptr, framebuffer_info,
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
nullptr, nullptr,
std::make_unique<flutter::SurfaceFrame>(
nullptr, framebuffer_info,
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
}
void DrawFrameWithView(
@ -487,11 +488,12 @@ void DrawFrameWithView(
external_view_embedder.EndFrame(false, nullptr);
flutter::SurfaceFrame::FramebufferInfo framebuffer_info;
external_view_embedder.SubmitFrame(
nullptr, std::make_unique<flutter::SurfaceFrame>(
nullptr, framebuffer_info,
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
nullptr, nullptr,
std::make_unique<flutter::SurfaceFrame>(
nullptr, framebuffer_info,
[](const flutter::SurfaceFrame& surface_frame,
flutter::DlCanvas* canvas) { return true; },
frame_size));
}
FramePresentedInfo MakeFramePresentedInfoForOnePresent(