From 0416dbf43ae2fa812f70b9a034aaa11fe1686889 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 3 Mar 2020 14:17:12 -0800 Subject: [PATCH 1/2] Implement asynchronous texture uploads when using the Metal backend on iOS. This moves the Metal `GrContext` creation utilities from `GPUSurfaceMetal` into a separate `IOSContext` object subclass. An analogue of this object was used in the GL regime for the management of onscreen and offscreen contexts that were not tied to the lifecycle of the `GPUSurface`. This pattern has now been generalized for use with all backends that need a resource context (`IOSContextGL` and `IOContextMetal`). The platform views controller management in the `ExternalViewEmbedder` interface implementation was repeated three times for [Metal][metal], [OpenGL](opengl) and [Software](software) rendering. This repetition has been removed and a single implementation present in the base `IOSSurface` and used on all platforms. Addition of new client rendering APIs should not affect how the engine renders into the platform view interleaving levels. All rendering API selection logic has been moved into a single set of utilities in `rendering_api_selection.h`. This enables the removal of a lot of code blocks guarded by `FLUTTER_SHELL_ENABLE_METAL`. The remaining uses of this will be removed when unified builds are enabled. The Metal backend now also adds traces similar to the GL backend. The `IOGLContext` has been renamed to `IOContextGL` to be more in line with the convention used in this library. Fixes https://github.com/flutter/flutter/issues/41827 Adds https://github.com/flutter/flutter/issues/52150 [metal]: https://github.com/flutter/engine/blob/1194ba2b218706a201c5d2c5325b55a5932546c5/shell/platform/darwin/ios/ios_surface_metal.mm#L55 [opengl]: https://github.com/flutter/engine/blob/1194ba2b218706a201c5d2c5325b55a5932546c5/shell/platform/darwin/ios/ios_surface_gl.mm#L95 [software]: https://github.com/flutter/engine/blob/1194ba2b218706a201c5d2c5325b55a5932546c5/shell/platform/darwin/ios/ios_surface_software.mm#L146 --- flow/compositor_context.cc | 1 + lib/ui/painting/image_decoder.cc | 1 + shell/common/rasterizer.cc | 2 + shell/gpu/gpu_surface_gl.h | 1 + shell/gpu/gpu_surface_metal.h | 7 +- shell/gpu/gpu_surface_metal.mm | 78 +++-------- shell/platform/darwin/ios/BUILD.gn | 30 +++-- .../ios/framework/Source/FlutterEngine.mm | 6 +- .../ios/framework/Source/FlutterOverlayView.h | 4 +- .../framework/Source/FlutterOverlayView.mm | 45 ++----- .../framework/Source/FlutterPlatformViews.mm | 8 +- .../Source/FlutterPlatformViews_Internal.h | 7 +- .../darwin/ios/framework/Source/FlutterView.h | 4 +- .../ios/framework/Source/FlutterView.mm | 109 ++-------------- shell/platform/darwin/ios/ios_context.h | 45 +++++++ shell/platform/darwin/ios/ios_context.mm | 37 ++++++ .../{ios_gl_context.h => ios_context_gl.h} | 42 +++--- shell/platform/darwin/ios/ios_context_gl.mm | 61 +++++++++ shell/platform/darwin/ios/ios_context_metal.h | 61 +++++++++ .../platform/darwin/ios/ios_context_metal.mm | 91 +++++++++++++ .../darwin/ios/ios_external_texture_gl.h | 23 ++-- shell/platform/darwin/ios/ios_gl_context.mm | 63 --------- .../darwin/ios/ios_gl_render_target.h | 57 -------- shell/platform/darwin/ios/ios_render_target.h | 34 +++++ .../platform/darwin/ios/ios_render_target.mm | 13 ++ .../darwin/ios/ios_render_target_gl.h | 56 ++++++++ ...nder_target.mm => ios_render_target_gl.mm} | 60 +++++---- shell/platform/darwin/ios/ios_surface.h | 51 +++++++- shell/platform/darwin/ios/ios_surface.mm | 123 ++++++++++++++++-- shell/platform/darwin/ios/ios_surface_gl.h | 56 ++------ shell/platform/darwin/ios/ios_surface_gl.mm | 108 +++------------ shell/platform/darwin/ios/ios_surface_metal.h | 52 ++------ .../platform/darwin/ios/ios_surface_metal.mm | 121 ++++++----------- .../darwin/ios/ios_surface_software.h | 31 +---- .../darwin/ios/ios_surface_software.mm | 70 +--------- shell/platform/darwin/ios/platform_view_ios.h | 9 +- .../platform/darwin/ios/platform_view_ios.mm | 21 +-- .../darwin/ios/rendering_api_selection.h | 27 ++++ .../darwin/ios/rendering_api_selection.mm | 70 ++++++++++ 39 files changed, 907 insertions(+), 778 deletions(-) create mode 100644 shell/platform/darwin/ios/ios_context.h create mode 100644 shell/platform/darwin/ios/ios_context.mm rename shell/platform/darwin/ios/{ios_gl_context.h => ios_context_gl.h} (50%) create mode 100644 shell/platform/darwin/ios/ios_context_gl.mm create mode 100644 shell/platform/darwin/ios/ios_context_metal.h create mode 100644 shell/platform/darwin/ios/ios_context_metal.mm delete mode 100644 shell/platform/darwin/ios/ios_gl_context.mm delete mode 100644 shell/platform/darwin/ios/ios_gl_render_target.h create mode 100644 shell/platform/darwin/ios/ios_render_target.h create mode 100644 shell/platform/darwin/ios/ios_render_target.mm create mode 100644 shell/platform/darwin/ios/ios_render_target_gl.h rename shell/platform/darwin/ios/{ios_gl_render_target.mm => ios_render_target_gl.mm} (70%) create mode 100644 shell/platform/darwin/ios/rendering_api_selection.h create mode 100644 shell/platform/darwin/ios/rendering_api_selection.mm diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index 68f308fbf2f57..d816ca53ef877 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -70,6 +70,7 @@ CompositorContext::ScopedFrame::~ScopedFrame() { RasterStatus CompositorContext::ScopedFrame::Raster( flutter::LayerTree& layer_tree, bool ignore_raster_cache) { + TRACE_EVENT0("flutter", "CompositorContext::ScopedFrame::Raster"); bool root_needs_readback = layer_tree.Preroll(*this, ignore_raster_cache); bool needs_save_layer = root_needs_readback && !surface_supports_readback(); PostPrerollResult post_preroll_result = PostPrerollResult::kSuccess; diff --git a/lib/ui/painting/image_decoder.cc b/lib/ui/painting/image_decoder.cc index b730de7d66c35..604b41d7dcd95 100644 --- a/lib/ui/painting/image_decoder.cc +++ b/lib/ui/painting/image_decoder.cc @@ -282,6 +282,7 @@ static SkiaGPUObject UploadRasterImage( }) .SetIfFalse([&result, context = io_manager->GetResourceContext(), &pixmap, queue = io_manager->GetSkiaUnrefQueue()] { + TRACE_EVENT0("flutter", "MakeCrossContextImageFromPixmap"); sk_sp texture_image = SkImage::MakeCrossContextFromPixmap( context.get(), // context pixmap, // pixmap diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 7d6a7a74e8a91..acad5ada8510a 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -295,6 +295,7 @@ RasterStatus Rasterizer::DoDraw( } RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) { + TRACE_EVENT0("flutter", "Rasterizer::DrawToSurface"); FML_DCHECK(surface_); auto frame = surface_->AcquireFrame(layer_tree.frame_size()); @@ -350,6 +351,7 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) { FireNextFrameCallbackIfPresent(); if (surface_->GetContext()) { + TRACE_EVENT0("flutter", "PerformDeferredSkiaCleanup"); surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration); } diff --git a/shell/gpu/gpu_surface_gl.h b/shell/gpu/gpu_surface_gl.h index d2e62d7e1fefd..0a0806040adef 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -26,6 +26,7 @@ class GPUSurfaceGL : public Surface { GPUSurfaceGLDelegate* delegate, bool render_to_surface); + // |Surface| ~GPUSurfaceGL() override; // |Surface| diff --git a/shell/gpu/gpu_surface_metal.h b/shell/gpu/gpu_surface_metal.h index fc6b0964766ce..3332dca6585fe 100644 --- a/shell/gpu/gpu_surface_metal.h +++ b/shell/gpu/gpu_surface_metal.h @@ -19,11 +19,12 @@ namespace flutter { class GPUSurfaceMetal : public Surface { public: - GPUSurfaceMetal(GPUSurfaceDelegate* delegate, fml::scoped_nsobject layer); GPUSurfaceMetal(GPUSurfaceDelegate* delegate, - sk_sp gr_context, - fml::scoped_nsobject layer); + fml::scoped_nsobject layer, + sk_sp context, + fml::scoped_nsprotocol> command_queue); + // |Surface| ~GPUSurfaceMetal() override; private: diff --git a/shell/gpu/gpu_surface_metal.mm b/shell/gpu/gpu_surface_metal.mm index bb436d2138768..154e951319bdb 100644 --- a/shell/gpu/gpu_surface_metal.mm +++ b/shell/gpu/gpu_surface_metal.mm @@ -6,6 +6,7 @@ #include +#include "flutter/fml/trace_event.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/ports/SkCFObject.h" @@ -15,62 +16,17 @@ namespace flutter { 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; - } - - layer.get().pixelFormat = MTLPixelFormatBGRA8Unorm; + fml::scoped_nsobject layer, + sk_sp context, + fml::scoped_nsprotocol> command_queue) + : delegate_(delegate), + layer_(std::move(layer)), + context_(std::move(context)), + command_queue_(std::move(command_queue)) { + layer_.get().pixelFormat = MTLPixelFormatBGRA8Unorm; // Flutter needs to read from the color attachment in cases where there are effects such as // backdrop filters. - layer.get().framebufferOnly = NO; - - 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; - - // The context creation routine accepts arguments using transfer semantics. - auto context = GrContext::MakeMetal(metal_device.release(), metal_queue.release()); - if (!context) { - FML_LOG(ERROR) << "Could not create Skia metal context."; - return; - } - - 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; + layer_.get().framebufferOnly = NO; } GPUSurfaceMetal::~GPUSurfaceMetal() { @@ -95,13 +51,20 @@ } const auto bounds = layer_.get().bounds.size; - if (bounds.width <= 0.0 || bounds.height <= 0.0) { + const auto scale = layer_.get().contentsScale; + if (bounds.width <= 0.0 || bounds.height <= 0.0 || scale <= 0.0) { FML_LOG(ERROR) << "Metal layer bounds were invalid."; return nullptr; } + const auto scaled_bounds = CGSizeMake(bounds.width * scale, bounds.height * scale); + ReleaseUnusedDrawableIfNecessary(); + if (!CGSizeEqualToSize(scaled_bounds, layer_.get().drawableSize)) { + layer_.get().drawableSize = scaled_bounds; + } + auto surface = SkSurface::MakeFromCAMetalLayer(context_.get(), // context layer_.get(), // layer kTopLeft_GrSurfaceOrigin, // origin @@ -118,6 +81,7 @@ } auto submit_callback = [this](const SurfaceFrame& surface_frame, SkCanvas* canvas) -> bool { + TRACE_EVENT0("flutter", "GPUSurfaceMetal::Submit"); canvas->flush(); if (next_drawable_ == nullptr) { @@ -159,9 +123,7 @@ SkMatrix GPUSurfaceMetal::GetRootTransformation() const { // This backend does not currently support root surface transformations. Just // return identity. - SkMatrix matrix; - matrix.reset(); - return matrix; + return {}; } // |Surface| diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 014b51c90ed30..3aec32226a165 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -44,6 +44,8 @@ shared_library("create_flutter_framework_dylib") { ldflags = [ "-Wl,-install_name,@rpath/Flutter.framework/Flutter" ] + public = _flutter_framework_headers + sources = [ "framework/Source/FlutterAppDelegate.mm", "framework/Source/FlutterBinaryMessengerRelay.mm", @@ -81,12 +83,16 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/platform_message_router.mm", "framework/Source/vsync_waiter_ios.h", "framework/Source/vsync_waiter_ios.mm", + "ios_context.h", + "ios_context.mm", + "ios_context_gl.h", + "ios_context_gl.mm", "ios_external_texture_gl.h", "ios_external_texture_gl.mm", - "ios_gl_context.h", - "ios_gl_context.mm", - "ios_gl_render_target.h", - "ios_gl_render_target.mm", + "ios_render_target.h", + "ios_render_target.mm", + "ios_render_target_gl.h", + "ios_render_target_gl.mm", "ios_surface.h", "ios_surface.mm", "ios_surface_gl.h", @@ -95,15 +101,10 @@ shared_library("create_flutter_framework_dylib") { "ios_surface_software.mm", "platform_view_ios.h", "platform_view_ios.mm", + "rendering_api_selection.h", + "rendering_api_selection.mm", ] - if (shell_enable_metal) { - sources += [ - "ios_surface_metal.h", - "ios_surface_metal.mm", - ] - } - sources += _flutter_framework_headers deps = [ @@ -126,6 +127,13 @@ shared_library("create_flutter_framework_dylib") { if (shell_enable_metal) { defines += [ "FLUTTER_SHELL_ENABLE_METAL=1" ] + + sources += [ + "ios_context_metal.h", + "ios_context_metal.mm", + "ios_surface_metal.h", + "ios_surface_metal.mm", + ] } libs = [ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index cdab6c4b0d685..c267518929685 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -26,6 +26,7 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h" #import "flutter/shell/platform/darwin/ios/ios_surface.h" #import "flutter/shell/platform/darwin/ios/platform_view_ios.h" +#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h" NSString* const FlutterDefaultDartEntrypoint = nil; @@ -427,7 +428,7 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI { } const auto threadLabel = [NSString stringWithFormat:@"%@.%zu", _labelPrefix, shellCount++]; - FML_DLOG(INFO) << "Creating threadHost for " << threadLabel.UTF8String; + // The current thread will be used as the platform thread. Ensure that the message loop is // initialized. fml::MessageLoop::EnsureInitializedForCurrentThread(); @@ -441,7 +442,8 @@ - (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI { // synchronous. flutter::Shell::CreateCallback on_create_platform_view = [](flutter::Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique( + shell, flutter::GetRenderingAPIForProcess(), shell.GetTaskRunners()); }; flutter::Shell::CreateCallback on_create_rasterizer = diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h index 0ace741ccab80..088959e69876c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h @@ -13,7 +13,7 @@ #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/shell.h" -#include "flutter/shell/platform/darwin/ios/ios_gl_context.h" +#include "flutter/shell/platform/darwin/ios/ios_context_gl.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" #include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" @@ -36,7 +36,7 @@ - (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)initWithContentsScale:(CGFloat)contentsScale; - (std::unique_ptr)createSurface: - (std::shared_ptr)gl_context; + (std::shared_ptr)ios_context; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm index bf4c1c21f62a8..f263660a33abf 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.mm @@ -14,9 +14,6 @@ #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" -#if FLUTTER_SHELL_ENABLE_METAL -#include "flutter/shell/platform/darwin/ios/ios_surface_metal.h" -#endif #include "flutter/shell/platform/darwin/ios/ios_surface_software.h" #include "third_party/skia/include/utils/mac/SkCGUtils.h" @@ -50,18 +47,10 @@ - (instancetype)init { - (instancetype)initWithContentsScale:(CGFloat)contentsScale { self = [self init]; - if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { - CAEAGLLayer* layer = reinterpret_cast(self.layer); - 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 + if ([self.layer isKindOfClass:[CAEAGLLayer class]] || + [self.layer isKindOfClass:[CAMetalLayer class]]) { + self.layer.contentsScale = contentsScale; + self.layer.rasterizationScale = contentsScale; } return self; @@ -72,27 +61,11 @@ + (Class)layerClass { } - (std::unique_ptr)createSurface: - (std::shared_ptr)gl_context { - 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); - } + (std::shared_ptr)ios_context { + return flutter::IOSSurface::Create(std::move(ios_context), // context + fml::scoped_nsobject{[self.layer retain]}, // layer + nullptr // platform views controller + ); } // TODO(amirh): implement drawLayer to support snapshotting. diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index fa5f8d4aba8d5..33c6d53a7b970 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -367,12 +367,12 @@ } bool FlutterPlatformViewsController::SubmitFrame(GrContext* gr_context, - std::shared_ptr gl_context) { + std::shared_ptr ios_context) { DisposeViews(); bool did_submit = true; for (int64_t view_id : composition_order_) { - EnsureOverlayInitialized(view_id, gl_context, gr_context); + EnsureOverlayInitialized(view_id, ios_context, gr_context); auto frame = overlays_[view_id]->surface->AcquireFrame(frame_size_); // If frame is null, AcquireFrame already printed out an error message. if (frame) { @@ -460,7 +460,7 @@ void FlutterPlatformViewsController::EnsureOverlayInitialized( int64_t overlay_id, - std::shared_ptr gl_context, + std::shared_ptr ios_context, GrContext* gr_context) { FML_DCHECK(flutter_view_); @@ -500,7 +500,7 @@ overlay_view.get().autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); std::unique_ptr ios_surface = - [overlay_view.get() createSurface:std::move(gl_context)]; + [overlay_view.get() createSurface:std::move(ios_context)]; std::unique_ptr surface = ios_surface->CreateGPUSurface(gr_context); overlays_[overlay_id] = std::make_unique( std::move(overlay_view), std::move(ios_surface), std::move(surface)); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index bdd013c98e07f..d135d7d2ac290 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -12,6 +12,7 @@ #include "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" // A UIView that is used as the parent for embedded UIViews. // @@ -53,7 +54,7 @@ CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix); // The position of the `layer` should be unchanged after resetting the anchor. void ResetAnchor(CALayer* layer); -class IOSGLContext; +class IOSContextGL; class IOSSurface; struct FlutterPlatformViewLayer { @@ -111,7 +112,7 @@ class FlutterPlatformViewsController { // Discards all platform views instances and auxiliary resources. void Reset(); - bool SubmitFrame(GrContext* gr_context, std::shared_ptr gl_context); + bool SubmitFrame(GrContext* gr_context, std::shared_ptr ios_context); void OnMethodCall(FlutterMethodCall* call, FlutterResult& result); @@ -173,7 +174,7 @@ class FlutterPlatformViewsController { // Dispose the views in `views_to_dispose_`. void DisposeViews(); void EnsureOverlayInitialized(int64_t overlay_id, - std::shared_ptr gl_context, + std::shared_ptr ios_context, GrContext* gr_context); // This will return true after pre-roll if any of the embedded views diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.h b/shell/platform/darwin/ios/framework/Source/FlutterView.h index 0da2d5b0bc71d..b767ceb6e8384 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -13,6 +13,7 @@ #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/shell.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" @protocol FlutterViewEngineDelegate @@ -33,8 +34,7 @@ - (instancetype)initWithDelegate:(id)delegate opaque:(BOOL)opaque NS_DESIGNATED_INITIALIZER; -- (std::unique_ptr)createSurface: - (std::shared_ptr)context; +- (std::unique_ptr)createSurface:(std::shared_ptr)context; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index 6ea664013575f..cba510f6b59ea 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -17,10 +17,6 @@ #include "flutter/shell/platform/darwin/ios/ios_surface_software.h" #include "third_party/skia/include/utils/mac/SkCGUtils.h" -#if FLUTTER_SHELL_ENABLE_METAL -#include "flutter/shell/platform/darwin/ios/ios_surface_metal.h" -#endif // FLUTTER_SHELL_ENABLE_METAL - @implementation FlutterView id _delegate; @@ -56,110 +52,27 @@ - (instancetype)initWithDelegate:(id)delegate opaque: } - (void)layoutSubviews { - if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { - CAEAGLLayer* layer = reinterpret_cast(self.layer); - layer.allowsGroupOpacity = YES; + if ([self.layer isKindOfClass:[CAEAGLLayer class]] || + [self.layer isKindOfClass:[CAMetalLayer class]]) { CGFloat screenScale = [UIScreen mainScreen].scale; - layer.contentsScale = screenScale; - layer.rasterizationScale = screenScale; - } - -#if FLUTTER_SHELL_ENABLE_METAL - if ([self.layer isKindOfClass:[CAMetalLayer class]]) { - const CGFloat screenScale = [UIScreen mainScreen].scale; - - auto metal_layer = reinterpret_cast(self.layer); - metal_layer.contentsScale = screenScale; - metal_layer.rasterizationScale = screenScale; - - const auto layer_size = self.bounds.size; - metal_layer.drawableSize = - CGSizeMake(layer_size.width * screenScale, layer_size.height * screenScale); + self.layer.contentsScale = screenScale; + self.layer.rasterizationScale = screenScale; } -#endif // FLUTTER_SHELL_ENABLE_METAL [super layoutSubviews]; } -#if FLUTTER_SHELL_ENABLE_METAL -static bool UseMetalRenderer() { - // If there is a command line argument that says Metal should not be used, that takes precedence - // over everything else. This allows disabling Metal on a per run basis to check for regressions - // on an application that has otherwise opted into Metal on an iOS version that supports it. - if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--disable-metal"]) { - return false; - } - - // If the application wants to use metal on a per run basis with disregard for version checks or - // plist based opt ins, respect that opinion. This allows selectively testing features on older - // version of iOS than those explicitly stated as being supported. - if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--force-metal"]) { - return true; - } - - // This is just a version we picked that is easy to support and has all necessary Metal features. - bool ios_version_supports_metal = false; - if (@available(iOS 11.0, *)) { - ios_version_supports_metal = true; - } - - // The application must opt-in by default to use Metal without command line flags. - bool application_opts_into_metal = - [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"io.flutter.metal_preview"] boolValue]; - - return ios_version_supports_metal && application_opts_into_metal; -} -#endif // FLUTTER_SHELL_ENABLE_METAL - + (Class)layerClass { -#if TARGET_IPHONE_SIMULATOR - return [CALayer class]; -#else // TARGET_IPHONE_SIMULATOR -#if FLUTTER_SHELL_ENABLE_METAL - if (UseMetalRenderer()) { - return [CAMetalLayer class]; - } else { - return [CAEAGLLayer class]; - } -#else // FLUTTER_SHELL_ENABLE_METAL - return [CAEAGLLayer class]; -#endif // FLUTTER_SHELL_ENABLE_METAL -#endif // TARGET_IPHONE_SIMULATOR + return flutter::GetQuartzLayerClassForRenderingAPI(); } - (std::unique_ptr)createSurface: - (std::shared_ptr)context { - if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { - fml::scoped_nsobject eagl_layer( - reinterpret_cast([self.layer retain])); - if (flutter::IsIosEmbeddedViewsPreviewEnabled()) { - if (@available(iOS 9.0, *)) { - // TODO(amirh): only do this if there's an embedded view. - // https://github.com/flutter/flutter/issues/24133 - eagl_layer.get().presentsWithTransaction = YES; - } - } - return std::make_unique(context, std::move(eagl_layer), - [_delegate platformViewsController]); -#if FLUTTER_SHELL_ENABLE_METAL - } 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 { - fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); - return std::make_unique(std::move(layer), - [_delegate platformViewsController]); - } + (std::shared_ptr)ios_context { + return flutter::IOSSurface::Create( + std::move(ios_context), // context + fml::scoped_nsobject{[self.layer retain]}, // layer + [_delegate platformViewsController] // platform views controller + ); } - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context { diff --git a/shell/platform/darwin/ios/ios_context.h b/shell/platform/darwin/ios/ios_context.h new file mode 100644 index 0000000000000..4914af38438f0 --- /dev/null +++ b/shell/platform/darwin/ios/ios_context.h @@ -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. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_RESOURCE_CONTEXT_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_RESOURCE_CONTEXT_H_ + +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/platform/darwin/ios/ios_render_target.h" +#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h" +#include "third_party/skia/include/gpu/GrContext.h" + +@class CALayer; + +namespace flutter { + +class IOSContext { + public: + static std::unique_ptr Create(IOSRenderingAPI rendering_api); + + IOSContext(); + + virtual ~IOSContext(); + + virtual std::unique_ptr CreateRenderTarget( + fml::scoped_nsobject layer) = 0; + + virtual sk_sp CreateResourceContext() = 0; + + virtual bool MakeCurrent() = 0; + + virtual bool ResourceMakeCurrent() = 0; + + virtual bool ClearCurrent() = 0; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(IOSContext); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_RESOURCE_CONTEXT_H_ diff --git a/shell/platform/darwin/ios/ios_context.mm b/shell/platform/darwin/ios/ios_context.mm new file mode 100644 index 0000000000000..6b0c34e635ff0 --- /dev/null +++ b/shell/platform/darwin/ios/ios_context.mm @@ -0,0 +1,37 @@ +// 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/darwin/ios/ios_context.h" + +#include "flutter/fml/logging.h" +#include "flutter/shell/platform/darwin/ios/ios_context_gl.h" + +#if FLUTTER_SHELL_ENABLE_METAL +#include "flutter/shell/platform/darwin/ios/ios_context_metal.h" +#endif // FLUTTER_SHELL_ENABLE_METAL + +namespace flutter { + +IOSContext::IOSContext() = default; + +IOSContext::~IOSContext() = default; + +std::unique_ptr IOSContext::Create(IOSRenderingAPI rendering_api) { + switch (rendering_api) { + case IOSRenderingAPI::kOpenGLES: + return std::make_unique(); + case IOSRenderingAPI::kSoftware: + break; +#if FLUTTER_SHELL_ENABLE_METAL + case IOSRenderingAPI::kMetal: + return std::make_unique(); +#endif // FLUTTER_SHELL_ENABLE_METAL + default: + break; + } + FML_CHECK(false); + return nullptr; +} + +} // namespace flutter diff --git a/shell/platform/darwin/ios/ios_gl_context.h b/shell/platform/darwin/ios/ios_context_gl.h similarity index 50% rename from shell/platform/darwin/ios/ios_gl_context.h rename to shell/platform/darwin/ios/ios_context_gl.h index 232645d9c8592..c648d57c49238 100644 --- a/shell/platform/darwin/ios/ios_gl_context.h +++ b/shell/platform/darwin/ios/ios_context_gl.h @@ -5,39 +5,43 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_CONTEXT_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_CONTEXT_H_ -#import -#import -#import -#import - #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/platform_view.h" -#include "ios_gl_render_target.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" +#include "flutter/shell/platform/darwin/ios/ios_render_target_gl.h" + +@class CAEAGLLayer; namespace flutter { -class IOSGLContext { +class IOSContextGL final : public IOSContext { public: - IOSGLContext(); + IOSContextGL(); - ~IOSGLContext(); + // |IOSContext| + ~IOSContextGL() override; - std::unique_ptr CreateRenderTarget( - fml::scoped_nsobject layer); + private: + fml::scoped_nsobject context_; + fml::scoped_nsobject resource_context_; - bool MakeCurrent(); + // |IOSContext| + std::unique_ptr CreateRenderTarget(fml::scoped_nsobject layer) override; - bool ResourceMakeCurrent(); + // |IOSContext| + sk_sp CreateResourceContext() override; - sk_sp ColorSpace() const { return color_space_; } + // |IOSContext| + bool MakeCurrent() override; - private: - fml::scoped_nsobject context_; - fml::scoped_nsobject resource_context_; - sk_sp color_space_; + // |IOSContext| + bool ClearCurrent() override; + + // |IOSContext| + bool ResourceMakeCurrent() override; - FML_DISALLOW_COPY_AND_ASSIGN(IOSGLContext); + FML_DISALLOW_COPY_AND_ASSIGN(IOSContextGL); }; } // namespace flutter diff --git a/shell/platform/darwin/ios/ios_context_gl.mm b/shell/platform/darwin/ios/ios_context_gl.mm new file mode 100644 index 0000000000000..e01b6120e497e --- /dev/null +++ b/shell/platform/darwin/ios/ios_context_gl.mm @@ -0,0 +1,61 @@ +// 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/darwin/ios/ios_context_gl.h" + +#import + +#include "flutter/shell/common/shell_io_manager.h" +#include "flutter/shell/gpu/gpu_surface_gl_delegate.h" + +namespace flutter { + +IOSContextGL::IOSContextGL() { + resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]); + if (resource_context_ != nullptr) { + context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 + sharegroup:resource_context_.get().sharegroup]); + } else { + resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]); + context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 + sharegroup:resource_context_.get().sharegroup]); + } +} + +IOSContextGL::~IOSContextGL() = default; + +std::unique_ptr IOSContextGL::CreateRenderTarget( + fml::scoped_nsobject layer) { + return std::make_unique(std::move(layer), context_, resource_context_); +} + +// |IOSContext| +sk_sp IOSContextGL::CreateResourceContext() { + // TODO(chinmaygarde): Now that this is here, can ResourceMakeCurrent be removed? + if (![EAGLContext setCurrentContext:resource_context_.get()]) { + FML_DLOG(INFO) << "Could not make resource context current on IO thread. Async texture uploads " + "will be disabled. On Simulators, this is expected."; + return nullptr; + } + + return ShellIOManager::CreateCompatibleResourceLoadingContext( + GrBackend::kOpenGL_GrBackend, GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface()); +} + +// |IOSContext| +bool IOSContextGL::MakeCurrent() { + return [EAGLContext setCurrentContext:context_.get()]; +} + +// |IOSContext| +bool IOSContextGL::ResourceMakeCurrent() { + return [EAGLContext setCurrentContext:resource_context_.get()]; +} + +// |IOSContext| +bool IOSContextGL::ClearCurrent() { + return [EAGLContext setCurrentContext:nil]; +} + +} // namespace flutter diff --git a/shell/platform/darwin/ios/ios_context_metal.h b/shell/platform/darwin/ios/ios_context_metal.h new file mode 100644 index 0000000000000..b26ad7813a0d4 --- /dev/null +++ b/shell/platform/darwin/ios/ios_context_metal.h @@ -0,0 +1,61 @@ +// 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_DARWIN_IOS_IOS_CONTEXT_METAL_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_CONTEXT_METAL_H_ + +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" +#include "third_party/skia/include/gpu/GrContext.h" + +namespace flutter { + +class IOSContextMetal final : public IOSContext { + public: + IOSContextMetal(); + + ~IOSContextMetal(); + + fml::scoped_nsprotocol> GetDevice() const; + + fml::scoped_nsprotocol> GetMainCommandQueue() const; + + fml::scoped_nsprotocol> GetResourceCommandQueue() const; + + sk_sp GetMainContext() const; + + sk_sp GetResourceContext() const; + + private: + fml::scoped_nsprotocol> device_; + fml::scoped_nsprotocol> main_queue_; + sk_sp main_context_; + sk_sp resource_context_; + bool is_valid_ = false; + + // |IOSContext| + std::unique_ptr CreateRenderTarget( + fml::scoped_nsobject layer) override; + + // |IOSContext| + sk_sp CreateResourceContext() override; + + // |IOSContext| + bool MakeCurrent() override; + + // |IOSContext| + bool ResourceMakeCurrent() override; + + // |IOSContext| + bool ClearCurrent() override; + + FML_DISALLOW_COPY_AND_ASSIGN(IOSContextMetal); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_CONTEXT_METAL_H_ diff --git a/shell/platform/darwin/ios/ios_context_metal.mm b/shell/platform/darwin/ios/ios_context_metal.mm new file mode 100644 index 0000000000000..7646d2caa70e7 --- /dev/null +++ b/shell/platform/darwin/ios/ios_context_metal.mm @@ -0,0 +1,91 @@ +// 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/darwin/ios/ios_context_metal.h" + +#include "flutter/fml/logging.h" + +namespace flutter { + +IOSContextMetal::IOSContextMetal() { + device_.reset([MTLCreateSystemDefaultDevice() retain]); + if (!device_) { + FML_LOG(ERROR) << "Could not acquire Metal device."; + return; + } + + main_queue_.reset([device_ newCommandQueue]); + + if (!main_queue_) { + FML_LOG(ERROR) << "Could not create Metal command queue."; + return; + } + + [main_queue_ setLabel:@"Flutter Main Queue"]; + + main_context_ = GrContext::MakeMetal([device_ retain], [main_queue_ retain]); + resource_context_ = GrContext::MakeMetal([device_ retain], [main_queue_ retain]); + + if (!main_context_ || !resource_context_) { + FML_LOG(ERROR) << "Could not create Skia Metal contexts."; + return; + } + + is_valid_ = false; +} + +IOSContextMetal::~IOSContextMetal() = default; + +fml::scoped_nsprotocol> IOSContextMetal::GetDevice() const { + return device_; +} + +fml::scoped_nsprotocol> IOSContextMetal::GetMainCommandQueue() const { + return main_queue_; +} + +fml::scoped_nsprotocol> IOSContextMetal::GetResourceCommandQueue() const { + // TODO(52150): Create a dedicated resource queue once multiple queues are supported in Skia. + return main_queue_; +} + +sk_sp IOSContextMetal::GetMainContext() const { + return main_context_; +} + +sk_sp IOSContextMetal::GetResourceContext() const { + return resource_context_; +} + +// |IOSContext| +std::unique_ptr IOSContextMetal::CreateRenderTarget( + fml::scoped_nsobject layer) { + FML_CHECK(false) << "WIP"; + return nullptr; +} + +// |IOSContext| +sk_sp IOSContextMetal::CreateResourceContext() { + return resource_context_; +} + +// |IOSContext| +bool IOSContextMetal::MakeCurrent() { + // This only makes sense for context that need to be bound to a specific thread. + return true; +} + +// |IOSContext| +bool IOSContextMetal::ResourceMakeCurrent() { + // This only makes sense for context that need to be bound to a specific thread. + return true; +} + +// |IOSContext| +bool IOSContextMetal::ClearCurrent() { + // This only makes sense for context that need to be bound to a specific thread. + return true; +} + +} // namespace flutter diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.h b/shell/platform/darwin/ios/ios_external_texture_gl.h index 30c138af76584..46033ecb7ac50 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.h +++ b/shell/platform/darwin/ios/ios_external_texture_gl.h @@ -12,34 +12,41 @@ namespace flutter { -class IOSExternalTextureGL : public flutter::Texture { +class IOSExternalTextureGL final : public Texture { public: IOSExternalTextureGL(int64_t textureId, NSObject* externalTexture); + // |Texture| ~IOSExternalTextureGL() override; - // Called from GPU thread. + private: + bool new_frame_ready_ = false; + fml::scoped_nsobject> external_texture_; + fml::CFRef cache_ref_; + fml::CFRef texture_ref_; + fml::CFRef buffer_ref_; + + // |Texture| void Paint(SkCanvas& canvas, const SkRect& bounds, bool freeze, GrContext* context) override; + // |Texture| void OnGrContextCreated() override; + // |Texture| void OnGrContextDestroyed() override; + // |Texture| void MarkNewFrameAvailable() override; + // |Texture| void OnTextureUnregistered() override; - private: void CreateTextureFromPixelBuffer(); void EnsureTextureCacheExists(); + bool NeedUpdateTexture(bool freeze); - bool new_frame_ready_ = false; - fml::scoped_nsobject> external_texture_; - fml::CFRef cache_ref_; - fml::CFRef texture_ref_; - fml::CFRef buffer_ref_; FML_DISALLOW_COPY_AND_ASSIGN(IOSExternalTextureGL); }; diff --git a/shell/platform/darwin/ios/ios_gl_context.mm b/shell/platform/darwin/ios/ios_gl_context.mm deleted file mode 100644 index 52fb85f8f19a9..0000000000000 --- a/shell/platform/darwin/ios/ios_gl_context.mm +++ /dev/null @@ -1,63 +0,0 @@ -// 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/darwin/ios/ios_gl_context.h" - -#include - -#include "flutter/fml/trace_event.h" -#include "third_party/skia/include/gpu/GrContextOptions.h" -#include "third_party/skia/include/gpu/gl/GrGLInterface.h" - -namespace flutter { - -IOSGLContext::IOSGLContext() { - resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]); - if (resource_context_ != nullptr) { - context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 - sharegroup:resource_context_.get().sharegroup]); - } else { - resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]); - context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 - sharegroup:resource_context_.get().sharegroup]); - } - - // TODO: - // iOS displays are more variable than just P3 or sRGB. Reading the display - // gamut just tells us what color space it makes sense to render into. We - // should use iOS APIs to perform the final correction step based on the - // device properties. Ex: We can indicate that we have rendered in P3, and - // the framework will do the final adjustment for us. - color_space_ = SkColorSpace::MakeSRGB(); - if (@available(iOS 10, *)) { - UIDisplayGamut displayGamut = [UIScreen mainScreen].traitCollection.displayGamut; - switch (displayGamut) { - case UIDisplayGamutP3: - // Should we consider using more than 8-bits of precision given that - // P3 specifies a wider range of colors? - color_space_ = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); - break; - default: - break; - } - } -} - -IOSGLContext::~IOSGLContext() = default; - -std::unique_ptr IOSGLContext::CreateRenderTarget( - fml::scoped_nsobject layer) { - return std::make_unique(std::move(layer), context_.get(), - resource_context_.get()); -} - -bool IOSGLContext::MakeCurrent() { - return [EAGLContext setCurrentContext:context_.get()]; -} - -bool IOSGLContext::ResourceMakeCurrent() { - return [EAGLContext setCurrentContext:resource_context_.get()]; -} - -} // namespace flutter diff --git a/shell/platform/darwin/ios/ios_gl_render_target.h b/shell/platform/darwin/ios/ios_gl_render_target.h deleted file mode 100644 index b2eafe16e0950..0000000000000 --- a/shell/platform/darwin/ios/ios_gl_render_target.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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_DARWIN_IOS_IOS_GL_RENDER_TARGET_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_RENDER_TARGET_H_ - -#import -#import -#import -#import - -#include "flutter/fml/macros.h" -#include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/shell/common/platform_view.h" - -namespace flutter { - -class IOSGLRenderTarget { - public: - IOSGLRenderTarget(fml::scoped_nsobject layer, - EAGLContext* context, - EAGLContext* resource_context); - - ~IOSGLRenderTarget(); - - bool IsValid() const; - - bool PresentRenderBuffer() const; - - GLuint framebuffer() const { return framebuffer_; } - - bool UpdateStorageSizeIfNecessary(); - - bool MakeCurrent(); - - bool ResourceMakeCurrent(); - - sk_sp ColorSpace() const { return color_space_; } - - private: - fml::scoped_nsobject layer_; - fml::scoped_nsobject context_; - fml::scoped_nsobject resource_context_; - GLuint framebuffer_; - GLuint colorbuffer_; - GLint storage_size_width_; - GLint storage_size_height_; - sk_sp color_space_; - bool valid_; - - FML_DISALLOW_COPY_AND_ASSIGN(IOSGLRenderTarget); -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_GL_RENDER_TARGET_H_ diff --git a/shell/platform/darwin/ios/ios_render_target.h b/shell/platform/darwin/ios/ios_render_target.h new file mode 100644 index 0000000000000..47f0e0587087d --- /dev/null +++ b/shell/platform/darwin/ios/ios_render_target.h @@ -0,0 +1,34 @@ +// 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_DARWIN_IOS_IOS_RENDER_TARGET_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_RENDER_TARGET_H_ + +#include + +#include "flutter/fml/macros.h" + +namespace flutter { + +class IOSRenderTarget { + public: + IOSRenderTarget(); + + virtual ~IOSRenderTarget(); + + virtual bool IsValid() const = 0; + + virtual bool PresentRenderBuffer() const = 0; + + virtual intptr_t GetFramebuffer() const = 0; + + virtual bool UpdateStorageSizeIfNecessary() = 0; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(IOSRenderTarget); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_RENDER_TARGET_H_ diff --git a/shell/platform/darwin/ios/ios_render_target.mm b/shell/platform/darwin/ios/ios_render_target.mm new file mode 100644 index 0000000000000..c11c85c39db8b --- /dev/null +++ b/shell/platform/darwin/ios/ios_render_target.mm @@ -0,0 +1,13 @@ +// 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/darwin/ios/ios_render_target.h" + +namespace flutter { + +IOSRenderTarget::IOSRenderTarget() = default; + +IOSRenderTarget::~IOSRenderTarget() = default; + +} // namespace flutter diff --git a/shell/platform/darwin/ios/ios_render_target_gl.h b/shell/platform/darwin/ios/ios_render_target_gl.h new file mode 100644 index 0000000000000..203634df0d0f7 --- /dev/null +++ b/shell/platform/darwin/ios/ios_render_target_gl.h @@ -0,0 +1,56 @@ +// 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_DARWIN_IOS_IOS_RENDER_TARGET_GL_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_RENDER_TARGET_GL_H_ + +#import +#import +#import +#import + +#include "flutter/fml/macros.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/platform/darwin/ios/ios_render_target.h" + +namespace flutter { + +class IOSRenderTargetGL final : public IOSRenderTarget { + public: + IOSRenderTargetGL(fml::scoped_nsobject layer, + fml::scoped_nsobject context, + fml::scoped_nsobject resource_context); + + // |IOSRenderTarget| + ~IOSRenderTargetGL() override; + + private: + fml::scoped_nsobject layer_; + fml::scoped_nsobject context_; + fml::scoped_nsobject resource_context_; + GLuint framebuffer_ = GL_NONE; + GLuint colorbuffer_ = GL_NONE; + GLint storage_size_width_ = GL_NONE; + GLint storage_size_height_ = GL_NONE; + bool valid_ = false; + + // |IOSRenderTarget| + bool IsValid() const override; + + // |IOSRenderTarget| + bool PresentRenderBuffer() const override; + + // |IOSRenderTarget| + intptr_t GetFramebuffer() const override; + + // |IOSRenderTarget| + bool UpdateStorageSizeIfNecessary() override; + + FML_DISALLOW_COPY_AND_ASSIGN(IOSRenderTargetGL); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_RENDER_TARGET_GL_H_ diff --git a/shell/platform/darwin/ios/ios_gl_render_target.mm b/shell/platform/darwin/ios/ios_render_target_gl.mm similarity index 70% rename from shell/platform/darwin/ios/ios_gl_render_target.mm rename to shell/platform/darwin/ios/ios_render_target_gl.mm index a57ba9c46b414..d9288a5d4c297 100644 --- a/shell/platform/darwin/ios/ios_gl_render_target.mm +++ b/shell/platform/darwin/ios/ios_render_target_gl.mm @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/darwin/ios/ios_gl_render_target.h" +#include "flutter/shell/platform/darwin/ios/ios_render_target_gl.h" #include @@ -12,21 +12,25 @@ namespace flutter { -IOSGLRenderTarget::IOSGLRenderTarget(fml::scoped_nsobject layer, - EAGLContext* context, - EAGLContext* resource_context) - : layer_(std::move(layer)), - context_([context retain]), - resource_context_([resource_context retain]), - framebuffer_(GL_NONE), - colorbuffer_(GL_NONE), - storage_size_width_(0), - storage_size_height_(0), - valid_(false) { +static fml::scoped_nsobject CastEAGLLayer(fml::scoped_nsobject layer) { + FML_DCHECK([layer isKindOfClass:[CAEAGLLayer class]]); + return fml::scoped_nsobject{reinterpret_cast([layer.get() retain])}; +} + +IOSRenderTargetGL::IOSRenderTargetGL(fml::scoped_nsobject layer, + fml::scoped_nsobject context, + fml::scoped_nsobject resource_context) + : layer_(CastEAGLLayer(std::move(layer))), + context_(std::move(context)), + resource_context_(std::move(resource_context)) { FML_DCHECK(layer_ != nullptr); FML_DCHECK(context_ != nullptr); FML_DCHECK(resource_context_ != nullptr); + if (@available(iOS 9.0, *)) { + [layer_ setPresentsWithTransaction:YES]; + } + bool context_current = [EAGLContext setCurrentContext:context_]; FML_DCHECK(context_current); @@ -61,7 +65,7 @@ valid_ = true; } -IOSGLRenderTarget::~IOSGLRenderTarget() { +IOSRenderTargetGL::~IOSRenderTargetGL() { EAGLContext* context = EAGLContext.currentContext; [EAGLContext setCurrentContext:context_]; FML_DCHECK(glGetError() == GL_NO_ERROR); @@ -74,11 +78,18 @@ [EAGLContext setCurrentContext:context]; } -bool IOSGLRenderTarget::IsValid() const { +// |IOSRenderTarget| +bool IOSRenderTargetGL::IsValid() const { return valid_; } -bool IOSGLRenderTarget::PresentRenderBuffer() const { +// |IOSRenderTarget| +intptr_t IOSRenderTargetGL::GetFramebuffer() const { + return framebuffer_; +} + +// |IOSRenderTarget| +bool IOSRenderTargetGL::PresentRenderBuffer() const { const GLenum discards[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT, @@ -87,20 +98,23 @@ glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof(discards) / sizeof(GLenum), discards); glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); - return [[EAGLContext currentContext] presentRenderbuffer:GL_RENDERBUFFER]; + auto current_context = [EAGLContext currentContext]; + FML_DCHECK(current_context != nullptr); + return [current_context presentRenderbuffer:GL_RENDERBUFFER]; } -bool IOSGLRenderTarget::UpdateStorageSizeIfNecessary() { +// |IOSRenderTarget| +bool IOSRenderTargetGL::UpdateStorageSizeIfNecessary() { const CGSize layer_size = [layer_.get() bounds].size; const CGFloat contents_scale = layer_.get().contentsScale; const GLint size_width = layer_size.width * contents_scale; const GLint size_height = layer_size.height * contents_scale; if (size_width == storage_size_width_ && size_height == storage_size_height_) { - // Nothing to since the stoage size is already consistent with the layer. + // Nothing to do since the storage size is already consistent with the layer. return true; } - TRACE_EVENT_INSTANT0("flutter", "IOSGLRenderTarget::UpdateStorageSizeIfNecessary"); + TRACE_EVENT_INSTANT0("flutter", "IOSRenderTargetGL::UpdateStorageSizeIfNecessary"); FML_DLOG(INFO) << "Updating render buffer storage size."; FML_DCHECK(glGetError() == GL_NO_ERROR); @@ -132,12 +146,4 @@ return true; } -bool IOSGLRenderTarget::MakeCurrent() { - return UpdateStorageSizeIfNecessary() && [EAGLContext setCurrentContext:context_.get()]; -} - -bool IOSGLRenderTarget::ResourceMakeCurrent() { - return [EAGLContext setCurrentContext:resource_context_.get()]; -} - } // namespace flutter diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index 49f40f9eec76a..713239cee651e 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -9,25 +9,37 @@ #include +#include "flutter/flow/embedded_views.h" #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/surface.h" +@class CALayer; + namespace flutter { // Returns true if the app explicitly specified to use the iOS view embedding // mechanism which is still in a release preview. bool IsIosEmbeddedViewsPreviewEnabled(); -class IOSSurface { +class IOSSurface : public ExternalViewEmbedder { public: - IOSSurface(FlutterPlatformViewsController* platform_views_controller); + static std::unique_ptr Create( + std::shared_ptr context, + fml::scoped_nsobject layer, + FlutterPlatformViewsController* platform_views_controller); + // |ExternalViewEmbedder| virtual ~IOSSurface(); - virtual bool IsValid() const = 0; + std::shared_ptr GetContext() const; + + ExternalViewEmbedder* GetExternalViewEmbedderIfEnabled(); - virtual bool ResourceContextMakeCurrent() = 0; + bool ResourceContextMakeCurrent(); + + // TODO(chinmaygarde): Required? + virtual bool IsValid() const = 0; virtual void UpdateStorageSizeIfNecessary() = 0; @@ -36,15 +48,40 @@ class IOSSurface { // will be used. // // If a GrContext is supplied, creates a secondary surface. - virtual std::unique_ptr CreateGPUSurface( - GrContext* gr_context = nullptr) = 0; + virtual std::unique_ptr CreateGPUSurface(GrContext* gr_context = nullptr) = 0; protected: - FlutterPlatformViewsController* GetPlatformViewsController(); + IOSSurface(std::shared_ptr ios_context, + FlutterPlatformViewsController* platform_views_controller); private: + std::shared_ptr ios_context_; FlutterPlatformViewsController* platform_views_controller_; + // |ExternalViewEmbedder| + SkCanvas* GetRootCanvas() override; + + // |ExternalViewEmbedder| + void CancelFrame() override; + + // |ExternalViewEmbedder| + void BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) 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; + public: FML_DISALLOW_COPY_AND_ASSIGN(IOSSurface); }; diff --git a/shell/platform/darwin/ios/ios_surface.mm b/shell/platform/darwin/ios/ios_surface.mm index 4c2b4efd85fa4..7b4cb4649a2d2 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -4,26 +4,133 @@ #include "flutter/shell/platform/darwin/ios/ios_surface.h" -#include - #include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" #include "flutter/shell/platform/darwin/ios/ios_surface_software.h" +#if FLUTTER_SHELL_ENABLE_METAL +#include "flutter/shell/platform/darwin/ios/ios_surface_metal.h" +#endif // FLUTTER_SHELL_ENABLE_METAL + namespace flutter { // The name of the Info.plist flag to enable the embedded iOS views preview. -const char* const kEmbeddedViewsPreview = "io.flutter.embedded_views_preview"; +constexpr const char* kEmbeddedViewsPreview = "io.flutter.embedded_views_preview"; bool IsIosEmbeddedViewsPreviewEnabled() { - return [[[NSBundle mainBundle] objectForInfoDictionaryKey:@(kEmbeddedViewsPreview)] boolValue]; + static bool preview_enabled = + [[[NSBundle mainBundle] objectForInfoDictionaryKey:@(kEmbeddedViewsPreview)] boolValue]; + return preview_enabled; +} + +std::unique_ptr IOSSurface::Create( + std::shared_ptr context, + fml::scoped_nsobject layer, + FlutterPlatformViewsController* platform_views_controller) { + FML_DCHECK(layer); + FML_DCHECK(context); + + if ([layer.get() isKindOfClass:[CAEAGLLayer class]]) { + return std::make_unique(std::move(layer), std::move(context), + platform_views_controller); + } + +#if FLUTTER_SHELL_ENABLE_METAL + if ([layer.get() isKindOfClass:[CAMetalLayer class]]) { + return std::make_unique(std::move(layer), std::move(context), + platform_views_controller); + } +#endif // FLUTTER_SHELL_ENABLE_METAL + + return std::make_unique(std::move(layer), std::move(context), + platform_views_controller); } -IOSSurface::IOSSurface(FlutterPlatformViewsController* platform_views_controller) - : platform_views_controller_(platform_views_controller) {} +IOSSurface::IOSSurface(std::shared_ptr ios_context, + FlutterPlatformViewsController* platform_views_controller) + : ios_context_(std::move(ios_context)), platform_views_controller_(platform_views_controller) { + FML_DCHECK(ios_context_); +} IOSSurface::~IOSSurface() = default; -FlutterPlatformViewsController* IOSSurface::GetPlatformViewsController() { - return platform_views_controller_; +bool IOSSurface::ResourceContextMakeCurrent() { + return GetContext()->ResourceMakeCurrent(); +} + +std::shared_ptr IOSSurface::GetContext() const { + return ios_context_; +} + +// |ExternalViewEmbedder| +SkCanvas* IOSSurface::GetRootCanvas() { + // 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; +} + +ExternalViewEmbedder* IOSSurface::GetExternalViewEmbedderIfEnabled() { + if (IsIosEmbeddedViewsPreviewEnabled()) { + return this; + } else { + return nullptr; + } +} + +// |ExternalViewEmbedder| +void IOSSurface::CancelFrame() { + TRACE_EVENT0("flutter", "IOSSurface::CancelFrame"); + FML_CHECK(platform_views_controller_ != nullptr); + platform_views_controller_->CancelFrame(); + // Committing the current transaction as |BeginFrame| will create a nested + // CATransaction otherwise. + [CATransaction commit]; +} + +// |ExternalViewEmbedder| +void IOSSurface::BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) { + TRACE_EVENT0("flutter", "IOSSurface::BeginFrame"); + FML_CHECK(platform_views_controller_ != nullptr); + platform_views_controller_->SetFrameSize(frame_size); + [CATransaction begin]; +} + +// |ExternalViewEmbedder| +void IOSSurface::PrerollCompositeEmbeddedView(int view_id, + std::unique_ptr params) { + TRACE_EVENT0("flutter", "IOSSurface::PrerollCompositeEmbeddedView"); + + FML_CHECK(platform_views_controller_ != nullptr); + platform_views_controller_->PrerollCompositeEmbeddedView(view_id, std::move(params)); +} + +// |ExternalViewEmbedder| +PostPrerollResult IOSSurface::PostPrerollAction( + fml::RefPtr gpu_thread_merger) { + TRACE_EVENT0("flutter", "IOSSurface::PostPrerollAction"); + FML_CHECK(platform_views_controller_ != nullptr); + return platform_views_controller_->PostPrerollAction(gpu_thread_merger); } + +// |ExternalViewEmbedder| +std::vector IOSSurface::GetCurrentCanvases() { + FML_CHECK(platform_views_controller_ != nullptr); + return platform_views_controller_->GetCurrentCanvases(); +} + +// |ExternalViewEmbedder| +SkCanvas* IOSSurface::CompositeEmbeddedView(int view_id) { + TRACE_EVENT0("flutter", "IOSSurface::CompositeEmbeddedView"); + FML_CHECK(platform_views_controller_ != nullptr); + return platform_views_controller_->CompositeEmbeddedView(view_id); +} + +// |ExternalViewEmbedder| +bool IOSSurface::SubmitFrame(GrContext* context) { + TRACE_EVENT0("flutter", "IOSSurface::SubmitFrame"); + FML_CHECK(platform_views_controller_ != nullptr); + bool submitted = platform_views_controller_->SubmitFrame(std::move(context), ios_context_); + [CATransaction commit]; + return submitted; +} + } // namespace flutter diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index 906f3be92b2d8..a1e66b77855f6 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -8,79 +8,51 @@ #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/gpu/gpu_surface_gl.h" -#include "flutter/shell/platform/darwin/ios/ios_gl_context.h" -#include "flutter/shell/platform/darwin/ios/ios_gl_render_target.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" +#include "flutter/shell/platform/darwin/ios/ios_render_target.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" -@class CAEAGLLayer; +@class CALayer; namespace flutter { -class IOSSurfaceGL final : public IOSSurface, - public GPUSurfaceGLDelegate, - public ExternalViewEmbedder { +class IOSSurfaceGL final : public IOSSurface, public GPUSurfaceGLDelegate { public: - IOSSurfaceGL(std::shared_ptr context, - fml::scoped_nsobject layer, - FlutterPlatformViewsController* platform_views_controller); - - IOSSurfaceGL(fml::scoped_nsobject layer, std::shared_ptr context); + IOSSurfaceGL(fml::scoped_nsobject layer, + std::shared_ptr context, + FlutterPlatformViewsController* platform_views_controller = nullptr); ~IOSSurfaceGL() override; // |IOSSurface| bool IsValid() const override; - // |IOSSurface| - bool ResourceContextMakeCurrent() override; - // |IOSSurface| void UpdateStorageSizeIfNecessary() override; // |IOSSurface| - std::unique_ptr CreateGPUSurface(GrContext* gr_context = nullptr) override; + std::unique_ptr CreateGPUSurface(GrContext* gr_context) override; + // |GPUSurfaceGLDelegate| bool GLContextMakeCurrent() override; + // |GPUSurfaceGLDelegate| bool GLContextClearCurrent() override; + // |GPUSurfaceGLDelegate| bool GLContextPresent() override; + // |GPUSurfaceGLDelegate| intptr_t GLContextFBO() const override; + // |GPUSurfaceGLDelegate| bool SurfaceSupportsReadback() const override; // |GPUSurfaceGLDelegate| ExternalViewEmbedder* GetExternalViewEmbedder() override; - // |ExternalViewEmbedder| - SkCanvas* GetRootCanvas() override; - - // |ExternalViewEmbedder| - void CancelFrame() override; - - // |ExternalViewEmbedder| - void BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) 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: - std::shared_ptr context_; - std::unique_ptr render_target_; + std::unique_ptr render_target_; FML_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceGL); }; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 4f1da5a593a02..7b3cced79eb77 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -9,35 +9,28 @@ namespace flutter { -IOSSurfaceGL::IOSSurfaceGL(std::shared_ptr context, - fml::scoped_nsobject layer, +IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, + std::shared_ptr context, FlutterPlatformViewsController* platform_views_controller) - : IOSSurface(platform_views_controller), context_(context) { - render_target_ = context_->CreateRenderTarget(std::move(layer)); -} - -IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, - std::shared_ptr context) - : IOSSurface(nullptr), context_(context) { - render_target_ = context_->CreateRenderTarget(std::move(layer)); + : IOSSurface(context, platform_views_controller) { + render_target_ = context->CreateRenderTarget(std::move(layer)); } IOSSurfaceGL::~IOSSurfaceGL() = default; +// |IOSSurface| bool IOSSurfaceGL::IsValid() const { return render_target_->IsValid(); } -bool IOSSurfaceGL::ResourceContextMakeCurrent() { - return context_->ResourceMakeCurrent(); -} - +// |IOSSurface| void IOSSurfaceGL::UpdateStorageSizeIfNecessary() { if (IsValid()) { render_target_->UpdateStorageSizeIfNecessary(); } } +// |IOSSurface| std::unique_ptr IOSSurfaceGL::CreateGPUSurface(GrContext* gr_context) { if (gr_context) { return std::make_unique(sk_ref_sp(gr_context), this, true); @@ -45,10 +38,12 @@ return std::make_unique(this, true); } +// |GPUSurfaceGLDelegate| intptr_t IOSSurfaceGL::GLContextFBO() const { - return IsValid() ? render_target_->framebuffer() : GL_NONE; + return IsValid() ? render_target_->GetFramebuffer() : 0; } +// |GPUSurfaceGLDelegate| bool IOSSurfaceGL::SurfaceSupportsReadback() const { // The onscreen surface wraps a GL renderbuffer, which is extremely slow to read on iOS. // Certain filter effects, in particular BackdropFilter, require making a copy of @@ -58,98 +53,29 @@ return false; } +// |GPUSurfaceGLDelegate| bool IOSSurfaceGL::GLContextMakeCurrent() { if (!IsValid()) { return false; } - return render_target_->UpdateStorageSizeIfNecessary() && context_->MakeCurrent(); + return render_target_->UpdateStorageSizeIfNecessary() && GetContext()->MakeCurrent(); } +// |GPUSurfaceGLDelegate| bool IOSSurfaceGL::GLContextClearCurrent() { [EAGLContext setCurrentContext:nil]; return true; } +// |GPUSurfaceGLDelegate| bool IOSSurfaceGL::GLContextPresent() { TRACE_EVENT0("flutter", "IOSSurfaceGL::GLContextPresent"); return IsValid() && render_target_->PresentRenderBuffer(); } -// |ExternalViewEmbedder| -SkCanvas* IOSSurfaceGL::GetRootCanvas() { - // 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; -} - -// |ExternalViewEmbedder| -flutter::ExternalViewEmbedder* IOSSurfaceGL::GetExternalViewEmbedder() { - if (IsIosEmbeddedViewsPreviewEnabled()) { - return this; - } else { - return nullptr; - } -} - -// |ExternalViewEmbedder| -void IOSSurfaceGL::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]; -} - -// |ExternalViewEmbedder| -void IOSSurfaceGL::BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - platform_views_controller->SetFrameSize(frame_size); - [CATransaction begin]; -} - -// |ExternalViewEmbedder| -void IOSSurfaceGL::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 IOSSurfaceGL::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); -} - -// |ExternalViewEmbedder| -std::vector IOSSurfaceGL::GetCurrentCanvases() { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->GetCurrentCanvases(); -} - -// |ExternalViewEmbedder| -SkCanvas* IOSSurfaceGL::CompositeEmbeddedView(int view_id) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->CompositeEmbeddedView(view_id); -} - -// |ExternalViewEmbedder| -bool IOSSurfaceGL::SubmitFrame(GrContext* context) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - if (platform_views_controller == nullptr) { - return true; - } - - bool submitted = platform_views_controller->SubmitFrame(std::move(context), context_); - [CATransaction commit]; - return submitted; +// |GPUSurfaceGLDelegate| +ExternalViewEmbedder* IOSSurfaceGL::GetExternalViewEmbedder() { + return GetExternalViewEmbedderIfEnabled(); } } // namespace flutter diff --git a/shell/platform/darwin/ios/ios_surface_metal.h b/shell/platform/darwin/ios/ios_surface_metal.h index 2b001ea2b692d..30e59b5d2f335 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.h +++ b/shell/platform/darwin/ios/ios_surface_metal.h @@ -6,68 +6,38 @@ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_METAL_H_ #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" +@class CALayer; @class CAMetalLayer; namespace flutter { -class IOSSurfaceMetal final : public IOSSurface, - public GPUSurfaceDelegate, - public ExternalViewEmbedder { +class IOSSurfaceMetal final : public IOSSurface, public GPUSurfaceDelegate { public: - IOSSurfaceMetal(fml::scoped_nsobject layer, + IOSSurfaceMetal(fml::scoped_nsobject layer, + std::shared_ptr context, FlutterPlatformViewsController* platform_views_controller); - IOSSurfaceMetal(fml::scoped_nsobject layer); - + // |IOSSurface| ~IOSSurfaceMetal() override; - // |IOSSurface| - bool IsValid() const override; + private: + fml::scoped_nsobject layer_; + bool is_valid_ = false; // |IOSSurface| - bool ResourceContextMakeCurrent() override; + bool IsValid() const override; // |IOSSurface| void UpdateStorageSizeIfNecessary() override; // |IOSSurface| - std::unique_ptr CreateGPUSurface(GrContext* gr_context = nullptr) override; + std::unique_ptr CreateGPUSurface(GrContext* gr_context) override; // |GPUSurfaceDelegate| - flutter::ExternalViewEmbedder* GetExternalViewEmbedder() override; - - // |ExternalViewEmbedder| - SkCanvas* GetRootCanvas() override; - - // |ExternalViewEmbedder| - void CancelFrame() override; - - // |ExternalViewEmbedder| - void BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) 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_; + ExternalViewEmbedder* GetExternalViewEmbedder() override; 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 58a5fc328647b..9a2cfa51d4c03 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.mm +++ b/shell/platform/darwin/ios/ios_surface_metal.mm @@ -3,110 +3,65 @@ // found in the LICENSE file. #include "flutter/shell/platform/darwin/ios/ios_surface_metal.h" + #include "flutter/shell/gpu/gpu_surface_metal.h" +#include "flutter/shell/platform/darwin/ios/ios_context_metal.h" namespace flutter { -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| -bool IOSSurfaceMetal::IsValid() const { - return layer_; +static fml::scoped_nsobject CastToMetalLayer(fml::scoped_nsobject layer) { + FML_DCHECK([layer isKindOfClass:[CAMetalLayer class]]); + return fml::scoped_nsobject{reinterpret_cast([layer.get() retain])}; } -// |IOSSurface| -bool IOSSurfaceMetal::ResourceContextMakeCurrent() { - return false; +static IOSContextMetal* CastToMetalContext(const std::shared_ptr& context) { + return reinterpret_cast(context.get()); } -// |IOSSurface| -void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() {} - -// |IOSSurface| -std::unique_ptr IOSSurfaceMetal::CreateGPUSurface(GrContext* gr_context) { - if (gr_context) { - return std::make_unique(this, sk_ref_sp(gr_context), layer_); +IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject layer, + std::shared_ptr context, + FlutterPlatformViewsController* platform_views_controller) + : IOSSurface(std::move(context), platform_views_controller), + layer_(CastToMetalLayer(std::move(layer))) { + if (!layer_) { + return; } - return std::make_unique(this, layer_); -} -// |ExternalViewEmbedder| -SkCanvas* IOSSurfaceMetal::GetRootCanvas() { - // 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; -} + auto metal_context = CastToMetalContext(GetContext()); -flutter::ExternalViewEmbedder* IOSSurfaceMetal::GetExternalViewEmbedder() { - if (IsIosEmbeddedViewsPreviewEnabled()) { - return this; - } else { - return nullptr; - } -} + layer_.get().device = metal_context->GetDevice().get(); + layer_.get().presentsWithTransaction = YES; -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]; + is_valid_ = true; } -void IOSSurfaceMetal::BeginFrame(SkISize frame_size, - GrContext* context, - double device_pixel_ratio) { - 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)); -} +// |IOSSurface| +IOSSurfaceMetal::~IOSSurfaceMetal() = default; -// |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); +// |IOSSurface| +bool IOSSurfaceMetal::IsValid() const { + return is_valid_; } -std::vector IOSSurfaceMetal::GetCurrentCanvases() { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->GetCurrentCanvases(); +// |IOSSurface| +void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() { + // Nothing to do. } -SkCanvas* IOSSurfaceMetal::CompositeEmbeddedView(int view_id) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->CompositeEmbeddedView(view_id); +// |IOSSurface| +std::unique_ptr IOSSurfaceMetal::CreateGPUSurface(GrContext* /* unused */) { + auto metal_context = CastToMetalContext(GetContext()); + + return std::make_unique(this, // Metal surface delegate + layer_, // layer + metal_context->GetMainContext(), // context + metal_context->GetMainCommandQueue() // command queue + ); } -bool IOSSurfaceMetal::SubmitFrame(GrContext* context) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - if (platform_views_controller == nullptr) { - return true; - } - - bool submitted = platform_views_controller->SubmitFrame(context, nullptr); - [CATransaction commit]; - return submitted; +// |GPUSurfaceDelegate| +ExternalViewEmbedder* IOSSurfaceMetal::GetExternalViewEmbedder() { + return GetExternalViewEmbedderIfEnabled(); } } // namespace flutter diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index daac2ffc77231..86e6b6b209785 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -9,17 +9,17 @@ #include "flutter/fml/macros.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/gpu/gpu_surface_software.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" @class CALayer; namespace flutter { -class IOSSurfaceSoftware final : public IOSSurface, - public GPUSurfaceSoftwareDelegate, - public ExternalViewEmbedder { +class IOSSurfaceSoftware final : public IOSSurface, public GPUSurfaceSoftwareDelegate { public: IOSSurfaceSoftware(fml::scoped_nsobject layer, + std::shared_ptr context, FlutterPlatformViewsController* platform_views_controller); ~IOSSurfaceSoftware() override; @@ -27,9 +27,6 @@ class IOSSurfaceSoftware final : public IOSSurface, // |IOSSurface| bool IsValid() const override; - // |IOSSurface| - bool ResourceContextMakeCurrent() override; - // |IOSSurface| void UpdateStorageSizeIfNecessary() override; @@ -45,28 +42,6 @@ class IOSSurfaceSoftware final : public IOSSurface, // |GPUSurfaceSoftwareDelegate| ExternalViewEmbedder* GetExternalViewEmbedder() override; - // |ExternalViewEmbedder| - SkCanvas* GetRootCanvas() override; - - // |ExternalViewEmbedder| - void CancelFrame() override; - - // |ExternalViewEmbedder| - void BeginFrame(SkISize frame_size, GrContext* context, double device_pixel_ratio) override; - - // |ExternalViewEmbedder| - void PrerollCompositeEmbeddedView(int view_id, - std::unique_ptr params) override; - - // |ExternalViewEmbedder| - std::vector GetCurrentCanvases() override; - - // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; - - // |ExternalViewEmbedder| - bool SubmitFrame(GrContext* context) override; - private: fml::scoped_nsobject layer_; sk_sp sk_surface_; diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index ab5490cf25140..06abe29c661e8 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -16,10 +16,9 @@ namespace flutter { IOSSurfaceSoftware::IOSSurfaceSoftware(fml::scoped_nsobject layer, + std::shared_ptr context, FlutterPlatformViewsController* platform_views_controller) - : IOSSurface(platform_views_controller), layer_(std::move(layer)) { - UpdateStorageSizeIfNecessary(); -} + : IOSSurface(std::move(context), platform_views_controller), layer_(std::move(layer)) {} IOSSurfaceSoftware::~IOSSurfaceSoftware() = default; @@ -27,10 +26,6 @@ return layer_; } -bool IOSSurfaceSoftware::ResourceContextMakeCurrent() { - return false; -} - void IOSSurfaceSoftware::UpdateStorageSizeIfNecessary() { // Nothing to do here. We don't need an external entity to tell us when our // backing store needs to be updated. Instead, we let the frame tell us its @@ -127,66 +122,9 @@ return true; } +// |GPUSurfaceSoftwareDelegate| ExternalViewEmbedder* IOSSurfaceSoftware::GetExternalViewEmbedder() { - if (IsIosEmbeddedViewsPreviewEnabled()) { - return this; - } else { - return nullptr; - } -} - -// |ExternalViewEmbedder| -SkCanvas* IOSSurfaceSoftware::GetRootCanvas() { - // On iOS, the root surface is created using a managed allocation that is submitted to the - // platform. Only the surfaces for the various overlays are controlled by this class. - return nullptr; -} - -// |ExternalViewEmbedder| -void IOSSurfaceSoftware::CancelFrame() { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - platform_views_controller->CancelFrame(); -} - -// |ExternalViewEmbedder| -void IOSSurfaceSoftware::BeginFrame(SkISize frame_size, - GrContext* context, - double device_pixel_ratio) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - platform_views_controller->SetFrameSize(frame_size); -} - -// |ExternalViewEmbedder| -void IOSSurfaceSoftware::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| -std::vector IOSSurfaceSoftware::GetCurrentCanvases() { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->GetCurrentCanvases(); -} - -// |ExternalViewEmbedder| -SkCanvas* IOSSurfaceSoftware::CompositeEmbeddedView(int view_id) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->CompositeEmbeddedView(view_id); -} - -// |ExternalViewEmbedder| -bool IOSSurfaceSoftware::SubmitFrame(GrContext* context) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - if (platform_views_controller == nullptr) { - return true; - } - return platform_views_controller->SubmitFrame(nullptr, nullptr); + return GetExternalViewEmbedderIfEnabled(); } } // namespace flutter diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index 00e9130f70142..4bd76980f8879 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -17,8 +17,9 @@ #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h" #include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h" -#include "flutter/shell/platform/darwin/ios/ios_gl_context.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" +#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h" @class FlutterViewController; @@ -26,7 +27,9 @@ namespace flutter { class PlatformViewIOS final : public PlatformView { public: - explicit PlatformViewIOS(PlatformView::Delegate& delegate, flutter::TaskRunners task_runners); + explicit PlatformViewIOS(PlatformView::Delegate& delegate, + IOSRenderingAPI rendering_api, + flutter::TaskRunners task_runners); ~PlatformViewIOS() override; @@ -68,7 +71,7 @@ class PlatformViewIOS final : public PlatformView { // used on the GPU thread we need to protect it with a mutex. std::mutex ios_surface_mutex_; std::unique_ptr ios_surface_; - std::shared_ptr gl_context_; + std::shared_ptr ios_context_; PlatformMessageRouter platform_message_router_; std::unique_ptr accessibility_bridge_; fml::scoped_nsprotocol text_input_plugin_; diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index 3207744c3438d..09d19b4e61699 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -20,12 +20,10 @@ namespace flutter { PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate, + IOSRenderingAPI rendering_api, flutter::TaskRunners task_runners) - : PlatformView(delegate, std::move(task_runners)) { -#if !TARGET_IPHONE_SIMULATOR - gl_context_ = std::make_shared(); -#endif // !TARGET_IPHONE_SIMULATOR -} + : PlatformView(delegate, std::move(task_runners)), + ios_context_(IOSContext::Create(rendering_api)) {} PlatformViewIOS::~PlatformViewIOS() = default; @@ -76,7 +74,7 @@ void PlatformViewIOS::attachView() { FML_DCHECK(owner_controller_); ios_surface_ = - [static_cast(owner_controller_.get().view) createSurface:gl_context_]; + [static_cast(owner_controller_.get().view) createSurface:ios_context_]; FML_DCHECK(ios_surface_ != nullptr); if (accessibility_bridge_) { @@ -111,16 +109,7 @@ new AccessibilityBridge(static_cast(owner_controller_.get().view), // |PlatformView| sk_sp PlatformViewIOS::CreateResourceContext() const { - FML_DCHECK(task_runners_.GetIOTaskRunner()->RunsTasksOnCurrentThread()); - if (!gl_context_ || !gl_context_->ResourceMakeCurrent()) { - FML_DLOG(INFO) << "Could not make resource context current on IO thread. " - "Async texture uploads will be disabled. On Simulators, " - "this is expected."; - return nullptr; - } - - return ShellIOManager::CreateCompatibleResourceLoadingContext( - GrBackend::kOpenGL_GrBackend, GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface()); + return ios_context_->CreateResourceContext(); } // |PlatformView| diff --git a/shell/platform/darwin/ios/rendering_api_selection.h b/shell/platform/darwin/ios/rendering_api_selection.h new file mode 100644 index 0000000000000..de2ca5ec5827c --- /dev/null +++ b/shell/platform/darwin/ios/rendering_api_selection.h @@ -0,0 +1,27 @@ +// 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_DARWIN_IOS_RENDERING_API_SELECTION_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_RENDERING_API_SELECTION_H_ + +#include + +#include "flutter/fml/macros.h" + +namespace flutter { + +enum class IOSRenderingAPI { + kSoftware, + kOpenGLES, + kMetal, +}; + +IOSRenderingAPI GetRenderingAPIForProcess(); + +Class GetQuartzLayerClassForRenderingAPI( + IOSRenderingAPI rendering_api = GetRenderingAPIForProcess()); + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_RENDERING_API_SELECTION_H_ diff --git a/shell/platform/darwin/ios/rendering_api_selection.mm b/shell/platform/darwin/ios/rendering_api_selection.mm new file mode 100644 index 0000000000000..3bd12368a2287 --- /dev/null +++ b/shell/platform/darwin/ios/rendering_api_selection.mm @@ -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. + +#include "flutter/shell/platform/darwin/ios/rendering_api_selection.h" + +#include +#include +#include + +#include "flutter/fml/logging.h" + +namespace flutter { + +bool ShouldUseMetalRenderer() { + // If there is a command line argument that says Metal should not be used, that takes precedence + // over everything else. This allows disabling Metal on a per run basis to check for regressions + // on an application that has otherwise opted into Metal on an iOS version that supports it. + if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--disable-metal"]) { + return false; + } + + // If the application wants to use metal on a per run basis with disregard for version checks or + // plist based opt ins, respect that opinion. This allows selectively testing features on older + // version of iOS than those explicitly stated as being supported. + if ([[[NSProcessInfo processInfo] arguments] containsObject:@"--force-metal"]) { + return true; + } + + // This is just a version we picked that is easy to support and has all necessary Metal features. + bool ios_version_supports_metal = false; + if (@available(iOS 11.0, *)) { + ios_version_supports_metal = true; + } + + // The application must opt-in by default to use Metal without command line flags. + bool application_opts_into_metal = + [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"io.flutter.metal_preview"] boolValue]; + + return ios_version_supports_metal && application_opts_into_metal; +} + +IOSRenderingAPI GetRenderingAPIForProcess() { +#if TARGET_IPHONE_SIMULATOR + return IOSRenderingAPI::kSoftware; +#endif // TARGET_IPHONE_SIMULATOR + +#if FLUTTER_SHELL_ENABLE_METAL + static bool should_use_metal = ShouldUseMetalRenderer(); + if (should_use_metal) { + return IOSRenderingAPI::kMetal; + } +#endif // FLUTTER_SHELL_ENABLE_METAL + return IOSRenderingAPI::kOpenGLES; +} + +Class GetQuartzLayerClassForRenderingAPI(IOSRenderingAPI rendering_api) { + switch (rendering_api) { + case IOSRenderingAPI::kSoftware: + return [CALayer class]; + case IOSRenderingAPI::kOpenGLES: + return [CAEAGLLayer class]; + case IOSRenderingAPI::kMetal: + return [CAMetalLayer class]; + } + FML_CHECK(false) << "Unknown client rendering API"; + return [CALayer class]; +} + +} // namespace flutter From 1cf871f2b68034293350874847c9a3b2438bd711 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 9 Mar 2020 18:34:06 -0400 Subject: [PATCH 2/2] Licenses. --- ci/licenses_golden/licenses_flutter | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d0182f4580ab0..11fc1324db611 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -863,12 +863,18 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_messa FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/module.modulemap +FILE: ../../../flutter/shell/platform/darwin/ios/ios_context.h +FILE: ../../../flutter/shell/platform/darwin/ios/ios_context.mm +FILE: ../../../flutter/shell/platform/darwin/ios/ios_context_gl.h +FILE: ../../../flutter/shell/platform/darwin/ios/ios_context_gl.mm +FILE: ../../../flutter/shell/platform/darwin/ios/ios_context_metal.h +FILE: ../../../flutter/shell/platform/darwin/ios/ios_context_metal.mm FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.h FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.mm -FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context.h -FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_context.mm -FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_render_target.h -FILE: ../../../flutter/shell/platform/darwin/ios/ios_gl_render_target.mm +FILE: ../../../flutter/shell/platform/darwin/ios/ios_render_target.h +FILE: ../../../flutter/shell/platform/darwin/ios/ios_render_target.mm +FILE: ../../../flutter/shell/platform/darwin/ios/ios_render_target_gl.h +FILE: ../../../flutter/shell/platform/darwin/ios/ios_render_target_gl.mm FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.h FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface.mm FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_gl.h @@ -879,6 +885,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.h FILE: ../../../flutter/shell/platform/darwin/ios/ios_surface_software.mm FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.h FILE: ../../../flutter/shell/platform/darwin/ios/platform_view_ios.mm +FILE: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.h +FILE: ../../../flutter/shell/platform/darwin/ios/rendering_api_selection.mm FILE: ../../../flutter/shell/platform/darwin/macos/framework/FlutterMacOS.podspec FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h FILE: ../../../flutter/shell/platform/darwin/macos/framework/Headers/FlutterDartProject.h