Fix Opacity performance regression on Fuchsia (flutter/engine#15573)

* Add more profile markers

* Revert FuchsiaSystemCompistedLayer changes

* Re-add opacity w/o elevation changes

* Fix formatting
This commit is contained in:
David Worsham 2020-01-16 15:28:48 -08:00 committed by Kaushik Iska
parent 8ca3dd95d8
commit ec3aedb2f2
21 changed files with 254 additions and 401 deletions

View File

@ -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

View File

@ -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",

View File

@ -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_);

View File

@ -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_,

View File

@ -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_,

View File

@ -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_,

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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);
}

View File

@ -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 {

View File

@ -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);

View File

@ -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> 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);
};

View File

@ -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);

View File

@ -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; }
PhysicalShapeLayer(SkColor color,
SkColor shadow_color,
float elevation,
const SkPath& path,
Clip clip_behavior);
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
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_;

View File

@ -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;
}

View File

@ -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> 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_,

View File

@ -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_);

View File

@ -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<Layer*> 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());
// Frames always clip their children.
SkRect shape_bounds = rrect.getBounds();
SetEntityNodeClipPlanes(entity_node, shape_bounds);
// 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
// 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<Layer*> 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<SkAlpha>(
((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);
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.
entity_node().AddChild(shape_node_);
// 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

View File

@ -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:
const SkRRect rrect_;
SkColor const color_;
SkAlpha const opacity_;
scenic::OpacityNodeHACK opacity_node_;
scenic::ShapeNode shape_node_;
std::vector<Layer*> paint_layers_;
Layer* layer_;
SkRRect rrect_;
SkRect paint_bounds_;
SkColor color_;
float opacity_;
Layer* layer_;
};
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<Layer*> paint_layers,
Layer* layer);
void SetShapeTextureAndColor(scenic::ShapeNode& shape_node,
SkColor color,
SkScalar scale_x,
SkScalar scale_y,
const SkRect& paint_bounds,
std::vector<Layer*> 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<Layer*> 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,