diff --git a/flow/compositor_context.h b/flow/compositor_context.h index ca1bb662f68cf..7c10f3b147e58 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -46,8 +46,12 @@ enum class RasterStatus { kEnqueuePipeline, // Failed to rasterize the frame. kFailed, - // Layer tree was discarded due to LayerTreeDiscardCallback - kDiscarded + // Layer tree was discarded due to LayerTreeDiscardCallback or inability to + // access the GPU. + kDiscarded, + // Drawing was yielded to allow the correct thread to draw as a result of the + // RasterThreadMerger. + kYielded, }; class CompositorContext { diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index bf4ccaad319fb..9441c8dc9470c 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -6,10 +6,8 @@ namespace flutter { -void ExternalViewEmbedder::SubmitFrame( - GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { +void ExternalViewEmbedder::SubmitFrame(GrDirectContext* context, + std::unique_ptr frame) { frame->Submit(); }; diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 8f8e228636169..c94d671752e0c 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -10,7 +10,6 @@ #include "flutter/flow/surface_frame.h" #include "flutter/fml/memory/ref_counted.h" #include "flutter/fml/raster_thread_merger.h" -#include "flutter/fml/synchronization/sync_switch.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPoint.h" @@ -313,10 +312,8 @@ class ExternalViewEmbedder { // This method can mutate the root Skia canvas before submitting the frame. // // It can also allocate frames for overlay surfaces to compose hybrid views. - virtual void SubmitFrame( - GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch); + virtual void SubmitFrame(GrDirectContext* context, + std::unique_ptr frame); // This method provides the embedder a way to do additional tasks after // |SubmitFrame|. For example, merge task runners if `should_resubmit_frame` diff --git a/flow/surface.cc b/flow/surface.cc index 7dbe56c1e8e78..79c8c8d7245d8 100644 --- a/flow/surface.cc +++ b/flow/surface.cc @@ -18,4 +18,8 @@ bool Surface::ClearRenderContext() { return false; } +bool Surface::AllowsDrawingWhenGpuDisabled() const { + return true; +} + } // namespace flutter diff --git a/flow/surface.h b/flow/surface.h index 21b248c074d4c..fc8daaebfa771 100644 --- a/flow/surface.h +++ b/flow/surface.h @@ -33,6 +33,8 @@ class Surface { virtual bool ClearRenderContext(); + virtual bool AllowsDrawingWhenGpuDisabled() const; + private: FML_DISALLOW_COPY_AND_ASSIGN(Surface); }; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 502e04c4416ae..fe399580ed306 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -147,7 +147,7 @@ void Rasterizer::DrawLastLayerTree( DrawToSurface(*frame_timings_recorder, *last_layer_tree_); } -void Rasterizer::Draw( +RasterStatus Rasterizer::Draw( std::unique_ptr frame_timings_recorder, std::shared_ptr> pipeline, LayerTreeDiscardCallback discardCallback) { @@ -156,7 +156,7 @@ void Rasterizer::Draw( if (raster_thread_merger_ && !raster_thread_merger_->IsOnRasterizingThread()) { // we yield and let this frame be serviced on the right thread. - return; + return RasterStatus::kYielded; } FML_DCHECK(delegate_.GetTaskRunners() .GetRasterTaskRunner() @@ -217,6 +217,8 @@ void Rasterizer::Draw( default: break; } + + return raster_status; } namespace { @@ -385,6 +387,8 @@ RasterStatus Rasterizer::DoDraw( raster_status == RasterStatus::kSkipAndRetry) { resubmitted_layer_tree_ = std::move(layer_tree); return raster_status; + } else if (raster_status == RasterStatus::kDiscarded) { + return raster_status; } if (persistent_cache->IsDumpingSkp() && @@ -465,6 +469,31 @@ RasterStatus Rasterizer::DrawToSurface( TRACE_EVENT0("flutter", "Rasterizer::DrawToSurface"); FML_DCHECK(surface_); + RasterStatus raster_status; + if (surface_->AllowsDrawingWhenGpuDisabled()) { + raster_status = DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree); + } else { + delegate_.GetIsGpuDisabledSyncSwitch()->Execute( + fml::SyncSwitch::Handlers() + .SetIfTrue([&] { raster_status = RasterStatus::kDiscarded; }) + .SetIfFalse([&] { + raster_status = + DrawToSurfaceUnsafe(frame_timings_recorder, layer_tree); + })); + } + + return raster_status; +} + +/// Unsafe because it assumes we have access to the GPU which isn't the case +/// when iOS is backgrounded, for example. +/// \see Rasterizer::DrawToSurface +RasterStatus Rasterizer::DrawToSurfaceUnsafe( + FrameTimingsRecorder& frame_timings_recorder, + flutter::LayerTree& layer_tree) { + TRACE_EVENT0("flutter", "Rasterizer::DrawToSurfaceUnsafe"); + FML_DCHECK(surface_); + compositor_context_->ui_time().SetLapTime( frame_timings_recorder.GetBuildDuration()); @@ -512,9 +541,8 @@ RasterStatus Rasterizer::DrawToSurface( if (external_view_embedder_ && (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) { FML_DCHECK(!frame->IsSubmitted()); - external_view_embedder_->SubmitFrame( - surface_->GetContext(), std::move(frame), - delegate_.GetIsGpuDisabledSyncSwitch()); + external_view_embedder_->SubmitFrame(surface_->GetContext(), + std::move(frame)); } else { frame->Submit(); } diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 15beadf5511a5..2829f0c8dc487 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -233,9 +233,10 @@ class Rasterizer final : public SnapshotDelegate { /// @param[in] discardCallback if specified and returns true, the layer tree /// is discarded instead of being rendered /// - void Draw(std::unique_ptr frame_timings_recorder, - std::shared_ptr> pipeline, - LayerTreeDiscardCallback discardCallback = NoDiscard); + RasterStatus Draw( + std::unique_ptr frame_timings_recorder, + std::shared_ptr> pipeline, + LayerTreeDiscardCallback discardCallback = NoDiscard); //---------------------------------------------------------------------------- /// @brief The type of the screenshot to obtain of the previously @@ -492,6 +493,9 @@ class Rasterizer final : public SnapshotDelegate { RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder, flutter::LayerTree& layer_tree); + RasterStatus DrawToSurfaceUnsafe(FrameTimingsRecorder& frame_timings_recorder, + flutter::LayerTree& layer_tree); + void FireNextFrameCallbackIfPresent(); static bool NoDiscard(const flutter::LayerTree& layer_tree) { return false; } diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index 3bd3f82465285..5d082a68eb493 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -45,6 +45,7 @@ class MockSurface : public Surface { MOCK_METHOD0(GetExternalViewEmbedder, ExternalViewEmbedder*()); MOCK_METHOD0(MakeRenderContextCurrent, std::unique_ptr()); MOCK_METHOD0(ClearRenderContext, bool()); + MOCK_CONST_METHOD0(AllowsDrawingWhenGpuDisabled, bool()); }; class MockExternalViewEmbedder : public ExternalViewEmbedder { @@ -63,11 +64,9 @@ class MockExternalViewEmbedder : public ExternalViewEmbedder { fml::RefPtr raster_thread_merger)); MOCK_METHOD0(GetCurrentCanvases, std::vector()); MOCK_METHOD1(CompositeEmbeddedView, SkCanvas*(int view_id)); - MOCK_METHOD3(SubmitFrame, + MOCK_METHOD2(SubmitFrame, void(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch)); + std::unique_ptr frame)); MOCK_METHOD2(EndFrame, void(bool should_resubmit_frame, fml::RefPtr raster_thread_merger)); @@ -142,6 +141,7 @@ TEST(RasterizerTest, auto surface_frame = std::make_unique( /*surface=*/nullptr, /*supports_readback=*/true, /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); EXPECT_CALL(*surface, MakeRenderContextCurrent()) @@ -202,6 +202,7 @@ TEST( auto surface_frame = std::make_unique( /*surface=*/nullptr, /*supports_readback=*/true, /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); EXPECT_CALL(*surface, MakeRenderContextCurrent()) @@ -262,6 +263,7 @@ TEST( auto surface_frame = std::make_unique( /*surface=*/nullptr, /*supports_readback=*/true, /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); EXPECT_CALL(*surface, AcquireFrame(SkISize())) .WillOnce(Return(ByMove(std::move(surface_frame)))); EXPECT_CALL(*surface, MakeRenderContextCurrent()) @@ -325,4 +327,200 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) { }); latch.Wait(); } + +TEST(RasterizerTest, + drawWithGpuEnabledAndSurfaceAllowsDrawingWhenGpuDisabledDoesAcquireFrame) { + std::string test_name = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + ThreadHost thread_host("io.flutter.test." + test_name + ".", + ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + MockDelegate delegate; + EXPECT_CALL(delegate, GetTaskRunners()) + .WillRepeatedly(ReturnRef(task_runners)); + EXPECT_CALL(delegate, OnFrameRasterized(_)); + + auto rasterizer = std::make_unique(delegate); + auto surface = std::make_unique(); + auto is_gpu_disabled_sync_switch = + std::make_shared(false); + + auto surface_frame = std::make_unique( + /*surface=*/nullptr, /*supports_readback=*/true, + /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); + ON_CALL(delegate, GetIsGpuDisabledSyncSwitch()) + .WillByDefault(Return(is_gpu_disabled_sync_switch)); + EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0); + EXPECT_CALL(*surface, AcquireFrame(SkISize())) + .WillOnce(Return(ByMove(std::move(surface_frame)))); + EXPECT_CALL(*surface, MakeRenderContextCurrent()) + .WillOnce(Return(ByMove(std::make_unique(true)))); + + rasterizer->Setup(std::move(surface)); + fml::AutoResetWaitableEvent latch; + thread_host.raster_thread->GetTaskRunner()->PostTask([&] { + auto pipeline = std::make_shared>(/*depth=*/10); + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + /*device_pixel_ratio=*/2.0f); + bool result = pipeline->Produce().Complete(std::move(layer_tree)); + EXPECT_TRUE(result); + auto no_discard = [](LayerTree&) { return false; }; + rasterizer->Draw(CreateFinishedBuildRecorder(), pipeline, no_discard); + latch.Signal(); + }); + latch.Wait(); +} + +TEST( + RasterizerTest, + drawWithGpuDisabledAndSurfaceAllowsDrawingWhenGpuDisabledDoesAcquireFrame) { + std::string test_name = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + ThreadHost thread_host("io.flutter.test." + test_name + ".", + ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + MockDelegate delegate; + EXPECT_CALL(delegate, GetTaskRunners()) + .WillRepeatedly(ReturnRef(task_runners)); + EXPECT_CALL(delegate, OnFrameRasterized(_)); + auto rasterizer = std::make_unique(delegate); + auto surface = std::make_unique(); + auto is_gpu_disabled_sync_switch = + std::make_shared(true); + + auto surface_frame = std::make_unique( + /*surface=*/nullptr, /*supports_readback=*/true, + /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(true)); + ON_CALL(delegate, GetIsGpuDisabledSyncSwitch()) + .WillByDefault(Return(is_gpu_disabled_sync_switch)); + EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()).Times(0); + EXPECT_CALL(*surface, AcquireFrame(SkISize())) + .WillOnce(Return(ByMove(std::move(surface_frame)))); + EXPECT_CALL(*surface, MakeRenderContextCurrent()) + .WillOnce(Return(ByMove(std::make_unique(true)))); + + rasterizer->Setup(std::move(surface)); + fml::AutoResetWaitableEvent latch; + thread_host.raster_thread->GetTaskRunner()->PostTask([&] { + auto pipeline = std::make_shared>(/*depth=*/10); + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + /*device_pixel_ratio=*/2.0f); + bool result = pipeline->Produce().Complete(std::move(layer_tree)); + EXPECT_TRUE(result); + auto no_discard = [](LayerTree&) { return false; }; + RasterStatus status = + rasterizer->Draw(CreateFinishedBuildRecorder(), pipeline, no_discard); + EXPECT_EQ(status, RasterStatus::kSuccess); + latch.Signal(); + }); + latch.Wait(); +} + +TEST( + RasterizerTest, + drawWithGpuEnabledAndSurfaceDisallowsDrawingWhenGpuDisabledDoesAcquireFrame) { + std::string test_name = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + ThreadHost thread_host("io.flutter.test." + test_name + ".", + ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + MockDelegate delegate; + EXPECT_CALL(delegate, GetTaskRunners()) + .WillRepeatedly(ReturnRef(task_runners)); + EXPECT_CALL(delegate, OnFrameRasterized(_)); + auto rasterizer = std::make_unique(delegate); + auto surface = std::make_unique(); + auto is_gpu_disabled_sync_switch = + std::make_shared(false); + + auto surface_frame = std::make_unique( + /*surface=*/nullptr, /*supports_readback=*/true, + /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false)); + EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()) + .WillOnce(Return(is_gpu_disabled_sync_switch)); + EXPECT_CALL(*surface, AcquireFrame(SkISize())) + .WillOnce(Return(ByMove(std::move(surface_frame)))); + EXPECT_CALL(*surface, MakeRenderContextCurrent()) + .WillOnce(Return(ByMove(std::make_unique(true)))); + + rasterizer->Setup(std::move(surface)); + fml::AutoResetWaitableEvent latch; + thread_host.raster_thread->GetTaskRunner()->PostTask([&] { + auto pipeline = std::make_shared>(/*depth=*/10); + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + /*device_pixel_ratio=*/2.0f); + bool result = pipeline->Produce().Complete(std::move(layer_tree)); + EXPECT_TRUE(result); + auto no_discard = [](LayerTree&) { return false; }; + RasterStatus status = + rasterizer->Draw(CreateFinishedBuildRecorder(), pipeline, no_discard); + EXPECT_EQ(status, RasterStatus::kSuccess); + latch.Signal(); + }); + latch.Wait(); +} + +TEST( + RasterizerTest, + drawWithGpuDisabledAndSurfaceDisallowsDrawingWhenGpuDisabledDoesntAcquireFrame) { + std::string test_name = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + ThreadHost thread_host("io.flutter.test." + test_name + ".", + ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI); + TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(), + thread_host.raster_thread->GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + MockDelegate delegate; + EXPECT_CALL(delegate, GetTaskRunners()) + .WillRepeatedly(ReturnRef(task_runners)); + EXPECT_CALL(delegate, OnFrameRasterized(_)).Times(0); + auto rasterizer = std::make_unique(delegate); + auto surface = std::make_unique(); + auto is_gpu_disabled_sync_switch = + std::make_shared(true); + + auto surface_frame = std::make_unique( + /*surface=*/nullptr, /*supports_readback=*/true, + /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()).WillOnce(Return(false)); + EXPECT_CALL(delegate, GetIsGpuDisabledSyncSwitch()) + .WillOnce(Return(is_gpu_disabled_sync_switch)); + EXPECT_CALL(*surface, AcquireFrame(SkISize())).Times(0); + EXPECT_CALL(*surface, MakeRenderContextCurrent()) + .WillOnce(Return(ByMove(std::make_unique(true)))); + + rasterizer->Setup(std::move(surface)); + fml::AutoResetWaitableEvent latch; + thread_host.raster_thread->GetTaskRunner()->PostTask([&] { + auto pipeline = std::make_shared>(/*depth=*/10); + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + /*device_pixel_ratio=*/2.0f); + bool result = pipeline->Produce().Complete(std::move(layer_tree)); + EXPECT_TRUE(result); + auto no_discard = [](LayerTree&) { return false; }; + RasterStatus status = + rasterizer->Draw(CreateFinishedBuildRecorder(), pipeline, no_discard); + EXPECT_EQ(status, RasterStatus::kDiscarded); + latch.Signal(); + }); + latch.Wait(); +} + } // namespace flutter diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index 300fc6a57328f..5a8edc19fb45a 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -63,8 +63,7 @@ SkCanvas* ShellTestExternalViewEmbedder::CompositeEmbeddedView(int view_id) { // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::SubmitFrame( GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { + std::unique_ptr frame) { frame->Submit(); if (frame && frame->SkiaSurface()) { last_submitted_frame_size_ = SkISize::Make(frame->SkiaSurface()->width(), diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index cd4d6c6ae4baf..72c101ed1f4bc 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -63,9 +63,7 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch) override; + std::unique_ptr frame) override; // |ExternalViewEmbedder| void EndFrame( diff --git a/shell/gpu/gpu_surface_gl.cc b/shell/gpu/gpu_surface_gl.cc index e78135663764b..9d06aa9d35715 100644 --- a/shell/gpu/gpu_surface_gl.cc +++ b/shell/gpu/gpu_surface_gl.cc @@ -318,4 +318,9 @@ bool GPUSurfaceGL::ClearRenderContext() { return delegate_->GLContextClearCurrent(); } +// |Surface| +bool GPUSurfaceGL::AllowsDrawingWhenGpuDisabled() const { + return delegate_->AllowsDrawingWhenGpuDisabled(); +} + } // namespace flutter diff --git a/shell/gpu/gpu_surface_gl.h b/shell/gpu/gpu_surface_gl.h index f1be74c495b2d..e4b04d31f9ed5 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -50,6 +50,9 @@ class GPUSurfaceGL : public Surface { // |Surface| bool ClearRenderContext() override; + // |Surface| + bool AllowsDrawingWhenGpuDisabled() const override; + private: GPUSurfaceGLDelegate* delegate_; sk_sp context_; diff --git a/shell/gpu/gpu_surface_gl_delegate.cc b/shell/gpu/gpu_surface_gl_delegate.cc index 66f9df261f0ab..70bdfc03ba4bb 100644 --- a/shell/gpu/gpu_surface_gl_delegate.cc +++ b/shell/gpu/gpu_surface_gl_delegate.cc @@ -99,4 +99,8 @@ GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface() { return CreateGLInterface(nullptr); } +bool GPUSurfaceGLDelegate::AllowsDrawingWhenGpuDisabled() const { + return true; +} + } // namespace flutter diff --git a/shell/gpu/gpu_surface_gl_delegate.h b/shell/gpu/gpu_surface_gl_delegate.h index fff96945e00a8..fb13c8212390c 100644 --- a/shell/gpu/gpu_surface_gl_delegate.h +++ b/shell/gpu/gpu_surface_gl_delegate.h @@ -69,6 +69,9 @@ class GPUSurfaceGLDelegate { // instrumentation to specific GL calls can specify custom GL functions // here. virtual GLProcResolver GetGLProcResolver() const; + + // Whether to allow drawing to the surface when the GPU is disabled + virtual bool AllowsDrawingWhenGpuDisabled() const; }; } // namespace flutter diff --git a/shell/gpu/gpu_surface_metal.h b/shell/gpu/gpu_surface_metal.h index bd715ecb407d9..8899089383df5 100644 --- a/shell/gpu/gpu_surface_metal.h +++ b/shell/gpu/gpu_surface_metal.h @@ -49,6 +49,9 @@ class SK_API_AVAILABLE_CA_METAL_LAYER GPUSurfaceMetal : public Surface { // |Surface| std::unique_ptr MakeRenderContextCurrent() override; + // |Surface| + bool AllowsDrawingWhenGpuDisabled() const override; + std::unique_ptr AcquireFrameFromCAMetalLayer( const SkISize& frame_info); diff --git a/shell/gpu/gpu_surface_metal.mm b/shell/gpu/gpu_surface_metal.mm index ea40dda5893dd..d3ec678d8bb5e 100644 --- a/shell/gpu/gpu_surface_metal.mm +++ b/shell/gpu/gpu_surface_metal.mm @@ -184,6 +184,10 @@ return std::make_unique(true); } +bool GPUSurfaceMetal::AllowsDrawingWhenGpuDisabled() const { + return delegate_->AllowsDrawingWhenGpuDisabled(); +} + void GPUSurfaceMetal::ReleaseUnusedDrawableIfNecessary() { // If the previous surface frame was not submitted before a new one is acquired, the old drawable // needs to be released. An RAII wrapper may not be used because this needs to interoperate with diff --git a/shell/gpu/gpu_surface_metal_delegate.cc b/shell/gpu/gpu_surface_metal_delegate.cc index 427614e1b41d8..7a22d8de88a89 100644 --- a/shell/gpu/gpu_surface_metal_delegate.cc +++ b/shell/gpu/gpu_surface_metal_delegate.cc @@ -16,4 +16,8 @@ MTLRenderTargetType GPUSurfaceMetalDelegate::GetRenderTargetType() { return render_target_type_; } +bool GPUSurfaceMetalDelegate::AllowsDrawingWhenGpuDisabled() const { + return true; +} + } // namespace flutter diff --git a/shell/gpu/gpu_surface_metal_delegate.h b/shell/gpu/gpu_surface_metal_delegate.h index b11a622bd7489..56112042fbc1d 100644 --- a/shell/gpu/gpu_surface_metal_delegate.h +++ b/shell/gpu/gpu_surface_metal_delegate.h @@ -89,6 +89,11 @@ class GPUSurfaceMetalDelegate { /// virtual bool PresentTexture(GPUMTLTextureInfo texture) const = 0; + //------------------------------------------------------------------------------ + /// @brief Whether to allow drawing to the surface when the GPU is disabled + /// + virtual bool AllowsDrawingWhenGpuDisabled() const; + MTLRenderTargetType GetRenderTargetType(); private: diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index dd7c45148ef17..08596ba8ad925 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -75,8 +75,7 @@ SkRect AndroidExternalViewEmbedder::GetViewRect(int view_id) const { // |ExternalViewEmbedder| void AndroidExternalViewEmbedder::SubmitFrame( GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { + std::unique_ptr frame) { TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::SubmitFrame"); if (!FrameHasPlatformLayers()) { diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.h b/shell/platform/android/external_view_embedder/external_view_embedder.h index f456674be9a94..a0386167418d1 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -47,9 +47,7 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch) override; + std::unique_ptr frame) override; // |ExternalViewEmbedder| PostPrerollResult PostPrerollAction( diff --git a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index 24d0063c81714..0b07e6c3a9f2e 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -334,7 +334,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) { return true; }); - embedder->SubmitFrame(gr_context.get(), std::move(surface_frame), nullptr); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); // Submits frame if no Android view in the current frame. EXPECT_TRUE(did_submit_frame); // Doesn't resubmit frame. @@ -401,7 +401,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) { return true; }); - embedder->SubmitFrame(gr_context.get(), std::move(surface_frame), nullptr); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); // Doesn't submit frame if there aren't Android views in the previous frame. EXPECT_FALSE(did_submit_frame); // Resubmits frame. @@ -465,7 +465,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) { } return true; }); - embedder->SubmitFrame(gr_context.get(), std::move(surface_frame), nullptr); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); // Submits frame if there are Android views in the previous frame. EXPECT_TRUE(did_submit_frame); // Doesn't resubmit frame. @@ -573,7 +573,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__overlayComposition) { return true; }); - embedder->SubmitFrame(gr_context.get(), std::move(surface_frame), nullptr); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); EXPECT_CALL(*jni_mock, FlutterViewEndFrame()); embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger); @@ -640,7 +640,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame__platformViewWithoutAnyOverlay) { return true; }); - embedder->SubmitFrame(gr_context.get(), std::move(surface_frame), nullptr); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); EXPECT_CALL(*jni_mock, FlutterViewEndFrame()); embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger); @@ -734,7 +734,7 @@ TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) { std::make_unique(SkSurface::MakeNull(1000, 1000), false, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; }); - embedder->SubmitFrame(gr_context.get(), std::move(surface_frame), nullptr); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); EXPECT_CALL(*jni_mock, FlutterViewEndFrame()); embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger); @@ -816,7 +816,7 @@ TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) { std::make_unique(SkSurface::MakeNull(1000, 1000), false, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; }); - embedder->SubmitFrame(gr_context.get(), std::move(surface_frame), nullptr); + embedder->SubmitFrame(gr_context.get(), std::move(surface_frame)); EXPECT_CALL(*jni_mock, FlutterViewEndFrame()); embedder->EndFrame(/*should_resubmit_frame=*/false, raster_thread_merger); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index ed622f070733b..fdd540c2aa658 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -462,22 +462,9 @@ ); } -bool FlutterPlatformViewsController::SubmitFrame( - GrDirectContext* gr_context, - std::shared_ptr ios_context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { - bool result = false; - gpu_disable_sync_switch->Execute( - fml::SyncSwitch::Handlers().SetIfTrue([&] { result = false; }).SetIfFalse([&] { - result = SubmitFrameGpuSafe(gr_context, ios_context, std::move(frame)); - })); - return result; -} - -bool FlutterPlatformViewsController::SubmitFrameGpuSafe(GrDirectContext* gr_context, - std::shared_ptr ios_context, - std::unique_ptr frame) { +bool FlutterPlatformViewsController::SubmitFrame(GrDirectContext* gr_context, + std::shared_ptr ios_context, + std::unique_ptr frame) { // Any UIKit related code has to run on main thread. FML_DCHECK([[NSThread currentThread] isMainThread]); if (flutter_view_ == nullptr) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index 6cd7c349c8dfe..0bcb1b483846b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -968,10 +968,8 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin auto mock_surface = std::make_unique( nullptr, true, [](const flutter::SurfaceFrame& surface_frame, SkCanvas* canvas) { return false; }); - auto is_gpu_disabled = std::make_shared(); - is_gpu_disabled->SetSwitch(false); - XCTAssertFalse(flutterPlatformViewsController->SubmitFrame( - nullptr, nullptr, std::move(mock_surface), is_gpu_disabled)); + XCTAssertFalse( + flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface))); auto embeddedViewParams_2 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); @@ -980,10 +978,8 @@ - (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashin auto mock_surface_submit_false = std::make_unique( nullptr, true, [](const flutter::SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; }); - auto gpu_is_disabled = std::make_shared(); - gpu_is_disabled->SetSwitch(false); - XCTAssertTrue(flutterPlatformViewsController->SubmitFrame( - nullptr, nullptr, std::move(mock_surface_submit_false), gpu_is_disabled)); + XCTAssertTrue(flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, + std::move(mock_surface_submit_false))); } - (void) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index c195f870653c2..f886bd0df7df3 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -173,8 +173,7 @@ class FlutterPlatformViewsController { bool SubmitFrame(GrDirectContext* gr_context, std::shared_ptr ios_context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch); + std::unique_ptr frame); void OnMethodCall(FlutterMethodCall* call, FlutterResult& result); @@ -300,10 +299,6 @@ class FlutterPlatformViewsController { // Commit a CATransaction if |BeginCATransaction| has been called during the frame. void CommitCATransactionIfNeeded(); - bool SubmitFrameGpuSafe(GrDirectContext* gr_context, - std::shared_ptr ios_context, - std::unique_ptr frame); - // Resets the state of the frame. void ResetFrameState(); diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index b6ca3b6e6f948..6c023d1b793e1 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -54,9 +54,7 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch) override; + std::unique_ptr frame) override; // |ExternalViewEmbedder| void EndFrame( diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index 391044d7e90ab..a4921af254af9 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -72,14 +72,11 @@ } // |ExternalViewEmbedder| -void IOSExternalViewEmbedder::SubmitFrame( - GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { +void IOSExternalViewEmbedder::SubmitFrame(GrDirectContext* context, + std::unique_ptr frame) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::SubmitFrame"); FML_CHECK(platform_views_controller_); - platform_views_controller_->SubmitFrame(std::move(context), ios_context_, std::move(frame), - gpu_disable_sync_switch); + platform_views_controller_->SubmitFrame(std::move(context), ios_context_, std::move(frame)); TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::DidSubmitFrame"); } diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index 0172e225a6bd8..a541e28e7c21c 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -46,6 +46,9 @@ class IOSSurfaceGL final : public IOSSurface, public GPUSurfaceGLDelegate { // |GPUSurfaceGLDelegate| bool SurfaceSupportsReadback() const override; + // |GPUSurfaceGLDelegate| + bool AllowsDrawingWhenGpuDisabled() const override; + private: std::unique_ptr render_target_; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 34983f3a5bb21..e1c5bde675499 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -89,4 +89,9 @@ return IsValid() && render_target_->PresentRenderBuffer(); } +// |GPUSurfaceGLDelegate| +bool IOSSurfaceGL::AllowsDrawingWhenGpuDisabled() const { + return false; +} + } // namespace flutter diff --git a/shell/platform/darwin/ios/ios_surface_metal.h b/shell/platform/darwin/ios/ios_surface_metal.h index c2e9b8c50d0da..2424ceafca3e6 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.h +++ b/shell/platform/darwin/ios/ios_surface_metal.h @@ -49,6 +49,9 @@ class SK_API_AVAILABLE_CA_METAL_LAYER IOSSurfaceMetal final : public IOSSurface, // |GPUSurfaceMetalDelegate| bool PresentTexture(GPUMTLTextureInfo texture) const override; + // |GPUSurfaceMetalDelegate| + bool AllowsDrawingWhenGpuDisabled() const 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 64909e0b15b1b..2df3fd0840897 100644 --- a/shell/platform/darwin/ios/ios_surface_metal.mm +++ b/shell/platform/darwin/ios/ios_surface_metal.mm @@ -98,4 +98,9 @@ return false; } +// |GPUSurfaceMetalDelegate| +bool IOSSurfaceMetal::AllowsDrawingWhenGpuDisabled() const { + return false; +} + } // namespace flutter diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index 1d816ab64e274..a890260887e26 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -135,8 +135,7 @@ static FlutterBackingStoreConfig MakeBackingStoreConfig( // |ExternalViewEmbedder| void EmbedderExternalViewEmbedder::SubmitFrame( GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { + std::unique_ptr frame) { auto [matched_render_targets, pending_keys] = render_target_cache_.GetExistingTargetsInCache(pending_views_); diff --git a/shell/platform/embedder/embedder_external_view_embedder.h b/shell/platform/embedder/embedder_external_view_embedder.h index 62b4540c92a2c..98fe8b2a56639 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.h +++ b/shell/platform/embedder/embedder_external_view_embedder.h @@ -98,9 +98,7 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch) override; + std::unique_ptr frame) override; // |ExternalViewEmbedder| SkCanvas* GetRootCanvas() override; diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index e84bdf852cac2..1071d4e881dbb 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -105,8 +105,7 @@ void FlatlandExternalViewEmbedder::EndFrame( void FlatlandExternalViewEmbedder::SubmitFrame( GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { + std::unique_ptr frame) { TRACE_EVENT0("flutter", "FlatlandExternalViewEmbedder::SubmitFrame"); std::vector> frame_surfaces; std::unordered_map frame_surface_indices; diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h index 0084efc819c65..9ee0c42dcdff3 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h @@ -86,9 +86,7 @@ class FlatlandExternalViewEmbedder final // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch) override; + std::unique_ptr frame) override; // |ExternalViewEmbedder| void CancelFrame() override { Reset(); } diff --git a/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc b/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc index 639dd3c1b11c6..c485c04edb482 100644 --- a/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc @@ -244,8 +244,7 @@ void FuchsiaExternalViewEmbedder::EndFrame( void FuchsiaExternalViewEmbedder::SubmitFrame( GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& gpu_disable_sync_switch) { + std::unique_ptr frame) { TRACE_EVENT0("flutter", "FuchsiaExternalViewEmbedder::SubmitFrame"); std::vector> frame_surfaces; std::unordered_map frame_surface_indices; diff --git a/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.h b/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.h index 125c8f843ec56..a5eb09d23d442 100644 --- a/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.h @@ -104,9 +104,7 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder { // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch) override; + std::unique_ptr frame) override; // |ExternalViewEmbedder| void CancelFrame() override { Reset(); } diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 28501ad4e5cb0..6db634d16595f 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -53,9 +53,7 @@ class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder { double device_pixel_ratio, fml::RefPtr raster_thread_merger) override {} void SubmitFrame(GrDirectContext* context, - std::unique_ptr frame, - const std::shared_ptr& - gpu_disable_sync_switch) override { + std::unique_ptr frame) override { return; }