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

Commit ea67e5b

Browse files
committed
Wire up OpacityLayer to Scenic
1 parent c4df6df commit ea67e5b

11 files changed

+199
-174
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: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,21 @@
77
namespace flutter {
88

99
FuchsiaSystemCompositedLayer::FuchsiaSystemCompositedLayer(SkColor color,
10+
SkAlpha opacity,
1011
float elevation)
11-
: ElevatedContainerLayer(elevation), color_(color) {}
12+
: ElevatedContainerLayer(elevation), color_(color), opacity_(opacity) {}
13+
14+
void FuchsiaSystemCompositedLayer::Preroll(PrerollContext* context,
15+
const SkMatrix& matrix) {
16+
TRACE_EVENT0("flutter", "FuchsiaSystemCompositedLayer::Preroll");
17+
18+
const float parent_is_opaque = context->is_opaque;
19+
context->mutators_stack.PushOpacity(opacity_);
20+
context->is_opaque = parent_is_opaque && (opacity_ == SK_AlphaOPAQUE);
21+
ElevatedContainerLayer::Preroll(context, matrix);
22+
context->is_opaque = parent_is_opaque;
23+
context->mutators_stack.Pop();
24+
}
1225

1326
void FuchsiaSystemCompositedLayer::UpdateScene(SceneUpdateContext& context) {
1427
FML_DCHECK(needs_system_composite());
@@ -28,14 +41,15 @@ void FuchsiaSystemCompositedLayer::UpdateScene(SceneUpdateContext& context) {
2841

2942
TRACE_EVENT_INSTANT0("flutter", "retained cache miss, creating");
3043
// If we can't find an existing retained surface, create one.
31-
SceneUpdateContext::Frame frame(context, rrect_, color_, elevation(), this);
44+
SceneUpdateContext::Frame frame(context, rrect_, color_, opacity_ / 255.0f,
45+
elevation(), this);
3246
for (auto& layer : layers()) {
3347
if (layer->needs_painting()) {
3448
frame.AddPaintLayer(layer.get());
3549
}
3650
}
3751

38-
ContainerLayer::UpdateScene(context);
52+
ElevatedContainerLayer::UpdateScene(context);
3953
}
4054

4155
} // namespace flutter

flow/layers/fuchsia_system_composited_layer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,20 @@ class FuchsiaSystemCompositedLayer : public ElevatedContainerLayer {
1414
public:
1515
static bool can_system_composite() { return true; }
1616

17-
FuchsiaSystemCompositedLayer(SkColor color, float elevation);
17+
FuchsiaSystemCompositedLayer(SkColor color, SkAlpha opacity, float elevation);
1818

19+
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
1920
void UpdateScene(SceneUpdateContext& context) override;
2021

2122
void set_dimensions(SkRRect rrect) { rrect_ = rrect; }
2223

2324
SkColor color() const { return color_; }
25+
SkAlpha opacity() const { return opacity_; }
2426

2527
private:
2628
SkRRect rrect_ = SkRRect::MakeEmpty();
2729
SkColor color_ = SK_ColorTRANSPARENT;
30+
SkAlpha opacity_ = SK_AlphaOPAQUE;
2831

2932
FML_DISALLOW_COPY_AND_ASSIGN(FuchsiaSystemCompositedLayer);
3033
};

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/opacity_layer.cc

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,29 @@
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.01f;
16+
17+
#if !defined(OS_FUCHSIA)
18+
void OpacityLayerBase::Preroll(PrerollContext* context,
19+
const SkMatrix& matrix) {
20+
const float parent_is_opaque = context->is_opaque;
21+
22+
context->mutators_stack.PushOpacity(opacity_);
23+
context->is_opaque = parent_is_opaque && (opacity_ == SK_AlphaOPAQUE);
24+
ContainerLayer::Preroll(context, matrix);
25+
context->is_opaque = parent_is_opaque;
26+
context->mutators_stack.Pop();
27+
}
28+
#endif
29+
30+
OpacityLayer::OpacityLayer(SkAlpha opacity, const SkPoint& offset)
31+
: OpacityLayerBase(SK_ColorTRANSPARENT,
32+
opacity,
33+
kOpacityElevationWhenUsingSystemCompositor),
34+
offset_(offset) {
1435
// Ensure OpacityLayer has only one direct child.
1536
//
1637
// This is needed to ensure that retained rendering can always be applied to
@@ -31,32 +52,53 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
3152
ContainerLayer* container = GetChildContainer();
3253
FML_DCHECK(!container->layers().empty()); // OpacityLayer can't be a leaf.
3354

55+
// Factor in the offset during Preroll. |OpacityLayerBase| will handle the
56+
// opacity.
3457
SkMatrix child_matrix = matrix;
3558
child_matrix.postTranslate(offset_.fX, offset_.fY);
3659
context->mutators_stack.PushTransform(
3760
SkMatrix::MakeTrans(offset_.fX, offset_.fY));
38-
context->mutators_stack.PushOpacity(alpha_);
39-
ContainerLayer::Preroll(context, child_matrix);
40-
context->mutators_stack.Pop();
61+
OpacityLayerBase::Preroll(context, child_matrix);
4162
context->mutators_stack.Pop();
42-
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
4363

44-
if (!context->has_platform_view && context->raster_cache &&
45-
SkRect::Intersects(context->cull_rect, paint_bounds())) {
46-
SkMatrix ctm = child_matrix;
64+
// When using the system compositor, do not include the offset since we are
65+
// rendering as a separate piece of geometry and the offset will be baked into
66+
// that geometry's transform.
67+
if (OpacityLayerBase::can_system_composite()) {
68+
set_dimensions(SkRRect::MakeRect(paint_bounds()));
69+
set_needs_system_composite(true);
70+
} else {
71+
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
72+
73+
if (!context->has_platform_view && context->raster_cache &&
74+
SkRect::Intersects(context->cull_rect, paint_bounds())) {
75+
SkMatrix ctm = child_matrix;
4776
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
48-
ctm = RasterCache::GetIntegralTransCTM(ctm);
77+
ctm = RasterCache::GetIntegralTransCTM(ctm);
4978
#endif
50-
context->raster_cache->Prepare(context, container, ctm);
79+
context->raster_cache->Prepare(context, container, ctm);
80+
}
5181
}
5282
}
5383

84+
#if defined(OS_FUCHSIA)
85+
86+
void OpacityLayer::UpdateScene(SceneUpdateContext& context) {
87+
SceneUpdateContext::Transform transform(
88+
context, SkMatrix::MakeTrans(offset_.fX, offset_.fY));
89+
90+
// OpacityLayerBase will handle applying the opacity itself.
91+
OpacityLayerBase::UpdateScene(context);
92+
}
93+
94+
#endif
95+
5496
void OpacityLayer::Paint(PaintContext& context) const {
5597
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
5698
FML_DCHECK(needs_painting());
5799

58100
SkPaint paint;
59-
paint.setAlpha(alpha_);
101+
paint.setAlpha(opacity());
60102

61103
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
62104
context.internal_nodes_canvas->translate(offset_.fX, offset_.fY);
@@ -83,16 +125,15 @@ void OpacityLayer::Paint(PaintContext& context) const {
83125
// RasterCache::GetIntegralTransCTM optimization.
84126
//
85127
// Note that the following lines are only accessible when the raster cache is
86-
// not available (e.g., when we're using the software backend in golden
87-
// tests).
128+
// not available, or when a cache miss occurs.
88129
SkRect saveLayerBounds;
89130
paint_bounds()
90131
.makeOffset(-offset_.fX, -offset_.fY)
91132
.roundOut(&saveLayerBounds);
92133

93134
Layer::AutoSaveLayer save_layer =
94135
Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint);
95-
PaintChildren(context);
136+
OpacityLayerBase::Paint(context);
96137
}
97138

98139
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+
class OpacityLayerBase : public ContainerLayer {
17+
public:
18+
static bool can_system_composite() { return false; }
19+
20+
OpacityLayerBase(SkColor color, SkAlpha opacity, float elevation)
21+
: color_(color), opacity_(opacity) {}
22+
23+
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
24+
25+
void set_dimensions(SkRRect rrect) {}
26+
27+
SkColor color() const { return color_; }
28+
SkAlpha opacity() const { return opacity_; }
29+
float elevation() const { return 0; }
30+
31+
private:
32+
SkColor color_;
33+
SkAlpha opacity_;
34+
};
35+
#else
36+
using OpacityLayerBase = FuchsiaSystemCompositedLayer;
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,
1542
// |Preroll| 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,21 +52,19 @@ 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

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

3259
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
33-
60+
#if defined(OS_FUCHSIA)
61+
void UpdateScene(SceneUpdateContext& context) override;
62+
#endif
3463
void Paint(PaintContext& context) const override;
3564

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

42-
int alpha_;
4368
SkPoint offset_;
4469

4570
FML_DISALLOW_COPY_AND_ASSIGN(OpacityLayer);

flow/layers/physical_shape_layer.cc

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ PhysicalShapeLayer::PhysicalShapeLayer(SkColor color,
1717
float elevation,
1818
const SkPath& path,
1919
Clip clip_behavior)
20-
: PhysicalShapeLayerBase(color, elevation),
20+
: PhysicalShapeLayerBase(color, SK_AlphaOPAQUE, elevation),
2121
shadow_color_(shadow_color),
2222
path_(path),
2323
isRect_(false),
@@ -58,53 +58,15 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context,
5858
set_needs_system_composite(true);
5959
return;
6060
}
61-
//#if defined(OS_FUCHSIA)
62-
// // Let the system compositor draw all shadows for us.
63-
// set_needs_system_composite(true);
64-
//#else
61+
6562
// We will draw the shadow in Paint(), so add some margin to the paint
6663
// bounds to leave space for the shadow. We fill this whole region and clip
6764
// children to it so we don't need to join the child paint bounds.
6865
set_paint_bounds(ComputeShadowBounds(path_.getBounds(), elevation(),
6966
context->frame_device_pixel_ratio));
70-
//#endif // defined(OS_FUCHSIA)
7167
}
7268
}
7369

