From 453be9ea16e9fd088c64dbb3503e3034ba622db6 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 3 Mar 2020 14:17:12 -0800 Subject: [PATCH 1/3] 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 --- ci/licenses_golden/licenses_flutter | 16 ++- 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 | 46 ++---- .../framework/Source/FlutterPlatformViews.mm | 13 +- .../Source/FlutterPlatformViews_Internal.h | 7 +- .../darwin/ios/framework/Source/FlutterView.h | 4 +- .../ios/framework/Source/FlutterView.mm | 110 ++------------- shell/platform/darwin/ios/ios_context.h | 131 ++++++++++++++++++ shell/platform/darwin/ios/ios_context.mm | 38 +++++ .../{ios_gl_context.h => ios_context_gl.h} | 41 +++--- shell/platform/darwin/ios/ios_context_gl.mm | 61 ++++++++ shell/platform/darwin/ios/ios_context_metal.h | 57 ++++++++ .../platform/darwin/ios/ios_context_metal.mm | 86 ++++++++++++ .../darwin/ios/ios_context_software.h | 38 +++++ .../darwin/ios/ios_context_software.mm | 34 +++++ .../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 -------- .../darwin/ios/ios_render_target_gl.h | 50 +++++++ ...nder_target.mm => ios_render_target_gl.mm} | 53 +++---- shell/platform/darwin/ios/ios_surface.h | 50 ++++++- 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 | 116 ++++------------ 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 | 82 +++++++++++ 40 files changed, 1034 insertions(+), 782 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} (51%) 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 create mode 100644 shell/platform/darwin/ios/ios_context_software.h create mode 100644 shell/platform/darwin/ios/ios_context_software.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_gl.h rename shell/platform/darwin/ios/{ios_gl_render_target.mm => ios_render_target_gl.mm} (75%) 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/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 6056147ddc95f..7417f1b6af6a3 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -865,12 +865,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_context_software.h +FILE: ../../../flutter/shell/platform/darwin/ios/ios_context_software.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_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 @@ -881,6 +887,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 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..1671975c8d0e5 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_context_software.h", + "ios_context_software.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_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..11c0d60618886 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,11 @@ - (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:NSClassFromString(@"CAEAGLLayer")] || + [self.layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) { + self.layer.allowsGroupOpacity = NO; + self.layer.contentsScale = contentsScale; + self.layer.rasterizationScale = contentsScale; } return self; @@ -72,27 +62,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..b86c4623fa7a7 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -308,7 +308,7 @@ // // The UIKit frame is set based on the logical resolution instead of physical. // (https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html). - // However, flow is based on the physical resolution. For eaxmple, 1000 pixels in flow equals + // However, flow is based on the physical resolution. For example, 1000 pixels in flow equals // 500 points in UIKit. And until this point, we did all the calculation based on the flow // resolution. So we need to scale down to match UIKit's logical resolution. CGFloat screenScale = [UIScreen mainScreen].scale; @@ -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_); @@ -474,7 +474,8 @@ 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 ios_surface = + [overlay_view.get() createSurface:std::move(ios_context)]; std::unique_ptr surface = ios_surface->CreateGPUSurface(); overlays_[overlay_id] = std::make_unique( std::move(overlay_view), std::move(ios_surface), std::move(surface)); @@ -500,7 +501,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..ed2d1f02b7127 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,28 @@ - (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:NSClassFromString(@"CAEAGLLayer")] || + [self.layer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) { 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.allowsGroupOpacity = YES; + 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::GetCoreAnimationLayerClassForRenderingAPI(); } - (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..dffe50aa835e5 --- /dev/null +++ b/shell/platform/darwin/ios/ios_context.h @@ -0,0 +1,131 @@ +// 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/rendering_api_selection.h" +#include "third_party/skia/include/gpu/GrContext.h" + +namespace flutter { + +//------------------------------------------------------------------------------ +/// @brief Manages the lifetime of the on-screen and off-screen rendering +/// contexts on iOS. On-screen contexts are used by Flutter for +/// rendering into the surface. The lifecycle of this context may be +/// tied to the lifecycle of the surface. On the other hand, the +/// lifecycle of the the off-screen context it tied to that of the +/// platform view. This one object used to manage both context +/// because GPU handles may need to be shared between the two +/// context. To achieve this, context may need references to one +/// another at creation time. This one object manages the creation, +/// use and collection of both contexts in a client rendering API +/// agnostic manner. +/// +class IOSContext { + public: + //---------------------------------------------------------------------------- + /// @brief Create an iOS context object capable of creating the on-screen + /// and off-screen GPU context for use by Skia. + /// + /// In case the engine does not support the specified client + /// rendering API, this a `nullptr` may be returned. + /// + /// @param[in] rendering_api A client rendering API supported by the + /// engine/platform. + /// + /// @return A valid context on success. `nullptr` on failure. + /// + static std::unique_ptr Create(IOSRenderingAPI rendering_api); + + //---------------------------------------------------------------------------- + /// @brief Collects the context object. This must happen on the thread on + /// which this object was created. + /// + virtual ~IOSContext(); + + //---------------------------------------------------------------------------- + /// @brief Create a resource context for use on the IO task runner. This + /// resource context is used by Skia to upload texture to + /// asynchronously and collect resources that are no longer needed + /// on the render task runner. + /// + /// @attention Client rendering APIs for which a GrContext cannot be realized + /// (software rendering), this method will always return null. + /// + /// @return A non-null Skia context on success. `nullptr` on failure. + /// + virtual sk_sp CreateResourceContext() = 0; + + //---------------------------------------------------------------------------- + /// @brief When using client rendering APIs whose contexts need to be + /// bound to a specific thread, the engine will call this method + /// to give the on-screen context a chance to bind to the current + /// thread. + /// + /// @attention Client rendering APIs that have no-concept of thread local + /// bindings (anything that is not OpenGL) will always return + /// `true`. + /// + /// @attention Client rendering APIs for which a GrContext cannot be created + /// (software rendering) will always return `false`. + /// + /// @attention This binds the on-screen context to the current thread. To + /// bind the off-screen context to the thread, use the + /// `ResoruceMakeCurrent` method instead. + /// + /// @attention Only one context may be bound to a thread at any given time. + /// Making a binding on a thread, clears the old binding. + /// + /// @return If the on-screen context could be bound to the current thread. + /// + virtual bool MakeCurrent() = 0; + + //---------------------------------------------------------------------------- + /// @brief When using client rendering APIs whose contexts need to be + /// bound to a specific thread, the engine will call this method + /// to give the off-screen context a chance to bind to the current + /// thread. + /// + /// @attention Client rendering APIs that have no-concept of thread local + /// bindings (anything that is not OpenGL) will always return + /// `true`. + /// + /// @attention Client rendering APIs for which a GrContext cannot be created + /// (software rendering) will always return `false`. + /// + /// @attention This binds the off-screen context to the current thread. To + /// bind the on-screen context to the thread, use the + /// `MakeCurrent` method instead. + /// + /// @attention Only one context may be bound to a thread at any given time. + /// Making a binding on a thread, clears the old binding. + /// + /// @return If the off-screen context could be bound to the current + /// thread. + /// + virtual bool ResourceMakeCurrent() = 0; + + //---------------------------------------------------------------------------- + /// @brief Clears the context binding of the current thread if one is + /// present. Does noting otherwise. + /// + /// @return Clears the current context binding. + /// + virtual bool ClearCurrent() = 0; + + protected: + IOSContext(); + + 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..4cdd22a9fdd0a --- /dev/null +++ b/shell/platform/darwin/ios/ios_context.mm @@ -0,0 +1,38 @@ +// 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" +#include "flutter/shell/platform/darwin/ios/ios_context_software.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: + return std::make_unique(); +#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 51% rename from shell/platform/darwin/ios/ios_gl_context.h rename to shell/platform/darwin/ios/ios_context_gl.h index 232645d9c8592..fd8885a42395a 100644 --- a/shell/platform/darwin/ios/ios_gl_context.h +++ b/shell/platform/darwin/ios/ios_context_gl.h @@ -5,39 +5,42 @@ #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(); - - ~IOSGLContext(); - - std::unique_ptr CreateRenderTarget( - fml::scoped_nsobject layer); - - bool MakeCurrent(); + IOSContextGL(); - bool ResourceMakeCurrent(); + // |IOSContext| + ~IOSContextGL() override; - sk_sp ColorSpace() const { return color_space_; } + std::unique_ptr CreateRenderTarget(fml::scoped_nsobject layer); private: fml::scoped_nsobject context_; fml::scoped_nsobject resource_context_; - sk_sp color_space_; - FML_DISALLOW_COPY_AND_ASSIGN(IOSGLContext); + // |IOSContext| + sk_sp CreateResourceContext() override; + + // |IOSContext| + bool MakeCurrent() override; + + // |IOSContext| + bool ClearCurrent() override; + + // |IOSContext| + bool ResourceMakeCurrent() override; + + 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..1396198338193 --- /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..f98b11f72d9cc --- /dev/null +++ b/shell/platform/darwin/ios/ios_context_metal.h @@ -0,0 +1,57 @@ +// 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| + 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..8b9cbda33455b --- /dev/null +++ b/shell/platform/darwin/ios/ios_context_metal.mm @@ -0,0 +1,86 @@ +// 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"]; + + // Skia expect arguments to `MakeMetal` transfer ownership of the reference in for release later + // when the GrContext is collected. + 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| +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_context_software.h b/shell/platform/darwin/ios/ios_context_software.h new file mode 100644 index 0000000000000..558f39a637f97 --- /dev/null +++ b/shell/platform/darwin/ios/ios_context_software.h @@ -0,0 +1,38 @@ +// 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_SOFTWARE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_CONTEXT_SOFTWARE_H_ + +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/darwin/ios/ios_context.h" + +namespace flutter { + +class IOSContextSoftware final : public IOSContext { + public: + IOSContextSoftware(); + + // |IOSContext| + ~IOSContextSoftware(); + + // |IOSContext| + sk_sp CreateResourceContext() override; + + // |IOSContext| + bool MakeCurrent() override; + + // |IOSContext| + bool ResourceMakeCurrent() override; + + // |IOSContext| + bool ClearCurrent() override; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(IOSContextSoftware); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_CONTEXT_SOFTWARE_H_ diff --git a/shell/platform/darwin/ios/ios_context_software.mm b/shell/platform/darwin/ios/ios_context_software.mm new file mode 100644 index 0000000000000..8bb029d5792d3 --- /dev/null +++ b/shell/platform/darwin/ios/ios_context_software.mm @@ -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. + +#include "flutter/shell/platform/darwin/ios/ios_context_software.h" + +namespace flutter { + +IOSContextSoftware::IOSContextSoftware() = default; + +// |IOSContext| +IOSContextSoftware::~IOSContextSoftware() = default; + +// |IOSContext| +sk_sp IOSContextSoftware::CreateResourceContext() { + return nullptr; +} + +// |IOSContext| +bool IOSContextSoftware::MakeCurrent() { + return false; +} + +// |IOSContext| +bool IOSContextSoftware::ResourceMakeCurrent() { + return false; +} + +// |IOSContext| +bool IOSContextSoftware::ClearCurrent() { + return false; +} + +} // 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_gl.h b/shell/platform/darwin/ios/ios_render_target_gl.h new file mode 100644 index 0000000000000..f83679f29bcf1 --- /dev/null +++ b/shell/platform/darwin/ios/ios_render_target_gl.h @@ -0,0 +1,50 @@ +// 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" + +namespace flutter { + +class IOSRenderTargetGL { + public: + IOSRenderTargetGL(fml::scoped_nsobject layer, + fml::scoped_nsobject context, + fml::scoped_nsobject resource_context); + + ~IOSRenderTargetGL(); + + bool IsValid() const; + + bool PresentRenderBuffer() const; + + intptr_t GetFramebuffer() const; + + bool UpdateStorageSizeIfNecessary(); + + 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; + + 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 75% rename from shell/platform/darwin/ios/ios_gl_render_target.mm rename to shell/platform/darwin/ios/ios_render_target_gl.mm index a57ba9c46b414..34b57a787d843 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,20 @@ namespace flutter { -IOSGLRenderTarget::IOSGLRenderTarget(fml::scoped_nsobject layer, - EAGLContext* context, - EAGLContext* resource_context) +IOSRenderTargetGL::IOSRenderTargetGL(fml::scoped_nsobject layer, + fml::scoped_nsobject context, + fml::scoped_nsobject 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) { + 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 +60,7 @@ valid_ = true; } -IOSGLRenderTarget::~IOSGLRenderTarget() { +IOSRenderTargetGL::~IOSRenderTargetGL() { EAGLContext* context = EAGLContext.currentContext; [EAGLContext setCurrentContext:context_]; FML_DCHECK(glGetError() == GL_NO_ERROR); @@ -74,11 +73,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 +93,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 +141,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..43049d6c367b8 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -9,25 +9,36 @@ #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(); + + virtual bool IsValid() const = 0; virtual void UpdateStorageSizeIfNecessary() = 0; @@ -36,15 +47,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..48d995ac9e437 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_gl.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..521c5f7bb7cfd 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -6,38 +6,41 @@ #include "flutter/fml/trace_event.h" #include "flutter/shell/gpu/gpu_surface_gl.h" +#include "flutter/shell/platform/darwin/ios/ios_context_gl.h" namespace flutter { -IOSSurfaceGL::IOSSurfaceGL(std::shared_ptr context, - fml::scoped_nsobject layer, - FlutterPlatformViewsController* platform_views_controller) - : IOSSurface(platform_views_controller), context_(context) { - render_target_ = context_->CreateRenderTarget(std::move(layer)); +static IOSContextGL* CastToGLContext(const std::shared_ptr& context) { + return reinterpret_cast(context.get()); +} + +static fml::scoped_nsobject CastEAGLLayer(fml::scoped_nsobject layer) { + FML_DCHECK([layer isKindOfClass:[CAEAGLLayer class]]); + return fml::scoped_nsobject{reinterpret_cast([layer.get() retain])}; } -IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, - std::shared_ptr context) - : IOSSurface(nullptr), context_(context) { - render_target_ = context_->CreateRenderTarget(std::move(layer)); +IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, + std::shared_ptr context, + FlutterPlatformViewsController* platform_views_controller) + : IOSSurface(context, platform_views_controller) { + render_target_ = CastToGLContext(context)->CreateRenderTarget(CastEAGLLayer(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 +48,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() : GL_NONE; } +// |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 +63,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..f30a49a091e21 --- /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 GetCoreAnimationLayerClassForRenderingAPI( + 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..c7117fd3d8c49 --- /dev/null +++ b/shell/platform/darwin/ios/rendering_api_selection.mm @@ -0,0 +1,82 @@ +// 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 ShouldUseSoftwareRenderer() { + return [[[NSProcessInfo processInfo] arguments] containsObject:@"--force-software"]; +} + +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_software = ShouldUseSoftwareRenderer(); + if (should_use_software) { + return IOSRenderingAPI::kSoftware; + } + static bool should_use_metal = ShouldUseMetalRenderer(); + if (should_use_metal) { + return IOSRenderingAPI::kMetal; + } +#endif // FLUTTER_SHELL_ENABLE_METAL + return IOSRenderingAPI::kOpenGLES; +} + +Class GetCoreAnimationLayerClassForRenderingAPI(IOSRenderingAPI rendering_api) { + switch (rendering_api) { + case IOSRenderingAPI::kSoftware: + return [CALayer class]; + case IOSRenderingAPI::kOpenGLES: + return [CAEAGLLayer class]; +#if !TARGET_IPHONE_SIMULATOR + case IOSRenderingAPI::kMetal: + return [CAMetalLayer class]; +#endif // !TARGET_IPHONE_SIMULATOR + default: + break; + } + FML_CHECK(false) << "Unknown client rendering API"; + return [CALayer class]; +} + +} // namespace flutter From bb204f54fe40c63994d46c96b48209933e857032 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 10 Mar 2020 14:52:37 -0700 Subject: [PATCH 2/3] =?UTF-8?q?Don=E2=80=99t=20cast=20in=20ctor.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shell/platform/darwin/ios/ios_context.h | 2 +- shell/platform/darwin/ios/ios_surface.mm | 23 ++++++++++++++----- shell/platform/darwin/ios/ios_surface_gl.h | 4 ++-- shell/platform/darwin/ios/ios_surface_gl.mm | 9 ++------ shell/platform/darwin/ios/ios_surface_metal.h | 3 +-- .../platform/darwin/ios/ios_surface_metal.mm | 10 ++------ 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/shell/platform/darwin/ios/ios_context.h b/shell/platform/darwin/ios/ios_context.h index dffe50aa835e5..6615821905807 100644 --- a/shell/platform/darwin/ios/ios_context.h +++ b/shell/platform/darwin/ios/ios_context.h @@ -115,7 +115,7 @@ class IOSContext { /// @brief Clears the context binding of the current thread if one is /// present. Does noting otherwise. /// - /// @return Clears the current context binding. + /// @return `true` is the current context bound to the thread is cleared. /// virtual bool ClearCurrent() = 0; diff --git a/shell/platform/darwin/ios/ios_surface.mm b/shell/platform/darwin/ios/ios_surface.mm index 7b4cb4649a2d2..d0a931f7b1f46 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -30,19 +30,30 @@ bool IsIosEmbeddedViewsPreviewEnabled() { FML_DCHECK(context); if ([layer.get() isKindOfClass:[CAEAGLLayer class]]) { - return std::make_unique(std::move(layer), std::move(context), - platform_views_controller); + return std::make_unique( + fml::scoped_nsobject( + reinterpret_cast([layer.get() retain])), // EAGL layer + std::move(context), // context + platform_views_controller // 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); + return std::make_unique( + fml::scoped_nsobject( + reinterpret_cast([layer.get() retain])), // Metal layer + std::move(context), // context + platform_views_controller // platform views controller + ); } #endif // FLUTTER_SHELL_ENABLE_METAL - return std::make_unique(std::move(layer), std::move(context), - platform_views_controller); + return std::make_unique( + std::move(layer), // layer + std::move(context), // context + platform_views_controller // platform views controller + ); } IOSSurface::IOSSurface(std::shared_ptr ios_context, diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index 48d995ac9e437..3cbc6ebd047ad 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -12,13 +12,13 @@ #include "flutter/shell/platform/darwin/ios/ios_render_target_gl.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" -@class CALayer; +@class CAEAGLLayer; namespace flutter { class IOSSurfaceGL final : public IOSSurface, public GPUSurfaceGLDelegate { public: - IOSSurfaceGL(fml::scoped_nsobject layer, + IOSSurfaceGL(fml::scoped_nsobject layer, std::shared_ptr context, FlutterPlatformViewsController* platform_views_controller = nullptr); diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 521c5f7bb7cfd..b3aa25a4e66cd 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -14,16 +14,11 @@ return reinterpret_cast(context.get()); } -static fml::scoped_nsobject CastEAGLLayer(fml::scoped_nsobject layer) { - FML_DCHECK([layer isKindOfClass:[CAEAGLLayer class]]); - return fml::scoped_nsobject{reinterpret_cast([layer.get() retain])}; -} - -IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, +IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, std::shared_ptr context, FlutterPlatformViewsController* platform_views_controller) : IOSSurface(context, platform_views_controller) { - render_target_ = CastToGLContext(context)->CreateRenderTarget(CastEAGLLayer(std::move(layer))); + render_target_ = CastToGLContext(context)->CreateRenderTarget(std::move(layer)); } IOSSurfaceGL::~IOSSurfaceGL() = default; diff --git a/shell/platform/darwin/ios/ios_surface_metal.h b/shell/platform/darwin/ios/ios_surface_metal.h index 30e59b5d2f335..e700bc02a3eb2 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.h +++ b/shell/platform/darwin/ios/ios_surface_metal.h @@ -9,14 +9,13 @@ #include "flutter/shell/gpu/gpu_surface_delegate.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" -@class CALayer; @class CAMetalLayer; namespace flutter { 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); diff --git a/shell/platform/darwin/ios/ios_surface_metal.mm b/shell/platform/darwin/ios/ios_surface_metal.mm index 9a2cfa51d4c03..db345b383ef7b 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.mm +++ b/shell/platform/darwin/ios/ios_surface_metal.mm @@ -9,20 +9,14 @@ namespace flutter { -static fml::scoped_nsobject CastToMetalLayer(fml::scoped_nsobject layer) { - FML_DCHECK([layer isKindOfClass:[CAMetalLayer class]]); - return fml::scoped_nsobject{reinterpret_cast([layer.get() retain])}; -} - static IOSContextMetal* CastToMetalContext(const std::shared_ptr& context) { return reinterpret_cast(context.get()); } -IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject 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))) { + : IOSSurface(std::move(context), platform_views_controller), layer_(std::move(layer)) { if (!layer_) { return; } From 86dad0f63a805c8b845804e3530b0b28cfc41da4 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 10 Mar 2020 15:01:41 -0700 Subject: [PATCH 3/3] Metal version selection TODO. --- shell/platform/darwin/ios/rendering_api_selection.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/darwin/ios/rendering_api_selection.mm b/shell/platform/darwin/ios/rendering_api_selection.mm index c7117fd3d8c49..c6ef89c47cc24 100644 --- a/shell/platform/darwin/ios/rendering_api_selection.mm +++ b/shell/platform/darwin/ios/rendering_api_selection.mm @@ -33,6 +33,7 @@ bool ShouldUseMetalRenderer() { // This is just a version we picked that is easy to support and has all necessary Metal features. bool ios_version_supports_metal = false; + // TODO(52356): Update this to be the version selected for release. if (@available(iOS 11.0, *)) { ios_version_supports_metal = true; }