diff --git a/engine/src/flutter/impeller/renderer/backend/metal/surface_mtl.mm b/engine/src/flutter/impeller/renderer/backend/metal/surface_mtl.mm index 6299f4524f..d28ab9d61f 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/surface_mtl.mm +++ b/engine/src/flutter/impeller/renderer/backend/metal/surface_mtl.mm @@ -13,6 +13,8 @@ #include "impeller/renderer/backend/metal/texture_mtl.h" #include "impeller/renderer/render_target.h" +static_assert(__has_feature(objc_arc), "ARC must be enabled."); + @protocol FlutterMetalDrawable - (void)flutterPrepareForPresent:(nonnull id)commandBuffer; @end diff --git a/engine/src/flutter/shell/gpu/BUILD.gn b/engine/src/flutter/shell/gpu/BUILD.gn index ebf3bc45e1..ed3dbfbf5b 100644 --- a/engine/src/flutter/shell/gpu/BUILD.gn +++ b/engine/src/flutter/shell/gpu/BUILD.gn @@ -69,25 +69,30 @@ source_set("gpu_surface_vulkan") { } } -source_set("gpu_surface_metal") { - sources = [ - "gpu_surface_metal_delegate.cc", - "gpu_surface_metal_delegate.h", - "gpu_surface_metal_skia.h", - "gpu_surface_metal_skia.mm", - "gpu_surface_noop.h", - "gpu_surface_noop.mm", - ] - - public_deps = gpu_common_deps - - if (impeller_enable_metal) { - sources += [ - "gpu_surface_metal_impeller.h", - "gpu_surface_metal_impeller.mm", +if (shell_enable_metal) { + source_set("gpu_surface_metal") { + sources = [ + "gpu_surface_metal_delegate.cc", + "gpu_surface_metal_delegate.h", + "gpu_surface_metal_skia.h", + "gpu_surface_metal_skia.mm", + "gpu_surface_noop.h", + "gpu_surface_noop.mm", ] - public_deps += [ "//flutter/impeller" ] + cflags_objc = flutter_cflags_objc_arc + cflags_objcc = flutter_cflags_objcc_arc + + public_deps = gpu_common_deps + + if (impeller_enable_metal) { + sources += [ + "gpu_surface_metal_impeller.h", + "gpu_surface_metal_impeller.mm", + ] + + public_deps += [ "//flutter/impeller" ] + } } } diff --git a/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.h b/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.h index 02407fd639..5aebb87bad 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.h +++ b/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.h @@ -36,7 +36,7 @@ class IMPELLER_CA_METAL_LAYER_AVAILABLE GPUSurfaceMetalImpeller const GPUSurfaceMetalDelegate* delegate_; const MTLRenderTargetType render_target_type_; std::shared_ptr aiks_context_; - fml::scoped_nsprotocol> last_texture_; + id 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 @@ -45,8 +45,8 @@ class IMPELLER_CA_METAL_LAYER_AVAILABLE GPUSurfaceMetalImpeller bool disable_partial_repaint_ = false; // Accumulated damage for each framebuffer; Key is address of underlying // MTLTexture for each drawable - std::shared_ptr> damage_ = - std::make_shared>(); + std::shared_ptr> damage_ = + std::make_shared>(); // |Surface| std::unique_ptr AcquireFrame( diff --git a/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm b/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm index 5ec05628f4..b35d509f14 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm +++ b/engine/src/flutter/shell/gpu/gpu_surface_metal_impeller.mm @@ -18,7 +18,7 @@ #include "impeller/renderer/backend/metal/surface_mtl.h" #include "impeller/typographer/backends/skia/typographer_context_skia.h" -static_assert(!__has_feature(objc_arc), "ARC must be disabled."); +static_assert(__has_feature(objc_arc), "ARC must be enabled."); namespace flutter { @@ -80,40 +80,41 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrame(const SkISiz std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLayer( const SkISize& frame_size) { - auto layer = delegate_->GetCAMetalLayer(frame_size); - + CAMetalLayer* layer = (__bridge CAMetalLayer*)delegate_->GetCAMetalLayer(frame_size); if (!layer) { FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder."; return nullptr; } - auto* mtl_layer = (CAMetalLayer*)layer; - - auto drawable = - impeller::SurfaceMTL::GetMetalDrawableAndValidate(aiks_context_->GetContext(), mtl_layer); + id drawable = + impeller::SurfaceMTL::GetMetalDrawableAndValidate(aiks_context_->GetContext(), layer); if (!drawable) { return nullptr; } if (Settings::kSurfaceDataAccessible) { - last_texture_.reset([drawable.texture retain]); + last_texture_ = drawable.texture; } #ifdef IMPELLER_DEBUG impeller::ContextMTL::Cast(*aiks_context_->GetContext()).GetCaptureManager()->StartCapture(); #endif // IMPELLER_DEBUG - id last_texture = static_cast>(last_texture_); - + __weak id weak_last_texture = last_texture_; + __weak CAMetalLayer* weak_layer = layer; SurfaceFrame::EncodeCallback encode_callback = fml::MakeCopyable([damage = damage_, disable_partial_repaint = disable_partial_repaint_, // aiks_context = aiks_context_, // drawable, // - last_texture, // - mtl_layer // + weak_last_texture, // + weak_layer // ](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool { - mtl_layer.presentsWithTransaction = surface_frame.submit_info().present_with_transaction; - + id strong_last_texture = weak_last_texture; + CAMetalLayer* strong_layer = weak_layer; + if (!strong_last_texture || !strong_layer) { + return false; + } + strong_layer.presentsWithTransaction = surface_frame.submit_info().present_with_transaction; if (!aiks_context) { return false; } @@ -125,8 +126,7 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa } if (!disable_partial_repaint && damage) { - uintptr_t texture = reinterpret_cast(last_texture); - + void* texture = (__bridge void*)strong_last_texture; for (auto& entry : *damage) { if (entry.first != texture) { // Accumulate damage for other framebuffers @@ -192,7 +192,7 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa if (!disable_partial_repaint_) { // Provide accumulated damage to rasterizer (area in current framebuffer that lags behind // front buffer) - uintptr_t texture = reinterpret_cast(drawable.texture); + void* texture = (__bridge void*)drawable.texture; auto i = damage_->find(texture); if (i != damage_->end()) { framebuffer_info.existing_damage = i->second; @@ -214,31 +214,34 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromCAMetalLa std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromMTLTexture( const SkISize& frame_size) { GPUMTLTextureInfo texture_info = delegate_->GetMTLTexture(frame_size); - id mtl_texture = (id)(texture_info.texture); - + id mtl_texture = (__bridge id)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]); + last_texture_ = mtl_texture; } #ifdef IMPELLER_DEBUG impeller::ContextMTL::Cast(*aiks_context_->GetContext()).GetCaptureManager()->StartCapture(); #endif // IMPELLER_DEBUG + __weak id weak_texture = mtl_texture; SurfaceFrame::EncodeCallback encode_callback = fml::MakeCopyable([disable_partial_repaint = disable_partial_repaint_, // damage = damage_, aiks_context = aiks_context_, // - mtl_texture // + weak_texture // ](SurfaceFrame& surface_frame, DlCanvas* canvas) mutable -> bool { + id strong_texture = weak_texture; + if (!strong_texture) { + return false; + } 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."; @@ -246,8 +249,7 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur } if (!disable_partial_repaint && damage) { - uintptr_t texture_ptr = reinterpret_cast(mtl_texture); - + void* texture_ptr = (__bridge void*)strong_texture; for (auto& entry : *damage) { if (entry.first != texture_ptr) { // Accumulate damage for other framebuffers @@ -268,7 +270,7 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur } auto surface = impeller::SurfaceMTL::MakeFromTexture(aiks_context->GetContext(), - mtl_texture, clip_rect); + strong_texture, clip_rect); surface->PresentWithTransaction(surface_frame.submit_info().present_with_transaction); @@ -308,7 +310,7 @@ std::unique_ptr GPUSurfaceMetalImpeller::AcquireFrameFromMTLTextur if (!disable_partial_repaint_) { // Provide accumulated damage to rasterizer (area in current framebuffer that lags behind // front buffer) - uintptr_t texture = reinterpret_cast(mtl_texture); + void* texture = (__bridge void*)mtl_texture; auto i = damage_->find(texture); if (i != damage_->end()) { framebuffer_info.existing_damage = i->second; @@ -362,7 +364,7 @@ Surface::SurfaceData GPUSurfaceMetalImpeller::GetSurfaceData() const { if (!(last_texture_ && [last_texture_ conformsToProtocol:@protocol(MTLTexture)])) { return {}; } - id texture = last_texture_.get(); + id texture = last_texture_; int bytesPerPixel = 0; std::string pixel_format; switch (texture.pixelFormat) { diff --git a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h index 15322c87a4..e4fb83127c 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h +++ b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h @@ -40,7 +40,7 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalSkia : public Surface { // Accumulated damage for each framebuffer; Key is address of underlying // MTLTexture for each drawable - std::map damage_; + std::map damage_; // |Surface| std::unique_ptr AcquireFrame(const SkISize& size) override; diff --git a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm index 085b70419a..9a22c214f6 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm +++ b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm @@ -34,7 +34,7 @@ #include "third_party/skia/include/gpu/ganesh/mtl/GrMtlTypes.h" #include "third_party/skia/include/ports/SkCFObject.h" -static_assert(!__has_feature(objc_arc), "ARC must be disabled."); +static_assert(__has_feature(objc_arc), "ARC must be enabled."); namespace flutter { @@ -48,7 +48,7 @@ sk_sp CreateSurfaceFromMetalTexture(GrDirectContext* context, SkSurfaces::TextureReleaseProc release_proc, SkSurface::ReleaseContext release_context) { GrMtlTextureInfo info; - info.fTexture.reset([texture retain]); + info.fTexture.retain((__bridge GrMTLHandle)texture); GrBackendTexture backend_texture = GrBackendTextures::MakeMtl(texture.width, texture.height, skgpu::Mipmapped::kNo, info); return SkSurfaces::WrapBackendTexture(context, backend_texture, origin, 1, color_type, @@ -127,23 +127,20 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrame(const SkISize& f std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer( const SkISize& frame_info) { - auto layer = delegate_->GetCAMetalLayer(frame_info); + CAMetalLayer* layer = (__bridge CAMetalLayer*)delegate_->GetCAMetalLayer(frame_info); if (!layer) { FML_LOG(ERROR) << "Invalid CAMetalLayer given by the embedder."; return nullptr; } - auto* mtl_layer = (CAMetalLayer*)layer; // Get the drawable eagerly, we will need texture object to identify target framebuffer - fml::scoped_nsprotocol> drawable( - reinterpret_cast>([[mtl_layer nextDrawable] retain])); - - if (!drawable.get()) { + id drawable = [layer nextDrawable]; + if (!drawable) { FML_LOG(ERROR) << "Could not obtain drawable from the metal layer."; return nullptr; } - auto surface = CreateSurfaceFromMetalTexture(context_.get(), drawable.get().texture, + auto surface = CreateSurfaceFromMetalTexture(context_.get(), drawable.texture, kTopLeft_GrSurfaceOrigin, // origin kBGRA_8888_SkColorType, // color type nullptr, // colorspace @@ -157,9 +154,10 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer( return nullptr; } + // drawable is a local and needs to be strongly-captured. SurfaceFrame::EncodeCallback encode_callback = - [this, drawable, mtl_layer](const SurfaceFrame& surface_frame, DlCanvas* canvas) -> bool { - mtl_layer.presentsWithTransaction = surface_frame.submit_info().present_with_transaction; + [this, drawable, layer](const SurfaceFrame& surface_frame, DlCanvas* canvas) -> bool { + layer.presentsWithTransaction = surface_frame.submit_info().present_with_transaction; if (canvas == nullptr) { FML_DLOG(ERROR) << "Canvas not available."; return false; @@ -171,7 +169,7 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer( } if (!disable_partial_repaint_) { - uintptr_t texture = reinterpret_cast(drawable.get().texture); + void* texture = (__bridge void*)drawable.texture; for (auto& entry : damage_) { if (entry.first != texture) { // Accumulate damage for other framebuffers @@ -187,10 +185,11 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer( return true; }; + // drawable is a local and needs to be strongly-captured. SurfaceFrame::SubmitCallback submit_callback = [this, drawable](const SurfaceFrame& surface_frame) -> bool { TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit"); - return delegate_->PresentDrawable(drawable); + return delegate_->PresentDrawable((__bridge GrMTLHandle)drawable); }; SurfaceFrame::FramebufferInfo framebuffer_info; @@ -199,7 +198,7 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer( if (!disable_partial_repaint_) { // Provide accumulated damage to rasterizer (area in current framebuffer that lags behind // front buffer) - uintptr_t texture = reinterpret_cast(drawable.get().texture); + void* texture = (__bridge void*)drawable.texture; auto i = damage_.find(texture); if (i != damage_.end()) { framebuffer_info.existing_damage = i->second; @@ -214,7 +213,7 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer( std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromMTLTexture( const SkISize& frame_info) { GPUMTLTextureInfo texture = delegate_->GetMTLTexture(frame_info); - id mtl_texture = (id)(texture.texture); + id mtl_texture = (__bridge id)texture.texture; if (!mtl_texture) { FML_LOG(ERROR) << "Invalid MTLTexture given by the embedder."; diff --git a/engine/src/flutter/shell/gpu/gpu_surface_noop.mm b/engine/src/flutter/shell/gpu/gpu_surface_noop.mm index 31e15d6a43..1b40d51eec 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_noop.mm +++ b/engine/src/flutter/shell/gpu/gpu_surface_noop.mm @@ -13,7 +13,7 @@ #include "flutter/fml/mapping.h" #include "flutter/fml/trace_event.h" -static_assert(!__has_feature(objc_arc), "ARC must be disabled."); +static_assert(__has_feature(objc_arc), "ARC must be enabled."); namespace flutter { diff --git a/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm b/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm index fb2d561aff..6998861091 100644 --- a/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm +++ b/engine/src/flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.mm @@ -91,8 +91,8 @@ FLUTTER_ASSERT_ARC GrMtlBackendContext backendContext = {}; // Skia expect arguments to `MakeMetal` transfer ownership of the reference in for release later // when the GrDirectContext is collected. - backendContext.fDevice.reset((__bridge_retained void*)device); - backendContext.fQueue.reset((__bridge_retained void*)commandQueue); + backendContext.fDevice.retain((__bridge void*)device); + backendContext.fQueue.retain((__bridge void*)commandQueue); return GrDirectContexts::MakeMetal(backendContext, contextOptions); }