diff --git a/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm b/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm index 18869d69b82..79da2757fe0 100644 --- a/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm +++ b/engine/src/flutter/shell/common/shell_test_platform_view_metal.mm @@ -91,7 +91,7 @@ PointerDataDispatcherMaker ShellTestPlatformViewMetal::GetDispatcherMaker() { // |PlatformView| std::unique_ptr ShellTestPlatformViewMetal::CreateRenderingSurface() { - return std::make_unique(this, [metal_context_->context() mainContext]); + return std::make_unique(this, [metal_context_->context() mainContext], 1); } // |GPUSurfaceMetalDelegate| diff --git a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h index 378051ba325..fd5c07fc27e 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h +++ b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.h @@ -17,6 +17,7 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalSkia : public Surface { public: GPUSurfaceMetalSkia(GPUSurfaceMetalDelegate* delegate, sk_sp context, + int msaa_samples, bool render_to_surface = true); // |Surface| @@ -30,6 +31,7 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalSkia : public Surface { const MTLRenderTargetType render_target_type_; sk_sp context_; GrDirectContext* precompiled_sksl_context_ = nullptr; + int msaa_samples_ = 1; // TODO(38466): Refactor GPU surface APIs take into account the fact that an // external view embedder may want to render to the root surface. This is a // hack to make avoid allocating resources for the root surface when an diff --git a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm index e14cc98bf73..e98952d8c10 100644 --- a/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm +++ b/engine/src/flutter/shell/gpu/gpu_surface_metal_skia.mm @@ -47,11 +47,18 @@ sk_sp CreateSurfaceFromMetalTexture(GrDirectContext* context, GPUSurfaceMetalSkia::GPUSurfaceMetalSkia(GPUSurfaceMetalDelegate* delegate, sk_sp context, + int msaa_samples, bool render_to_surface) : delegate_(delegate), render_target_type_(delegate->GetRenderTargetType()), context_(std::move(context)), - render_to_surface_(render_to_surface) {} + msaa_samples_(msaa_samples), + render_to_surface_(render_to_surface) { + // Skia allows 0 and clamps it to 1. + FML_CHECK(msaa_samples_ == 0 || msaa_samples_ == 1 || msaa_samples_ == 2 || msaa_samples_ == 4 || + msaa_samples_ == 8) + << "Invalid MSAA sample count value: " << msaa_samples_; +} GPUSurfaceMetalSkia::~GPUSurfaceMetalSkia() = default; @@ -120,20 +127,9 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromCAMetalLayer( return nullptr; } - // TODO(dnfield): Enable MSAA behind a flag if the settings say to. - // https://github.com/flutter/flutter/issues/100392 - // Rough outline of steps needed: - // Create memoryless texture - // auto texture = drawable.get().texture; - // MTLTextureDescriptor* desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: - // texture.pixelFormat width: texture.width height: texture.height: mipmapped: texture.mipmapped]; - // desc.sampleCount = 4; - // Type should be multisample, count 4 or 8 (4 always supported) - // Give the new texture to skia in this call, using the same sampleCount value - // Resolve texture auto surface = CreateSurfaceFromMetalTexture(context_.get(), drawable.get().texture, kTopLeft_GrSurfaceOrigin, // origin - 1, // sample count + msaa_samples_, // sample count kBGRA_8888_SkColorType, // color type nullptr, // colorspace nullptr // surface properties @@ -197,8 +193,8 @@ std::unique_ptr GPUSurfaceMetalSkia::AcquireFrameFromMTLTexture( } sk_sp surface = - CreateSurfaceFromMetalTexture(context_.get(), mtl_texture, kTopLeft_GrSurfaceOrigin, 1, - kBGRA_8888_SkColorType, nullptr, nullptr); + CreateSurfaceFromMetalTexture(context_.get(), mtl_texture, kTopLeft_GrSurfaceOrigin, + msaa_samples_, kBGRA_8888_SkColorType, nullptr, nullptr); if (!surface) { FML_LOG(ERROR) << "Could not create the SkSurface from the metal texture."; diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm index 270aab3fba5..1b08af91238 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm @@ -19,6 +19,7 @@ namespace flutter { namespace { class FakeDelegate : public PlatformView::Delegate { + public: void OnPlatformViewCreated(std::unique_ptr surface) override {} void OnPlatformViewDestroyed() override {} void OnPlatformViewScheduleFrame() override {} @@ -47,7 +48,6 @@ class FakeDelegate : public PlatformView::Delegate { void UpdateAssetResolverByType(std::unique_ptr updated_asset_resolver, AssetResolver::AssetResolverType type) override {} - private: flutter::Settings settings_; }; @@ -87,6 +87,29 @@ flutter::FakeDelegate fake_delegate; return weak_factory->GetWeakPtr(); } +- (void)testMsaaSampleCount { + // Default should be 1. + XCTAssertEqual(platform_view->GetIosContext()->GetMsaaSampleCount(), 1); + + // Verify the platform view creates a new context with updated msaa_samples. + // Need to use Metal, since this is ignored for Software/GL. + fake_delegate.settings_.msaa_samples = 4; + + auto thread_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); + flutter::TaskRunners runners(/*label=*/self.name.UTF8String, + /*platform=*/thread_task_runner, + /*raster=*/thread_task_runner, + /*ui=*/thread_task_runner, + /*io=*/thread_task_runner); + auto msaa_4x_platform_view = std::make_unique( + /*delegate=*/fake_delegate, + /*rendering_api=*/flutter::IOSRenderingAPI::kMetal, + /*platform_views_controller=*/nil, + /*task_runners=*/runners); + + XCTAssertEqual(msaa_4x_platform_view->GetIosContext()->GetMsaaSampleCount(), 4); +} + - (void)testCallsNotifyLowMemory { id project = OCMClassMock([FlutterDartProject class]); FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"tester" project:project]; diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context.h b/engine/src/flutter/shell/platform/darwin/ios/ios_context.h index 8cf8fb0fb72..10844c49df3 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context.h +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context.h @@ -21,6 +21,9 @@ class Context; namespace flutter { +// Supported MSAA sample count values for iOS. +enum class MsaaSampleCount { kNone = 1, kTwo = 2, kFour = 4, kEight = 8 }; + //------------------------------------------------------------------------------ /// @brief Manages the lifetime of the on-screen and off-screen rendering /// contexts on iOS. On-screen contexts are used by Flutter for @@ -45,10 +48,17 @@ class IOSContext { /// /// @param[in] api A client rendering API supported by the /// engine/platform. + /// @param[in] backend A client rendering backend supported by the + /// engine/platform. + /// @param[in] msaa_samples + /// The number of MSAA samples to use. Only supplied to + /// Skia, must be either 0, 1, 2, 4, or 8. /// /// @return A valid context on success. `nullptr` on failure. /// - static std::unique_ptr Create(IOSRenderingAPI api, IOSRenderingBackend backend); + static std::unique_ptr Create(IOSRenderingAPI api, + IOSRenderingBackend backend, + MsaaSampleCount msaa_samples); //---------------------------------------------------------------------------- /// @brief Collects the context object. This must happen on the thread on @@ -133,10 +143,13 @@ class IOSContext { virtual std::shared_ptr GetImpellerContext() const; + int GetMsaaSampleCount() const { return static_cast(msaa_samples_); } + protected: - IOSContext(); + explicit IOSContext(MsaaSampleCount msaa_samples); private: + MsaaSampleCount msaa_samples_ = MsaaSampleCount::kNone; FML_DISALLOW_COPY_AND_ASSIGN(IOSContext); }; diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm index 5fd6de9c941..59b8c6fcc10 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context.mm @@ -15,11 +15,13 @@ namespace flutter { -IOSContext::IOSContext() = default; +IOSContext::IOSContext(MsaaSampleCount msaa_samples) : msaa_samples_(msaa_samples) {} IOSContext::~IOSContext() = default; -std::unique_ptr IOSContext::Create(IOSRenderingAPI api, IOSRenderingBackend backend) { +std::unique_ptr IOSContext::Create(IOSRenderingAPI api, + IOSRenderingBackend backend, + MsaaSampleCount msaa_samples) { switch (api) { case IOSRenderingAPI::kOpenGLES: return std::make_unique(); @@ -29,7 +31,7 @@ std::unique_ptr IOSContext::Create(IOSRenderingAPI api, IOSRendering case IOSRenderingAPI::kMetal: switch (backend) { case IOSRenderingBackend::kSkia: - return std::make_unique(); + return std::make_unique(msaa_samples); case IOSRenderingBackend::kImpeller: return std::make_unique(); } diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm index d183a29150f..b92bc6d01c2 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_gl.mm @@ -13,7 +13,7 @@ namespace flutter { -IOSContextGL::IOSContextGL() { +IOSContextGL::IOSContextGL() : IOSContext(MsaaSampleCount::kNone) { resource_context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]); if (resource_context_ != nullptr) { context_.reset([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3 diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm index b3b4cfdac28..1b159432557 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_impeller.mm @@ -22,7 +22,8 @@ static std::shared_ptr CreateImpellerContext() { return context; } -IOSContextMetalImpeller::IOSContextMetalImpeller() : context_(CreateImpellerContext()) {} +IOSContextMetalImpeller::IOSContextMetalImpeller() + : IOSContext(MsaaSampleCount::kFour), context_(CreateImpellerContext()) {} IOSContextMetalImpeller::~IOSContextMetalImpeller() = default; diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.h b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.h index 9d0eac239a1..9c6193c21fd 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.h +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.h @@ -18,7 +18,7 @@ namespace flutter { class IOSContextMetalSkia final : public IOSContext { public: - IOSContextMetalSkia(); + explicit IOSContextMetalSkia(MsaaSampleCount msaa_samples); ~IOSContextMetalSkia(); diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.mm index 0e1d53beba1..5476f45611e 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_metal_skia.mm @@ -12,7 +12,7 @@ namespace flutter { -IOSContextMetalSkia::IOSContextMetalSkia() { +IOSContextMetalSkia::IOSContextMetalSkia(MsaaSampleCount msaa_samples) : IOSContext(msaa_samples) { darwin_context_metal_ = fml::scoped_nsobject{ [[FlutterDarwinContextMetal alloc] initWithDefaultMTLDevice]}; diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_context_software.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_context_software.mm index 7005b504640..c58ad6dc93e 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_context_software.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_context_software.mm @@ -3,10 +3,11 @@ // found in the LICENSE file. #import "flutter/shell/platform/darwin/ios/ios_context_software.h" +#include "ios_context.h" namespace flutter { -IOSContextSoftware::IOSContextSoftware() = default; +IOSContextSoftware::IOSContextSoftware() : IOSContext(MsaaSampleCount::kNone) {} // |IOSContext| IOSContextSoftware::~IOSContextSoftware() = default; diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_surface_metal_skia.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_surface_metal_skia.mm index b0e76f5e108..9a4d8b2e48d 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_surface_metal_skia.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_surface_metal_skia.mm @@ -42,8 +42,9 @@ void IOSSurfaceMetalSkia::UpdateStorageSizeIfNecessary() { // |IOSSurface| std::unique_ptr IOSSurfaceMetalSkia::CreateGPUSurface(GrDirectContext* context) { FML_DCHECK(context); - return std::make_unique(this, // layer - sk_ref_sp(context) // context + return std::make_unique(this, // delegate + sk_ref_sp(context), // context + GetContext()->GetMsaaSampleCount() // sample count ); } diff --git a/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm b/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm index b2f549887a3..61b9c3aeaad 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/platform_view_ios.mm @@ -55,13 +55,15 @@ PlatformViewIOS::PlatformViewIOS( IOSRenderingAPI rendering_api, const std::shared_ptr& platform_views_controller, flutter::TaskRunners task_runners) - : PlatformViewIOS(delegate, - IOSContext::Create(rendering_api, - delegate.OnPlatformViewGetSettings().enable_impeller - ? IOSRenderingBackend::kImpeller - : IOSRenderingBackend::kSkia), - platform_views_controller, - task_runners) {} + : PlatformViewIOS( + delegate, + IOSContext::Create( + rendering_api, + delegate.OnPlatformViewGetSettings().enable_impeller ? IOSRenderingBackend::kImpeller + : IOSRenderingBackend::kSkia, + static_cast(delegate.OnPlatformViewGetSettings().msaa_samples)), + platform_views_controller, + task_runners) {} PlatformViewIOS::~PlatformViewIOS() = default; diff --git a/engine/src/flutter/shell/platform/embedder/embedder_surface_metal.mm b/engine/src/flutter/shell/platform/embedder/embedder_surface_metal.mm index 8499cab0486..080f44d14e5 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder_surface_metal.mm +++ b/engine/src/flutter/shell/platform/embedder/embedder_surface_metal.mm @@ -44,7 +44,7 @@ std::unique_ptr EmbedderSurfaceMetal::CreateGPUSurface() API_AVAILABLE( } const bool render_to_surface = !external_view_embedder_; - auto surface = std::make_unique(this, main_context_, render_to_surface); + auto surface = std::make_unique(this, main_context_, render_to_surface, 1); if (!surface->IsValid()) { return nullptr;