74-
#if defined(OS_FUCHSIA)
75-
76-
void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) {
77-
FML_DCHECK(needs_system_composite());
78-
TRACE_EVENT0("flutter", "PhysicalShapeLayer::UpdateScene");
79-
80-
// Retained rendering: speedup by reusing a retained entity node if possible.
81-
// When an entity node is reused, no paint layer is added to the frame so we
82-
// won't call PhysicalShapeLayer::Paint.
83-
LayerRasterCacheKey key(unique_id(), context.Matrix());
84-
if (context.HasRetainedNode(key)) {
85-
TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit");
86-
const scenic::EntityNode& retained_node = context.GetRetainedNode(key);
87-
FML_DCHECK(context.top_entity());
88-
FML_DCHECK(retained_node.session() == context.session());
89-
context.top_entity()->entity_node().AddChild(retained_node);
90-
return;
91-
}
92-
93-
TRACE_EVENT_INSTANT0("flutter", "cache miss, creating");
94-
// If we can't find an existing retained surface, create one.
95-
SceneUpdateContext::Frame frame(context, frameRRect_, color(), elevation(),
96-
this);
97-
for (auto& layer : layers()) {
98-
if (layer->needs_painting()) {
99-
frame.AddPaintLayer(layer.get());
100-
}
101-
}
102-
103-
UpdateSceneChildren(context);
104-
}
105-
106-
#endif // defined(OS_FUCHSIA)
107-
10870
void PhysicalShapeLayer::Paint(PaintContext& context) const {
10971
TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint");
11072
FML_DCHECK(needs_painting());

0 commit comments

Comments
 (0)