Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 69635fd

Browse files
committed
Wire up OpacityLayer to Scenic
1 parent 865fce8 commit 69635fd

13 files changed

+261
-146
lines changed

flow/layers/child_scene_layer.cc

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,25 @@ ChildSceneLayer::ChildSceneLayer(zx_koid_t layer_id,
2020
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
2121
TRACE_EVENT0("flutter", "ChildSceneLayer::Preroll");
2222
set_needs_system_composite(true);
23+
24+
// An alpha "hole punch" is required if the frame behind us is not opaque.
25+
if (!context->is_opaque) {
26+
set_paint_bounds(
27+
SkRect::MakeXYWH(offset_.fX, offset_.fY, size_.fWidth, size_.fHeight));
28+
}
2329
}
2430

2531
void ChildSceneLayer::Paint(PaintContext& context) const {
26-
FML_NOTREACHED() << "This layer never needs painting.";
32+
TRACE_EVENT0("flutter", "ChildSceneLayer::Paint");
33+
FML_DCHECK(needs_painting());
34+
35+
// If we are being rendered into our own frame using the system compositor,
36+
// then it is neccesary to "punch a hole" in the canvas/frame behind us so
37+
// that group opacity looks correct.
38+
SkPaint paint;
39+
paint.setColor(SK_ColorTRANSPARENT);
40+
paint.setBlendMode(SkBlendMode::kSrc);
41+
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
2742
}
2843

