From eaae8a67bc5dc2357bbabf2a01b9d77200340dd0 Mon Sep 17 00:00:00 2001 From: liyuqian Date: Mon, 4 Feb 2019 13:31:10 -0800 Subject: [PATCH] Retained rendering in Fuchsia PhysicalShapeLayer (#6558) For flutter/flutter#23535 When this lands/rolls into Fuchsia, a manual roll with https://fuchsia-review.googlesource.com/c/topaz/+/241557 is needed. --- flow/layers/physical_shape_layer.cc | 16 ++++++- flow/scene_update_context.cc | 61 ++++++++++++++---------- flow/scene_update_context.h | 73 ++++++++++++++++++++++++----- 3 files changed, 113 insertions(+), 37 deletions(-) diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index fc1568028..841ae4cf6 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -66,7 +66,21 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context, void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) { FML_DCHECK(needs_system_composite()); - SceneUpdateContext::Frame frame(context, frameRRect_, color_, elevation_); + // Retained rendering: speedup by reusing a retained entity node if possible. + // When an entity node is reused, no paint layer is added to the frame so we + // won't call PhysicalShapeLayer::Paint. + LayerRasterCacheKey key(this, context.Matrix()); + if (context.HasRetainedNode(key)) { + const scenic::EntityNode& retained_node = context.GetRetainedNode(key); + FML_DCHECK(context.top_entity()); + FML_DCHECK(retained_node.session() == context.session()); + context.top_entity()->entity_node().AddChild(retained_node); + return; + } + + // If we can't find an existing retained surface, create one. + SceneUpdateContext::Frame frame(context, frameRRect_, color_, elevation_, + this); for (auto& layer : layers()) { if (layer->needs_painting()) { frame.AddPaintLayer(layer.get()); diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc index e5e4bac42..bebe2ef67 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -40,13 +40,15 @@ void SceneUpdateContext::RemoveExportNode(ExportNode* export_node) { export_nodes_.erase(export_node); } -void SceneUpdateContext::CreateFrame(scenic::EntityNode& entity_node, - const SkRRect& rrect, - SkColor color, - const SkRect& paint_bounds, - std::vector paint_layers) { +void SceneUpdateContext::CreateFrame( + std::unique_ptr entity_node, + const SkRRect& rrect, + SkColor color, + const SkRect& paint_bounds, + std::vector paint_layers, + Layer* layer) { // Frames always clip their children. - entity_node.SetClip(0u, true /* clip to self */); + entity_node->SetClip(0u, true /* clip to self */); // We don't need a shape if the frame is zero size. if (rrect.isEmpty()) @@ -70,7 +72,7 @@ void SceneUpdateContext::CreateFrame(scenic::EntityNode& entity_node, shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(), shape_bounds.height() * 0.5f + shape_bounds.top(), 0.f); - entity_node.AddPart(shape_node); + entity_node->AddPart(shape_node); // Check whether the painted layers will be visible. if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds)) @@ -83,8 +85,8 @@ void SceneUpdateContext::CreateFrame(scenic::EntityNode& entity_node, } // Apply current metrics and transformation scale factors. - const float scale_x = metrics_->scale_x * top_scale_x_; - const float scale_y = metrics_->scale_y * top_scale_y_; + const float scale_x = ScaleX(); + const float scale_y = ScaleY(); // If the painted area only covers a portion of the frame then we can // reduce the texture size by drawing just that smaller area. @@ -100,15 +102,17 @@ void SceneUpdateContext::CreateFrame(scenic::EntityNode& entity_node, inner_node.SetTranslation(inner_bounds.width() * 0.5f + inner_bounds.left(), inner_bounds.height() * 0.5f + inner_bounds.top(), 0.f); - entity_node.AddPart(inner_node); + entity_node->AddPart(inner_node); SetShapeTextureOrColor(inner_node, color, scale_x, scale_y, inner_bounds, - std::move(paint_layers)); + std::move(paint_layers), layer, + std::move(entity_node)); return; } // Apply a texture to the whole shape. SetShapeTextureOrColor(shape_node, color, scale_x, scale_y, shape_bounds, - std::move(paint_layers)); + std::move(paint_layers), layer, + std::move(entity_node)); } void SceneUpdateContext::SetShapeTextureOrColor( @@ -117,9 +121,12 @@ void SceneUpdateContext::SetShapeTextureOrColor( SkScalar scale_x, SkScalar scale_y, const SkRect& paint_bounds, - std::vector paint_layers) { + std::vector paint_layers, + Layer* layer, + std::unique_ptr entity_node) { scenic::Image* image = GenerateImageIfNeeded( - color, scale_x, scale_y, paint_bounds, std::move(paint_layers)); + color, scale_x, scale_y, paint_bounds, std::move(paint_layers), layer, + std::move(entity_node)); if (image != nullptr) { scenic::Material material(session_); material.SetTexture(*image); @@ -146,7 +153,9 @@ scenic::Image* SceneUpdateContext::GenerateImageIfNeeded( SkScalar scale_x, SkScalar scale_y, const SkRect& paint_bounds, - std::vector paint_layers) { + std::vector paint_layers, + Layer* layer, + std::unique_ptr entity_node) { // Bail if there's nothing to paint. if (paint_layers.empty()) return nullptr; @@ -158,7 +167,10 @@ scenic::Image* SceneUpdateContext::GenerateImageIfNeeded( return nullptr; // Acquire a surface from the surface producer and register the paint tasks. - auto surface = surface_producer_->ProduceSurface(physical_size); + std::unique_ptr surface = + surface_producer_->ProduceSurface(physical_size, + LayerRasterCacheKey(layer, Matrix()), + std::move(entity_node)); if (!surface) { FML_LOG(ERROR) << "Could not acquire a surface from the surface producer " @@ -210,11 +222,10 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) { } SceneUpdateContext::Entity::Entity(SceneUpdateContext& context) - : context_(context), - previous_entity_(context.top_entity_), - entity_node_(context.session()) { + : context_(context), previous_entity_(context.top_entity_) { + entity_node_ptr_ = std::make_unique(context.session()); if (previous_entity_) - previous_entity_->entity_node_.AddChild(entity_node_); + previous_entity_->entity_node_ptr_->AddChild(*entity_node_ptr_); context.top_entity_ = this; } @@ -292,18 +303,20 @@ SceneUpdateContext::Transform::~Transform() { SceneUpdateContext::Frame::Frame(SceneUpdateContext& context, const SkRRect& rrect, SkColor color, - float elevation) + float elevation, + Layer* layer) : Entity(context), rrect_(rrect), color_(color), - paint_bounds_(SkRect::MakeEmpty()) { + paint_bounds_(SkRect::MakeEmpty()), + layer_(layer) { if (elevation != 0.0) entity_node().SetTranslation(0.f, 0.f, elevation); } SceneUpdateContext::Frame::~Frame() { - context().CreateFrame(entity_node(), rrect_, color_, paint_bounds_, - std::move(paint_layers_)); + context().CreateFrame(std::move(entity_node_ptr()), rrect_, color_, + paint_bounds_, std::move(paint_layers_), layer_); } void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) { diff --git a/flow/scene_update_context.h b/flow/scene_update_context.h index 22e39e63a..378af4211 100644 --- a/flow/scene_update_context.h +++ b/flow/scene_update_context.h @@ -10,6 +10,7 @@ #include #include "flutter/flow/compositor_context.h" +#include "flutter/flow/raster_cache_key.h" #include "flutter/fml/build_config.h" #include "flutter/fml/compiler_specific.h" #include "flutter/fml/logging.h" @@ -50,8 +51,19 @@ class SceneUpdateContext { public: virtual ~SurfaceProducer() = default; + // The produced surface owns the entity_node and has a layer_key for + // retained rendering. The surface will only be retained if the layer_key + // has a non-null layer pointer (layer_key.id()). virtual std::unique_ptr ProduceSurface( - const SkISize& size) = 0; + const SkISize& size, + const LayerRasterCacheKey& layer_key, + std::unique_ptr entity_node) = 0; + + // Query a retained entity node (owned by a retained surface) for retained + // rendering. + virtual bool HasRetainedNode(const LayerRasterCacheKey& key) const = 0; + virtual const scenic::EntityNode& GetRetainedNode( + const LayerRasterCacheKey& key) = 0; virtual void SubmitSurface( std::unique_ptr surface) = 0; @@ -63,13 +75,16 @@ class SceneUpdateContext { ~Entity(); SceneUpdateContext& context() { return context_; } - scenic::EntityNode& entity_node() { return entity_node_; } + scenic::EntityNode& entity_node() { return *entity_node_ptr_; } + std::unique_ptr& entity_node_ptr() { + return entity_node_ptr_; + } private: SceneUpdateContext& context_; Entity* const previous_entity_; - scenic::EntityNode entity_node_; + std::unique_ptr entity_node_ptr_; }; class Clip : public Entity { @@ -96,10 +111,15 @@ class SceneUpdateContext { class Frame : public Entity { public: + // When layer is not nullptr, the frame is associated with a layer subtree + // rooted with that layer. The frame may then create a surface that will be + // retained for that layer. Frame(SceneUpdateContext& context, const SkRRect& rrect, SkColor color, - float elevation); + float elevation, + Layer* layer = nullptr); + ~Frame(); void AddPaintLayer(Layer* layer); @@ -110,6 +130,7 @@ class SceneUpdateContext { std::vector paint_layers_; SkRect paint_bounds_; + Layer* layer_; }; SceneUpdateContext(scenic::Session* session, @@ -119,6 +140,8 @@ class SceneUpdateContext { scenic::Session* session() { return session_; } + Entity* top_entity() { return top_entity_; } + bool has_metrics() const { return !!metrics_; } void set_metrics(fuchsia::ui::gfx::MetricsPtr metrics) { metrics_ = std::move(metrics); @@ -147,6 +170,20 @@ class SceneUpdateContext { std::vector> ExecutePaintTasks( CompositorContext::ScopedFrame& frame); + float ScaleX() const { return metrics_->scale_x * top_scale_x_; } + float ScaleY() const { return metrics_->scale_y * top_scale_y_; } + + // The transformation matrix of the current context. It's used to construct + // the LayerRasterCacheKey for a given layer. + SkMatrix Matrix() const { return SkMatrix::MakeScale(ScaleX(), ScaleY()); } + + bool HasRetainedNode(const LayerRasterCacheKey& key) const { + return surface_producer_->HasRetainedNode(key); + } + const scenic::EntityNode& GetRetainedNode(const LayerRasterCacheKey& key) { + return surface_producer_->GetRetainedNode(key); + } + private: struct PaintTask { std::unique_ptr surface; @@ -158,23 +195,35 @@ class SceneUpdateContext { std::vector layers; }; - void CreateFrame(scenic::EntityNode& entity_node, + // Setup the entity_node as a frame that materialize all the paint_layers. In + // most cases, this creates a VulkanSurface (SurfaceProducerSurface) by + // calling SetShapeTextureOrColor and GenerageImageIfNeeded. Such surface will + // own the associated entity_node. If the layer pointer isn't nullptr, the + // surface (and thus the entity_node) will be retained for that layer to + // improve the performance. + void CreateFrame(std::unique_ptr entity_node, const SkRRect& rrect, SkColor color, const SkRect& paint_bounds, - std::vector paint_layers); + std::vector paint_layers, + Layer* layer); void SetShapeTextureOrColor(scenic::ShapeNode& shape_node, SkColor color, SkScalar scale_x, SkScalar scale_y, const SkRect& paint_bounds, - std::vector paint_layers); + std::vector paint_layers, + Layer* layer, + std::unique_ptr entity_node); void SetShapeColor(scenic::ShapeNode& shape_node, SkColor color); - scenic::Image* GenerateImageIfNeeded(SkColor color, - SkScalar scale_x, - SkScalar scale_y, - const SkRect& paint_bounds, - std::vector paint_layers); + scenic::Image* GenerateImageIfNeeded( + SkColor color, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers, + Layer* layer, + std::unique_ptr entity_node); Entity* top_entity_ = nullptr; float top_scale_x_ = 1.f;