From 66636eaded7ddd6850a8d78c69246c724b331fa7 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Fri, 23 Aug 2019 16:15:41 -0700 Subject: [PATCH] Platform View implemenation for Metal (#11070) --- ci/licenses_golden/licenses_flutter | 1 + shell/common/animator.cc | 11 ++- shell/gpu/BUILD.gn | 2 + shell/gpu/gpu_surface_delegate.h | 18 +++++ shell/gpu/gpu_surface_gl_delegate.h | 7 +- shell/gpu/gpu_surface_metal.h | 10 ++- shell/gpu/gpu_surface_metal.mm | 57 +++++++++++-- .../ios/framework/Source/FlutterOverlayView.h | 3 +- .../framework/Source/FlutterOverlayView.mm | 48 +++++++---- .../framework/Source/FlutterPlatformViews.mm | 73 ++++++++--------- .../Source/FlutterPlatformViews_Internal.h | 11 +-- .../ios/framework/Source/FlutterView.mm | 23 +++--- shell/platform/darwin/ios/ios_surface.h | 8 +- shell/platform/darwin/ios/ios_surface_gl.h | 8 +- shell/platform/darwin/ios/ios_surface_gl.mm | 11 ++- shell/platform/darwin/ios/ios_surface_metal.h | 43 ++++++++-- .../platform/darwin/ios/ios_surface_metal.mm | 80 ++++++++++++++++++- .../darwin/ios/ios_surface_software.h | 2 +- .../darwin/ios/ios_surface_software.mm | 4 +- 19 files changed, 317 insertions(+), 103 deletions(-) create mode 100644 shell/gpu/gpu_surface_delegate.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 0c68979c1d7..b23bffe7edf 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -513,6 +513,7 @@ FILE: ../../../flutter/shell/common/vsync_waiter.cc FILE: ../../../flutter/shell/common/vsync_waiter.h FILE: ../../../flutter/shell/common/vsync_waiter_fallback.cc FILE: ../../../flutter/shell/common/vsync_waiter_fallback.h +FILE: ../../../flutter/shell/gpu/gpu_surface_delegate.h FILE: ../../../flutter/shell/gpu/gpu_surface_gl.cc FILE: ../../../flutter/shell/gpu/gpu_surface_gl.h FILE: ../../../flutter/shell/gpu/gpu_surface_gl_delegate.cc diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 3632476ff6a..c987805784c 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -27,14 +27,18 @@ Animator::Animator(Delegate& delegate, waiter_(std::move(waiter)), last_begin_frame_time_(), dart_frame_deadline_(0), +#if FLUTTER_SHELL_ENABLE_METAL + layer_tree_pipeline_(fml::MakeRefCounted(2)), +#else // FLUTTER_SHELL_ENABLE_METAL // TODO(dnfield): We should remove this logic and set the pipeline depth - // back to 2 in this case. See https://github.com/flutter/engine/pull/9132 - // for discussion. + // back to 2 in this case. See + // https://github.com/flutter/engine/pull/9132 for discussion. layer_tree_pipeline_(fml::MakeRefCounted( task_runners.GetPlatformTaskRunner() == task_runners.GetGPUTaskRunner() ? 1 : 2)), +#endif // FLUTTER_SHELL_ENABLE_METAL pending_frame_semaphore_(1), frame_number_(1), paused_(false), @@ -42,7 +46,8 @@ Animator::Animator(Delegate& delegate, frame_scheduled_(false), notify_idle_task_id_(0), dimension_change_pending_(false), - weak_factory_(this) {} + weak_factory_(this) { +} Animator::~Animator() = default; diff --git a/shell/gpu/BUILD.gn b/shell/gpu/BUILD.gn index e7b3d679bb3..9bd51d5b9ed 100644 --- a/shell/gpu/BUILD.gn +++ b/shell/gpu/BUILD.gn @@ -27,6 +27,7 @@ source_set("gpu_surface_software") { source_set("gpu_surface_gl") { sources = [ + "$gpu_dir/gpu_surface_delegate.h", "$gpu_dir/gpu_surface_gl.cc", "$gpu_dir/gpu_surface_gl.h", "$gpu_dir/gpu_surface_gl_delegate.cc", @@ -50,6 +51,7 @@ source_set("gpu_surface_vulkan") { source_set("gpu_surface_metal") { sources = [ + "$gpu_dir/gpu_surface_delegate.h", "$gpu_dir/gpu_surface_metal.h", "$gpu_dir/gpu_surface_metal.mm", ] diff --git a/shell/gpu/gpu_surface_delegate.h b/shell/gpu/gpu_surface_delegate.h new file mode 100644 index 00000000000..4f9f16fdbb4 --- /dev/null +++ b/shell/gpu/gpu_surface_delegate.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_DELEGATE_H_ +#define FLUTTER_SHELL_GPU_GPU_SURFACE_DELEGATE_H_ + +#include "flutter/flow/embedded_views.h" +#include "flutter/fml/macros.h" + +namespace flutter { + +class GPUSurfaceDelegate { + public: + // Get a reference to the external views embedder. This happens on the same + // thread that the renderer is operating on. + virtual ExternalViewEmbedder* GetExternalViewEmbedder() = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_GPU_GPU_SURFACE_DELEGATE_H_ diff --git a/shell/gpu/gpu_surface_gl_delegate.h b/shell/gpu/gpu_surface_gl_delegate.h index 44dd872a73b..dfe0ce7f468 100644 --- a/shell/gpu/gpu_surface_gl_delegate.h +++ b/shell/gpu/gpu_surface_gl_delegate.h @@ -7,12 +7,13 @@ #include "flutter/flow/embedded_views.h" #include "flutter/fml/macros.h" +#include "flutter/shell/gpu/gpu_surface_delegate.h" #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/gpu/gl/GrGLInterface.h" namespace flutter { -class GPUSurfaceGLDelegate { +class GPUSurfaceGLDelegate : public GPUSurfaceDelegate { public: // Called to make the main GL context current on the current thread. virtual bool GLContextMakeCurrent() = 0; @@ -42,10 +43,6 @@ class GPUSurfaceGLDelegate { // flushed. virtual SkMatrix GLContextSurfaceTransformation() const; - // Get a reference to the external views embedder. This happens on the same - // thread that the renderer is operating on. - virtual ExternalViewEmbedder* GetExternalViewEmbedder() = 0; - sk_sp GetGLInterface() const; // TODO(chinmaygarde): The presence of this method is to work around the fact diff --git a/shell/gpu/gpu_surface_metal.h b/shell/gpu/gpu_surface_metal.h index 894aab6d8d0..a2a5fef3b88 100644 --- a/shell/gpu/gpu_surface_metal.h +++ b/shell/gpu/gpu_surface_metal.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/surface.h" +#include "flutter/shell/gpu/gpu_surface_delegate.h" #include "third_party/skia/include/gpu/GrContext.h" @class CAMetalLayer; @@ -18,11 +19,15 @@ namespace flutter { class GPUSurfaceMetal : public Surface { public: - GPUSurfaceMetal(fml::scoped_nsobject layer); + GPUSurfaceMetal(GPUSurfaceDelegate* delegate, fml::scoped_nsobject layer); + GPUSurfaceMetal(GPUSurfaceDelegate* delegate, + sk_sp gr_context, + fml::scoped_nsobject layer); ~GPUSurfaceMetal() override; private: + GPUSurfaceDelegate* delegate_; fml::scoped_nsobject layer_; sk_sp context_; fml::scoped_nsprotocol> command_queue_; @@ -39,6 +44,9 @@ class GPUSurfaceMetal : public Surface { // |Surface| GrContext* GetContext() override; + // |Surface| + flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override; + // |Surface| bool MakeRenderContextCurrent() override; diff --git a/shell/gpu/gpu_surface_metal.mm b/shell/gpu/gpu_surface_metal.mm index 88e814af12b..e81ac9b62b1 100644 --- a/shell/gpu/gpu_surface_metal.mm +++ b/shell/gpu/gpu_surface_metal.mm @@ -12,8 +12,9 @@ namespace flutter { -GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject layer) - : layer_(std::move(layer)) { +GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceDelegate* delegate, + fml::scoped_nsobject layer) + : delegate_(delegate), layer_(std::move(layer)) { if (!layer_) { FML_LOG(ERROR) << "Could not create metal surface because of invalid layer."; return; @@ -41,6 +42,32 @@ GPUSurfaceMetal::GPUSurfaceMetal(fml::scoped_nsobject layer) context_ = context; } +GPUSurfaceMetal::GPUSurfaceMetal(GPUSurfaceDelegate* delegate, + sk_sp gr_context, + fml::scoped_nsobject layer) + : delegate_(delegate), layer_(std::move(layer)), context_(gr_context) { + if (!layer_) { + FML_LOG(ERROR) << "Could not create metal surface because of invalid layer."; + return; + } + if (!context_) { + FML_LOG(ERROR) << "Could not create metal surface because of invalid Skia metal context."; + return; + } + + layer.get().pixelFormat = MTLPixelFormatBGRA8Unorm; + + auto metal_device = fml::scoped_nsprotocol>([layer_.get().device retain]); + auto metal_queue = fml::scoped_nsprotocol>([metal_device newCommandQueue]); + + if (!metal_device || !metal_queue) { + FML_LOG(ERROR) << "Could not create metal device or queue."; + return; + } + + command_queue_ = metal_queue; +} + GPUSurfaceMetal::~GPUSurfaceMetal() = default; // |Surface| @@ -112,11 +139,26 @@ std::unique_ptr GPUSurfaceMetal::AcquireFrame(const SkISize& size) return nullptr; } - auto submit_callback = [drawable = next_drawable, command_buffer]( + bool hasExternalViewEmbedder = delegate_->GetExternalViewEmbedder() != nullptr; + + // External views need to present with transaction. When presenting with + // transaction, we have to block, otherwise we risk presenting the drawable + // after the CATransaction has completed. + // See: + // https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction + // TODO(dnfield): only do this if transactions are actually being used. + // https://github.com/flutter/flutter/issues/24133 + auto submit_callback = [drawable = next_drawable, command_buffer, hasExternalViewEmbedder]( const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool { canvas->flush(); - [command_buffer.get() presentDrawable:drawable.get()]; - [command_buffer.get() commit]; + if (!hasExternalViewEmbedder) { + [command_buffer.get() presentDrawable:drawable.get()]; + [command_buffer.get() commit]; + } else { + [command_buffer.get() commit]; + [command_buffer.get() waitUntilScheduled]; + [drawable.get() present]; + } return true; }; @@ -137,6 +179,11 @@ GrContext* GPUSurfaceMetal::GetContext() { return context_.get(); } +// |Surface| +flutter::ExternalViewEmbedder* GPUSurfaceMetal::GetExternalViewEmbedder() { + return delegate_->GetExternalViewEmbedder(); +} + // |Surface| bool GPUSurfaceMetal::MakeRenderContextCurrent() { // This backend has no such concept. diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index dddfd6ca87d..fac783f87f3 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -24,8 +24,7 @@ - (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)initWithContentsScale:(CGFloat)contentsScale; -- (std::unique_ptr)createSoftwareSurface; -- (std::unique_ptr)createGLSurfaceWithContext: +- (std::unique_ptr)createSurface: (std::shared_ptr)gl_context; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index 091b13e7063..41bf3edcf3d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -13,6 +13,7 @@ #include "flutter/shell/common/platform_view.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" +#include "flutter/shell/platform/darwin/ios/ios_surface_metal.h" #include "flutter/shell/platform/darwin/ios/ios_surface_software.h" #include "third_party/skia/include/utils/mac/SkCGUtils.h" @@ -51,6 +52,13 @@ layer.allowsGroupOpacity = NO; layer.contentsScale = contentsScale; layer.rasterizationScale = contentsScale; +#if FLUTTER_SHELL_ENABLE_METAL + } else if ([self.layer isKindOfClass:[CAMetalLayer class]]) { + CAMetalLayer* layer = reinterpret_cast(self.layer); + layer.allowsGroupOpacity = NO; + layer.contentsScale = contentsScale; + layer.rasterizationScale = contentsScale; +#endif // FLUTTER_SHELL_ENABLE_METAL } return self; @@ -59,27 +67,39 @@ + (Class)layerClass { #if TARGET_IPHONE_SIMULATOR return [CALayer class]; -#else // TARGET_IPHONE_SIMULATOR +#else // TARGET_IPHONE_SIMULATOR +#if FLUTTER_SHELL_ENABLE_METAL + return [CAMetalLayer class]; +#else // FLUTTER_SHELL_ENABLE_METAL return [CAEAGLLayer class]; +#endif // FLUTTER_SHELL_ENABLE_METAL #endif // TARGET_IPHONE_SIMULATOR } -- (std::unique_ptr)createSoftwareSurface { - fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); - return std::make_unique(std::move(layer), nullptr); -} - -- (std::unique_ptr)createGLSurfaceWithContext: +- (std::unique_ptr)createSurface: (std::shared_ptr)gl_context { - fml::scoped_nsobject eagl_layer(reinterpret_cast([self.layer retain])); - // TODO(amirh): We can lower this to iOS 8.0 once we have a Metal rendering backend. - // https://github.com/flutter/flutter/issues/24132 - if (@available(iOS 9.0, *)) { - eagl_layer.get().presentsWithTransaction = YES; + if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { + fml::scoped_nsobject eagl_layer( + reinterpret_cast([self.layer retain])); + if (@available(iOS 9.0, *)) { + eagl_layer.get().presentsWithTransaction = YES; + } + return std::make_unique(std::move(eagl_layer), gl_context); +#if FLUTTER_SHELL_ENABLE_METAL + } else if ([self.layer isKindOfClass:[CAMetalLayer class]]) { + fml::scoped_nsobject metalLayer( + reinterpret_cast([self.layer retain])); + if (@available(iOS 8.0, *)) { + metalLayer.get().presentsWithTransaction = YES; + } + return std::make_unique(std::move(metalLayer)); +#endif // FLUTTER_SHELL_ENABLE_METAL + } else { + fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); + return std::make_unique(std::move(layer), nullptr); } - return std::make_unique(eagl_layer, std::move(gl_context)); } -// TODO(amirh): implement drawLayer to suppoer snapshotting. +// TODO(amirh): implement drawLayer to support snapshotting. @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 5bb5b411ef7..00a7c9ecda5 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -361,19 +361,13 @@ void FlutterPlatformViewsController::Reset() { views_to_recomposite_.clear(); } -bool FlutterPlatformViewsController::SubmitFrame(bool gl_rendering, - GrContext* gr_context, +bool FlutterPlatformViewsController::SubmitFrame(GrContext* gr_context, std::shared_ptr gl_context) { DisposeViews(); bool did_submit = true; - for (size_t i = 0; i < composition_order_.size(); i++) { - int64_t view_id = composition_order_[i]; - if (gl_rendering) { - EnsureGLOverlayInitialized(view_id, gl_context, gr_context); - } else { - EnsureOverlayInitialized(view_id); - } + for (int64_t view_id : composition_order_) { + EnsureOverlayInitialized(view_id, std::move(gl_context), gr_context); auto frame = overlays_[view_id]->surface->AcquireFrame(frame_size_); SkCanvas* canvas = frame->SkiaCanvas(); canvas->drawPicture(picture_recorders_[view_id]->finishRecordingAsPicture()); @@ -455,46 +449,53 @@ void FlutterPlatformViewsController::DisposeViews() { views_to_dispose_.clear(); } -void FlutterPlatformViewsController::EnsureOverlayInitialized(int64_t overlay_id) { - if (overlays_.count(overlay_id) != 0) { - return; - } - FlutterOverlayView* overlay_view = [[FlutterOverlayView alloc] init]; - overlay_view.frame = flutter_view_.get().bounds; - overlay_view.autoresizingMask = - (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - std::unique_ptr ios_surface = overlay_view.createSoftwareSurface; - std::unique_ptr surface = ios_surface->CreateGPUSurface(); - overlays_[overlay_id] = std::make_unique( - fml::scoped_nsobject(overlay_view), std::move(ios_surface), std::move(surface)); -} - -void FlutterPlatformViewsController::EnsureGLOverlayInitialized( +void FlutterPlatformViewsController::EnsureOverlayInitialized( int64_t overlay_id, std::shared_ptr gl_context, GrContext* gr_context) { - if (overlays_.count(overlay_id) != 0) { + FML_DCHECK(flutter_view_); + + auto overlay_it = overlays_.find(overlay_id); + + if (!gr_context) { + FML_DLOG(ERROR) << "No GrContext"; + if (overlays_.count(overlay_id) != 0) { + return; + } + fml::scoped_nsobject overlay_view( + [[[FlutterOverlayView alloc] init] retain]); + overlay_view.get().frame = flutter_view_.get().bounds; + overlay_view.get().autoresizingMask = + (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + std::unique_ptr ios_surface = [overlay_view.get() createSurface:nil]; + std::unique_ptr surface = ios_surface->CreateGPUSurface(); + overlays_[overlay_id] = std::make_unique( + std::move(overlay_view), std::move(ios_surface), std::move(surface)); + return; + } + + if (overlay_it != overlays_.end()) { if (gr_context != overlays_gr_context_) { overlays_gr_context_ = gr_context; // The overlay already exists, but the GrContext was changed so we need to recreate // the rendering surface with the new GrContext. - IOSSurfaceGL* ios_surface_gl = (IOSSurfaceGL*)overlays_[overlay_id]->ios_surface.get(); - std::unique_ptr surface = ios_surface_gl->CreateSecondaryGPUSurface(gr_context); - overlays_[overlay_id]->surface = std::move(surface); + IOSSurface* ios_surface = overlay_it->second->ios_surface.get(); + std::unique_ptr surface = ios_surface->CreateGPUSurface(gr_context); + overlay_it->second->surface = std::move(surface); } return; } auto contentsScale = flutter_view_.get().layer.contentsScale; - FlutterOverlayView* overlay_view = - [[FlutterOverlayView alloc] initWithContentsScale:contentsScale]; - overlay_view.frame = flutter_view_.get().bounds; - overlay_view.autoresizingMask = + fml::scoped_nsobject overlay_view( + [[[FlutterOverlayView alloc] initWithContentsScale:contentsScale] retain]); + overlay_view.get().frame = flutter_view_.get().bounds; + overlay_view.get().autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - std::unique_ptr ios_surface = - [overlay_view createGLSurfaceWithContext:std::move(gl_context)]; - std::unique_ptr surface = ios_surface->CreateSecondaryGPUSurface(gr_context); + std::unique_ptr ios_surface = + [overlay_view.get() createSurface:std::move(gl_context)]; + std::unique_ptr surface = ios_surface->CreateGPUSurface(gr_context); overlays_[overlay_id] = std::make_unique( - fml::scoped_nsobject(overlay_view), std::move(ios_surface), std::move(surface)); + std::move(overlay_view), std::move(ios_surface), std::move(surface)); overlays_gr_context_ = gr_context; } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 3d23431f5d7..f9f0eefece6 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -100,9 +100,7 @@ class FlutterPlatformViewsController { // Discards all platform views instances and auxiliary resources. void Reset(); - bool SubmitFrame(bool gl_rendering, - GrContext* gr_context, - std::shared_ptr gl_context); + bool SubmitFrame(GrContext* gr_context, std::shared_ptr gl_context); void OnMethodCall(FlutterMethodCall* call, FlutterResult& result); @@ -163,10 +161,9 @@ class FlutterPlatformViewsController { void DetachUnusedLayers(); // Dispose the views in `views_to_dispose_`. void DisposeViews(); - void EnsureOverlayInitialized(int64_t overlay_id); - void EnsureGLOverlayInitialized(int64_t overlay_id, - std::shared_ptr gl_context, - GrContext* gr_context); + void EnsureOverlayInitialized(int64_t overlay_id, + std::shared_ptr gl_context, + GrContext* gr_context); // This will return true after pre-roll if any of the embedded views // have mutated for last layer tree. diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index 06e73d1538d..4e4acdfc043 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -99,8 +99,6 @@ id _delegate; fml::scoped_nsobject eagl_layer( reinterpret_cast([self.layer retain])); if (flutter::IsIosEmbeddedViewsPreviewEnabled()) { - // TODO(amirh): We can lower this to iOS 8.0 once we have a Metal rendering backend. - // https://github.com/flutter/flutter/issues/24132 if (@available(iOS 9.0, *)) { // TODO(amirh): only do this if there's an embedded view. // https://github.com/flutter/flutter/issues/24133 @@ -109,16 +107,21 @@ id _delegate; } return std::make_unique(context, std::move(eagl_layer), [_delegate platformViewsController]); - } #if FLUTTER_SHELL_ENABLE_METAL - else if ([self.layer isKindOfClass:[CAMetalLayer class]]) { - return std::make_unique( - fml::scoped_nsobject(reinterpret_cast([self.layer retain])), - [_delegate platformViewsController]); - } + } else if ([self.layer isKindOfClass:[CAMetalLayer class]]) { + fml::scoped_nsobject metalLayer( + reinterpret_cast([self.layer retain])); + if (flutter::IsIosEmbeddedViewsPreviewEnabled()) { + if (@available(iOS 8.0, *)) { + // TODO(amirh): only do this if there's an embedded view. + // https://github.com/flutter/flutter/issues/24133 + metalLayer.get().presentsWithTransaction = YES; + } + } + return std::make_unique(std::move(metalLayer), + [_delegate platformViewsController]); #endif // FLUTTER_SHELL_ENABLE_METAL - - else { + } else { fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); return std::make_unique(std::move(layer), [_delegate platformViewsController]); diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index 8b065bb9ef8..49f40f9eec7 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -31,7 +31,13 @@ class IOSSurface { virtual void UpdateStorageSizeIfNecessary() = 0; - virtual std::unique_ptr CreateGPUSurface() = 0; + // Creates a GPU surface. If no GrContext is supplied and the rendering mode + // supports one, a new one will be created; otherwise, the software backend + // will be used. + // + // If a GrContext is supplied, creates a secondary surface. + virtual std::unique_ptr CreateGPUSurface( + GrContext* gr_context = nullptr) = 0; protected: FlutterPlatformViewsController* GetPlatformViewsController(); diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index b9a0238dd88..964cc7adb69 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -28,15 +28,17 @@ class IOSSurfaceGL final : public IOSSurface, ~IOSSurfaceGL() override; + // |IOSSurface| bool IsValid() const override; + // |IOSSurface| bool ResourceContextMakeCurrent() override; + // |IOSSurface| void UpdateStorageSizeIfNecessary() override; - std::unique_ptr CreateGPUSurface() override; - - std::unique_ptr CreateSecondaryGPUSurface(GrContext* gr_context); + // |IOSSurface| + std::unique_ptr CreateGPUSurface(GrContext* gr_context = nullptr) override; bool GLContextMakeCurrent() override; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index f087be2719a..9e838e200df 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -38,14 +38,13 @@ void IOSSurfaceGL::UpdateStorageSizeIfNecessary() { } } -std::unique_ptr IOSSurfaceGL::CreateGPUSurface() { +std::unique_ptr IOSSurfaceGL::CreateGPUSurface(GrContext* gr_context) { + if (gr_context) { + return std::make_unique(sk_ref_sp(gr_context), this, true); + } return std::make_unique(this, true); } -std::unique_ptr IOSSurfaceGL::CreateSecondaryGPUSurface(GrContext* gr_context) { - return std::make_unique(sk_ref_sp(gr_context), this, true); -} - intptr_t IOSSurfaceGL::GLContextFBO() const { return IsValid() ? render_target_->framebuffer() : GL_NONE; } @@ -146,7 +145,7 @@ bool IOSSurfaceGL::SubmitFrame(GrContext* context) { return true; } - bool submitted = platform_views_controller->SubmitFrame(true, std::move(context), context_); + bool submitted = platform_views_controller->SubmitFrame(std::move(context), context_); [CATransaction commit]; return submitted; } diff --git a/shell/platform/darwin/ios/ios_surface_metal.h b/shell/platform/darwin/ios/ios_surface_metal.h index 38340e5dc78..f43cada80a8 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.h +++ b/shell/platform/darwin/ios/ios_surface_metal.h @@ -7,6 +7,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/gpu/gpu_surface_delegate.h" #include "flutter/shell/gpu/gpu_surface_metal.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" @@ -14,15 +15,16 @@ namespace flutter { -class IOSSurfaceMetal final : public IOSSurface { +class IOSSurfaceMetal final : public IOSSurface, + public GPUSurfaceDelegate, + public ExternalViewEmbedder { public: IOSSurfaceMetal(fml::scoped_nsobject layer, FlutterPlatformViewsController* platform_views_controller); - ~IOSSurfaceMetal() override; + IOSSurfaceMetal(fml::scoped_nsobject layer); - private: - fml::scoped_nsobject layer_; + ~IOSSurfaceMetal() override; // |IOSSurface| bool IsValid() const override; @@ -34,7 +36,38 @@ class IOSSurfaceMetal final : public IOSSurface { void UpdateStorageSizeIfNecessary() override; // |IOSSurface| - std::unique_ptr CreateGPUSurface() override; + std::unique_ptr CreateGPUSurface(GrContext* gr_context = nullptr) override; + + // |GPUSurfaceDelegate| + flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override; + + // |ExternalViewEmbedder| + sk_sp GetRootSurface() override; + + // |ExternalViewEmbedder| + void CancelFrame() override; + + // |ExternalViewEmbedder| + void BeginFrame(SkISize frame_size, GrContext* context) override; + + // |ExternalViewEmbedder| + void PrerollCompositeEmbeddedView(int view_id, + std::unique_ptr params) override; + + // |ExternalViewEmbedder| + PostPrerollResult PostPrerollAction(fml::RefPtr gpu_thread_merger) override; + + // |ExternalViewEmbedder| + std::vector GetCurrentCanvases() override; + + // |ExternalViewEmbedder| + SkCanvas* CompositeEmbeddedView(int view_id) override; + + // |ExternalViewEmbedder| + bool SubmitFrame(GrContext* context) override; + + private: + fml::scoped_nsobject layer_; FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceMetal); }; diff --git a/shell/platform/darwin/ios/ios_surface_metal.mm b/shell/platform/darwin/ios/ios_surface_metal.mm index 665049ac874..a3778b4f2a1 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.mm +++ b/shell/platform/darwin/ios/ios_surface_metal.mm @@ -11,6 +11,9 @@ IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject layer, FlutterPlatformViewsController* platform_views_controller) : IOSSurface(platform_views_controller), layer_(std::move(layer)) {} +IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject layer) + : IOSSurface(nullptr), layer_(std::move(layer)) {} + IOSSurfaceMetal::~IOSSurfaceMetal() = default; // |IOSSurface| @@ -27,8 +30,81 @@ bool IOSSurfaceMetal::ResourceContextMakeCurrent() { void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() {} // |IOSSurface| -std::unique_ptr IOSSurfaceMetal::CreateGPUSurface() { - return std::make_unique(layer_); +std::unique_ptr IOSSurfaceMetal::CreateGPUSurface(GrContext* gr_context) { + if (gr_context) { + return std::make_unique(this, sk_ref_sp(gr_context), layer_); + } + return std::make_unique(this, layer_); +} + +// |ExternalViewEmbedder| +sk_sp IOSSurfaceMetal::GetRootSurface() { + // On iOS, the root surface is created from the on-screen render target. Only the surfaces for the + // various overlays are controlled by this class. + return nullptr; +} + +flutter::ExternalViewEmbedder* IOSSurfaceMetal::GetExternalViewEmbedder() { + if (IsIosEmbeddedViewsPreviewEnabled()) { + return this; + } else { + return nullptr; + } +} + +void IOSSurfaceMetal::CancelFrame() { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + platform_views_controller->CancelFrame(); + // Committing the current transaction as |BeginFrame| will create a nested + // CATransaction otherwise. + [CATransaction commit]; +} + +void IOSSurfaceMetal::BeginFrame(SkISize frame_size, GrContext* context) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + platform_views_controller->SetFrameSize(frame_size); + [CATransaction begin]; +} + +void IOSSurfaceMetal::PrerollCompositeEmbeddedView( + int view_id, + std::unique_ptr params) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + platform_views_controller->PrerollCompositeEmbeddedView(view_id, std::move(params)); +} + +// |ExternalViewEmbedder| +PostPrerollResult IOSSurfaceMetal::PostPrerollAction( + fml::RefPtr gpu_thread_merger) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + return platform_views_controller->PostPrerollAction(gpu_thread_merger); +} + +std::vector IOSSurfaceMetal::GetCurrentCanvases() { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + return platform_views_controller->GetCurrentCanvases(); +} + +SkCanvas* IOSSurfaceMetal::CompositeEmbeddedView(int view_id) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + return platform_views_controller->CompositeEmbeddedView(view_id); +} + +bool IOSSurfaceMetal::SubmitFrame(GrContext* context) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + if (platform_views_controller == nullptr) { + return true; + } + + bool submitted = platform_views_controller->SubmitFrame(std::move(context), nullptr); + [CATransaction commit]; + return submitted; } } // namespace flutter diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index 2b96e9bd3c9..d2ff61efdc4 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -34,7 +34,7 @@ class IOSSurfaceSoftware final : public IOSSurface, void UpdateStorageSizeIfNecessary() override; // |IOSSurface| - std::unique_ptr CreateGPUSurface() override; + std::unique_ptr CreateGPUSurface(GrContext* gr_context = nullptr) override; // |GPUSurfaceSoftwareDelegate| sk_sp AcquireBackingStore(const SkISize& size) override; diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index 89d6de8f925..4566bbf3f36 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -38,7 +38,7 @@ void IOSSurfaceSoftware::UpdateStorageSizeIfNecessary() { // Android oddities. } -std::unique_ptr IOSSurfaceSoftware::CreateGPUSurface() { +std::unique_ptr IOSSurfaceSoftware::CreateGPUSurface(GrContext* gr_context) { if (!IsValid()) { return nullptr; } @@ -184,7 +184,7 @@ bool IOSSurfaceSoftware::SubmitFrame(GrContext* context) { if (platform_views_controller == nullptr) { return true; } - return platform_views_controller->SubmitFrame(false, nullptr, nullptr); + return platform_views_controller->SubmitFrame(nullptr, nullptr); } } // namespace flutter