2944
void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {

flow/layers/fuchsia_system_composited_layer.cc

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@
66

77
namespace flutter {
88

9-
FuchsiaSystemCompositedLayer::FuchsiaSystemCompositedLayer(
10-
SkColor color,
11-
float elevation)
12-
: ElevatedContainerLayer(elevation), color_(color) {}
9+
FuchsiaSystemCompositedLayer::FuchsiaSystemCompositedLayer(SkColor color,
10+
SkAlpha opacity,
11+
float elevation)
12+
: ElevatedContainerLayer(elevation), color_(color), opacity_(opacity) {}
1313

1414
void FuchsiaSystemCompositedLayer::Preroll(PrerollContext* context,
15-
const SkMatrix& matrix) {
15+
const SkMatrix& matrix) {
1616
TRACE_EVENT0("flutter", "FuchsiaSystemCompositedLayer::Preroll");
17-
#if !defined(OS_FUCHSIA)
18-
FML_NOTIMPLEMENTED();
19-
#endif // !defined(OS_FUCHSIA)
2017

18+
const float parent_is_opaque = context->is_opaque;
19+
context->mutators_stack.PushOpacity(opacity_);
20+
context->is_opaque = parent_is_opaque && (opacity_ == 255);
2121
ElevatedContainerLayer::Preroll(context, matrix);
22+
context->is_opaque = parent_is_opaque;
23+
context->mutators_stack.Pop();
2224

2325
// System-composite this layer if its elevated.
2426
if (elevation() != 0.0f) {
@@ -28,19 +30,20 @@ void FuchsiaSystemCompositedLayer::Preroll(PrerollContext* context,
2830

2931
void FuchsiaSystemCompositedLayer::Paint(PaintContext& context) const {
3032
TRACE_EVENT0("flutter", "FuchsiaSystemCompositedLayer::Paint");
31-
#if !defined(OS_FUCHSIA)
32-
FML_NOTIMPLEMENTED();
33-
#endif // !defined(OS_FUCHSIA)
33+
FML_DCHECK(needs_painting());
3434

35-
// TODO: hole punch
36-
// If this is actually called, it's because flow is attempting to paint this
37-
// layer onto the frame behind it which gives us a chance to hole-punch
35+
if (needs_system_composite()) {
36+
// If we are being rendered into our own frame using the system compositor,
37+
// then it is neccesary to "punch a hole" in the canvas/frame behind us so
38+
// that group opacity looks correct.
39+
SkPaint paint;
40+
paint.setColor(SK_ColorTRANSPARENT);
41+
paint.setBlendMode(SkBlendMode::kSrc);
42+
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
43+
}
3844
}
3945

40-
#if defined(OS_FUCHSIA)
41-
42-
void FuchsiaSystemCompositedLayer::UpdateScene(
43-
SceneUpdateContext& context) {
46+
void FuchsiaSystemCompositedLayer::UpdateScene(SceneUpdateContext& context) {
4447
FML_DCHECK(needs_system_composite());
4548

4649
// Retained rendering: speedup by reusing a retained entity node if
@@ -58,16 +61,15 @@ void FuchsiaSystemCompositedLayer::UpdateScene(
5861

5962
TRACE_EVENT_INSTANT0("flutter", "retained cache miss, creating");
6063
// If we can't find an existing retained surface, create one.
61-
SceneUpdateContext::Frame frame(context, rrect_, color_, elevation(), this);
64+
SceneUpdateContext::Frame frame(context, rrect_, color_, opacity_ / 255.0f,
65+
elevation(), this);
6266
for (auto& layer : layers()) {
6367
if (layer->needs_painting()) {
6468
frame.AddPaintLayer(layer.get());
6569
}
6670
}
6771

68-
ContainerLayer::UpdateScene(context);
72+
ElevatedContainerLayer::UpdateScene(context);
6973
}
7074

71-
#endif // defined(OS_FUCHSIA)
72-
7375
} // namespace flutter

flow/layers/fuchsia_system_composited_layer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class FuchsiaSystemCompositedLayer : public ElevatedContainerLayer {
1313
public:
1414
static bool can_system_composite() { return true; }
1515

16-
FuchsiaSystemCompositedLayer(SkColor color, float elevation);
16+
FuchsiaSystemCompositedLayer(SkColor color, SkAlpha opacity, float elevation);
1717
~FuchsiaSystemCompositedLayer() override = default;
1818

1919
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
@@ -25,10 +25,12 @@ class FuchsiaSystemCompositedLayer : public ElevatedContainerLayer {
2525
void set_dimensions(SkRRect rrect) { rrect_ = rrect; }
2626

2727
SkColor color() const { return color_; }
28+
SkAlpha opacity() const { return opacity_; }
2829

2930
private:
3031
SkRRect rrect_ = SkRRect::MakeEmpty();
3132
SkColor color_ = SK_ColorTRANSPARENT;
33+
SkAlpha opacity_ = 255;
3234

3335
FML_DISALLOW_COPY_AND_ASSIGN(FuchsiaSystemCompositedLayer);
3436
};

flow/layers/layer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,11 @@ struct PrerollContext {
6060
float frame_physical_depth;
6161
float frame_device_pixel_ratio;
6262

63-
// These allow us to track properties like elevation and opacity which stack
64-
// with each other during Preroll.
63+
// These allow us to track properties like elevation, opacity, and the
64+
// prescence of a platform view during Preroll.
6565
float total_elevation = 0.0f;
6666
bool has_platform_view = false;
67+
bool is_opaque = true;
6768
};
6869

6970
// Represents a single composited layer. Created on the UI thread but then

flow/layers/layer_tree.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void LayerTree::UpdateScene(SceneUpdateContext& context,
8181
context,
8282
SkRRect::MakeRect(
8383
SkRect::MakeWH(frame_size_.width(), frame_size_.height())),
84-
SK_ColorTRANSPARENT, /* elevation */ 0.0f);
84+
SK_ColorTRANSPARENT, /* opacity */ 1.0f, /* elevation */ 0.0f);
8585
if (root_layer_->needs_system_composite()) {
8686
root_layer_->UpdateScene(context);
8787
}

flow/layers/layer_tree_unittests.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ namespace testing {
1717

1818
class LayerTreeTest : public CanvasTest<::testing::Test> {
1919
public:
20-
LayerTreeTest() : layer_tree_(SkISize::Make(64, 64), 100.0f, 1.0f),
21-
compositor_context_(fml::kDefaultFrameBudget),
22-
root_transform_(SkMatrix::MakeTrans(1.0f, 1.0f)),
23-
scoped_frame_(compositor_context_.AcquireFrame(nullptr, &mock_canvas(), nullptr, root_transform_, false, nullptr)) {}
20+
LayerTreeTest()
21+
: layer_tree_(SkISize::Make(64, 64), 100.0f, 1.0f),
22+
compositor_context_(fml::kDefaultFrameBudget),
23+
root_transform_(SkMatrix::MakeTrans(1.0f, 1.0f)),
24+
scoped_frame_(compositor_context_.AcquireFrame(nullptr,
25+
&mock_canvas(),
26+
nullptr,
27+
root_transform_,
28+
false,
29+
nullptr)) {}
2430

2531
LayerTree& layer_tree() { return layer_tree_; }
2632
CompositorContext::ScopedFrame& frame() { return *scoped_frame_.get(); }

flow/layers/opacity_layer.cc

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,30 @@
99

1010
namespace flutter {
1111

12-
OpacityLayer::OpacityLayer(int alpha, const SkPoint& offset)
13-
: alpha_(alpha), offset_(offset) {
12+
// The OpacityLayer has no real "elevation", but we want to avoid Z-fighting
13+
// when using the system compositor. Choose a small but non-zero value for
14+
// this.
15+
constexpr float kOpacityElevationWhenUsingSystemCompositor = 0.0001f;
16+
17+
#if !defined(OS_FUCHSIA)
18+
void OpacityLayerBase::Preroll(PrerollContext* context,
19+
const SkMatrix& matrix) {
20+
const SkAlpha alpha = SkColorGetA(color());
21+
const float parent_is_opaque = context->is_opaque;
22+
23+
context->mutators_stack.PushOpacity(alpha);
24+
context->is_opaque = parent_is_opaque && (alpha == 255);
25+
ContainerLayer::Preroll(context, matrix);
26+
context->is_opaque = parent_is_opaque;
27+
context->mutators_stack.Pop();
28+
}
29+
#endif
30+
31+
OpacityLayer::OpacityLayer(SkAlpha opacity, const SkPoint& offset)
32+
: OpacityLayerBase(SK_ColorBLACK,
33+
opacity,
34+
kOpacityElevationWhenUsingSystemCompositor),
35+
offset_(offset) {
1436
// Ensure OpacityLayer has only one direct child.
1537
//
1638
// This is needed to ensure that retained rendering can always be applied to
@@ -33,15 +55,30 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
3355
ContainerLayer* container = GetChildContainer();
3456
FML_DCHECK(!container->layers().empty()); // OpacityLayer can't be a leaf.
3557

58+
// Factor in the offset during Preroll. |OpacityLayerBase| will handle the
59+
// opacity.
3660
SkMatrix child_matrix = matrix;
3761
child_matrix.postTranslate(offset_.fX, offset_.fY);
3862
context->mutators_stack.PushTransform(
3963
SkMatrix::MakeTrans(offset_.fX, offset_.fY));
40-
context->mutators_stack.PushOpacity(alpha_);
41-
ContainerLayer::Preroll(context, child_matrix);
42-
context->mutators_stack.Pop();
64+
OpacityLayerBase::Preroll(context, child_matrix);
4365
context->mutators_stack.Pop();
44-
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
66+
67+
// When using the system compositor, do not include the offset since we are
68+
// rendering as a separate piece of geometry and the offset will be baked into
69+
// that geometry's transform.
70+
if (OpacityLayerBase::can_system_composite()) {
71+
set_dimensions(SkRRect::MakeRect(paint_bounds()));
72+
73+
// If the frame behind us is opaque, don't punch a hole in it for group
74+
// opacity.
75+
if (context->is_opaque) {
76+
set_paint_bounds(SkRect::MakeEmpty());
77+
}
78+
set_needs_system_composite(true);
79+
} else {
80+
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
81+
}
4582

4683
if (!context->has_platform_view && context->raster_cache &&
4784
SkRect::Intersects(context->cull_rect, paint_bounds())) {
@@ -53,12 +90,38 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
5390
}
5491
}
5592

93+
#if defined(OS_FUCHSIA)
94+
95+
void OpacityLayer::UpdateScene(SceneUpdateContext& context) {
96+
SceneUpdateContext::Transform transform(
97+
context, SkMatrix::MakeTrans(offset_.fX, offset_.fY));
98+
99+
// OpacityLayerBase will handle applying the opacity itself.
100+
OpacityLayerBase::UpdateScene(context);
101+
}
102+
103+
#endif
104+
56105
void OpacityLayer::Paint(PaintContext& context) const {
57106
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
58107
FML_DCHECK(needs_painting());
59108

109+
// The compositor will paint this layer (which is |Sk_ColorBLACK| with alpha
110+
// scaled by opacity) via the model color on |SceneUpdateContext::Frame|.
111+
//
112+
// The child layers will be painted into the texture used by the Frame, so
113+
// painting them here would actually cause them to be painted on the display
114+
// twice -- once into the current canvas (which may be inside of another
115+
// Frame) and once into the Frame's texture (which is then drawn on top of the
116+
// current canvas).
117+
if (OpacityLayerBase::can_system_composite()) {
118+
FML_DCHECK(needs_system_composite());
119+
OpacityLayerBase::Paint(context);
120+
return;
121+
}
122+
60123
SkPaint paint;
61-
paint.setAlpha(alpha_);
124+
paint.setAlpha(opacity());
62125

63126
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
64127
context.internal_nodes_canvas->translate(offset_.fX, offset_.fY);
@@ -85,16 +148,15 @@ void OpacityLayer::Paint(PaintContext& context) const {
85148
// RasterCache::GetIntegralTransCTM optimization.
86149
//
87150
// Note that the following lines are only accessible when the raster cache is
88-
// not available (e.g., when we're using the software backend in golden
89-
// tests).
151+
// not available, or when a cache miss occurs.
90152
SkRect saveLayerBounds;
91153
paint_bounds()
92154
.makeOffset(-offset_.fX, -offset_.fY)
93155
.roundOut(&saveLayerBounds);
94156

95157
Layer::AutoSaveLayer save_layer =
96158
Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint);
97-
PaintChildren(context);
159+
OpacityLayerBase::Paint(context);
98160
}
99161

100162
ContainerLayer* OpacityLayer::GetChildContainer() const {

flow/layers/opacity_layer.h

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,42 @@
55
#ifndef FLUTTER_FLOW_LAYERS_OPACITY_LAYER_H_
66
#define FLUTTER_FLOW_LAYERS_OPACITY_LAYER_H_
77

8-
#include "flutter/flow/layers/container_layer.h"
8+
#include "flutter/flow/layers/elevated_container_layer.h"
9+
#if defined(OS_FUCHSIA)
10+
#include "flutter/flow/layers/fuchsia_system_composited_layer.h"
11+
#endif
912

1013
namespace flutter {
1114

15+
#if defined(OS_FUCHSIA)
16+
using OpacityLayerBase = FuchsiaSystemCompositedLayer;
17+
#else
18+
class OpacityLayerBase : public ContainerLayer {
19+
public:
20+
static bool can_system_composite() { return false; }
21+
22+
OpacityLayerBase(SkColor color, SkAlpha opacity, float elevation)
23+
: color_(color), opacity_(opacity) {}
24+
25+
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
26+
27+
void set_dimensions(SkRRect rrect) {}
28+
29+
SkColor color() const { return color_; }
30+
SkAlpha opacity() const { return opacity_; }
31+
float elevation() const { return 0; }
32+
33+
private:
34+
SkColor color_;
35+
SkAlpha opacity_;
36+
};
37+
#endif
38+
1239
// Don't add an OpacityLayer with no children to the layer tree. Painting an
1340
// OpacityLayer is very costly due to the saveLayer call. If there's no child,
1441
// having the OpacityLayer or not has the same effect. In debug_unopt build, the
1542
// |EnsureSingleChild| will assert if there are no children.
16-
class OpacityLayer : public ContainerLayer {
43+
class OpacityLayer : public OpacityLayerBase {
1744
public:
1845
// An offset is provided here because OpacityLayer.addToScene method in the
1946
// Flutter framework can take an optional offset argument.
@@ -25,22 +52,20 @@ class OpacityLayer : public ContainerLayer {
2552
// the retained rendering inefficient as a small offset change could propagate
2653
// to many leaf layers. Therefore we try to capture that offset here to stop
2754
// the propagation as repainting the OpacityLayer is expensive.
28-
OpacityLayer(int alpha, const SkPoint& offset);
55+
OpacityLayer(SkAlpha alpha, const SkPoint& offset);
2956
~OpacityLayer() override;
3057

3158
void Add(std::shared_ptr<Layer> layer) override;
3259

3360
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
34-
61+
#if defined(OS_FUCHSIA)
62+
void UpdateScene(SceneUpdateContext& context) override;
63+
#endif
3564
void Paint(PaintContext& context) const override;
3665

37-
// TODO(chinmaygarde): Once SCN-139 is addressed, introduce a new node in the
38-
// session scene hierarchy.
39-
4066
private:
4167
ContainerLayer* GetChildContainer() const;
4268

43-
int alpha_;
4469
SkPoint offset_;
4570

4671
FML_DISALLOW_COPY_AND_ASSIGN(OpacityLayer);

0 commit comments

Comments
 (0)