From 04274160e60cafc4b5c843d7968fce241d50f03d Mon Sep 17 00:00:00 2001 From: David Worsham Date: Thu, 16 Jan 2020 15:28:48 -0800 Subject: [PATCH] Fix Opacity performance regression on Fuchsia (#15573) * Add more profile markers * Revert FuchsiaSystemCompistedLayer changes * Re-add opacity w/o elevation changes * Fix formatting --- ci/licenses_golden/licenses_flutter | 4 - flow/BUILD.gn | 4 - flow/layers/child_scene_layer.cc | 2 + flow/layers/clip_path_layer.cc | 9 +- flow/layers/clip_rect_layer.cc | 9 +- flow/layers/clip_rrect_layer.cc | 9 +- flow/layers/elevated_container_layer.cc | 49 ------- flow/layers/elevated_container_layer.h | 34 ----- .../layers/fuchsia_system_composited_layer.cc | 55 ------- flow/layers/fuchsia_system_composited_layer.h | 37 ----- flow/layers/layer_tree.cc | 2 +- flow/layers/layer_tree.h | 1 + flow/layers/opacity_layer.cc | 106 ++++++++------ flow/layers/opacity_layer.h | 40 ++--- flow/layers/physical_shape_layer.cc | 48 +++--- flow/layers/physical_shape_layer.h | 41 ++---- flow/layers/picture_layer.cc | 5 + flow/layers/texture_layer.cc | 5 + flow/layers/transform_layer.cc | 3 + flow/scene_update_context.cc | 138 ++++++++++-------- flow/scene_update_context.h | 54 +++---- 21 files changed, 254 insertions(+), 401 deletions(-) delete mode 100644 flow/layers/elevated_container_layer.cc delete mode 100644 flow/layers/elevated_container_layer.h delete mode 100644 flow/layers/fuchsia_system_composited_layer.cc delete mode 100644 flow/layers/fuchsia_system_composited_layer.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ca89f381bd203..b6d7374267808 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -48,10 +48,6 @@ FILE: ../../../flutter/flow/layers/color_filter_layer_unittests.cc FILE: ../../../flutter/flow/layers/container_layer.cc FILE: ../../../flutter/flow/layers/container_layer.h FILE: ../../../flutter/flow/layers/container_layer_unittests.cc -FILE: ../../../flutter/flow/layers/elevated_container_layer.cc -FILE: ../../../flutter/flow/layers/elevated_container_layer.h -FILE: ../../../flutter/flow/layers/fuchsia_system_composited_layer.cc -FILE: ../../../flutter/flow/layers/fuchsia_system_composited_layer.h FILE: ../../../flutter/flow/layers/image_filter_layer.cc FILE: ../../../flutter/flow/layers/image_filter_layer.h FILE: ../../../flutter/flow/layers/image_filter_layer_unittests.cc diff --git a/flow/BUILD.gn b/flow/BUILD.gn index dad0635fa760a..9fde3ec1da84c 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -28,8 +28,6 @@ source_set("flow") { "layers/color_filter_layer.h", "layers/container_layer.cc", "layers/container_layer.h", - "layers/elevated_container_layer.cc", - "layers/elevated_container_layer.h", "layers/image_filter_layer.cc", "layers/image_filter_layer.h", "layers/layer.cc", @@ -80,8 +78,6 @@ source_set("flow") { sources += [ "layers/child_scene_layer.cc", "layers/child_scene_layer.h", - "layers/fuchsia_system_composited_layer.cc", - "layers/fuchsia_system_composited_layer.h", "scene_update_context.cc", "scene_update_context.h", "view_holder.cc", diff --git a/flow/layers/child_scene_layer.cc b/flow/layers/child_scene_layer.cc index 10b5a277db575..4a5358053928f 100644 --- a/flow/layers/child_scene_layer.cc +++ b/flow/layers/child_scene_layer.cc @@ -31,6 +31,7 @@ void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { void ChildSceneLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ChildSceneLayer::Paint"); FML_DCHECK(needs_painting()); + FML_DCHECK(needs_system_composite()); // If we are being rendered into our own frame using the system compositor, // then it is neccesary to "punch a hole" in the canvas/frame behind us so @@ -42,6 +43,7 @@ void ChildSceneLayer::Paint(PaintContext& context) const { } void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) { + TRACE_EVENT0("flutter", "ChildSceneLayer::UpdateScene"); FML_DCHECK(needs_system_composite()); auto* view_holder = ViewHolder::FromId(layer_id_); diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 3d420657bf079..b85b48fb082b6 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -18,10 +18,14 @@ ClipPathLayer::ClipPathLayer(const SkPath& clip_path, Clip clip_behavior) } void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "ClipPathLayer::Preroll"); + SkRect previous_cull_rect = context->cull_rect; SkRect clip_path_bounds = clip_path_.getBounds(); children_inside_clip_ = context->cull_rect.intersect(clip_path_bounds); if (children_inside_clip_) { + TRACE_EVENT_INSTANT0("flutter", "children inside clip rect"); + Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer()); context->mutators_stack.PushClipPath(clip_path_); @@ -39,6 +43,7 @@ void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { #if defined(OS_FUCHSIA) void ClipPathLayer::UpdateScene(SceneUpdateContext& context) { + TRACE_EVENT0("flutter", "ClipPathLayer::UpdateScene"); FML_DCHECK(needs_system_composite()); // TODO(liyuqian): respect clip_behavior_ @@ -52,8 +57,10 @@ void ClipPathLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ClipPathLayer::Paint"); FML_DCHECK(needs_painting()); - if (!children_inside_clip_) + if (!children_inside_clip_) { + TRACE_EVENT_INSTANT0("flutter", "children not inside clip rect, skipping"); return; + } SkAutoCanvasRestore save(context.internal_nodes_canvas, true); context.internal_nodes_canvas->clipPath(clip_path_, diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index af6c490f27a7d..cc58e721c7f75 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -12,9 +12,13 @@ ClipRectLayer::ClipRectLayer(const SkRect& clip_rect, Clip clip_behavior) } void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "ClipRectLayer::Preroll"); + SkRect previous_cull_rect = context->cull_rect; children_inside_clip_ = context->cull_rect.intersect(clip_rect_); if (children_inside_clip_) { + TRACE_EVENT_INSTANT0("flutter", "children inside clip rect"); + Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer()); context->mutators_stack.PushClipRect(clip_rect_); @@ -32,6 +36,7 @@ void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { #if defined(OS_FUCHSIA) void ClipRectLayer::UpdateScene(SceneUpdateContext& context) { + TRACE_EVENT0("flutter", "ClipRectLayer::UpdateScene"); FML_DCHECK(needs_system_composite()); // TODO(liyuqian): respect clip_behavior_ @@ -45,8 +50,10 @@ void ClipRectLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ClipRectLayer::Paint"); FML_DCHECK(needs_painting()); - if (!children_inside_clip_) + if (!children_inside_clip_) { + TRACE_EVENT_INSTANT0("flutter", "children not inside clip rect, skipping"); return; + } SkAutoCanvasRestore save(context.internal_nodes_canvas, true); context.internal_nodes_canvas->clipRect(clip_rect_, diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index d640b8b47171f..054379a4088bc 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -12,10 +12,14 @@ ClipRRectLayer::ClipRRectLayer(const SkRRect& clip_rrect, Clip clip_behavior) } void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "ClipRRectLayer::Preroll"); + SkRect previous_cull_rect = context->cull_rect; SkRect clip_rrect_bounds = clip_rrect_.getBounds(); children_inside_clip_ = context->cull_rect.intersect(clip_rrect_bounds); if (children_inside_clip_) { + TRACE_EVENT_INSTANT0("flutter", "children inside clip rect"); + Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer()); context->mutators_stack.PushClipRRect(clip_rrect_); @@ -33,6 +37,7 @@ void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { #if defined(OS_FUCHSIA) void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) { + TRACE_EVENT0("flutter", "ClipRRectLayer::UpdateScene"); FML_DCHECK(needs_system_composite()); // TODO(liyuqian): respect clip_behavior_ @@ -46,8 +51,10 @@ void ClipRRectLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ClipRRectLayer::Paint"); FML_DCHECK(needs_painting()); - if (!children_inside_clip_) + if (!children_inside_clip_) { + TRACE_EVENT_INSTANT0("flutter", "children not inside clip rect, skipping"); return; + } SkAutoCanvasRestore save(context.internal_nodes_canvas, true); context.internal_nodes_canvas->clipRRect(clip_rrect_, diff --git a/flow/layers/elevated_container_layer.cc b/flow/layers/elevated_container_layer.cc deleted file mode 100644 index cd68b06713992..0000000000000 --- a/flow/layers/elevated_container_layer.cc +++ /dev/null @@ -1,49 +0,0 @@ -// 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/flow/layers/elevated_container_layer.h" - -namespace flutter { -namespace { - -float ClampElevation(float elevation, - float parent_elevation, - float max_elevation) { - // TODO(mklim): Deal with bounds overflow more elegantly. We'd like to be - // able to have developers specify the behavior here to alternatives besides - // clamping, like normalization on some arbitrary curve. - float clamped_elevation = elevation; - if (max_elevation > -1 && (parent_elevation + elevation) > max_elevation) { - // Clamp the local z coordinate at our max bound. Take into account the - // parent z position here to fix clamping in cases where the child is - // overflowing because of its parents. - clamped_elevation = max_elevation - parent_elevation; - } - - return clamped_elevation; -} - -} // namespace - -ElevatedContainerLayer::ElevatedContainerLayer(float elevation) - : elevation_(elevation), clamped_elevation_(elevation) {} - -void ElevatedContainerLayer::Preroll(PrerollContext* context, - const SkMatrix& matrix) { - TRACE_EVENT0("flutter", "ElevatedContainerLayer::Preroll"); - - // Track total elevation as we walk the tree, in order to deal with bounds - // overflow in z. - parent_elevation_ = context->total_elevation; - clamped_elevation_ = ClampElevation(elevation_, parent_elevation_, - context->frame_physical_depth); - context->total_elevation += clamped_elevation_; - - ContainerLayer::Preroll(context, matrix); - - // Restore the elevation for our parent. - context->total_elevation = parent_elevation_; -} - -} // namespace flutter diff --git a/flow/layers/elevated_container_layer.h b/flow/layers/elevated_container_layer.h deleted file mode 100644 index 9c7a8b051f118..0000000000000 --- a/flow/layers/elevated_container_layer.h +++ /dev/null @@ -1,34 +0,0 @@ -// 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_FLOW_LAYERS_ELEVATED_CONTAINER_LAYER_H_ -#define FLUTTER_FLOW_LAYERS_ELEVATED_CONTAINER_LAYER_H_ - -#include "flutter/flow/layers/container_layer.h" - -namespace flutter { - -class ElevatedContainerLayer : public ContainerLayer { - public: - ElevatedContainerLayer(float elevation); - ~ElevatedContainerLayer() override = default; - - void Preroll(PrerollContext* context, const SkMatrix& matrix) override; - - float elevation() const { return clamped_elevation_; } - float total_elevation() const { - return parent_elevation_ + clamped_elevation_; - } - - private: - float parent_elevation_ = 0.0f; - float elevation_ = 0.0f; - float clamped_elevation_ = 0.0f; - - FML_DISALLOW_COPY_AND_ASSIGN(ElevatedContainerLayer); -}; - -} // namespace flutter - -#endif // FLUTTER_FLOW_LAYERS_ELEVATED_CONTAINER_LAYER_H_ diff --git a/flow/layers/fuchsia_system_composited_layer.cc b/flow/layers/fuchsia_system_composited_layer.cc deleted file mode 100644 index 8c4a1b2ae26e3..0000000000000 --- a/flow/layers/fuchsia_system_composited_layer.cc +++ /dev/null @@ -1,55 +0,0 @@ -// 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/flow/layers/fuchsia_system_composited_layer.h" - -namespace flutter { - -FuchsiaSystemCompositedLayer::FuchsiaSystemCompositedLayer(SkColor color, - SkAlpha opacity, - float elevation) - : ElevatedContainerLayer(elevation), color_(color), opacity_(opacity) {} - -void FuchsiaSystemCompositedLayer::Preroll(PrerollContext* context, - const SkMatrix& matrix) { - TRACE_EVENT0("flutter", "FuchsiaSystemCompositedLayer::Preroll"); - - const float parent_is_opaque = context->is_opaque; - context->mutators_stack.PushOpacity(opacity_); - context->is_opaque = parent_is_opaque && (opacity_ == SK_AlphaOPAQUE); - ElevatedContainerLayer::Preroll(context, matrix); - context->is_opaque = parent_is_opaque; - context->mutators_stack.Pop(); -} - -void FuchsiaSystemCompositedLayer::UpdateScene(SceneUpdateContext& context) { - FML_DCHECK(needs_system_composite()); - - // 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 Paint. - LayerRasterCacheKey key(unique_id(), context.Matrix()); - if (context.HasRetainedNode(key)) { - TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit"); - const scenic::EntityNode& retained_node = context.GetRetainedNode(key); - FML_DCHECK(context.top_entity()); - FML_DCHECK(retained_node.session() == context.session()); - context.top_entity()->embedder_node().AddChild(retained_node); - return; - } - - TRACE_EVENT_INSTANT0("flutter", "retained cache miss, creating"); - // If we can't find an existing retained surface, create one. - SceneUpdateContext::Frame frame(context, rrect_, color_, opacity_ / 255.0f, - elevation(), this); - for (auto& layer : layers()) { - if (layer->needs_painting()) { - frame.AddPaintLayer(layer.get()); - } - } - - ElevatedContainerLayer::UpdateScene(context); -} - -} // namespace flutter diff --git a/flow/layers/fuchsia_system_composited_layer.h b/flow/layers/fuchsia_system_composited_layer.h deleted file mode 100644 index 2fe00ee6d550f..0000000000000 --- a/flow/layers/fuchsia_system_composited_layer.h +++ /dev/null @@ -1,37 +0,0 @@ -// 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_FLOW_LAYERS_FUCHSIA_SYSTEM_COMPOSITED_LAYER_H_ -#define FLUTTER_FLOW_LAYERS_FUCHSIA_SYSTEM_COMPOSITED_LAYER_H_ - -#include "flutter/flow/layers/elevated_container_layer.h" -#include "flutter/flow/scene_update_context.h" - -namespace flutter { - -class FuchsiaSystemCompositedLayer : public ElevatedContainerLayer { - public: - static bool can_system_composite() { return true; } - - FuchsiaSystemCompositedLayer(SkColor color, SkAlpha opacity, float elevation); - - void Preroll(PrerollContext* context, const SkMatrix& matrix) override; - void UpdateScene(SceneUpdateContext& context) override; - - void set_dimensions(SkRRect rrect) { rrect_ = rrect; } - - SkColor color() const { return color_; } - SkAlpha opacity() const { return opacity_; } - - private: - SkRRect rrect_ = SkRRect::MakeEmpty(); - SkColor color_ = SK_ColorTRANSPARENT; - SkAlpha opacity_ = SK_AlphaOPAQUE; - - FML_DISALLOW_COPY_AND_ASSIGN(FuchsiaSystemCompositedLayer); -}; - -} // namespace flutter - -#endif // FLUTTER_FLOW_LAYERS_FUCHSIA_SYSTEM_COMPOSITED_LAYER_H_ diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index dd9e6b4f02b01..37c28e861bf8a 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -83,7 +83,7 @@ void LayerTree::UpdateScene(SceneUpdateContext& context, context, SkRRect::MakeRect( SkRect::MakeWH(frame_size_.width(), frame_size_.height())), - SK_ColorTRANSPARENT); + SK_ColorTRANSPARENT, SK_AlphaOPAQUE); if (root_layer_->needs_system_composite()) { root_layer_->UpdateScene(context); } diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index 21ba509f09ae6..43fc58a9746b6 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -14,6 +14,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/time/time_delta.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkSize.h" namespace flutter { diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 5892fff7792a6..e6ca90a66a42f 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -14,24 +14,8 @@ namespace flutter { // this. constexpr float kOpacityElevationWhenUsingSystemCompositor = 0.01f; -#if !defined(OS_FUCHSIA) -void OpacityLayerBase::Preroll(PrerollContext* context, - const SkMatrix& matrix) { - const float parent_is_opaque = context->is_opaque; - - context->mutators_stack.PushOpacity(opacity_); - context->is_opaque = parent_is_opaque && (opacity_ == SK_AlphaOPAQUE); - ContainerLayer::Preroll(context, matrix); - context->is_opaque = parent_is_opaque; - context->mutators_stack.Pop(); -} -#endif - -OpacityLayer::OpacityLayer(SkAlpha opacity, const SkPoint& offset) - : OpacityLayerBase(SK_ColorTRANSPARENT, - opacity, - kOpacityElevationWhenUsingSystemCompositor), - offset_(offset) { +OpacityLayer::OpacityLayer(SkAlpha alpha, const SkPoint& offset) + : alpha_(alpha), offset_(offset) { // Ensure OpacityLayer has only one direct child. // // This is needed to ensure that retained rendering can always be applied to @@ -52,25 +36,35 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { ContainerLayer* container = GetChildContainer(); FML_DCHECK(!container->layers().empty()); // OpacityLayer can't be a leaf. - // Factor in the offset during Preroll. |OpacityLayerBase| will handle the - // opacity. + const bool parent_is_opaque = context->is_opaque; SkMatrix child_matrix = matrix; child_matrix.postTranslate(offset_.fX, offset_.fY); + + total_elevation_ = context->total_elevation; + context->total_elevation += kOpacityElevationWhenUsingSystemCompositor; + context->is_opaque = parent_is_opaque && (alpha_ == SK_AlphaOPAQUE); context->mutators_stack.PushTransform( SkMatrix::MakeTrans(offset_.fX, offset_.fY)); + context->mutators_stack.PushOpacity(alpha_); Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); - OpacityLayerBase::Preroll(context, child_matrix); + ContainerLayer::Preroll(context, child_matrix); + context->mutators_stack.Pop(); context->mutators_stack.Pop(); + context->is_opaque = parent_is_opaque; + context->total_elevation = total_elevation_; - // When using the system compositor, do not include the offset since we are - // rendering as a separate piece of geometry and the offset will be baked into - // that geometry's transform. - if (OpacityLayerBase::can_system_composite() && needs_system_composite()) { - set_dimensions(SkRRect::MakeRect(paint_bounds())); - } else { +#if defined(OS_FUCHSIA) + if (needs_system_composite()) { + // When using the system compositor, do not include the offset since we + // are rendering as a separate piece of geometry and the offset will be + // baked into that geometry's transform. + frameRRect_ = SkRRect::MakeRect(paint_bounds()); + set_paint_bounds(SkRect::MakeEmpty()); + } else +#endif + { set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY)); - if (!context->has_platform_view && context->raster_cache && SkRect::Intersects(context->cull_rect, paint_bounds())) { SkMatrix ctm = child_matrix; @@ -82,24 +76,12 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { } } -#if defined(OS_FUCHSIA) - -void OpacityLayer::UpdateScene(SceneUpdateContext& context) { - SceneUpdateContext::Transform transform( - context, SkMatrix::MakeTrans(offset_.fX, offset_.fY)); - - // OpacityLayerBase will handle applying the opacity itself. - OpacityLayerBase::UpdateScene(context); -} - -#endif - void OpacityLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "OpacityLayer::Paint"); FML_DCHECK(needs_painting()); SkPaint paint; - paint.setAlpha(opacity()); + paint.setAlpha(alpha_); SkAutoCanvasRestore save(context.internal_nodes_canvas, true); context.internal_nodes_canvas->translate(offset_.fX, offset_.fY); @@ -126,7 +108,8 @@ void OpacityLayer::Paint(PaintContext& context) const { // RasterCache::GetIntegralTransCTM optimization. // // Note that the following lines are only accessible when the raster cache is - // not available, or when a cache miss occurs. + // not available (e.g., when we're using the software backend in golden + // tests). SkRect saveLayerBounds; paint_bounds() .makeOffset(-offset_.fX, -offset_.fY) @@ -134,9 +117,46 @@ void OpacityLayer::Paint(PaintContext& context) const { Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint); - OpacityLayerBase::Paint(context); + PaintChildren(context); +} + +#if defined(OS_FUCHSIA) + +void OpacityLayer::UpdateScene(SceneUpdateContext& context) { + FML_DCHECK(needs_system_composite()); + TRACE_EVENT0("flutter", "OpacityLayer::UpdateScene"); + + ContainerLayer* container = GetChildContainer(); + FML_DCHECK(!container->layers().empty()); // OpacityLayer can't be a leaf. + + SceneUpdateContext::Transform transform( + context, SkMatrix::MakeTrans(offset_.fX, offset_.fY)); + + // 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(unique_id(), context.Matrix()); + if (context.HasRetainedNode(key)) { + TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit"); + const scenic::EntityNode& retained_node = context.GetRetainedNode(key); + FML_DCHECK(context.top_entity()); + FML_DCHECK(retained_node.session() == context.session()); + context.top_entity()->embedder_node().AddChild(retained_node); + return; + } + + TRACE_EVENT_INSTANT0("flutter", "cache miss, creating"); + // If we can't find an existing retained surface, create one. + SceneUpdateContext::Frame frame( + context, frameRRect_, SK_ColorTRANSPARENT, alpha_, + kOpacityElevationWhenUsingSystemCompositor, total_elevation_, this); + frame.AddPaintLayer(container); + + UpdateSceneChildren(context); } +#endif // defined(OS_FUCHSIA) + ContainerLayer* OpacityLayer::GetChildContainer() const { FML_DCHECK(layers().size() == 1); diff --git a/flow/layers/opacity_layer.h b/flow/layers/opacity_layer.h index f4951e0557c70..efc5dd4f83e04 100644 --- a/flow/layers/opacity_layer.h +++ b/flow/layers/opacity_layer.h @@ -5,42 +5,15 @@ #ifndef FLUTTER_FLOW_LAYERS_OPACITY_LAYER_H_ #define FLUTTER_FLOW_LAYERS_OPACITY_LAYER_H_ -#include "flutter/flow/layers/elevated_container_layer.h" -#if defined(OS_FUCHSIA) -#include "flutter/flow/layers/fuchsia_system_composited_layer.h" -#endif +#include "flutter/flow/layers/container_layer.h" namespace flutter { -#if !defined(OS_FUCHSIA) -class OpacityLayerBase : public ContainerLayer { - public: - static bool can_system_composite() { return false; } - - OpacityLayerBase(SkColor color, SkAlpha opacity, float elevation) - : color_(color), opacity_(opacity) {} - - void Preroll(PrerollContext* context, const SkMatrix& matrix) override; - - void set_dimensions(SkRRect rrect) {} - - SkColor color() const { return color_; } - SkAlpha opacity() const { return opacity_; } - float elevation() const { return 0; } - - private: - SkColor color_; - SkAlpha opacity_; -}; -#else -using OpacityLayerBase = FuchsiaSystemCompositedLayer; -#endif - // Don't add an OpacityLayer with no children to the layer tree. Painting an // OpacityLayer is very costly due to the saveLayer call. If there's no child, // having the OpacityLayer or not has the same effect. In debug_unopt build, // |Preroll| will assert if there are no children. -class OpacityLayer : public OpacityLayerBase { +class OpacityLayer : public ContainerLayer { public: // An offset is provided here because OpacityLayer.addToScene method in the // Flutter framework can take an optional offset argument. @@ -57,15 +30,20 @@ class OpacityLayer : public OpacityLayerBase { void Add(std::shared_ptr layer) override; void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + + void Paint(PaintContext& context) const override; + #if defined(OS_FUCHSIA) void UpdateScene(SceneUpdateContext& context) override; -#endif - void Paint(PaintContext& context) const override; +#endif // defined(OS_FUCHSIA) private: ContainerLayer* GetChildContainer() const; + SkAlpha alpha_; SkPoint offset_; + SkRRect frameRRect_; + float total_elevation_ = 0.0f; FML_DISALLOW_COPY_AND_ASSIGN(OpacityLayer); }; diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index 524c5a2ac939a..c64049222a8e7 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -17,12 +17,9 @@ PhysicalShapeLayer::PhysicalShapeLayer(SkColor color, float elevation, const SkPath& path, Clip clip_behavior) -#if !defined(OS_FUCHSIA) - : PhysicalShapeLayerBase(color, elevation), -#else - : PhysicalShapeLayerBase(color, /*opacity=*/1.f, elevation), -#endif + : color_(color), shadow_color_(shadow_color), + elevation_(elevation), path_(path), isRect_(false), clip_behavior_(clip_behavior) { @@ -45,35 +42,33 @@ PhysicalShapeLayer::PhysicalShapeLayer(SkColor color, // an SkPath. frameRRect_ = SkRRect::MakeRect(path.getBounds()); } - - set_dimensions(frameRRect_); } void PhysicalShapeLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "PhysicalShapeLayer::Preroll"); - Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer()); - PhysicalShapeLayerBase::Preroll(context, matrix); - if (elevation() == 0) { + context->total_elevation += elevation_; + total_elevation_ = context->total_elevation; + SkRect child_paint_bounds; + PrerollChildren(context, matrix, &child_paint_bounds); + context->total_elevation -= elevation_; + + if (elevation_ == 0) { set_paint_bounds(path_.getBounds()); } else { - if (PhysicalShapeLayerBase::can_system_composite()) { - set_needs_system_composite(true); - return; - } - //#if defined(OS_FUCHSIA) - // // Let the system compositor draw all shadows for us. - // set_needs_system_composite(true); - //#else +#if defined(OS_FUCHSIA) + // Let the system compositor draw all shadows for us. + set_needs_system_composite(true); +#else // We will draw the shadow in Paint(), so add some margin to the paint // bounds to leave space for the shadow. We fill this whole region and clip // children to it so we don't need to join the child paint bounds. - set_paint_bounds(ComputeShadowBounds(path_.getBounds(), elevation(), + set_paint_bounds(ComputeShadowBounds(path_.getBounds(), elevation_, context->frame_device_pixel_ratio)); - //#endif // defined(OS_FUCHSIA) +#endif // defined(OS_FUCHSIA) } } @@ -98,9 +93,8 @@ void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) { TRACE_EVENT_INSTANT0("flutter", "cache miss, creating"); // If we can't find an existing retained surface, create one. - SceneUpdateContext::Frame frame(context, frameRRect_, color(), opacity(), - elevation(), this); - + SceneUpdateContext::Frame frame(context, frameRRect_, color_, SK_AlphaOPAQUE, + elevation_, total_elevation_, this); for (auto& layer : layers()) { if (layer->needs_painting()) { frame.AddPaintLayer(layer.get()); @@ -116,14 +110,14 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint"); FML_DCHECK(needs_painting()); - if (elevation() != 0) { - DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation(), - SkColorGetA(color()) != 0xff, context.frame_device_pixel_ratio); + if (elevation_ != 0) { + DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation_, + SkColorGetA(color_) != 0xff, context.frame_device_pixel_ratio); } // Call drawPath without clip if possible for better performance. SkPaint paint; - paint.setColor(color()); + paint.setColor(color_); paint.setAntiAlias(true); if (clip_behavior_ != Clip::antiAliasWithSaveLayer) { context.leaf_nodes_canvas->drawPath(path_, paint); diff --git a/flow/layers/physical_shape_layer.h b/flow/layers/physical_shape_layer.h index 34b3c59fe355b..40ff19cfac348 100644 --- a/flow/layers/physical_shape_layer.h +++ b/flow/layers/physical_shape_layer.h @@ -5,33 +5,18 @@ #ifndef FLUTTER_FLOW_LAYERS_PHYSICAL_SHAPE_LAYER_H_ #define FLUTTER_FLOW_LAYERS_PHYSICAL_SHAPE_LAYER_H_ -#include "flutter/flow/layers/elevated_container_layer.h" -#if defined(OS_FUCHSIA) -#include "flutter/flow/layers/fuchsia_system_composited_layer.h" -#endif +#include "flutter/flow/layers/container_layer.h" namespace flutter { -#if !defined(OS_FUCHSIA) -class PhysicalShapeLayerBase : public ElevatedContainerLayer { +class PhysicalShapeLayer : public ContainerLayer { public: - static bool can_system_composite() { return false; } - - PhysicalShapeLayerBase(SkColor color, float elevation) - : ElevatedContainerLayer(elevation), color_(color) {} - - void set_dimensions(SkRRect rrect) {} - SkColor color() const { return color_; } - - private: - SkColor color_; -}; -#else -using PhysicalShapeLayerBase = FuchsiaSystemCompositedLayer; -#endif + PhysicalShapeLayer(SkColor color, + SkColor shadow_color, + float elevation, + const SkPath& path, + Clip clip_behavior); -class PhysicalShapeLayer : public PhysicalShapeLayerBase { - public: static SkRect ComputeShadowBounds(const SkRect& bounds, float elevation, float pixel_ratio); @@ -42,13 +27,8 @@ class PhysicalShapeLayer : public PhysicalShapeLayerBase { bool transparentOccluder, SkScalar dpr); - PhysicalShapeLayer(SkColor color, - SkColor shadow_color, - float elevation, - const SkPath& path, - Clip clip_behavior); - void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + void Paint(PaintContext& context) const override; bool UsesSaveLayer() const { @@ -59,8 +39,13 @@ class PhysicalShapeLayer : public PhysicalShapeLayerBase { void UpdateScene(SceneUpdateContext& context) override; #endif // defined(OS_FUCHSIA) + float total_elevation() const { return total_elevation_; } + private: + SkColor color_; SkColor shadow_color_; + float elevation_ = 0.0f; + float total_elevation_ = 0.0f; SkPath path_; bool isRect_; SkRRect frameRRect_; diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 230b648f50e80..3bc7e394c1033 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -18,9 +18,12 @@ PictureLayer::PictureLayer(const SkPoint& offset, will_change_(will_change) {} void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "PictureLayer::Preroll"); SkPicture* sk_picture = picture(); if (auto* cache = context->raster_cache) { + TRACE_EVENT0("flutter", "PictureLayer::RasterCache (Preroll)"); + SkMatrix ctm = matrix; ctm.postTranslate(offset_.x(), offset_.y()); #ifndef SUPPORT_FRACTIONAL_TRANSLATION @@ -50,6 +53,8 @@ void PictureLayer::Paint(PaintContext& context) const { const SkMatrix& ctm = context.leaf_nodes_canvas->getTotalMatrix(); RasterCacheResult result = context.raster_cache->Get(*picture(), ctm); if (result.is_valid()) { + TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); + result.draw(*context.leaf_nodes_canvas); return; } diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index 848f69c8a115a..e5df2b795dd34 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -15,14 +15,19 @@ TextureLayer::TextureLayer(const SkPoint& offset, : offset_(offset), size_(size), texture_id_(texture_id), freeze_(freeze) {} void TextureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "TextureLayer::Preroll"); + set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(), size_.height())); } void TextureLayer::Paint(PaintContext& context) const { + TRACE_EVENT0("flutter", "TextureLayer::Paint"); + std::shared_ptr texture = context.texture_registry.GetTexture(texture_id_); if (!texture) { + TRACE_EVENT_INSTANT0("flutter", "null texture"); return; } texture->Paint(*context.leaf_nodes_canvas, paint_bounds(), freeze_, diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index 9513e8bc0fec6..5c7bc44073236 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -25,6 +25,8 @@ TransformLayer::TransformLayer(const SkMatrix& transform) } void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + TRACE_EVENT0("flutter", "TransformLayer::Preroll"); + SkMatrix child_matrix; child_matrix.setConcat(matrix, transform_); context->mutators_stack.PushTransform(transform_); @@ -51,6 +53,7 @@ void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { #if defined(OS_FUCHSIA) void TransformLayer::UpdateScene(SceneUpdateContext& context) { + TRACE_EVENT0("flutter", "TransformLayer::UpdateScene"); FML_DCHECK(needs_system_composite()); SceneUpdateContext::Transform transform(context, transform_); diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc index 5ffcc4b272ce9..59524bc9c6e56 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -57,30 +57,21 @@ SceneUpdateContext::SceneUpdateContext(scenic::Session* session, } void SceneUpdateContext::CreateFrame(scenic::EntityNode entity_node, - scenic::ShapeNode shape_node, const SkRRect& rrect, SkColor color, - float opacity, + SkAlpha opacity, const SkRect& paint_bounds, std::vector paint_layers, Layer* layer) { - // We don't need a shape if the frame is zero size. - if (rrect.isEmpty()) - return; + FML_DCHECK(!rrect.isEmpty()); - SetEntityNodeClipPlanes(entity_node, rrect.getBounds()); - - // isEmpty should account for this, but we are adding these experimental - // checks to validate if this is the root cause for b/144933519. - if (std::isnan(rrect.width()) || std::isnan(rrect.height())) { - FML_LOG(ERROR) << "Invalid RoundedRectangle"; - return; - } + // Frames always clip their children. + SkRect shape_bounds = rrect.getBounds(); + SetEntityNodeClipPlanes(entity_node, shape_bounds); - // Add a part which represents the frame's geometry for clipping purposes // and possibly for its texture. // TODO(SCN-137): Need to be able to express the radii as vectors. - SkRect shape_bounds = rrect.getBounds(); + scenic::ShapeNode shape_node(session()); scenic::RoundedRectangle shape( session_, // session rrect.width(), // width @@ -99,48 +90,57 @@ void SceneUpdateContext::CreateFrame(scenic::EntityNode entity_node, if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds)) paint_layers.clear(); + scenic::Material material(session()); + shape_node.SetMaterial(material); + entity_node.AddChild(shape_node); + // Check whether a solid color will suffice. if (paint_layers.empty()) { - scenic::Material material(session_); SetMaterialColor(material, color, opacity); - shape_node.SetMaterial(material); - return; + } else { + // Apply current metrics and transformation scale factors. + const float scale_x = ScaleX(); + const float scale_y = ScaleY(); + + // Apply a texture to the whole shape. + SetMaterialTextureAndColor(material, color, opacity, scale_x, scale_y, + shape_bounds, std::move(paint_layers), layer, + std::move(entity_node)); } +} - // Apply current metrics and transformation scale factors. - const float scale_x = ScaleX(); - const float scale_y = ScaleY(); - +void SceneUpdateContext::SetMaterialTextureAndColor( + scenic::Material& material, + SkColor color, + SkAlpha opacity, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers, + Layer* layer, + scenic::EntityNode entity_node) { scenic::Image* image = GenerateImageIfNeeded( - color, scale_x, scale_y, shape_bounds, std::move(paint_layers), layer, + color, scale_x, scale_y, paint_bounds, std::move(paint_layers), layer, std::move(entity_node)); - if (image != nullptr) { - scenic::Material material(session_); + if (image != nullptr) { // The final shape's color is material_color * texture_color. The passed in // material color was already used as a background when generating the // texture, so set the model color to |SK_ColorWHITE| in order to allow // using the texture's color unmodified. SetMaterialColor(material, SK_ColorWHITE, opacity); material.SetTexture(*image); - shape_node.SetMaterial(material); - return; - } - - // No texture was needed, so apply a solid color to the whole shape. - if (SkColorGetA(color) != 0 && opacity != 0.0f) { - scenic::Material material(session_); - + } else { + // No texture was needed, so apply a solid color to the whole shape. SetMaterialColor(material, color, opacity); - shape_node.SetMaterial(material); - return; } } void SceneUpdateContext::SetMaterialColor(scenic::Material& material, SkColor color, - float opacity) { - const SkAlpha color_alpha = (SkAlpha)(SkColorGetA(color) * opacity); + SkAlpha opacity) { + const SkAlpha color_alpha = static_cast( + ((float)SkColorGetA(color) * (float)opacity) / 255.0f); material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), color_alpha); } @@ -231,7 +231,6 @@ SceneUpdateContext::Entity::Entity(SceneUpdateContext& context) entity_node_(context.session()) { if (previous_entity_) previous_entity_->embedder_node().AddChild(entity_node_); - context.top_entity_ = this; } @@ -290,37 +289,54 @@ SceneUpdateContext::Transform::~Transform() { context().top_scale_y_ = previous_scale_y_; } -SceneUpdateContext::Clip::Clip(SceneUpdateContext& context, - const SkRect& shape_bounds) - : Entity(context) { - SetEntityNodeClipPlanes(entity_node(), shape_bounds); -} - SceneUpdateContext::Frame::Frame(SceneUpdateContext& context, const SkRRect& rrect, SkColor color, - float opacity, - float elevation, + SkAlpha opacity, + float local_elevation, + float world_elevation, Layer* layer) : Entity(context), - opacity_node_(context.session()), - shape_node_(context.session()), - layer_(layer), rrect_(rrect), - paint_bounds_(SkRect::MakeEmpty()), color_(color), - opacity_(opacity) { - entity_node().SetTranslation(0.f, 0.f, -elevation); - - entity_node().AddChild(shape_node_); + opacity_(opacity), + opacity_node_(context.session()), + paint_bounds_(SkRect::MakeEmpty()), + layer_(layer) { + const float depth = context.frame_physical_depth(); + if (depth > -1 && world_elevation > depth) { + // TODO(mklim): Deal with bounds overflow more elegantly. We'd like to be + // able to have developers specify the behavior here to alternatives besides + // clamping, like normalization on some arbitrary curve. + + // Clamp the local z coordinate at our max bound. Take into account the + // parent z position here to fix clamping in cases where the child is + // overflowing because of its parents. + const float parent_elevation = world_elevation - local_elevation; + local_elevation = depth - parent_elevation; + } + if (local_elevation != 0.0) { + entity_node().SetTranslation(0.f, 0.f, -local_elevation); + } entity_node().AddChild(opacity_node_); - opacity_node_.SetOpacity(opacity_); + opacity_node_.SetOpacity(opacity_ / 255.0f); } SceneUpdateContext::Frame::~Frame() { - context().CreateFrame(std::move(entity_node()), std::move(shape_node_), - rrect_, color_, opacity_, paint_bounds_, - std::move(paint_layers_), layer_); + // We don't need a shape if the frame is zero size. + if (rrect_.isEmpty()) + return; + + // isEmpty should account for this, but we are adding these experimental + // checks to validate if this is the root cause for b/144933519. + if (std::isnan(rrect_.width()) || std::isnan(rrect_.height())) { + FML_LOG(ERROR) << "Invalid RoundedRectangle"; + return; + } + + // Add a part which represents the frame's geometry for clipping purposes + context().CreateFrame(std::move(entity_node()), rrect_, color_, opacity_, + paint_bounds_, std::move(paint_layers_), layer_); } void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) { @@ -329,4 +345,10 @@ void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) { paint_bounds_.join(layer->paint_bounds()); } +SceneUpdateContext::Clip::Clip(SceneUpdateContext& context, + const SkRect& shape_bounds) + : Entity(context) { + SetEntityNodeClipPlanes(entity_node(), shape_bounds); +} + } // namespace flutter diff --git a/flow/scene_update_context.h b/flow/scene_update_context.h index c992fa20bba36..31bcb1bd57253 100644 --- a/flow/scene_update_context.h +++ b/flow/scene_update_context.h @@ -89,19 +89,13 @@ class SceneUpdateContext { float scale_x, float scale_y, float scale_z); - ~Transform() override; + virtual ~Transform(); private: float const previous_scale_x_; float const previous_scale_y_; }; - class Clip : public Entity { - public: - Clip(SceneUpdateContext& context, const SkRect& shape_bounds); - ~Clip() override = default; - }; - class Frame : public Entity { public: // When layer is not nullptr, the frame is associated with a layer subtree @@ -110,25 +104,31 @@ class SceneUpdateContext { Frame(SceneUpdateContext& context, const SkRRect& rrect, SkColor color, - float opacity = 1.0f, - float elevation = 0.0f, + SkAlpha opacity, + float local_elevation = 0.0f, + float parent_elevation = 0.0f, Layer* layer = nullptr); - ~Frame() override; + virtual ~Frame(); scenic::ContainerNode& embedder_node() override { return opacity_node_; } + void AddPaintLayer(Layer* layer); private: - scenic::OpacityNodeHACK opacity_node_; - scenic::ShapeNode shape_node_; + const SkRRect rrect_; + SkColor const color_; + SkAlpha const opacity_; + scenic::OpacityNodeHACK opacity_node_; std::vector paint_layers_; + SkRect paint_bounds_; Layer* layer_; + }; - SkRRect rrect_; - SkRect paint_bounds_; - SkColor color_; - float opacity_; + class Clip : public Entity { + public: + Clip(SceneUpdateContext& context, const SkRect& shape_bounds); + ~Clip() = default; }; SceneUpdateContext(scenic::Session* session, @@ -198,24 +198,24 @@ class SceneUpdateContext { // surface (and thus the entity_node) will be retained for that layer to // improve the performance. void CreateFrame(scenic::EntityNode entity_node, - scenic::ShapeNode shape_node, const SkRRect& rrect, SkColor color, - float opacity, + SkAlpha opacity, const SkRect& paint_bounds, std::vector paint_layers, Layer* layer); - void SetShapeTextureAndColor(scenic::ShapeNode& shape_node, - SkColor color, - SkScalar scale_x, - SkScalar scale_y, - const SkRect& paint_bounds, - std::vector paint_layers, - Layer* layer, - scenic::EntityNode entity_node); + void SetMaterialTextureAndColor(scenic::Material& material, + SkColor color, + SkAlpha opacity, + SkScalar scale_x, + SkScalar scale_y, + const SkRect& paint_bounds, + std::vector paint_layers, + Layer* layer, + scenic::EntityNode entity_node); void SetMaterialColor(scenic::Material& material, SkColor color, - float opacity); + SkAlpha opacity); scenic::Image* GenerateImageIfNeeded(SkColor color, SkScalar scale_x, SkScalar scale_y,