diff --git a/flow/embedded_views.h b/flow/embedded_views.h index c1213a2e5b3d94e9f7cbac20560c9f050f9966e8..62ec08ad4094fe5e1bfcdb6297b7fb81c67d3b8d 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -16,7 +16,6 @@ class EmbeddedViewParams { public: SkPoint offsetPixels; SkSize sizePoints; - SkISize canvasBaseLayerSize; }; // This is only used on iOS when running in a non headless mode, @@ -26,6 +25,12 @@ class ExternalViewEmbedder { public: ExternalViewEmbedder() = default; + virtual void SetFrameSize(SkISize frame_size) = 0; + + virtual void PrerollCompositeEmbeddedView(int view_id) = 0; + + virtual std::vector GetCurrentCanvases() = 0; + // Must be called on the UI thread. virtual SkCanvas* CompositeEmbeddedView(int view_id, const EmbeddedViewParams& params) = 0; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 97177e9585bd2d3861d2730c27b7ae75060179ad..724c89edfba5f17d0f62aa4db4d17551947eaa80 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -25,6 +25,7 @@ #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/include/utils/SkNWayCanvas.h" #if defined(OS_FUCHSIA) @@ -44,6 +45,7 @@ class ContainerLayer; struct PrerollContext { RasterCache* raster_cache; GrContext* gr_context; + ExternalViewEmbedder* view_embedder; SkColorSpace* dst_color_space; SkRect child_paint_bounds; @@ -64,6 +66,21 @@ class Layer { virtual void Preroll(PrerollContext* context, const SkMatrix& matrix); struct PaintContext { + // When splitting the scene into multiple canvases (e.g when embedding + // a platform view on iOS) during the paint traversal we apply the non leaf + // flow layers to all canvases, and leaf layers just to the "current" + // canvas. Applying the non leaf layers to all canvases ensures that when + // we switch a canvas (when painting a PlatformViewLayer) the next canvas + // has the exact same state as the current canvas. + // The internal_nodes_canvas is a SkNWayCanvas which is used by non leaf + // and applies the operations to all canvases. + // The leaf_nodes_canvas is the "current" canvas and is used by leaf + // layers. + SkCanvas* internal_nodes_canvas; + // I'm temporarily leaving the name of this field to be canvas to reduce + // noise in the incremental change. A followup change will rename this + // and use the corrrect canvas in each callsite. + // TODO(amirh) rename canvas to leaf_nodes_canvas. SkCanvas* canvas; ExternalViewEmbedder* view_embedder; const Stopwatch& frame_time; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 2968da8c3374777c51885ad44124c163a76370a3..19df3d27c1286c7ddc251fa345309033f14a9791 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -7,6 +7,7 @@ #include "flutter/flow/layers/layer.h" #include "flutter/fml/trace_event.h" #include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/utils/SkNWayCanvas.h" namespace flow { @@ -28,6 +29,7 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, PrerollContext context = { ignore_raster_cache ? nullptr : &frame.context().raster_cache(), frame.gr_context(), + frame.view_embedder(), color_space, SkRect::MakeEmpty(), frame.context().frame_time(), @@ -66,7 +68,18 @@ void LayerTree::UpdateScene(SceneUpdateContext& context, void LayerTree::Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache) const { TRACE_EVENT0("flutter", "LayerTree::Paint"); + SkISize canvas_size = frame.canvas()->getBaseLayerSize(); + SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); + internal_nodes_canvas.addCanvas(frame.canvas()); + if (frame.view_embedder() != nullptr) { + auto overlay_canvases = frame.view_embedder()->GetCurrentCanvases(); + for (size_t i = 0; i < overlay_canvases.size(); i++) { + internal_nodes_canvas.addCanvas(overlay_canvases[i]); + } + } + Layer::PaintContext context = { + (SkCanvas*)&internal_nodes_canvas, frame.canvas(), frame.view_embedder(), frame.context().frame_time(), @@ -98,6 +111,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { PrerollContext preroll_context{ nullptr, // raster_cache (don't consult the cache) nullptr, // gr_context (used for the raster cache) + nullptr, // external view embedder nullptr, // SkColorSpace* dst_color_space SkRect::MakeEmpty(), // SkRect child_paint_bounds unused_stopwatch, // frame time (dont care) @@ -106,7 +120,12 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { false, // checkerboard_offscreen_layers }; + SkISize canvas_size = canvas->getBaseLayerSize(); + SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); + internal_nodes_canvas.addCanvas(canvas); + Layer::PaintContext paint_context = { + (SkCanvas*)&internal_nodes_canvas, canvas, // canvas nullptr, unused_stopwatch, // frame time (dont care) diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index 75153ab472a7867521b8ded43589e1c21bc4e838..a53e4c7321a7c431d477381039087b3fd00f1e90 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -14,6 +14,13 @@ void PlatformViewLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(), size_.height())); + + if (context->view_embedder == nullptr) { + FML_LOG(ERROR) << "Trying to embed a platform view but the PrerollContext " + "does not support embedding"; + return; + } + context->view_embedder->PrerollCompositeEmbeddedView(view_id_); } void PlatformViewLayer::Paint(PaintContext& context) const { @@ -27,12 +34,9 @@ void PlatformViewLayer::Paint(PaintContext& context) const { params.offsetPixels = SkPoint::Make(transform.getTranslateX(), transform.getTranslateY()); params.sizePoints = size_; - params.canvasBaseLayerSize = context.canvas->getBaseLayerSize(); SkCanvas* canvas = context.view_embedder->CompositeEmbeddedView(view_id_, params); - // TODO(amirh): copy the full canvas state here - canvas->concat(context.canvas->getTotalMatrix()); context.canvas = canvas; } } // namespace flow diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index d4f93063f07ef48504adf2fa8ccb7e4b90d43364..410204bed34c32cdbd7e48fd30fb4f9a88c43e7a 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -36,8 +36,8 @@ void TransformLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "TransformLayer::Paint"); FML_DCHECK(needs_painting()); - SkAutoCanvasRestore save(context.canvas, true); - context.canvas->concat(transform_); + SkAutoCanvasRestore save(context.internal_nodes_canvas, true); + context.internal_nodes_canvas->concat(transform_); PaintChildren(context); } diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index c2e43bda0e43459401c8db913ce16d66f12c9ea6..4de4e1e89a8a43e4eb43c270b7ca2f6913300a36 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -156,7 +156,12 @@ void RasterCache::Prepare(PrerollContext* context, entry.image = Rasterize(context->gr_context, ctm, context->dst_color_space, checkerboard_images_, layer->paint_bounds(), [layer, context](SkCanvas* canvas) { + SkISize canvas_size = canvas->getBaseLayerSize(); + SkNWayCanvas internal_nodes_canvas( + canvas_size.width(), canvas_size.height()); + internal_nodes_canvas.addCanvas(canvas); Layer::PaintContext paintContext = { + (SkCanvas*)&internal_nodes_canvas, canvas, nullptr, context->frame_time, diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc index 0404c849d6852443d0d2a89fa9aa46afe69b7cad..89a474bcdff1b29060a6a93507096c8ad44e1853 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -188,6 +188,7 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) { FML_DCHECK(task.surface); SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas(); Layer::PaintContext context = {canvas, + canvas, nullptr, frame.context().frame_time(), frame.context().engine_time(), diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index f69a268861952b99a7b11d1591c9f46e1436f94d..9684b4dcd9da547a9d59a26710febe17f550be45 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -164,6 +164,11 @@ bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) { auto external_view_embedder = surface_->GetExternalViewEmbedder(); + // TODO(amirh): uncomment this once external_view_embedder is populated. + // if (external_view_embedder != nullptr) { + // external_view_embedder->SetFrameSize(layer_tree.frame_size()); + // } + auto compositor_frame = compositor_context_->AcquireFrame( surface_->GetContext(), canvas, external_view_embedder, surface_->GetRootTransformation(), true); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 73a2779bb67572019b869361bf1d9e76e214b6bd..f9fbd6f2992d2e88f7546a46bd6d12bbd5e26739 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -128,6 +128,25 @@ void FlutterPlatformViewsController::RegisterViewFactory( fml::scoped_nsobject>([factory retain]); } +void FlutterPlatformViewsController::SetFrameSize(SkISize frame_size) { + frame_size_ = frame_size; +} + +void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(int view_id) { + EnsureOverlayInitialized(view_id); + composition_frames_[view_id] = (overlays_[view_id]->surface->AcquireFrame(frame_size_)); + composition_order_.push_back(view_id); +} + +std::vector FlutterPlatformViewsController::GetCurrentCanvases() { + std::vector canvases; + for (size_t i = 0; i < composition_order_.size(); i++) { + int64_t view_id = composition_order_[i]; + canvases.push_back(composition_frames_[view_id]->SkiaCanvas()); + } + return canvases; +} + SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView( int view_id, const flow::EmbeddedViewParams& params, @@ -135,7 +154,6 @@ SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView( // TODO(amirh): assert that this is running on the platform thread once we support the iOS // embedded views thread configuration. // TODO(amirh): do nothing if the params didn't change. - EnsureOverlayInitialized(view_id); CGFloat screenScale = [[UIScreen mainScreen] scale]; CGRect rect = CGRectMake(params.offsetPixels.x() / screenScale, params.offsetPixels.y() / screenScale, @@ -143,19 +161,17 @@ SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView( UIView* view = views_[view_id].get(); [view setFrame:rect]; - composition_order_.push_back(view_id); - composition_frames_.push_back( - overlays_[view_id]->surface->AcquireFrame(params.canvasBaseLayerSize)); - SkCanvas* canvas = composition_frames_.back()->SkiaCanvas(); + SkCanvas* canvas = composition_frames_[view_id]->SkiaCanvas(); canvas->clear(SK_ColorTRANSPARENT); return canvas; } bool FlutterPlatformViewsController::Present() { bool did_submit = true; - for (size_t i = 0; i < composition_frames_.size(); i++) { - did_submit &= composition_frames_[i]->Submit(); + for (size_t i = 0; i < composition_order_.size(); i++) { + int64_t view_id = composition_order_[i]; + did_submit &= composition_frames_[view_id]->Submit(); } composition_frames_.clear(); if (composition_order_ == active_composition_order_) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 709782c9987ca14f8001a3f310bb1d2f7d6893a4..db15c713bbe7768fb8717cfd03e7950dc280a04a 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -49,6 +49,12 @@ class FlutterPlatformViewsController { void RegisterViewFactory(NSObject* factory, NSString* factoryId); + void SetFrameSize(SkISize frame_size); + + void PrerollCompositeEmbeddedView(int view_id); + + std::vector GetCurrentCanvases(); + SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params, IOSSurface& surface); @@ -63,6 +69,7 @@ class FlutterPlatformViewsController { std::map>> factories_; std::map> views_; std::map> overlays_; + SkISize frame_size_; // A vector of embedded view IDs according to their composition order. // The last ID in this vector belond to the that is composited on top of all others. @@ -71,7 +78,7 @@ class FlutterPlatformViewsController { // The latest composition order that was presented in Present(). std::vector active_composition_order_; - std::vector> composition_frames_; + std::map> composition_frames_; void OnCreate(FlutterMethodCall* call, FlutterResult& result); void OnDispose(FlutterMethodCall* call, FlutterResult& result); diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index abc4f32aa509fa12e3e107dad1f5251e1f50b02b..066e5fdcaf6ce35d3ea64449374b7cf158d06af2 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -45,6 +45,15 @@ class IOSSurfaceGL : public IOSSurface, // |shell::GPUSurfaceGLDelegate| flow::ExternalViewEmbedder* GetExternalViewEmbedder() override; + // |flow::ExternalViewEmbedder| + void SetFrameSize(SkISize frame_size) override; + + // |flow::ExternalViewEmbedder| + void PrerollCompositeEmbeddedView(int view_id) override; + + // |flow::ExternalViewEmbedder| + std::vector GetCurrentCanvases() override; + // |flow::ExternalViewEmbedder| SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index c32d593210349dae1902e27d0805278f8566c244..6f0d7648051af44feb0f88d786e9683f8ff92fdb 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -74,6 +74,24 @@ flow::ExternalViewEmbedder* IOSSurfaceGL::GetExternalViewEmbedder() { } } +void IOSSurfaceGL::SetFrameSize(SkISize frame_size) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + platform_views_controller->SetFrameSize(frame_size); +} + +void IOSSurfaceGL::PrerollCompositeEmbeddedView(int view_id) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + platform_views_controller->PrerollCompositeEmbeddedView(view_id); +} + +std::vector IOSSurfaceGL::GetCurrentCanvases() { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + return platform_views_controller->GetCurrentCanvases(); +} + SkCanvas* IOSSurfaceGL::CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) { FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); FML_CHECK(platform_views_controller != nullptr); diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index 0e7fb305a7a7da7dac3ac9bf41e3c1e8f914f113..068d9f132257a2ca5d1ff0776340f938b45d0cfc 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -45,6 +45,15 @@ class IOSSurfaceSoftware final : public IOSSurface, // |shell::GPUSurfaceSoftwareDelegate| flow::ExternalViewEmbedder* GetExternalViewEmbedder() override; + // |flow::ExternalViewEmbedder| + void SetFrameSize(SkISize frame_size) override; + + // |flow::ExternalViewEmbedder| + void PrerollCompositeEmbeddedView(int view_id) override; + + // |flow::ExternalViewEmbedder| + std::vector GetCurrentCanvases() override; + // |flow::ExternalViewEmbedder| SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override; diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index 634c72749d52a9d9f83c0ea3d7305cad35a53e83..a5ca5357372d9e1c7b8187a9cab9b0dd899ee427 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -138,6 +138,24 @@ flow::ExternalViewEmbedder* IOSSurfaceSoftware::GetExternalViewEmbedder() { } } +void IOSSurfaceSoftware::SetFrameSize(SkISize frame_size) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + platform_views_controller->SetFrameSize(frame_size); +} + +void IOSSurfaceSoftware::PrerollCompositeEmbeddedView(int view_id) { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + platform_views_controller->PrerollCompositeEmbeddedView(view_id); +} + +std::vector IOSSurfaceSoftware::GetCurrentCanvases() { + FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController(); + FML_CHECK(platform_views_controller != nullptr); + return platform_views_controller->GetCurrentCanvases(); +} + SkCanvas* IOSSurfaceSoftware::CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) { FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();