diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index bd1bf3108e8d6..2f6c5c31fccef 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -868,12 +868,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 @@ -884,6 +890,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..6615821905807 --- /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 `true` is the current context bound to the thread is cleared. + /// + 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..d0a931f7b1f46 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -4,26 +4,144 @@ #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( + 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( + 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), // layer + std::move(context), // context + platform_views_controller // 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..3cbc6ebd047ad 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; 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..b3aa25a4e66cd 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -6,38 +6,36 @@ #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()); } IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer, - std::shared_ptr context) - : IOSSurface(nullptr), context_(context) { - render_target_ = context_->CreateRenderTarget(std::move(layer)); + std::shared_ptr context, + FlutterPlatformViewsController* platform_views_controller) + : IOSSurface(context, platform_views_controller) { + render_target_ = CastToGLContext(context)->CreateRenderTarget(std::move(layer)); } IOSSurfaceGL::~IOSSurfaceGL() = default; +// |IOSSurface| bool IOSSurfaceGL::IsValid() const { return render_target_->IsValid(); } -bool IOSSurfaceGL::ResourceContextMakeCurrent() { - return context_->ResourceMakeCurrent(); -} - +// |IOSSurface| void IOSSurfaceGL::UpdateStorageSizeIfNecessary() { if (IsValid()) { render_target_->UpdateStorageSizeIfNecessary(); } } +// |IOSSurface| std::unique_ptr IOSSurfaceGL::CreateGPUSurface(GrContext* gr_context) { if (gr_context) { return std::make_unique(sk_ref_sp(gr_context), this, true); @@ -45,10 +43,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 +58,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..e700bc02a3eb2 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.h +++ b/shell/platform/darwin/ios/ios_surface_metal.h @@ -6,68 +6,37 @@ #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 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, + 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..db345b383ef7b 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.mm +++ b/shell/platform/darwin/ios/ios_surface_metal.mm @@ -3,110 +3,59 @@ // 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 { +static IOSContextMetal* CastToMetalContext(const std::shared_ptr& context) { + return reinterpret_cast(context.get()); +} + IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject layer, + std::shared_ptr context, FlutterPlatformViewsController* platform_views_controller) - : IOSSurface(platform_views_controller), layer_(std::move(layer)) {} + : IOSSurface(std::move(context), platform_views_controller), layer_(std::move(layer)) { + if (!layer_) { + return; + } -IOSSurfaceMetal::IOSSurfaceMetal(fml::scoped_nsobject layer) - : IOSSurface(nullptr), layer_(std::move(layer)) {} + auto metal_context = CastToMetalContext(GetContext()); -IOSSurfaceMetal::~IOSSurfaceMetal() = default; + layer_.get().device = metal_context->GetDevice().get(); + layer_.get().presentsWithTransaction = YES; -// |IOSSurface| -bool IOSSurfaceMetal::IsValid() const { - return layer_; + is_valid_ = true; } // |IOSSurface| -bool IOSSurfaceMetal::ResourceContextMakeCurrent() { - return false; -} - -// |IOSSurface| -void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() {} +IOSSurfaceMetal::~IOSSurfaceMetal() = default; // |IOSSurface| -std::unique_ptr IOSSurfaceMetal::CreateGPUSurface(GrContext* gr_context) { - if (gr_context) { - return std::make_unique(this, sk_ref_sp(gr_context), layer_); - } - return std::make_unique(this, layer_); -} - -// |ExternalViewEmbedder| -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; -} - -flutter::ExternalViewEmbedder* IOSSurfaceMetal::GetExternalViewEmbedder() { - if (IsIosEmbeddedViewsPreviewEnabled()) { - return this; - } else { - return nullptr; - } -} - -void IOSSurfaceMetal::CancelFrame() { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - platform_views_controller->CancelFrame(); - // Committing the current transaction as |BeginFrame| will create a nested - // CATransaction otherwise. - [CATransaction commit]; -} - -void IOSSurfaceMetal::BeginFrame(SkISize frame_size, - GrContext* context, - 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)); +bool IOSSurfaceMetal::IsValid() const { + return is_valid_; } -// |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| +void IOSSurfaceMetal::UpdateStorageSizeIfNecessary() { + // Nothing to do. } -std::vector IOSSurfaceMetal::GetCurrentCanvases() { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->GetCurrentCanvases(); -} +// |IOSSurface| +std::unique_ptr IOSSurfaceMetal::CreateGPUSurface(GrContext* /* unused */) { + auto metal_context = CastToMetalContext(GetContext()); -SkCanvas* IOSSurfaceMetal::CompositeEmbeddedView(int view_id) { - FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); - FML_CHECK(platform_views_controller != nullptr); - return platform_views_controller->CompositeEmbeddedView(view_id); + 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..c6ef89c47cc24 --- /dev/null +++ b/shell/platform/darwin/ios/rendering_api_selection.mm @@ -0,0 +1,83 @@ +// 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; + // TODO(52356): Update this to be the version selected for release. + 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