Skip to content

Commit 5407bdd

Browse files
author
George Wright
authored
Add Metal to the FlutterCompositor struct in the Embedder API (flutter#25612)
1 parent fbdddfc commit 5407bdd

19 files changed

+644
-25
lines changed

shell/gpu/gpu_surface_metal.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ namespace flutter {
1616
class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
1717
public:
1818
GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate,
19-
sk_sp<GrDirectContext> context);
19+
sk_sp<GrDirectContext> context,
20+
bool render_to_surface = true);
2021

2122
// |Surface|
2223
~GPUSurfaceMetal();
@@ -30,6 +31,11 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface {
3031
GrMTLHandle next_drawable_ = nullptr;
3132
sk_sp<GrDirectContext> context_;
3233
GrDirectContext* precompiled_sksl_context_ = nullptr;
34+
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
35+
// external view embedder may want to render to the root surface. This is a
36+
// hack to make avoid allocating resources for the root surface when an
37+
// external view embedder is present.
38+
bool render_to_surface_;
3339

3440
// |Surface|
3541
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;

shell/gpu/gpu_surface_metal.mm

+10-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@
1919

2020
namespace flutter {
2121

22-
GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate, sk_sp<GrDirectContext> context)
22+
GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceMetalDelegate* delegate,
23+
sk_sp<GrDirectContext> context,
24+
bool render_to_surface)
2325
: delegate_(delegate),
2426
render_target_type_(delegate->GetRenderTargetType()),
25-
context_(std::move(context)) {}
27+
context_(std::move(context)),
28+
render_to_surface_(render_to_surface) {}
2629

2730
GPUSurfaceMetal::~GPUSurfaceMetal() {
2831
ReleaseUnusedDrawableIfNecessary();
@@ -55,6 +58,11 @@
5558
return nullptr;
5659
}
5760

61+
if (!render_to_surface_) {
62+
return std::make_unique<SurfaceFrame>(
63+
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; });
64+
}
65+
5866
PrecompileKnownSkSLsIfNecessary();
5967

