From dd8aabba6998d7d15b8c3066928f4afe2d1e982c Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 13 Apr 2023 20:02:17 -0700 Subject: [PATCH] [Impeller] Allow image rasterization/decoding before/without surface acquisition (#41168) [Impeller] Allow image rasterization/decoding before/without surface acquisition --- flow/surface.cc | 2 +- flow/surface.h | 2 +- shell/common/rasterizer.cc | 7 ++- shell/common/rasterizer.h | 28 +++++++++++ shell/common/shell.cc | 23 +++++---- shell/common/shell_test_platform_view_metal.h | 3 ++ .../common/shell_test_platform_view_metal.mm | 32 +++++++++++-- shell/common/shell_unittests.cc | 47 +++++++++++++++++++ shell/common/snapshot_controller.h | 5 ++ shell/common/snapshot_controller_impeller.cc | 7 +-- shell/gpu/gpu_surface_gl_impeller.cc | 5 +- shell/gpu/gpu_surface_gl_impeller.h | 2 +- shell/gpu/gpu_surface_metal_impeller.h | 2 +- shell/gpu/gpu_surface_metal_impeller.mm | 4 +- shell/gpu/gpu_surface_vulkan_impeller.cc | 5 +- shell/gpu/gpu_surface_vulkan_impeller.h | 2 +- 16 files changed, 144 insertions(+), 32 deletions(-) diff --git a/flow/surface.cc b/flow/surface.cc index fbd3d427c2de2..795d74780d8fc 100644 --- a/flow/surface.cc +++ b/flow/surface.cc @@ -26,7 +26,7 @@ bool Surface::EnableRasterCache() const { return true; } -impeller::AiksContext* Surface::GetAiksContext() const { +std::shared_ptr Surface::GetAiksContext() const { return nullptr; } diff --git a/flow/surface.h b/flow/surface.h index 5cc5d6def08a1..f824e0eb9bd8e 100644 --- a/flow/surface.h +++ b/flow/surface.h @@ -49,7 +49,7 @@ class Surface { virtual bool EnableRasterCache() const; - virtual impeller::AiksContext* GetAiksContext() const; + virtual std::shared_ptr GetAiksContext() const; /// Capture the `SurfaceData` currently present in the surface. /// diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 45335875da59e..5273d68e13707 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -51,6 +51,11 @@ fml::TaskRunnerAffineWeakPtr Rasterizer::GetSnapshotDelegate() return weak_factory_.GetWeakPtr(); } +void Rasterizer::SetImpellerContext( + std::weak_ptr impeller_context) { + impeller_context_ = std::move(impeller_context); +} + void Rasterizer::Setup(std::unique_ptr surface) { surface_ = std::move(surface); @@ -542,7 +547,7 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( .supports_readback, // surface supports pixel reads raster_thread_merger_, // thread merger frame->GetDisplayListBuilder().get(), // display list builder - surface_->GetAiksContext() // aiks context + surface_->GetAiksContext().get() // aiks context ); if (compositor_frame) { compositor_context_->raster_cache().BeginFrame(); diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 5249a4154cc2f..aafec7dc7fe2b 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -23,6 +23,11 @@ #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/fml/time/time_delta.h" #include "flutter/fml/time/time_point.h" +#if IMPELLER_SUPPORTS_RENDERING +// GN is having trouble understanding how this works in the Fuchsia builds. +#include "flutter/impeller/aiks/aiks_context.h" // nogncheck +#include "flutter/impeller/renderer/context.h" // nogncheck +#endif // IMPELLER_SUPPORTS_RENDERING #include "flutter/lib/ui/snapshot_delegate.h" #include "flutter/shell/common/pipeline.h" #include "flutter/shell/common/snapshot_controller.h" @@ -30,6 +35,13 @@ #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/gpu/GrDirectContext.h" +#if !IMPELLER_SUPPORTS_RENDERING +namespace impeller { +class Context; +class AiksContext; +} // namespace impeller +#endif // !IMPELLER_SUPPORTS_RENDERING + namespace flutter { //------------------------------------------------------------------------------ @@ -137,6 +149,8 @@ class Rasterizer final : public SnapshotDelegate, /// ~Rasterizer(); + void SetImpellerContext(std::weak_ptr impeller_context); + //---------------------------------------------------------------------------- /// @brief Rasterizers may be created well before an on-screen surface is /// available for rendering. Shells usually create a rasterizer in @@ -506,6 +520,19 @@ class Rasterizer final : public SnapshotDelegate, return surface_; } + // |SnapshotController::Delegate| + std::shared_ptr GetAiksContext() const override { +#if IMPELLER_SUPPORTS_RENDERING + if (surface_) { + return surface_->GetAiksContext(); + } + if (auto context = impeller_context_.lock()) { + return std::make_shared(context); + } +#endif + return nullptr; + } + // |SnapshotController::Delegate| const std::unique_ptr& GetSnapshotSurfaceProducer() const override { @@ -541,6 +568,7 @@ class Rasterizer final : public SnapshotDelegate, Delegate& delegate_; MakeGpuImageBehavior gpu_image_behavior_; + std::weak_ptr impeller_context_; std::unique_ptr surface_; std::unique_ptr snapshot_surface_producer_; std::unique_ptr compositor_context_; diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 32a777d3583ba..214b3b384569c 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -186,6 +186,12 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( !settings.skia_deterministic_rendering_on_cpu), is_gpu_disabled)); + // Create the platform view on the platform thread (this thread). + auto platform_view = on_create_platform_view(*shell.get()); + if (!platform_view || !platform_view->GetWeakPtr()) { + return nullptr; + } + // Create the rasterizer on the raster thread. std::promise> rasterizer_promise; auto rasterizer_future = rasterizer_promise.get_future(); @@ -193,23 +199,20 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( snapshot_delegate_promise; auto snapshot_delegate_future = snapshot_delegate_promise.get_future(); fml::TaskRunner::RunNowOrPostTask( - task_runners.GetRasterTaskRunner(), [&rasterizer_promise, // - &snapshot_delegate_promise, - on_create_rasterizer, // - shell = shell.get() // + task_runners.GetRasterTaskRunner(), + [&rasterizer_promise, // + &snapshot_delegate_promise, + on_create_rasterizer, // + shell = shell.get(), // + impeller_context = platform_view->GetImpellerContext() // ]() { TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem"); std::unique_ptr rasterizer(on_create_rasterizer(*shell)); + rasterizer->SetImpellerContext(impeller_context); snapshot_delegate_promise.set_value(rasterizer->GetSnapshotDelegate()); rasterizer_promise.set_value(std::move(rasterizer)); }); - // Create the platform view on the platform thread (this thread). - auto platform_view = on_create_platform_view(*shell.get()); - if (!platform_view || !platform_view->GetWeakPtr()) { - return nullptr; - } - // Ask the platform view for the vsync waiter. This will be used by the engine // to create the animator. auto vsync_waiter = platform_view->CreateVSyncWaiter(); diff --git a/shell/common/shell_test_platform_view_metal.h b/shell/common/shell_test_platform_view_metal.h index be9dc9ebd4de2..8dd015cd2408d 100644 --- a/shell/common/shell_test_platform_view_metal.h +++ b/shell/common/shell_test_platform_view_metal.h @@ -49,6 +49,9 @@ class ShellTestPlatformViewMetal final : public ShellTestPlatformView, // |PlatformView| std::unique_ptr CreateRenderingSurface() override; + // |PlatformView| + std::shared_ptr GetImpellerContext() const override; + // |GPUSurfaceMetalDelegate| GPUCAMetalLayerHandle GetCAMetalLayer( const SkISize& frame_info) const override; diff --git a/shell/common/shell_test_platform_view_metal.mm b/shell/common/shell_test_platform_view_metal.mm index 814e67e6f3933..701bba7737a22 100644 --- a/shell/common/shell_test_platform_view_metal.mm +++ b/shell/common/shell_test_platform_view_metal.mm @@ -9,7 +9,9 @@ #include #include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/gpu/gpu_surface_metal_impeller.h" #include "flutter/shell/gpu/gpu_surface_metal_skia.h" +#include "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalImpeller.h" #include "flutter/shell/platform/darwin/graphics/FlutterDarwinContextMetalSkia.h" namespace flutter { @@ -29,12 +31,18 @@ // non-Objective-C TUs. class DarwinContextMetal { public: - DarwinContextMetal() - : context_([[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice]), - offscreen_texture_(CreateOffscreenTexture([context_.get() device])) {} + explicit DarwinContextMetal(bool impeller) + : context_(impeller ? nil : [[FlutterDarwinContextMetalSkia alloc] initWithDefaultMTLDevice]), + impeller_context_(impeller ? [[FlutterDarwinContextMetalImpeller alloc] init] : nil), + offscreen_texture_(CreateOffscreenTexture( + impeller ? [impeller_context_ context]->GetMTLDevice() : [context_ device])) {} ~DarwinContextMetal() = default; + fml::scoped_nsobject impeller_context() const { + return impeller_context_; + } + fml::scoped_nsobject context() const { return context_; } fml::scoped_nsprotocol> offscreen_texture() const { return offscreen_texture_; } @@ -48,6 +56,7 @@ GPUMTLTextureInfo offscreen_texture_info() const { private: const fml::scoped_nsobject context_; + const fml::scoped_nsobject impeller_context_; const fml::scoped_nsprotocol> offscreen_texture_; FML_DISALLOW_COPY_AND_ASSIGN(DarwinContextMetal); @@ -61,11 +70,15 @@ GPUMTLTextureInfo offscreen_texture_info() const { std::shared_ptr shell_test_external_view_embedder) : ShellTestPlatformView(delegate, task_runners), GPUSurfaceMetalDelegate(MTLRenderTargetType::kMTLTexture), - metal_context_(std::make_unique()), + metal_context_(std::make_unique(GetSettings().enable_impeller)), create_vsync_waiter_(std::move(create_vsync_waiter)), vsync_clock_(std::move(vsync_clock)), shell_test_external_view_embedder_(std::move(shell_test_external_view_embedder)) { - FML_CHECK([metal_context_->context() mainContext] != nil); + if (GetSettings().enable_impeller) { + FML_CHECK([metal_context_->impeller_context() context] != nil); + } else { + FML_CHECK([metal_context_->context() mainContext] != nil); + } } ShellTestPlatformViewMetal::~ShellTestPlatformViewMetal() = default; @@ -93,10 +106,19 @@ GPUMTLTextureInfo offscreen_texture_info() const { // |PlatformView| std::unique_ptr ShellTestPlatformViewMetal::CreateRenderingSurface() { + if (GetSettings().enable_impeller) { + return std::make_unique(this, + [metal_context_->impeller_context() context]); + } return std::make_unique(this, [metal_context_->context() mainContext], MsaaSampleCount::kNone); } +// |PlatformView| +std::shared_ptr ShellTestPlatformViewMetal::GetImpellerContext() const { + return [metal_context_->impeller_context() context]; +} + // |GPUSurfaceMetalDelegate| GPUCAMetalLayerHandle ShellTestPlatformViewMetal::GetCAMetalLayer(const SkISize& frame_info) const { FML_CHECK(false) << "A Metal Delegate configured with MTLRenderTargetType::kMTLTexture was asked " diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index aac516ad37f38..82dc5b3682457 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -3986,6 +3986,53 @@ TEST_F(ShellTest, PictureToImageSync) { DestroyShell(std::move(shell)); } +TEST_F(ShellTest, PictureToImageSyncImpellerNoSurface) { +#if !SHELL_ENABLE_METAL + // This test uses the Metal backend. + GTEST_SKIP(); +#endif // !SHELL_ENABLE_METAL + auto settings = CreateSettingsForFixture(); + settings.enable_impeller = true; + std::unique_ptr shell = + CreateShell(settings, // + GetTaskRunnersForFixture(), // + false, // + nullptr, // + false, // + ShellTestPlatformView::BackendType::kMetalBackend // + ); + + AddNativeCallback("NativeOnBeforeToImageSync", + CREATE_NATIVE_ENTRY([&](auto args) { + // nop + })); + + fml::CountDownLatch latch(2); + AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&](auto args) { + // Teardown and set up rasterizer again. + PlatformViewNotifyDestroyed(shell.get()); + PlatformViewNotifyCreated(shell.get()); + latch.CountDown(); + })); + + ASSERT_NE(shell, nullptr); + ASSERT_TRUE(shell->IsSetup()); + auto configuration = RunConfiguration::InferFromSettings(settings); + + // Important: Do not create the platform view yet! + // This test is making sure that the rasterizer can create the texture + // as expected without a surface. + + configuration.SetEntrypoint("toImageSync"); + RunEngine(shell.get(), std::move(configuration)); + PumpOneFrame(shell.get()); + + latch.Wait(); + + PlatformViewNotifyDestroyed(shell.get()); + DestroyShell(std::move(shell)); +} + #if SHELL_ENABLE_GL // This test uses the GL backend and refers to symbols in egl.h TEST_F(ShellTest, PictureToImageSyncWithTrampledContext) { diff --git a/shell/common/snapshot_controller.h b/shell/common/snapshot_controller.h index 11651325edd43..54ad5e0b061c7 100644 --- a/shell/common/snapshot_controller.h +++ b/shell/common/snapshot_controller.h @@ -12,6 +12,10 @@ #include "flutter/lib/ui/snapshot_delegate.h" #include "flutter/shell/common/snapshot_surface_producer.h" +namespace impeller { +class AiksContext; +} + namespace flutter { class SnapshotController { @@ -20,6 +24,7 @@ class SnapshotController { public: virtual ~Delegate() = default; virtual const std::unique_ptr& GetSurface() const = 0; + virtual std::shared_ptr GetAiksContext() const = 0; virtual const std::unique_ptr& GetSnapshotSurfaceProducer() const = 0; virtual std::shared_ptr GetIsGpuDisabledSyncSwitch() diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index 5e7317805812d..c9bafd9c0e27a 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -36,11 +36,8 @@ sk_sp SnapshotControllerImpeller::DoMakeRasterSnapshot( impeller::DisplayListDispatcher dispatcher; display_list->Dispatch(dispatcher); impeller::Picture picture = dispatcher.EndRecordingAsPicture(); - if (GetDelegate().GetSurface() && - GetDelegate().GetSurface()->GetAiksContext()) { - impeller::AiksContext* context = - GetDelegate().GetSurface()->GetAiksContext(); - + auto context = GetDelegate().GetAiksContext(); + if (context) { auto max_size = context->GetContext() ->GetResourceAllocator() ->GetMaxTextureSizeSupported(); diff --git a/shell/gpu/gpu_surface_gl_impeller.cc b/shell/gpu/gpu_surface_gl_impeller.cc index 2a7386613c781..d65a9b5bd2666 100644 --- a/shell/gpu/gpu_surface_gl_impeller.cc +++ b/shell/gpu/gpu_surface_gl_impeller.cc @@ -160,8 +160,9 @@ bool GPUSurfaceGLImpeller::EnableRasterCache() const { } // |Surface| -impeller::AiksContext* GPUSurfaceGLImpeller::GetAiksContext() const { - return aiks_context_.get(); +std::shared_ptr GPUSurfaceGLImpeller::GetAiksContext() + const { + return aiks_context_; } } // namespace flutter diff --git a/shell/gpu/gpu_surface_gl_impeller.h b/shell/gpu/gpu_surface_gl_impeller.h index 367bad23835ac..048c8570e1140 100644 --- a/shell/gpu/gpu_surface_gl_impeller.h +++ b/shell/gpu/gpu_surface_gl_impeller.h @@ -56,7 +56,7 @@ class GPUSurfaceGLImpeller final : public Surface { bool EnableRasterCache() const override; // |Surface| - impeller::AiksContext* GetAiksContext() const override; + std::shared_ptr GetAiksContext() const override; FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGLImpeller); }; diff --git a/shell/gpu/gpu_surface_metal_impeller.h b/shell/gpu/gpu_surface_metal_impeller.h index 6254d851a5062..71a11013218b7 100644 --- a/shell/gpu/gpu_surface_metal_impeller.h +++ b/shell/gpu/gpu_surface_metal_impeller.h @@ -54,7 +54,7 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetalImpeller : public Surface { bool EnableRasterCache() const override; // |Surface| - impeller::AiksContext* GetAiksContext() const override; + std::shared_ptr GetAiksContext() const override; FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceMetalImpeller); }; diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index bad9f26ca780d..0362c7c86b1d1 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -129,8 +129,8 @@ } // |Surface| -impeller::AiksContext* GPUSurfaceMetalImpeller::GetAiksContext() const { - return aiks_context_.get(); +std::shared_ptr GPUSurfaceMetalImpeller::GetAiksContext() const { + return aiks_context_; } Surface::SurfaceData GPUSurfaceMetalImpeller::GetSurfaceData() const { diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index 0e3854900a54f..1e8d437f7b5c6 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -122,8 +122,9 @@ bool GPUSurfaceVulkanImpeller::EnableRasterCache() const { } // |Surface| -impeller::AiksContext* GPUSurfaceVulkanImpeller::GetAiksContext() const { - return aiks_context_.get(); +std::shared_ptr +GPUSurfaceVulkanImpeller::GetAiksContext() const { + return aiks_context_; } } // namespace flutter diff --git a/shell/gpu/gpu_surface_vulkan_impeller.h b/shell/gpu/gpu_surface_vulkan_impeller.h index cf72b2e0e18c9..7eca3ecd17f43 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.h +++ b/shell/gpu/gpu_surface_vulkan_impeller.h @@ -47,7 +47,7 @@ class GPUSurfaceVulkanImpeller final : public Surface { bool EnableRasterCache() const override; // |Surface| - impeller::AiksContext* GetAiksContext() const override; + std::shared_ptr GetAiksContext() const override; FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceVulkanImpeller); };