diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 8c799234cbf70..d45a03cf18b54 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -616,6 +616,8 @@ FILE: ../../../flutter/shell/common/skia_event_tracer_impl.cc FILE: ../../../flutter/shell/common/skia_event_tracer_impl.h FILE: ../../../flutter/shell/common/surface.cc FILE: ../../../flutter/shell/common/surface.h +FILE: ../../../flutter/shell/common/surface_frame.cc +FILE: ../../../flutter/shell/common/surface_frame.h FILE: ../../../flutter/shell/common/switches.cc FILE: ../../../flutter/shell/common/switches.h FILE: ../../../flutter/shell/common/thread_host.cc diff --git a/flow/BUILD.gn b/flow/BUILD.gn index c3fea8568e9ea..c21ba807803a6 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -73,6 +73,7 @@ source_set("flow") { deps = [ "//flutter/common", "//flutter/fml", + "//flutter/shell/common:surface_frame", "//third_party/skia", ] diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index 5234bf1e50c8c..d058acb11f89e 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -7,12 +7,10 @@ namespace flutter { bool ExternalViewEmbedder::SubmitFrame(GrContext* context, - SkCanvas* background_canvas) { - return false; + std::unique_ptr frame) { + return frame->Submit(); }; -void ExternalViewEmbedder::FinishFrame(){}; - void MutatorsStack::PushClipRect(const SkRect& rect) { std::shared_ptr element = std::make_shared(rect); vector_.push_back(element); diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 5888288bf92ed..59ffdf453bc5d 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -9,6 +9,7 @@ #include "flutter/fml/memory/ref_counted.h" #include "flutter/fml/raster_thread_merger.h" +#include "flutter/shell/common/surface_frame.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" @@ -248,10 +249,13 @@ class ExternalViewEmbedder { // Must be called on the UI thread. virtual SkCanvas* CompositeEmbeddedView(int view_id) = 0; - virtual bool SubmitFrame(GrContext* context, SkCanvas* background_canvas); - - // This is called after submitting the embedder frame and the surface frame. - virtual void FinishFrame(); + // Implementers must submit the frame by calling frame.Submit(). + // + // 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 bool SubmitFrame(GrContext* context, + std::unique_ptr frame); // This should only be called after |SubmitFrame|. // This method provides the embedder a way to do additional tasks after diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index e9e5965dffda0..9ec4ac91a5d2f 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -120,6 +120,7 @@ source_set("common") { ] deps = [ + ":surface_frame", "//flutter/assets", "//flutter/common", "//flutter/flow", @@ -141,6 +142,18 @@ source_set("common") { public_configs = [ "//flutter:config" ] } +source_set("surface_frame") { + sources = [ + "surface_frame.cc", + "surface_frame.h", + ] + + deps = [ + "//flutter/fml", + "//third_party/skia", + ] +} + template("shell_host_executable") { executable(target_name) { testonly = true diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 30d50dba03e25..e992f801d1f03 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -421,14 +421,9 @@ RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) { return raster_status; } if (external_view_embedder != nullptr) { + FML_DCHECK(!frame->IsSubmitted()); external_view_embedder->SubmitFrame(surface_->GetContext(), - root_surface_canvas); - // The external view embedder may mutate the root surface canvas while - // submitting the frame. - // Therefore, submit the final frame after asking the external view - // embedder to submit the frame. - frame->Submit(); - external_view_embedder->FinishFrame(); + std::move(frame)); } else { frame->Submit(); } diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index 683e21ad73c91..3930ab7b61717 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -33,14 +33,12 @@ SkCanvas* ShellTestExternalViewEmbedder::CompositeEmbeddedView(int view_id) { } // |ExternalViewEmbedder| -bool ShellTestExternalViewEmbedder::SubmitFrame(GrContext* context, - SkCanvas* background_canvas) { - return true; +bool ShellTestExternalViewEmbedder::SubmitFrame( + GrContext* context, + std::unique_ptr frame) { + return frame->Submit(); } -// |ExternalViewEmbedder| -void ShellTestExternalViewEmbedder::FinishFrame() {} - // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::EndFrame( fml::RefPtr raster_thread_merger) { diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index 56d9123ea8a7a..765ae5c8334e7 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -49,10 +49,8 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { SkCanvas* CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| - bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override; - - // |ExternalViewEmbedder| - void FinishFrame() override; + bool SubmitFrame(GrContext* context, + std::unique_ptr frame) override; // |ExternalViewEmbedder| void EndFrame( diff --git a/shell/common/surface.cc b/shell/common/surface.cc index 6a4f992e9137e..c12a35ba07081 100644 --- a/shell/common/surface.cc +++ b/shell/common/surface.cc @@ -4,58 +4,8 @@ #include "flutter/shell/common/surface.h" -#include "flutter/fml/logging.h" -#include "third_party/skia/include/core/SkSurface.h" - namespace flutter { -SurfaceFrame::SurfaceFrame(sk_sp surface, - bool supports_readback, - const SubmitCallback& submit_callback) - : submitted_(false), - surface_(surface), - supports_readback_(supports_readback), - submit_callback_(submit_callback) { - FML_DCHECK(submit_callback_); -} - -SurfaceFrame::~SurfaceFrame() { - if (submit_callback_ && !submitted_) { - // Dropping without a Submit. - submit_callback_(*this, nullptr); - } -} - -bool SurfaceFrame::Submit() { - if (submitted_) { - return false; - } - - submitted_ = PerformSubmit(); - - return submitted_; -} - -SkCanvas* SurfaceFrame::SkiaCanvas() { - return surface_ != nullptr ? surface_->getCanvas() : nullptr; -} - -sk_sp SurfaceFrame::SkiaSurface() const { - return surface_; -} - -bool SurfaceFrame::PerformSubmit() { - if (submit_callback_ == nullptr) { - return false; - } - - if (submit_callback_(*this, SkiaCanvas())) { - return true; - } - - return false; -} - Surface::Surface() = default; Surface::~Surface() = default; diff --git a/shell/common/surface.h b/shell/common/surface.h index 432f6be5e564b..2703fb83a26e3 100644 --- a/shell/common/surface.h +++ b/shell/common/surface.h @@ -10,42 +10,10 @@ #include "flutter/flow/compositor_context.h" #include "flutter/flow/embedded_views.h" #include "flutter/fml/macros.h" -#include "third_party/skia/include/core/SkCanvas.h" +#include "flutter/shell/common/surface_frame.h" namespace flutter { -/// Represents a Frame that has been fully configured for the underlying client -/// rendering API. A frame may only be submitted once. -class SurfaceFrame { - public: - using SubmitCallback = - std::function; - - SurfaceFrame(sk_sp surface, - bool supports_readback, - const SubmitCallback& submit_callback); - - ~SurfaceFrame(); - - bool Submit(); - - SkCanvas* SkiaCanvas(); - - sk_sp SkiaSurface() const; - - bool supports_readback() { return supports_readback_; } - - private: - bool submitted_; - sk_sp surface_; - bool supports_readback_; - SubmitCallback submit_callback_; - - bool PerformSubmit(); - - FML_DISALLOW_COPY_AND_ASSIGN(SurfaceFrame); -}; - /// Abstract Base Class that represents where we will be rendering content. class Surface { public: diff --git a/shell/common/surface_frame.cc b/shell/common/surface_frame.cc new file mode 100644 index 0000000000000..a99c8a88259d4 --- /dev/null +++ b/shell/common/surface_frame.cc @@ -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/common/surface_frame.h" + +#include "flutter/fml/logging.h" + +namespace flutter { + +SurfaceFrame::SurfaceFrame(sk_sp surface, + bool supports_readback, + const SubmitCallback& submit_callback) + : surface_(surface), + supports_readback_(supports_readback), + submit_callback_(submit_callback) { + FML_DCHECK(submit_callback_); +} + +SurfaceFrame::~SurfaceFrame() { + if (submit_callback_ && !submitted_) { + // Dropping without a Submit. + submit_callback_(*this, nullptr); + } +} + +bool SurfaceFrame::Submit() { + if (submitted_) { + return false; + } + + submitted_ = PerformSubmit(); + + return submitted_; +} + +bool SurfaceFrame::IsSubmitted() const { + return submitted_; +} + +SkCanvas* SurfaceFrame::SkiaCanvas() { + return surface_ != nullptr ? surface_->getCanvas() : nullptr; +} + +sk_sp SurfaceFrame::SkiaSurface() const { + return surface_; +} + +bool SurfaceFrame::PerformSubmit() { + if (submit_callback_ == nullptr) { + return false; + } + + if (submit_callback_(*this, SkiaCanvas())) { + return true; + } + + return false; +} + +} // namespace flutter diff --git a/shell/common/surface_frame.h b/shell/common/surface_frame.h new file mode 100644 index 0000000000000..b3ac64fb5d07e --- /dev/null +++ b/shell/common/surface_frame.h @@ -0,0 +1,52 @@ +// 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_COMMON_SURFACE_FRAME_H_ +#define FLUTTER_SHELL_COMMON_SURFACE_FRAME_H_ + +#include + +#include "flutter/fml/macros.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkSurface.h" + +namespace flutter { + +/// Represents a Frame that has been fully configured for the underlying client +/// rendering API. A frame may only be submitted once. +class SurfaceFrame { + public: + using SubmitCallback = + std::function; + + SurfaceFrame(sk_sp surface, + bool supports_readback, + const SubmitCallback& submit_callback); + + ~SurfaceFrame(); + + bool Submit(); + + bool IsSubmitted() const; + + SkCanvas* SkiaCanvas(); + + sk_sp SkiaSurface() const; + + bool supports_readback() { return supports_readback_; } + + private: + bool submitted_ = false; + sk_sp surface_; + bool supports_readback_; + SubmitCallback submit_callback_; + + bool PerformSubmit(); + + FML_DISALLOW_COPY_AND_ASSIGN(SurfaceFrame); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_COMMON_SURFACE_FRAME_H_ 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 3f4f1b3d5414f..30ecce3cc5e9f 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -40,17 +40,18 @@ std::vector AndroidExternalViewEmbedder::GetCurrentCanvases() { } // |ExternalViewEmbedder| -bool AndroidExternalViewEmbedder::SubmitFrame(GrContext* context, - SkCanvas* background_canvas) { +bool AndroidExternalViewEmbedder::SubmitFrame( + GrContext* context, + std::unique_ptr frame) { // TODO(egarciad): Implement hybrid composition. // https://github.com/flutter/flutter/issues/55270 TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::SubmitFrame"); for (size_t i = 0; i < composition_order_.size(); i++) { int64_t view_id = composition_order_[i]; - background_canvas->drawPicture( + frame->SkiaCanvas()->drawPicture( picture_recorders_[view_id]->finishRecordingAsPicture()); } - return true; + return frame->Submit(); } // |ExternalViewEmbedder| @@ -83,11 +84,6 @@ void AndroidExternalViewEmbedder::CancelFrame() { ClearFrame(); } -// |ExternalViewEmbedder| -void AndroidExternalViewEmbedder::FinishFrame() { - ClearFrame(); -} - // |ExternalViewEmbedder| void AndroidExternalViewEmbedder::EndFrame( fml::RefPtr raster_thread_merger) {} 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 75bbf55af894a..c01c4bae7bfe4 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -25,7 +25,8 @@ class AndroidExternalViewEmbedder : public ExternalViewEmbedder { std::vector GetCurrentCanvases() override; // |ExternalViewEmbedder| - bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override; + bool SubmitFrame(GrContext* context, + std::unique_ptr frame) override; // |ExternalViewEmbedder| PostPrerollResult PostPrerollAction( @@ -42,9 +43,6 @@ class AndroidExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| void CancelFrame() override; - // |ExternalViewEmbedder| - void FinishFrame() override; - // |ExternalViewEmbedder| void EndFrame( fml::RefPtr raster_thread_merger) override; 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 e9717f515e115..856c6e0e4893b 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 @@ -37,17 +37,6 @@ TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { ASSERT_TRUE(embedder->CompositeEmbeddedView(1) != nullptr); } -TEST(AndroidExternalViewEmbedder, FinishFrame) { - auto embedder = new AndroidExternalViewEmbedder(); - - embedder->PrerollCompositeEmbeddedView( - 0, std::make_unique()); - embedder->FinishFrame(); - - auto canvases = embedder->GetCurrentCanvases(); - ASSERT_EQ(0UL, canvases.size()); -} - TEST(AndroidExternalViewEmbedder, CancelFrame) { auto embedder = new AndroidExternalViewEmbedder(); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index d88f366e0113d..f590701e7e2cb 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -470,7 +470,7 @@ bool FlutterPlatformViewsController::SubmitFrame(GrContext* gr_context, std::shared_ptr ios_context, - SkCanvas* background_canvas) { + std::unique_ptr frame) { if (merge_threads_) { // Threads are about to be merged, we drop everything from this frame // and possibly resubmit the same layer tree in the next frame. @@ -488,6 +488,8 @@ DisposeViews(); + SkCanvas* background_canvas = frame->SkiaCanvas(); + // Resolve all pending GPU operations before allocating a new surface. background_canvas->flush(); // Clipping the background canvas before drawing the picture recorders requires to @@ -569,6 +571,8 @@ // Reset the composition order, so next frame starts empty. composition_order_.clear(); + did_submit &= frame->Submit(); + return did_submit; } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 822d6402d8388..b005af397e26a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -163,7 +163,7 @@ class FlutterPlatformViewsController { bool SubmitFrame(GrContext* gr_context, std::shared_ptr ios_context, - SkCanvas* background_canvas); + std::unique_ptr frame); // Invoked at the very end of a frame. // After invoking this method, nothing should happen on the current TaskRunner during the same diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index eae39031d77ce..ac4ab2af1f2c1 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -78,10 +78,7 @@ class IOSSurface : public ExternalViewEmbedder { SkCanvas* CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| - bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override; - - // |ExternalViewEmbedder| - void FinishFrame() override; + bool SubmitFrame(GrContext* context, std::unique_ptr frame) override; // |ExternalViewEmbedder| void EndFrame(fml::RefPtr raster_thread_merger) override; diff --git a/shell/platform/darwin/ios/ios_surface.mm b/shell/platform/darwin/ios/ios_surface.mm index bb630c3d9be44..36598c1b96a2b 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -132,11 +132,16 @@ bool IsIosEmbeddedViewsPreviewEnabled() { } // |ExternalViewEmbedder| -bool IOSSurface::SubmitFrame(GrContext* context, SkCanvas* background_canvas) { +bool IOSSurface::SubmitFrame(GrContext* context, std::unique_ptr frame) { TRACE_EVENT0("flutter", "IOSSurface::SubmitFrame"); FML_CHECK(platform_views_controller_ != nullptr); bool submitted = - platform_views_controller_->SubmitFrame(std::move(context), ios_context_, background_canvas); + platform_views_controller_->SubmitFrame(std::move(context), ios_context_, std::move(frame)); + + if (submitted) { + TRACE_EVENT0("flutter", "IOSSurface::DidSubmitFrame"); + [CATransaction commit]; + } return submitted; } @@ -147,9 +152,4 @@ bool IsIosEmbeddedViewsPreviewEnabled() { return platform_views_controller_->EndFrame(raster_thread_merger); } -// |ExternalViewEmbedder| -void IOSSurface::FinishFrame() { - TRACE_EVENT0("flutter", "IOSSurface::DidSubmitFrame"); - [CATransaction commit]; -} } // namespace flutter diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index a2e08644047a7..752efec53998c 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -129,8 +129,9 @@ static FlutterBackingStoreConfig MakeBackingStoreConfig( } // |ExternalViewEmbedder| -bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context, - SkCanvas* background_canvas) { +bool EmbedderExternalViewEmbedder::SubmitFrame( + GrContext* context, + std::unique_ptr frame) { auto [matched_render_targets, pending_keys] = render_target_cache_.GetExistingTargetsInCache(pending_views_); @@ -263,10 +264,7 @@ bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context, std::move(render_target.second)); } - return true; + return frame->Submit(); } -// |ExternalViewEmbedder| -void EmbedderExternalViewEmbedder::FinishFrame() {} - } // namespace flutter diff --git a/shell/platform/embedder/embedder_external_view_embedder.h b/shell/platform/embedder/embedder_external_view_embedder.h index 63c944a88d7ef..c78e39fd75415 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.h +++ b/shell/platform/embedder/embedder_external_view_embedder.h @@ -89,10 +89,8 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { SkCanvas* CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| - bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override; - - // |ExternalViewEmbedder| - void FinishFrame() override; + bool SubmitFrame(GrContext* context, + std::unique_ptr frame) override; // |ExternalViewEmbedder| SkCanvas* GetRootCanvas() override;