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

Commit 3d9bfe3

Browse files
committed
Enhance image_filter_layer caching to filter a cached child
1 parent bb6c9a3 commit 3d9bfe3

File tree

7 files changed

+93
-43
lines changed

7 files changed

+93
-43
lines changed

flow/layers/container_layer.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,36 @@ void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) {
8585

8686
#endif // defined(OS_FUCHSIA)
8787

88+
MergedContainerLayer::MergedContainerLayer() {
89+
// Ensure the layer has only one direct child.
90+
//
91+
// This intermediary container helps container layers that want or need
92+
// to cache the rendering of their children to do so more easily.
93+
// TBD (flar) - mention caveat and use of GetCacheableChild() here...
94+
//
95+
// Any children will be actually added as children of this empty
96+
// ContainerLayer.
97+
ContainerLayer::Add(std::make_shared<ContainerLayer>());
98+
}
99+
100+
void MergedContainerLayer::Add(std::shared_ptr<Layer> layer) {
101+
GetChildContainer()->Add(std::move(layer));
102+
}
103+
104+
ContainerLayer* MergedContainerLayer::GetChildContainer() const {
105+
FML_DCHECK(layers().size() == 1);
106+
107+
return static_cast<ContainerLayer*>(layers()[0].get());
108+
}
109+
110+
Layer* MergedContainerLayer::GetCacheableChild() const {
111+
ContainerLayer* child_container = GetChildContainer();
112+
if (child_container->layers().size() == 1) {
113+
return child_container->layers()[0].get();
114+
}
115+
116+
FML_LOG(INFO) << "Single child layer does not contain a single child";
117+
return child_container;
118+
}
119+
88120
} // namespace flutter

flow/layers/container_layer.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,33 @@ class ContainerLayer : public Layer {
3434
void UpdateSceneChildren(SceneUpdateContext& context);
3535
#endif // defined(OS_FUCHSIA)
3636

37-
// For OpacityLayer to restructure to have a single child.
38-
void ClearChildren() { layers_.clear(); }
39-
4037
private:
4138
std::vector<std::shared_ptr<Layer>> layers_;
4239

4340
FML_DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
4441
};
4542

43+
class MergedContainerLayer : public ContainerLayer {
44+
public:
45+
MergedContainerLayer();
46+
47+
void Add(std::shared_ptr<Layer> layer) override;
48+
49+
protected:
50+
ContainerLayer* GetChildContainer() const;
51+
52+
// The ChildContainer will be created anew whenever the MergedContainerLayer
53+
// subclass is created even though the real child of the container may be
54+
// the same child. If the MergedContainerLayer wants to cache the rendering
55+
// of its "child" then the cache will need to be redrawn on every frame that
56+
// the MergedContainer is different, defeating the purpose of caching. This
57+
// method will attempt to return the real child (if there is only one) to
58+
// improve the chance of caching.
59+
Layer* GetCacheableChild() const;
60+
61+
FML_DISALLOW_COPY_AND_ASSIGN(MergedContainerLayer);
62+
};
63+
4664
} // namespace flutter
4765

4866
#endif // FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_