6068
switch (render_target_type_) {

shell/platform/embedder/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ if (enable_unittests) {
230230

231231
if (test_enable_metal) {
232232
sources += [
233+
"tests/embedder_test_compositor_metal.cc",
234+
"tests/embedder_test_compositor_metal.h",
233235
"tests/embedder_test_context_metal.cc",
234236
"tests/embedder_test_context_metal.h",
235237
"tests/embedder_unittests_metal.mm",

shell/platform/embedder/embedder.cc

+49
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,51 @@ static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
565565
return surface;
566566
}
567567

568+
static sk_sp<SkSurface> MakeSkSurfaceFromBackingStore(
569+
GrDirectContext* context,
570+
const FlutterBackingStoreConfig& config,
571+
const FlutterMetalBackingStore* metal) {
572+
#ifdef SHELL_ENABLE_METAL
573+
GrMtlTextureInfo texture_info;
574+
if (!metal->texture.texture) {
575+
FML_LOG(ERROR) << "Embedder supplied null Metal texture.";
576+
return nullptr;
577+
}
578+
sk_cf_obj<FlutterMetalTextureHandle> mtl_texture;
579+
mtl_texture.retain(metal->texture.texture);
580+
texture_info.fTexture = mtl_texture;
581+
GrBackendTexture backend_texture(config.size.width, //
582+
config.size.height, //
583+
GrMipMapped::kNo, //
584+
texture_info //
585+
);
586+
587+
SkSurfaceProps surface_properties(0, kUnknown_SkPixelGeometry);
588+
589+
auto surface = SkSurface::MakeFromBackendTexture(
590+
context, // context
591+
backend_texture, // back-end texture
592+
kTopLeft_GrSurfaceOrigin, // surface origin
593+
1, // sample count
594+
kBGRA_8888_SkColorType, // color type
595+
nullptr, // color space
596+
&surface_properties, // surface properties
597+
static_cast<SkSurface::TextureReleaseProc>(
598+
metal->texture.destruction_callback), // release proc
599+
metal->texture.user_data // release context
600+
);
601+
602+
if (!surface) {
603+
FML_LOG(ERROR) << "Could not wrap embedder supplied Metal render texture.";
604+
return nullptr;
605+
}
606+
607+
return surface;
608+
#else
609+
return nullptr;
610+
#endif
611+
}
612+
568613
static std::unique_ptr<flutter::EmbedderRenderTarget>
569614
CreateEmbedderRenderTarget(const FlutterCompositor* compositor,
570615
const FlutterBackingStoreConfig& config,
@@ -622,6 +667,10 @@ CreateEmbedderRenderTarget(const FlutterCompositor* compositor,
622667
render_surface = MakeSkSurfaceFromBackingStore(context, config,
623668
&backing_store.software);
624669
break;
670+
case kFlutterBackingStoreTypeMetal:
671+
render_surface =
672+
MakeSkSurfaceFromBackingStore(context, config, &backing_store.metal);
673+
break;
625674
};
626675

627676
if (!render_surface) {

shell/platform/embedder/embedder.h

+22
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,13 @@ typedef struct {
495495
/// Handle to the MTLTexture that is owned by the embedder. Engine will render
496496
/// the frame into this texture.
497497
FlutterMetalTextureHandle texture;
498+
/// A baton that is not interpreted by the engine in any way. It will be given
499+
/// back to the embedder in the destruction callback below. Embedder resources
500+
/// may be associated with this baton.
501+
void* user_data;
502+
/// The callback invoked by the engine when it no longer needs this backing
503+
/// store.
504+
VoidCallback destruction_callback;
498505
} FlutterMetalTexture;
499506

500507
/// Callback for when a metal texture is requested.
@@ -944,6 +951,17 @@ typedef struct {
944951
VoidCallback destruction_callback;
945952
} FlutterSoftwareBackingStore;
946953

954+
typedef struct {
955+
/// The size of this struct. Must be sizeof(FlutterMetalBackingStore).
956+
size_t struct_size;
957+
union {
958+
// A Metal texture for Flutter to render into. Ownership is not transferred
959+
// to Flutter; the texture is CFRetained on successfully being passed in and
960+
// CFReleased when no longer used.
961+
FlutterMetalTexture texture;
962+
};
963+
} FlutterMetalBackingStore;
964+
947965
typedef enum {
948966
/// Indicates that the Flutter application requested that an opacity be
949967
/// applied to the platform view.
@@ -1001,6 +1019,8 @@ typedef enum {
10011019
kFlutterBackingStoreTypeOpenGL,
10021020
/// Specified an software allocation for Flutter to render into using the CPU.
10031021
kFlutterBackingStoreTypeSoftware,
1022+
/// Specifies a Metal backing store. This is backed by a Metal texture.
1023+
kFlutterBackingStoreTypeMetal,
10041024
} FlutterBackingStoreType;
10051025

10061026
typedef struct {
@@ -1020,6 +1040,8 @@ typedef struct {
10201040
FlutterOpenGLBackingStore open_gl;
10211041
/// The description of the software backing store.
10221042
FlutterSoftwareBackingStore software;
1043+
// The description of the Metal backing store.
1044+
FlutterMetalBackingStore metal;
10231045
};
10241046
} FlutterBackingStore;
10251047

shell/platform/embedder/embedder_surface_metal.mm

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
return nullptr;
4040
}
4141

42-
auto surface = std::make_unique<GPUSurfaceMetal>(this, main_context_);
42+
const bool render_to_surface = !external_view_embedder_;
43+
auto surface = std::make_unique<GPUSurfaceMetal>(this, main_context_, render_to_surface);
4344

4445
if (!surface->IsValid()) {
4546
return nullptr;

shell/platform/embedder/tests/embedder_assertions.h

+29
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,16 @@ inline bool operator==(const FlutterOpenGLFramebuffer& a,
6565
a.destruction_callback == b.destruction_callback;
6666
}
6767

68+
inline bool operator==(const FlutterMetalTexture& a,
69+
const FlutterMetalTexture& b) {
70+
return a.texture_id == b.texture_id && a.texture == b.texture;
71+
}
72+
73+
inline bool operator==(const FlutterMetalBackingStore& a,
74+
const FlutterMetalBackingStore& b) {
75+
return a.texture == b.texture;
76+
}
77+
6878
inline bool operator==(const FlutterOpenGLBackingStore& a,
6979
const FlutterOpenGLBackingStore& b) {
7080
if (!(a.type == b.type)) {
@@ -100,6 +110,8 @@ inline bool operator==(const FlutterBackingStore& a,
100110
return a.open_gl == b.open_gl;
101111
case kFlutterBackingStoreTypeSoftware:
102112
return a.software == b.software;
113+
case kFlutterBackingStoreTypeMetal:
114+
return a.metal == b.metal;
103115
}
104116

105117
return false;
@@ -216,6 +228,8 @@ inline std::string FlutterBackingStoreTypeToString(
216228
return "kFlutterBackingStoreTypeOpenGL";
217229
case kFlutterBackingStoreTypeSoftware:
218230
return "kFlutterBackingStoreTypeSoftware";
231+
case kFlutterBackingStoreTypeMetal:
232+
return "kFlutterBackingStoreTypeMetal";
219233
}
220234
return "Unknown";
221235
}
@@ -236,6 +250,12 @@ inline std::ostream& operator<<(std::ostream& out,
236250
<< reinterpret_cast<void*>(item.destruction_callback);
237251
}
238252

253+
inline std::ostream& operator<<(std::ostream& out,
254+
const FlutterMetalTexture& item) {
255+
return out << "(FlutterMetalTexture) Texture ID: " << std::hex
256+
<< item.texture_id << std::dec << " Handle: 0x" << std::hex
257+
<< item.texture;
258+
}
239259
inline std::string FlutterPlatformViewMutationTypeToString(
240260
FlutterPlatformViewMutationType type) {
241261
switch (type) {
@@ -322,6 +342,11 @@ inline std::ostream& operator<<(std::ostream& out,
322342
<< reinterpret_cast<void*>(item.destruction_callback);
323343
}
324344

345+
inline std::ostream& operator<<(std::ostream& out,
346+
const FlutterMetalBackingStore& item) {
347+
return out << "(FlutterMetalBackingStore) Texture: " << item.texture;
348+
}
349+
325350
inline std::ostream& operator<<(std::ostream& out,
326351
const FlutterBackingStore& backing_store) {
327352
out << "(FlutterBackingStore) Struct size: " << backing_store.struct_size
@@ -337,6 +362,10 @@ inline std::ostream& operator<<(std::ostream& out,
337362
case kFlutterBackingStoreTypeSoftware:
338363
out << backing_store.software;
339364
break;
365+
366+
case kFlutterBackingStoreTypeMetal:
367+
out << backing_store.metal;
368+
break;
340369
}
341370

342371
return out;

shell/platform/embedder/tests/embedder_config_builder.cc

+2-13
Original file line numberDiff line numberDiff line change
@@ -400,19 +400,8 @@ void EmbedderConfigBuilder::InitializeMetalRendererConfig() {
400400
metal_context.GetTestMetalContext()->GetMetalCommandQueue();
401401
metal_renderer_config_.get_next_drawable_callback =
402402
[](void* user_data, const FlutterFrameInfo* frame_info) {
403-
EmbedderTestContextMetal* metal_context =
404-
reinterpret_cast<EmbedderTestContextMetal*>(user_data);
405-
SkISize surface_size =
406-
SkISize::Make(frame_info->size.width, frame_info->size.height);
407-
TestMetalContext::TextureInfo texture_info =
408-
metal_context->GetTestMetalContext()->CreateMetalTexture(
409-
surface_size);
410-
FlutterMetalTexture texture;
411-
texture.struct_size = sizeof(FlutterMetalTexture);
412-
texture.texture_id = texture_info.texture_id;
413-
texture.texture =
414-
reinterpret_cast<FlutterMetalTextureHandle>(texture_info.texture);
415-
return texture;
403+
return reinterpret_cast<EmbedderTestContextMetal*>(user_data)
404+
->GetNextDrawable(frame_info);
416405
};
417406
metal_renderer_config_.present_drawable_callback =
418407
[](void* user_data, const FlutterMetalTexture* texture) -> bool {

shell/platform/embedder/tests/embedder_test_backingstore_producer.cc

+63-1
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,26 @@
55
#include "flutter/shell/platform/embedder/tests/embedder_test_backingstore_producer.h"
66

77
#include "flutter/fml/logging.h"
8+
#include "include/core/SkImageInfo.h"
9+
#include "include/core/SkSize.h"
810
#include "third_party/skia/include/core/SkSurface.h"
911

12+
#include <memory>
13+
1014
namespace flutter {
1115
namespace testing {
1216

1317
EmbedderTestBackingStoreProducer::EmbedderTestBackingStoreProducer(
1418
sk_sp<GrDirectContext> context,
1519
RenderTargetType type)
16-
: context_(context), type_(type) {}
20+
: context_(context),
21+
type_(type)
22+
#ifdef SHELL_ENABLE_METAL
23+
,
24+
test_metal_context_(std::make_unique<TestMetalContext>())
25+
#endif
26+
{
27+
}
1728

1829
EmbedderTestBackingStoreProducer::~EmbedderTestBackingStoreProducer() = default;
1930

@@ -28,6 +39,10 @@ bool EmbedderTestBackingStoreProducer::Create(
2839
return CreateTexture(config, renderer_out);
2940
case RenderTargetType::kOpenGLFramebuffer:
3041
return CreateFramebuffer(config, renderer_out);
42+
#endif
43+
#ifdef SHELL_ENABLE_METAL
44+
case RenderTargetType::kMetalTexture:
45+
return CreateMTLTexture(config, renderer_out);
3146
#endif
3247
default:
3348
return false;
@@ -174,5 +189,52 @@ bool EmbedderTestBackingStoreProducer::CreateSoftware(
174189
return true;
175190
}
176191

192+
bool EmbedderTestBackingStoreProducer::CreateMTLTexture(
193+
const FlutterBackingStoreConfig* config,
194+
FlutterBackingStore* backing_store_out) {
195+
#ifdef SHELL_ENABLE_METAL
196+
// TODO(gw280): Use SkSurface::MakeRenderTarget instead of generating our
197+
// own MTLTexture and wrapping it.
198+
auto surface_size = SkISize::Make(config->size.width, config->size.height);
199+
auto texture_info = test_metal_context_->CreateMetalTexture(surface_size);
200+
sk_cf_obj<FlutterMetalTextureHandle> texture;
201+
texture.retain(texture_info.texture);
202+
203+
GrMtlTextureInfo skia_texture_info;
204+
skia_texture_info.fTexture = texture;
205+
GrBackendTexture backend_texture(surface_size.width(), surface_size.height(),
206+
GrMipmapped::kNo, skia_texture_info);
207+
208+
SkSurface::TextureReleaseProc release_mtltexture = [](void* user_data) {
209+
SkCFSafeRelease(user_data);
210+
};
211+
212+
sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
213+
context_.get(), backend_texture, kTopLeft_GrSurfaceOrigin, 1,
214+
kBGRA_8888_SkColorType, nullptr, nullptr, release_mtltexture,
215+
texture_info.texture);
216+
217+
if (!surface) {
218+
FML_LOG(ERROR) << "Could not create Skia surface from a Metal texture.";
219+
return false;
220+
}
221+
222+
backing_store_out->type = kFlutterBackingStoreTypeMetal;
223+
backing_store_out->user_data = surface.get();
224+
backing_store_out->metal.texture.texture = texture_info.texture;
225+
// The balancing unref is in the destruction callback.
226+
surface->ref();
227+
backing_store_out->metal.struct_size = sizeof(FlutterMetalBackingStore);
228+
backing_store_out->metal.texture.user_data = surface.get();
229+
backing_store_out->metal.texture.destruction_callback = [](void* user_data) {
230+
reinterpret_cast<SkSurface*>(user_data)->unref();
231+
};
232+
233+
return true;
234+
#else
235+
return false;
236+
#endif
237+
}
238+
177239
} // namespace testing
178240
} // namespace flutter

0 commit comments

Comments
 (0)