flow/layers/image_filter_layer.cc

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
namespace flutter {
88

9+
#define MINIMUM_FILTER_CACHE 2
10+
911
ImageFilterLayer::ImageFilterLayer(sk_sp<SkImageFilter> filter)
10-
: filter_(std::move(filter)) {}
12+
: filter_(std::move(filter)), render_count_(1) {}
1113

1214
void ImageFilterLayer::Preroll(PrerollContext* context,
1315
const SkMatrix& matrix) {
@@ -16,25 +18,29 @@ void ImageFilterLayer::Preroll(PrerollContext* context,
1618
Layer::AutoPrerollSaveLayerState save =
1719
Layer::AutoPrerollSaveLayerState::Create(context);
1820

19-
child_paint_bounds_ = SkRect::MakeEmpty();
20-
PrerollChildren(context, matrix, &child_paint_bounds_);
21+
SkRect child_bounds = SkRect::MakeEmpty();
22+
PrerollChildren(context, matrix, &child_bounds);
2123
if (filter_) {
22-
const SkIRect filter_input_bounds = child_paint_bounds_.roundOut();
24+
const SkIRect filter_input_bounds = child_bounds.roundOut();
2325
SkIRect filter_output_bounds =
2426
filter_->filterBounds(filter_input_bounds, SkMatrix::I(),
2527
SkImageFilter::kForward_MapDirection);
26-
set_paint_bounds(SkRect::Make(filter_output_bounds));
27-
} else {
28-
set_paint_bounds(child_paint_bounds_);
28+
child_bounds = SkRect::Make(filter_output_bounds);
2929
}
30+
set_paint_bounds(child_bounds);
3031

3132
if (!context->has_platform_view && context->raster_cache &&
3233
SkRect::Intersects(context->cull_rect, paint_bounds())) {
3334
SkMatrix ctm = matrix;
3435
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
3536
ctm = RasterCache::GetIntegralTransCTM(ctm);
3637
#endif
37-
context->raster_cache->Prepare(context, this, ctm);
38+
if (render_count_ >= MINIMUM_FILTER_CACHE) {
39+
context->raster_cache->Prepare(context, this, ctm);
40+
} else {
41+
render_count_++;
42+
context->raster_cache->Prepare(context, GetCacheableChild(), ctm);
43+
}
3844
}
3945
}
4046

@@ -53,20 +59,36 @@ void ImageFilterLayer::Paint(PaintContext& context) const {
5359
RasterCacheResult layer_cache =
5460
context.raster_cache->Get((Layer*)this, ctm);
5561
if (layer_cache.is_valid()) {
62+
FML_LOG(ERROR) << "Rendering filtered output from cache";
5663
layer_cache.draw(*context.leaf_nodes_canvas);
5764
return;
5865
}
66+
layer_cache = context.raster_cache->Get(GetCacheableChild(), ctm);
67+
if (layer_cache.is_valid()) {
68+
sk_sp<SkImageFilter> transformed_filter =
69+
filter_->makeWithLocalMatrix(ctm);
70+
if (transformed_filter) {
71+
FML_LOG(ERROR) << "Filtering from cached child";
72+
73+
SkPaint paint;
74+
paint.setImageFilter(transformed_filter);
75+
76+
layer_cache.draw(*context.leaf_nodes_canvas, &paint);
77+
return;
78+
}
79+
}
5980
}
6081

82+
FML_LOG(ERROR) << "Applying filter to child on the fly";
6183
SkPaint paint;
6284
paint.setImageFilter(filter_);
6385

6486
// Normally a save_layer is sized to the current layer bounds, but in this
6587
// case the bounds of the child may not be the same as the filtered version
6688
// so we use the child_paint_bounds_ which were snapshotted from the
6789
// Preroll on the children before we adjusted them based on the filter.
68-
Layer::AutoSaveLayer save_layer =
69-
Layer::AutoSaveLayer::Create(context, child_paint_bounds_, &paint);
90+
Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create(
91+
context, GetChildContainer()->paint_bounds(), &paint);
7092
PaintChildren(context);
7193
}
7294

flow/layers/image_filter_layer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace flutter {
1313

14-
class ImageFilterLayer : public ContainerLayer {
14+
class ImageFilterLayer : public MergedContainerLayer {
1515
public:
1616
ImageFilterLayer(sk_sp<SkImageFilter> filter);
1717

@@ -21,7 +21,7 @@ class ImageFilterLayer : public ContainerLayer {
2121

2222
private:
2323
sk_sp<SkImageFilter> filter_;
24-
SkRect child_paint_bounds_;
24+
int render_count_;
2525

2626
FML_DISALLOW_COPY_AND_ASSIGN(ImageFilterLayer);
2727
};

flow/layers/opacity_layer.cc

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,7 @@ namespace flutter {
1515
constexpr float kOpacityElevationWhenUsingSystemCompositor = 0.01f;
1616

1717
OpacityLayer::OpacityLayer(SkAlpha alpha, const SkPoint& offset)
18-
: alpha_(alpha), offset_(offset) {
19-
// Ensure OpacityLayer has only one direct child.
20-
//
21-
// This is needed to ensure that retained rendering can always be applied to
22-
// save the costly saveLayer.
23-
//
24-
// Any children will be actually added as children of this empty
25-
// ContainerLayer.
26-
ContainerLayer::Add(std::make_shared<ContainerLayer>());
27-
}
28-
29-
void OpacityLayer::Add(std::shared_ptr<Layer> layer) {
30-
GetChildContainer()->Add(std::move(layer));
31-
}
18+
: alpha_(alpha), offset_(offset) {}
3219

3320
void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
3421
TRACE_EVENT0("flutter", "OpacityLayer::Preroll");
@@ -71,7 +58,7 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
7158
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
7259
ctm = RasterCache::GetIntegralTransCTM(ctm);
7360
#endif
74-
context->raster_cache->Prepare(context, container, ctm);
61+
context->raster_cache->Prepare(context, GetCacheableChild(), ctm);
7562
}
7663
}
7764
}
@@ -92,9 +79,9 @@ void OpacityLayer::Paint(PaintContext& context) const {
9279
#endif
9380

9481
if (context.raster_cache) {
95-
ContainerLayer* container = GetChildContainer();
82+
Layer* layer = GetCacheableChild();
9683
const SkMatrix& ctm = context.leaf_nodes_canvas->getTotalMatrix();
97-
RasterCacheResult child_cache = context.raster_cache->Get(container, ctm);
84+
RasterCacheResult child_cache = context.raster_cache->Get(layer, ctm);
9885
if (child_cache.is_valid()) {
9986
child_cache.draw(*context.leaf_nodes_canvas, &paint);
10087
return;
@@ -157,10 +144,4 @@ void OpacityLayer::UpdateScene(SceneUpdateContext& context) {
157144

158145
#endif // defined(OS_FUCHSIA)
159146

160-
ContainerLayer* OpacityLayer::GetChildContainer() const {
161-
FML_DCHECK(layers().size() == 1);
162-
163-
return static_cast<ContainerLayer*>(layers()[0].get());
164-
}
165-
166147
} // namespace flutter

flow/layers/opacity_layer.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace flutter {
1313
// OpacityLayer is very costly due to the saveLayer call. If there's no child,
1414
// having the OpacityLayer or not has the same effect. In debug_unopt build,
1515
// |Preroll| will assert if there are no children.
16-
class OpacityLayer : public ContainerLayer {
16+
class OpacityLayer : public MergedContainerLayer {
1717
public:
1818
// An offset is provided here because OpacityLayer.addToScene method in the
1919
// Flutter framework can take an optional offset argument.
@@ -27,8 +27,6 @@ class OpacityLayer : public ContainerLayer {
2727
// the propagation as repainting the OpacityLayer is expensive.
2828
OpacityLayer(SkAlpha alpha, const SkPoint& offset);
2929

30-
void Add(std::shared_ptr<Layer> layer) override;
31-
3230
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
3331

3432
void Paint(PaintContext& context) const override;
@@ -38,8 +36,6 @@ class OpacityLayer : public ContainerLayer {
3836
#endif // defined(OS_FUCHSIA)
3937

4038
private:
41-
ContainerLayer* GetChildContainer() const;
42-
4339
SkAlpha alpha_;
4440
SkPoint offset_;
4541
SkRRect frameRRect_;

flow/raster_cache.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ void RasterCache::Prepare(PrerollContext* context,
137137
entry.access_count++;
138138
entry.used_this_frame = true;
139139
if (!entry.image.is_valid()) {
140+
FML_LOG(ERROR) << "Rasterizing " << layer->unique_id();
140141
entry.image = Rasterize(
141142
context->gr_context, ctm, context->dst_color_space,
142143
checkerboard_images_, layer->paint_bounds(),

0 commit comments

Comments
 (0)