[Impeller] add mechanism for sharing bdf inputs. (#55701)
Introduces a mechanism to allow backdrop filters to 1) share backdrop inputs and 2) fuse filter applications for faster blurs.
This is a proposed solution to https://github.com/flutter/flutter/issues/131568
Implemented:
* Developer can specify a "backdrop id" which indicates that a backdrop layer should share the input texture and potentially cached filter for a layer.
* Removes second save layer for each backdrop filter
* Removes save layer trace event for backdrop filter
* Can fuse backdrop filters if there is more than one identical filter
TBD:
* Adjust heruristic to avoid applying bdf filter to entire screen
Suggestions: applying a bdf should be a distinct operation from a save layer in the DL builder/dispatcher. The saveLayer implmenentation in the impeller dispatcher is super convoluted because it needs to handle both.
### Video
Video starts with normal bdf then I hot reload to specify that the bdfs share inputs/filters. This is running on a pixel 8 pro
Change to the macrobenchmark app is just:
```dart
Widget build(BuildContext context) {
Widget addBlur(Widget child, bool shouldBlur) {
if (shouldBlur) {
return ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
backdropId: 1, // Added ID
child: child,
),
);
} else {
return child;
}
}
```
https://github.com/user-attachments/assets/22707f97-5825-43f1-91b4-1a02a43437f5
Requires framework changes in https://github.com/jonahwilliams/flutter/pull/new/backdrop_iddiff --git a/display_list/benchmarking/dl_complexity_gl.cc b/display_list/benchmarking/dl_complexity_gl.cc
index 44f658b..5da3703 100644
--- a/display_list/benchmarking/dl_complexity_gl.cc
+++ b/display_list/benchmarking/dl_complexity_gl.cc
@@ -51,7 +51,8 @@
void DisplayListGLComplexityCalculator::GLHelper::saveLayer(
const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
if (IsComplex()) {
return;
}
@@ -627,7 +628,8 @@
GLHelper helper(Ceiling() - CurrentComplexityScore());
if (opacity < SK_Scalar1 && !display_list->can_apply_group_opacity()) {
auto bounds = display_list->GetBounds();
- helper.saveLayer(bounds, SaveLayerOptions::kWithAttributes, nullptr);
+ helper.saveLayer(bounds, SaveLayerOptions::kWithAttributes, nullptr,
+ /*backdrop_id=*/-1);
}
display_list->Dispatch(helper);
AccumulateComplexity(helper.ComplexityScore());
diff --git a/display_list/benchmarking/dl_complexity_gl.h b/display_list/benchmarking/dl_complexity_gl.h
index d0fcbb9..3041f90 100644
--- a/display_list/benchmarking/dl_complexity_gl.h
+++ b/display_list/benchmarking/dl_complexity_gl.h
@@ -37,7 +37,8 @@
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override;
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
void drawLine(const DlPoint& p0, const DlPoint& p1) override;
void drawDashedLine(const DlPoint& p0,
diff --git a/display_list/benchmarking/dl_complexity_metal.cc b/display_list/benchmarking/dl_complexity_metal.cc
index 82f641e..25fa25a 100644
--- a/display_list/benchmarking/dl_complexity_metal.cc
+++ b/display_list/benchmarking/dl_complexity_metal.cc
@@ -65,7 +65,8 @@
void DisplayListMetalComplexityCalculator::MetalHelper::saveLayer(
const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
if (IsComplex()) {
return;
}
@@ -571,7 +572,8 @@
MetalHelper helper(Ceiling() - CurrentComplexityScore());
if (opacity < SK_Scalar1 && !display_list->can_apply_group_opacity()) {
auto bounds = display_list->GetBounds();
- helper.saveLayer(bounds, SaveLayerOptions::kWithAttributes, nullptr);
+ helper.saveLayer(bounds, SaveLayerOptions::kWithAttributes, nullptr,
+ /*backdrop_id=*/-1);
}
display_list->Dispatch(helper);
AccumulateComplexity(helper.ComplexityScore());
diff --git a/display_list/benchmarking/dl_complexity_metal.h b/display_list/benchmarking/dl_complexity_metal.h
index d11d0ff..79dd5c3 100644
--- a/display_list/benchmarking/dl_complexity_metal.h
+++ b/display_list/benchmarking/dl_complexity_metal.h
@@ -37,7 +37,8 @@
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override;
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
void drawLine(const DlPoint& p0, const DlPoint& p1) override;
void drawDashedLine(const DlPoint& p0,
diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc
index 0477bf2..524a5aa 100644
--- a/display_list/display_list_unittests.cc
+++ b/display_list/display_list_unittests.cc
@@ -1483,7 +1483,8 @@
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
FML_UNREACHABLE();
}
@@ -1491,7 +1492,8 @@
const SaveLayerOptions& options,
uint32_t total_content_depth,
DlBlendMode max_content_blend_mode,
- const DlImageFilter* backdrop = nullptr) {
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) {
ASSERT_LT(save_layer_count_, expected_.size()) << label();
auto expect = expected_[save_layer_count_];
if (expect.options.has_value()) {
@@ -3666,7 +3668,8 @@
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
ASSERT_LT(save_layer_count_, expected_.size());
auto expected = expected_[save_layer_count_];
EXPECT_EQ(options.bounds_from_caller(),
@@ -4131,7 +4134,8 @@
void saveLayer(const DlRect& bounds,
SaveLayerOptions options,
- const DlImageFilter* backdrop) override {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
// This method should not be called since we override the variant with
// the total_content_depth parameter.
FAIL() << "saveLayer(no depth parameter) method should not be called";
@@ -4141,7 +4145,8 @@
const SaveLayerOptions& options,
uint32_t total_content_depth,
DlBlendMode max_content_mode,
- const DlImageFilter* backdrop) override {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
ASSERT_LT(index_, depth_expectations_.size());
EXPECT_EQ(depth_expectations_[index_], total_content_depth)
<< "at index " << index_;
diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc
index 7db556f..39953df 100644
--- a/display_list/dl_builder.cc
+++ b/display_list/dl_builder.cc
@@ -409,7 +409,8 @@
void DisplayListBuilder::saveLayer(const DlRect& bounds,
const SaveLayerOptions in_options,
- const DlImageFilter* backdrop) {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
SaveLayerOptions options = in_options.without_optimizations();
DisplayListAttributeFlags flags = options.renders_with_attributes()
? kSaveLayerWithPaintFlags
@@ -524,7 +525,8 @@
}
if (backdrop) {
- Push<SaveLayerBackdropOp>(0, options, record_bounds, backdrop);
+ Push<SaveLayerBackdropOp>(0, options, record_bounds, backdrop,
+ backdrop_id);
} else {
Push<SaveLayerOp>(0, options, record_bounds);
}
@@ -542,7 +544,8 @@
}
void DisplayListBuilder::SaveLayer(std::optional<const DlRect>& bounds,
const DlPaint* paint,
- const DlImageFilter* backdrop) {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
SaveLayerOptions options;
DlRect temp_bounds;
if (bounds.has_value()) {
@@ -556,7 +559,7 @@
SetAttributesFromPaint(*paint,
DisplayListOpFlags::kSaveLayerWithPaintFlags);
}
- saveLayer(temp_bounds, options, backdrop);
+ saveLayer(temp_bounds, options, backdrop, backdrop_id);
}
void DisplayListBuilder::Restore() {
diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h
index c7ac969..58d343d 100644
--- a/display_list/dl_builder.h
+++ b/display_list/dl_builder.h
@@ -54,7 +54,8 @@
// |DlCanvas|
void SaveLayer(std::optional<const DlRect>& bounds,
const DlPaint* paint = nullptr,
- const DlImageFilter* backdrop = nullptr) override;
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) override;
// |DlCanvas|
void Restore() override;
// |DlCanvas|
@@ -354,7 +355,8 @@
// |DlOpReceiver|
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override;
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
// |DlOpReceiver|
void restore() override { Restore(); }
diff --git a/display_list/dl_canvas.h b/display_list/dl_canvas.h
index ff0ea7e..80076fc 100644
--- a/display_list/dl_canvas.h
+++ b/display_list/dl_canvas.h
@@ -62,7 +62,8 @@
virtual void Save() = 0;
virtual void SaveLayer(std::optional<const DlRect>& bounds,
const DlPaint* paint = nullptr,
- const DlImageFilter* backdrop = nullptr) = 0;
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) = 0;
virtual void Restore() = 0;
virtual int GetSaveCount() const = 0;
virtual void RestoreToCount(int restore_count) = 0;
@@ -233,9 +234,10 @@
void SaveLayer(const SkRect* bounds,
const DlPaint* paint = nullptr,
- const DlImageFilter* backdrop = nullptr) {
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) {
auto optional_bounds = ToOptDlRect(bounds);
- SaveLayer(optional_bounds, paint, backdrop);
+ SaveLayer(optional_bounds, paint, backdrop, backdrop_id);
}
void Transform(const SkMatrix* matrix) {
diff --git a/display_list/dl_op_receiver.h b/display_list/dl_op_receiver.h
index 091ed6f..79d5d28 100644
--- a/display_list/dl_op_receiver.h
+++ b/display_list/dl_op_receiver.h
@@ -17,8 +17,6 @@
#include "flutter/display_list/effects/dl_mask_filter.h"
#include "flutter/display_list/image/dl_image.h"
-#include "flutter/impeller/geometry/path.h"
-
namespace flutter {
class DisplayList;
@@ -143,15 +141,17 @@
// layer before further rendering happens.
virtual void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop = nullptr) = 0;
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) = 0;
// Optional variant of saveLayer() that passes the total depth count of
// all rendering operations that occur until the next restore() call.
virtual void saveLayer(const DlRect& bounds,
const SaveLayerOptions& options,
uint32_t total_content_depth,
DlBlendMode max_content_blend_mode,
- const DlImageFilter* backdrop = nullptr) {
- saveLayer(bounds, options, backdrop);
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) {
+ saveLayer(bounds, options, backdrop, backdrop_id);
}
virtual void restore() = 0;
@@ -170,13 +170,17 @@
// public DisplayListBuilder/DlCanvas public interfaces where possible,
// as tracked in:
// https://github.com/flutter/flutter/issues/144070
- virtual void saveLayer(const DlRect* bounds,
- const SaveLayerOptions options,
- const DlImageFilter* backdrop = nullptr) final {
+ virtual void saveLayer(
+ const DlRect* bounds,
+ const SaveLayerOptions options,
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) final {
if (bounds) {
- saveLayer(*bounds, options.with_bounds_from_caller(), backdrop);
+ saveLayer(*bounds, options.with_bounds_from_caller(), backdrop,
+ backdrop_id);
} else {
- saveLayer(DlRect(), options.without_bounds_from_caller(), backdrop);
+ saveLayer(DlRect(), options.without_bounds_from_caller(), backdrop,
+ backdrop_id);
}
}
// ---------------------------------------------------------------------
diff --git a/display_list/dl_op_records.h b/display_list/dl_op_records.h
index 592c31e..189038b 100644
--- a/display_list/dl_op_records.h
+++ b/display_list/dl_op_records.h
@@ -310,19 +310,24 @@
SaveLayerBackdropOp(const SaveLayerOptions& options,
const DlRect& rect,
- const DlImageFilter* backdrop)
- : SaveLayerOpBase(options, rect), backdrop(backdrop->shared()) {}
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id)
+ : SaveLayerOpBase(options, rect),
+ backdrop(backdrop->shared()),
+ backdrop_id_(backdrop_id) {}
const std::shared_ptr<DlImageFilter> backdrop;
+ std::optional<int64_t> backdrop_id_;
void dispatch(DlOpReceiver& receiver) const {
receiver.saveLayer(rect, options, total_content_depth, max_blend_mode,
- backdrop.get());
+ backdrop.get(), backdrop_id_);
}
DisplayListCompare equals(const SaveLayerBackdropOp* other) const {
return (options == other->options && rect == other->rect &&
- Equals(backdrop, other->backdrop))
+ Equals(backdrop, other->backdrop) &&
+ backdrop_id_ == other->backdrop_id_)
? DisplayListCompare::kEqual
: DisplayListCompare::kNotEqual;
}
diff --git a/display_list/effects/dl_image_filter.h b/display_list/effects/dl_image_filter.h
index f98010f..1e6b015 100644
--- a/display_list/effects/dl_image_filter.h
+++ b/display_list/effects/dl_image_filter.h
@@ -281,7 +281,8 @@
bool equals_(const DlImageFilter& other) const override {
FML_DCHECK(other.type() == DlImageFilterType::kBlur);
auto that = static_cast<const DlBlurImageFilter*>(&other);
- return (sigma_x_ == that->sigma_x_ && sigma_y_ == that->sigma_y_ &&
+ return (SkScalarNearlyEqual(sigma_x_, that->sigma_x_) &&
+ SkScalarNearlyEqual(sigma_y_, that->sigma_y_) &&
tile_mode_ == that->tile_mode_);
}
diff --git a/display_list/skia/dl_sk_canvas.cc b/display_list/skia/dl_sk_canvas.cc
index 8b19d74..a190519 100644
--- a/display_list/skia/dl_sk_canvas.cc
+++ b/display_list/skia/dl_sk_canvas.cc
@@ -54,7 +54,8 @@
void DlSkCanvasAdapter::SaveLayer(std::optional<const DlRect>& bounds,
const DlPaint* paint,
- const DlImageFilter* backdrop) {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
sk_sp<SkImageFilter> sk_backdrop = ToSk(backdrop);
SkOptionalPaint sk_paint(paint);
TRACE_EVENT0("flutter", "Canvas::saveLayer");
diff --git a/display_list/skia/dl_sk_canvas.h b/display_list/skia/dl_sk_canvas.h
index 804752c..7047f41 100644
--- a/display_list/skia/dl_sk_canvas.h
+++ b/display_list/skia/dl_sk_canvas.h
@@ -32,7 +32,8 @@
void Save() override;
void SaveLayer(std::optional<const DlRect>& bounds,
const DlPaint* paint = nullptr,
- const DlImageFilter* backdrop = nullptr) override;
+ const DlImageFilter* backdrop = nullptr,
+ std::optional<int64_t> backdrop_id = std::nullopt) override;
void Restore() override;
int GetSaveCount() const override;
void RestoreToCount(int restore_count) override;
diff --git a/display_list/skia/dl_sk_dispatcher.cc b/display_list/skia/dl_sk_dispatcher.cc
index 33b1116..45066eb 100644
--- a/display_list/skia/dl_sk_dispatcher.cc
+++ b/display_list/skia/dl_sk_dispatcher.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "flutter/display_list/skia/dl_sk_dispatcher.h"
+#include <cstdint>
#include "flutter/display_list/dl_blend_mode.h"
#include "flutter/display_list/skia/dl_sk_conversions.h"
@@ -46,7 +47,8 @@
}
void DlSkCanvasDispatcher::saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
if (!options.content_is_clipped() && options.can_distribute_opacity() &&
backdrop == nullptr) {
// We know that:
diff --git a/display_list/skia/dl_sk_dispatcher.h b/display_list/skia/dl_sk_dispatcher.h
index fa5fbdd..1455479 100644
--- a/display_list/skia/dl_sk_dispatcher.h
+++ b/display_list/skia/dl_sk_dispatcher.h
@@ -31,7 +31,8 @@
void restore() override;
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override;
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
void translate(DlScalar tx, DlScalar ty) override;
void scale(DlScalar sx, DlScalar sy) override;
diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc
index 05ca54d..64ce2a0 100644
--- a/display_list/testing/dl_test_snippets.cc
+++ b/display_list/testing/dl_test_snippets.cc
@@ -327,7 +327,7 @@
r.drawRect(DlRect::MakeLTRB(10, 10, 20, 20));
r.restore();
}},
- {5, 136, 3,
+ {5, 152, 3,
[](DlOpReceiver& r) {
r.saveLayer(nullptr, SaveLayerOptions::kNoAttributes,
&kTestCFImageFilter1);
@@ -337,7 +337,7 @@
r.drawRect(DlRect::MakeLTRB(10, 10, 20, 20));
r.restore();
}},
- {5, 136, 3,
+ {5, 152, 3,
[](DlOpReceiver& r) {
r.saveLayer(nullptr, SaveLayerOptions::kWithAttributes,
&kTestCFImageFilter1);
@@ -347,7 +347,7 @@
r.drawRect(DlRect::MakeLTRB(10, 10, 20, 20));
r.restore();
}},
- {5, 136, 3,
+ {5, 152, 3,
[](DlOpReceiver& r) {
r.saveLayer(&kTestBounds, SaveLayerOptions::kNoAttributes,
&kTestCFImageFilter1);
@@ -357,7 +357,7 @@
r.drawRect(DlRect::MakeLTRB(10, 10, 20, 20));
r.restore();
}},
- {5, 136, 3,
+ {5, 152, 3,
[](DlOpReceiver& r) {
r.saveLayer(&kTestBounds, SaveLayerOptions::kWithAttributes,
&kTestCFImageFilter1);
diff --git a/display_list/utils/dl_receiver_utils.h b/display_list/utils/dl_receiver_utils.h
index 257d276..fccc04c 100644
--- a/display_list/utils/dl_receiver_utils.h
+++ b/display_list/utils/dl_receiver_utils.h
@@ -82,7 +82,8 @@
void save() override {}
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override {}
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {}
void restore() override {}
void drawColor(DlColor color, DlBlendMode mode) override {}
void drawPaint() override {}
diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc
index 32707c4..aec04ba 100644
--- a/flow/layers/backdrop_filter_layer.cc
+++ b/flow/layers/backdrop_filter_layer.cc
@@ -8,8 +8,11 @@
BackdropFilterLayer::BackdropFilterLayer(
std::shared_ptr<const DlImageFilter> filter,
- DlBlendMode blend_mode)
- : filter_(std::move(filter)), blend_mode_(blend_mode) {}
+ DlBlendMode blend_mode,
+ std::optional<int64_t> backdrop_id)
+ : filter_(std::move(filter)),
+ blend_mode_(blend_mode),
+ backdrop_id_(backdrop_id) {}
void BackdropFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
DiffContext::AutoSubtreeRestore subtree(context);
@@ -57,7 +60,8 @@
FML_DCHECK(needs_painting(context));
auto mutator = context.state_stack.save();
- mutator.applyBackdropFilter(paint_bounds(), filter_, blend_mode_);
+ mutator.applyBackdropFilter(paint_bounds(), filter_, blend_mode_,
+ backdrop_id_);
PaintChildren(context);
}
diff --git a/flow/layers/backdrop_filter_layer.h b/flow/layers/backdrop_filter_layer.h
index d17fed1..180c5a6 100644
--- a/flow/layers/backdrop_filter_layer.h
+++ b/flow/layers/backdrop_filter_layer.h
@@ -13,7 +13,8 @@
class BackdropFilterLayer : public ContainerLayer {
public:
BackdropFilterLayer(std::shared_ptr<const DlImageFilter> filter,
- DlBlendMode blend_mode);
+ DlBlendMode blend_mode,
+ std::optional<int64_t> backdrop_id = std::nullopt);
void Diff(DiffContext* context, const Layer* old_layer) override;
@@ -24,6 +25,7 @@
private:
std::shared_ptr<const DlImageFilter> filter_;
DlBlendMode blend_mode_;
+ std::optional<int64_t> backdrop_id_;
FML_DISALLOW_COPY_AND_ASSIGN(BackdropFilterLayer);
};
diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc
index a3908df..15cf795 100644
--- a/flow/layers/layer_state_stack.cc
+++ b/flow/layers/layer_state_stack.cc
@@ -52,7 +52,8 @@
void saveLayer(const SkRect& bounds,
LayerStateStack::RenderingAttributes& attributes,
DlBlendMode blend,
- const DlImageFilter* backdrop) override {}
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {}
void restore() override {}
void translate(SkScalar tx, SkScalar ty) override {}
@@ -99,10 +100,13 @@
void saveLayer(const SkRect& bounds,
LayerStateStack::RenderingAttributes& attributes,
DlBlendMode blend_mode,
- const DlImageFilter* backdrop) override {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
TRACE_EVENT0("flutter", "Canvas::saveLayer");
DlPaint paint;
- canvas_->SaveLayer(&bounds, attributes.fill(paint, blend_mode), backdrop);
+ std::optional<const DlRect> rect = ToDlRect(bounds);
+ canvas_->SaveLayer(rect, attributes.fill(paint, blend_mode), backdrop,
+ backdrop_id);
}
void restore() override { canvas_->Restore(); }
@@ -157,7 +161,8 @@
void saveLayer(const SkRect& bounds,
LayerStateStack::RenderingAttributes& attributes,
DlBlendMode blend,
- const DlImageFilter* backdrop) override {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
save_stack_.emplace_back(state());
}
void restore() override { save_stack_.pop_back(); }
@@ -343,13 +348,16 @@
BackdropFilterEntry(const SkRect& bounds,
const std::shared_ptr<const DlImageFilter>& filter,
DlBlendMode blend_mode,
+ std::optional<int64_t> backdrop_id,
const LayerStateStack::RenderingAttributes& prev)
- : SaveLayerEntry(bounds, blend_mode, prev), filter_(filter) {}
+ : SaveLayerEntry(bounds, blend_mode, prev),
+ filter_(filter),
+ backdrop_id_(backdrop_id) {}
~BackdropFilterEntry() override = default;
void apply(LayerStateStack* stack) const override {
stack->delegate_->saveLayer(bounds_, stack->outstanding_, blend_mode_,
- filter_.get());
+ filter_.get(), backdrop_id_);
stack->outstanding_ = {};
}
@@ -366,6 +374,7 @@
private:
const std::shared_ptr<const DlImageFilter> filter_;
+ std::optional<int64_t> backdrop_id_;
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(BackdropFilterEntry);
};
@@ -558,8 +567,9 @@
void MutatorContext::applyBackdropFilter(
const SkRect& bounds,
const std::shared_ptr<const DlImageFilter>& filter,
- DlBlendMode blend_mode) {
- layer_state_stack_->push_backdrop(bounds, filter, blend_mode);
+ DlBlendMode blend_mode,
+ std::optional<int64_t> backdrop_id) {
+ layer_state_stack_->push_backdrop(bounds, filter, blend_mode, backdrop_id);
}
void MutatorContext::translate(SkScalar tx, SkScalar ty) {
@@ -706,9 +716,10 @@
void LayerStateStack::push_backdrop(
const SkRect& bounds,
const std::shared_ptr<const DlImageFilter>& filter,
- DlBlendMode blend_mode) {
+ DlBlendMode blend_mode,
+ std::optional<int64_t> backdrop_id) {
state_stack_.emplace_back(std::make_unique<BackdropFilterEntry>(
- bounds, filter, blend_mode, outstanding_));
+ bounds, filter, blend_mode, backdrop_id, outstanding_));
apply_last_entry();
}
diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h
index c9e606e..a5cec34 100644
--- a/flow/layers/layer_state_stack.h
+++ b/flow/layers/layer_state_stack.h
@@ -197,7 +197,8 @@
// will only see a saveLayer with the indicated blend_mode.
void applyBackdropFilter(const SkRect& bounds,
const std::shared_ptr<const DlImageFilter>& filter,
- DlBlendMode blend_mode);
+ DlBlendMode blend_mode,
+ std::optional<int64_t> backdrop_id);
void translate(SkScalar tx, SkScalar ty);
void translate(SkPoint tp) { translate(tp.fX, tp.fY); }
@@ -334,7 +335,8 @@
const std::shared_ptr<const DlImageFilter>& filter);
void push_backdrop(const SkRect& bounds,
const std::shared_ptr<const DlImageFilter>& filter,
- DlBlendMode blend_mode);
+ DlBlendMode blend_mode,
+ std::optional<int64_t> backdrop_id);
void push_translate(SkScalar tx, SkScalar ty);
void push_transform(const SkM44& matrix);
@@ -444,10 +446,12 @@
virtual bool content_culled(const SkRect& content_bounds) const = 0;
virtual void save() = 0;
- virtual void saveLayer(const SkRect& bounds,
- RenderingAttributes& attributes,
- DlBlendMode blend,
- const DlImageFilter* backdrop) = 0;
+ virtual void saveLayer(
+ const SkRect& bounds,
+ RenderingAttributes& attributes,
+ DlBlendMode blend,
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id = std::nullopt) = 0;
virtual void restore() = 0;
virtual void translate(SkScalar tx, SkScalar ty) = 0;
diff --git a/impeller/display_list/aiks_dl_blur_unittests.cc b/impeller/display_list/aiks_dl_blur_unittests.cc
index c224ac7..96f852b 100644
--- a/impeller/display_list/aiks_dl_blur_unittests.cc
+++ b/impeller/display_list/aiks_dl_blur_unittests.cc
@@ -268,6 +268,87 @@
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}
+TEST_P(AiksTest, CanRenderBackdropBlurWithSingleBackdropId) {
+ auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
+
+ DisplayListBuilder builder;
+
+ DlPaint paint;
+ builder.DrawImage(image, SkPoint::Make(50.0, 50.0),
+ DlImageSampling::kNearestNeighbor, &paint);
+
+ SkRRect rrect =
+ SkRRect::MakeRectXY(SkRect::MakeXYWH(50, 250, 100, 100), 20, 20);
+ builder.Save();
+ builder.ClipRRect(rrect);
+
+ DlPaint save_paint;
+ save_paint.setBlendMode(DlBlendMode::kSrc);
+ auto backdrop_filter = DlBlurImageFilter::Make(30, 30, DlTileMode::kClamp);
+ builder.SaveLayer(nullptr, &save_paint, backdrop_filter.get(),
+ /*backdrop_id=*/1);
+ builder.Restore();
+ builder.Restore();
+
+ ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
+}
+
+TEST_P(AiksTest, CanRenderMultipleBackdropBlurWithSingleBackdropId) {
+ auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
+
+ DisplayListBuilder builder;
+
+ DlPaint paint;
+ builder.DrawImage(image, SkPoint::Make(50.0, 50.0),
+ DlImageSampling::kNearestNeighbor, &paint);
+
+ for (int i = 0; i < 6; i++) {
+ SkRRect rrect = SkRRect::MakeRectXY(
+ SkRect::MakeXYWH(50 + (i * 100), 250, 100, 100), 20, 20);
+ builder.Save();
+ builder.ClipRRect(rrect);
+
+ DlPaint save_paint;
+ save_paint.setBlendMode(DlBlendMode::kSrc);
+ auto backdrop_filter = DlBlurImageFilter::Make(30, 30, DlTileMode::kClamp);
+ builder.SaveLayer(nullptr, &save_paint, backdrop_filter.get(),
+ /*backdrop_id=*/1);
+ builder.Restore();
+ builder.Restore();
+ }
+
+ ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
+}
+
+TEST_P(AiksTest,
+ CanRenderMultipleBackdropBlurWithSingleBackdropIdAndDistinctFilters) {
+ auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
+
+ DisplayListBuilder builder;
+
+ DlPaint paint;
+ builder.DrawImage(image, SkPoint::Make(50.0, 50.0),
+ DlImageSampling::kNearestNeighbor, &paint);
+
+ for (int i = 0; i < 6; i++) {
+ SkRRect rrect = SkRRect::MakeRectXY(
+ SkRect::MakeXYWH(50 + (i * 100), 250, 100, 100), 20, 20);
+ builder.Save();
+ builder.ClipRRect(rrect);
+
+ DlPaint save_paint;
+ save_paint.setBlendMode(DlBlendMode::kSrc);
+ auto backdrop_filter =
+ DlBlurImageFilter::Make(30 + i, 30, DlTileMode::kClamp);
+ builder.SaveLayer(nullptr, &save_paint, backdrop_filter.get(),
+ /*backdrop_id=*/1);
+ builder.Restore();
+ builder.Restore();
+ }
+
+ ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
+}
+
TEST_P(AiksTest, CanRenderBackdropBlurHugeSigma) {
DisplayListBuilder builder;
@@ -1258,5 +1339,41 @@
}
}
+TEST_P(AiksTest,
+ CanRenderMultipleBackdropBlurWithSingleBackdropIdDifferentLayers) {
+ auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
+
+ DisplayListBuilder builder;
+
+ DlPaint paint;
+ builder.DrawImage(image, SkPoint::Make(50.0, 50.0),
+ DlImageSampling::kNearestNeighbor, &paint);
+
+ for (int i = 0; i < 6; i++) {
+ if (i != 0) {
+ DlPaint paint;
+ paint.setColor(DlColor::kWhite().withAlphaF(0.95));
+ builder.SaveLayer(nullptr, &paint);
+ }
+ SkRRect rrect = SkRRect::MakeRectXY(
+ SkRect::MakeXYWH(50 + (i * 100), 250, 100, 100), 20, 20);
+ builder.Save();
+ builder.ClipRRect(rrect);
+
+ DlPaint save_paint;
+ save_paint.setBlendMode(DlBlendMode::kSrc);
+ auto backdrop_filter = DlBlurImageFilter::Make(30, 30, DlTileMode::kClamp);
+ builder.SaveLayer(nullptr, &save_paint, backdrop_filter.get(),
+ /*backdrop_id=*/1);
+ builder.Restore();
+ builder.Restore();
+ if (i != 0) {
+ builder.Restore();
+ }
+ }
+
+ ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
+}
+
} // namespace testing
} // namespace impeller
diff --git a/impeller/display_list/aiks_playground.cc b/impeller/display_list/aiks_playground.cc
index ae42bf9..6b2ac34 100644
--- a/impeller/display_list/aiks_playground.cc
+++ b/impeller/display_list/aiks_playground.cc
@@ -10,6 +10,7 @@
#include "impeller/display_list/dl_dispatcher.h"
#include "impeller/typographer/backends/skia/typographer_context_skia.h"
#include "impeller/typographer/typographer_context.h"
+#include "include/core/SkRect.h"
namespace impeller {
@@ -49,22 +50,14 @@
return Playground::OpenPlaygroundHere(
[&renderer, &callback](RenderTarget& render_target) -> bool {
- auto display_list = callback();
- TextFrameDispatcher collector(renderer.GetContentContext(), //
- Matrix(), //
- Rect::MakeMaximum() //
+ return RenderToOnscreen(
+ renderer.GetContentContext(), //
+ render_target, //
+ callback(), //
+ SkIRect::MakeWH(render_target.GetRenderTargetSize().width,
+ render_target.GetRenderTargetSize().height), //
+ /*reset_host_buffer=*/true //
);
- display_list->Dispatch(collector);
-
- CanvasDlDispatcher impeller_dispatcher(
- renderer.GetContentContext(), render_target,
- display_list->root_has_backdrop_filter(),
- display_list->max_root_blend_mode(), IRect::MakeMaximum());
- display_list->Dispatch(impeller_dispatcher);
- impeller_dispatcher.FinishRecording();
- renderer.GetContentContext().GetTransientsBuffer().Reset();
- renderer.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
- return true;
});
}
diff --git a/impeller/display_list/canvas.cc b/impeller/display_list/canvas.cc
index dedb9c3..f052634 100644
--- a/impeller/display_list/canvas.cc
+++ b/impeller/display_list/canvas.cc
@@ -6,6 +6,7 @@
#include <memory>
#include <optional>
+#include <unordered_map>
#include <utility>
#include "display_list/effects/dl_color_source.h"
@@ -93,11 +94,17 @@
///
/// Returns the previous render pass stored as a texture, or nullptr if there
/// was a validation failure.
+///
+/// [should_remove_texture] defaults to false. If true, the render target
+/// texture is removed from the entity pass target. This allows the texture to
+/// be cached by the canvas dispatcher for usage in the backdrop filter reuse
+/// mechanism.
static std::shared_ptr<Texture> FlipBackdrop(
std::vector<LazyRenderingConfig>& render_passes,
Point global_pass_position,
EntityPassClipStack& clip_coverage_stack,
- ContentContext& renderer) {
+ ContentContext& renderer,
+ bool should_remove_texture = false) {
auto rendering_config = std::move(render_passes.back());
render_passes.pop_back();
@@ -144,6 +151,14 @@
render_passes.push_back(LazyRenderingConfig(
renderer, std::move(rendering_config.entity_pass_target),
std::move(rendering_config.inline_pass_context)));
+ // If the current texture is being cached for a BDF we need to ensure we
+ // don't recycle it during recording; remove it from the entity pass target.
+ if (should_remove_texture) {
+ render_passes.back().entity_pass_target->RemoveSecondary();
+ }
+ RenderPass& current_render_pass =
+ *render_passes.back().inline_pass_context->GetRenderPass(0).pass;
+
// Eagerly restore the BDF contents.
// If the pass context returns a backdrop texture, we need to draw it to the
@@ -162,9 +177,7 @@
msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
- if (!msaa_backdrop_entity.Render(
- renderer,
- *render_passes.back().inline_pass_context->GetRenderPass(0).pass)) {
+ if (!msaa_backdrop_entity.Render(renderer, current_render_pass)) {
VALIDATION_LOG << "Failed to render MSAA backdrop entity.";
return nullptr;
}
@@ -173,13 +186,9 @@
// applied.
auto& replay_entities = clip_coverage_stack.GetReplayEntities();
for (const auto& replay : replay_entities) {
- SetClipScissor(
- replay.clip_coverage,
- *render_passes.back().inline_pass_context->GetRenderPass(0).pass,
- global_pass_position);
- if (!replay.entity.Render(
- renderer,
- *render_passes.back().inline_pass_context->GetRenderPass(0).pass)) {
+ SetClipScissor(replay.clip_coverage, current_render_pass,
+ global_pass_position);
+ if (!replay.entity.Render(renderer, current_render_pass)) {
VALIDATION_LOG << "Failed to render entity for clip restore.";
}
}
@@ -984,7 +993,8 @@
const flutter::DlImageFilter* backdrop_filter,
ContentBoundsPromise bounds_promise,
uint32_t total_content_depth,
- bool can_distribute_opacity) {
+ bool can_distribute_opacity,
+ std::optional<int64_t> backdrop_id) {
TRACE_EVENT0("flutter", "Canvas::saveLayer");
if (IsSkipping()) {
return SkipUntilMatchingRestore(total_content_depth);
@@ -1055,7 +1065,7 @@
// Backdrop filter state, ignored if there is no BDF.
std::shared_ptr<FilterContents> backdrop_filter_contents;
- Point local_position = {0, 0};
+ Point local_position = Point(0, 0);
if (backdrop_filter) {
local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
Canvas::BackdropFilterProc backdrop_filter_proc =
@@ -1068,14 +1078,41 @@
return filter;
};
- auto input_texture = FlipBackdrop(render_passes_, //
- GetGlobalPassPosition(), //
- clip_coverage_stack_, //
- renderer_ //
- );
- if (!input_texture) {
- // Validation failures are logged in FlipBackdrop.
- return;
+ std::shared_ptr<Texture> input_texture;
+
+ // If the backdrop ID is not the no-op id, and there is more than one usage
+ // of it in the current scene, cache the backdrop texture and remove it from
+ // the current entity pass flip.
+ bool will_cache_backdrop_texture = false;
+ BackdropData* backdrop_data = nullptr;
+ if (backdrop_id.has_value()) {
+ std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
+ backdrop_data_.find(backdrop_id.value());
+ if (backdrop_data_it != backdrop_data_.end()) {
+ backdrop_data = &backdrop_data_it->second;
+ will_cache_backdrop_texture =
+ backdrop_data_it->second.backdrop_count > 1;
+ }
+ }
+
+ if (!will_cache_backdrop_texture ||
+ (will_cache_backdrop_texture && !backdrop_data->texture_slot)) {
+ input_texture = FlipBackdrop(render_passes_, //
+ GetGlobalPassPosition(), //
+ clip_coverage_stack_, //
+ renderer_, //
+ will_cache_backdrop_texture //
+ );
+ if (!input_texture) {
+ // Validation failures are logged in FlipBackdrop.
+ return;
+ }
+
+ if (will_cache_backdrop_texture) {
+ backdrop_data->texture_slot = input_texture;
+ }
+ } else {
+ input_texture = backdrop_data->texture_slot;
}
backdrop_filter_contents = backdrop_filter_proc(
@@ -1086,6 +1123,42 @@
transform_stack_.back().transform.HasTranslation()
? Entity::RenderingMode::kSubpassPrependSnapshotTransform
: Entity::RenderingMode::kSubpassAppendSnapshotTransform);
+
+ if (will_cache_backdrop_texture) {
+ FML_DCHECK(backdrop_data);
+ // If all filters on the shared backdrop layer are equal, process the
+ // layer once.
+ if (backdrop_data->all_filters_equal &&
+ !backdrop_data->shared_filter_snapshot.has_value()) {
+ // TODO(157110): compute minimum input hint.
+ backdrop_data->shared_filter_snapshot =
+ backdrop_filter_contents->RenderToSnapshot(renderer_, {});
+ }
+
+ std::optional<Snapshot> maybe_snapshot =
+ backdrop_data->shared_filter_snapshot;
+ if (maybe_snapshot.has_value()) {
+ Snapshot snapshot = maybe_snapshot.value();
+ std::shared_ptr<TextureContents> contents = TextureContents::MakeRect(
+ subpass_coverage.Shift(-GetGlobalPassPosition()));
+ auto scaled =
+ subpass_coverage.TransformBounds(snapshot.transform.Invert());
+ contents->SetTexture(snapshot.texture);
+ contents->SetSourceRect(scaled);
+ contents->SetSamplerDescriptor(snapshot.sampler_descriptor);
+
+ // This backdrop entity sets a depth value as it is written to the newly
+ // flipped backdrop and not into a new saveLayer.
+ Entity backdrop_entity;
+ backdrop_entity.SetContents(std::move(contents));
+ backdrop_entity.SetClipDepth(++current_depth_);
+ backdrop_entity.SetBlendMode(paint.blend_mode);
+
+ backdrop_entity.Render(renderer_, GetCurrentRenderPass());
+ Save(0);
+ return;
+ }
+ }
}
// When applying a save layer, absorb any pending distributed opacity.
@@ -1119,18 +1192,18 @@
// the subpass will affect in the parent pass.
clip_coverage_stack_.PushSubpass(subpass_coverage, GetClipHeight());
- if (backdrop_filter_contents) {
- // Render the backdrop entity.
- Entity backdrop_entity;
- backdrop_entity.SetContents(std::move(backdrop_filter_contents));
- backdrop_entity.SetTransform(
- Matrix::MakeTranslation(Vector3(-local_position)));
- backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
-
- backdrop_entity.Render(
- renderer_,
- *render_passes_.back().inline_pass_context->GetRenderPass(0).pass);
+ if (!backdrop_filter_contents) {
+ return;
}
+
+ // Render the backdrop entity.
+ Entity backdrop_entity;
+ backdrop_entity.SetContents(std::move(backdrop_filter_contents));
+ backdrop_entity.SetTransform(
+ Matrix::MakeTranslation(Vector3(-local_position)));
+ backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
+
+ backdrop_entity.Render(renderer_, GetCurrentRenderPass());
}
bool Canvas::Restore() {
@@ -1300,9 +1373,7 @@
return true;
}
- entity.Render(
- renderer_,
- *render_passes_.back().inline_pass_context->GetRenderPass(0).pass);
+ entity.Render(renderer_, GetCurrentRenderPass());
}
return true;
@@ -1564,19 +1635,24 @@
if (clip_state_result.clip_did_change) {
// We only need to update the pass scissor if the clip state has changed.
- SetClipScissor(
- clip_coverage_stack_.CurrentClipCoverage(),
- *render_passes_.back().inline_pass_context->GetRenderPass(0).pass,
- GetGlobalPassPosition());
+ SetClipScissor(clip_coverage_stack_.CurrentClipCoverage(),
+ GetCurrentRenderPass(), GetGlobalPassPosition());
}
if (!clip_state_result.should_render) {
return;
}
- entity.Render(
- renderer_,
- *render_passes_.back().inline_pass_context->GetRenderPass(0).pass);
+ entity.Render(renderer_, GetCurrentRenderPass());
+}
+
+RenderPass& Canvas::GetCurrentRenderPass() const {
+ return *render_passes_.back().inline_pass_context->GetRenderPass(0).pass;
+}
+
+void Canvas::SetBackdropData(
+ std::unordered_map<int64_t, BackdropData> backdrop_data) {
+ backdrop_data_ = std::move(backdrop_data);
}
bool Canvas::BlitToOnscreen() {
@@ -1642,6 +1718,7 @@
FML_DCHECK(render_passes_.size() == 1u);
render_passes_.back().inline_pass_context->GetRenderPass(0);
render_passes_.back().inline_pass_context->EndPass();
+ backdrop_data_.clear();
// If requires_readback_ was true, then we rendered to an offscreen texture
// instead of to the onscreen provided in the render target. Now we need to
diff --git a/impeller/display_list/canvas.h b/impeller/display_list/canvas.h
index 387cb5c..f856c8c 100644
--- a/impeller/display_list/canvas.h
+++ b/impeller/display_list/canvas.h
@@ -9,6 +9,7 @@
#include <functional>
#include <memory>
#include <optional>
+#include <utility>
#include <vector>
#include "display_list/effects/dl_image_filter.h"
@@ -24,10 +25,21 @@
#include "impeller/geometry/path.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/vector.h"
+#include "impeller/renderer/snapshot.h"
#include "impeller/typographer/text_frame.h"
namespace impeller {
+struct BackdropData {
+ size_t backdrop_count = 0;
+ bool all_filters_equal = true;
+ std::shared_ptr<Texture> texture_slot;
+ // A single snapshot of the backdrop filter that is used when there are
+ // multiple backdrops that share an identical filter.
+ std::optional<Snapshot> shared_filter_snapshot;
+ std::shared_ptr<flutter::DlImageFilter> last_backdrop;
+};
+
struct CanvasStackEntry {
Matrix transform;
uint32_t clip_depth = 0u;
@@ -123,6 +135,10 @@
~Canvas() = default;
+ /// @brief Update the backdrop data used to group together backdrop filters
+ /// within the same layer.
+ void SetBackdropData(std::unordered_map<int64_t, BackdropData> backdrop_data);
+
/// @brief Return the culling bounds of the current render target, or nullopt
/// if there is no coverage.
std::optional<Rect> GetLocalCoverageLimit() const;
@@ -135,7 +151,8 @@
const flutter::DlImageFilter* backdrop_filter = nullptr,
ContentBoundsPromise bounds_promise = ContentBoundsPromise::kUnknown,
uint32_t total_content_depth = kMaxDepth,
- bool can_distribute_opacity = false);
+ bool can_distribute_opacity = false,
+ std::optional<int64_t> backdrop_id = std::nullopt);
bool Restore();
@@ -232,6 +249,7 @@
std::optional<Rect> initial_cull_rect_;
std::vector<LazyRenderingConfig> render_passes_;
std::vector<SaveLayerState> save_layer_state_;
+ std::unordered_map<int64_t, BackdropData> backdrop_data_;
// All geometry objects created for regular draws can be stack allocated,
// but clip geometries must be cached for record/replay for backdrop filters
@@ -277,6 +295,8 @@
Size corner_radii,
const Paint& paint);
+ RenderPass& GetCurrentRenderPass() const;
+
Canvas(const Canvas&) = delete;
Canvas& operator=(const Canvas&) = delete;
diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc
index ffdd0c6..895a4eb 100644
--- a/impeller/display_list/dl_dispatcher.cc
+++ b/impeller/display_list/dl_dispatcher.cc
@@ -8,14 +8,14 @@
#include <cstring>
#include <memory>
#include <optional>
-#include <utility>
#include <vector>
#include "display_list/effects/dl_color_source.h"
+#include "display_list/effects/dl_image_filter.h"
#include "flutter/fml/logging.h"
#include "impeller/core/formats.h"
#include "impeller/display_list/aiks_context.h"
-#include "impeller/display_list/color_filter.h"
+#include "impeller/display_list/canvas.h"
#include "impeller/display_list/dl_atlas_geometry.h"
#include "impeller/display_list/dl_vertices_geometry.h"
#include "impeller/display_list/nine_patch_converter.h"
@@ -302,7 +302,8 @@
const flutter::SaveLayerOptions& options,
uint32_t total_content_depth,
flutter::DlBlendMode max_content_mode,
- const flutter::DlImageFilter* backdrop) {
+ const flutter::DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
AUTO_DEPTH_WATCHER(1u);
auto paint = options.renders_with_attributes() ? paint_ : Paint{};
@@ -320,7 +321,9 @@
paint, impeller_bounds, backdrop, promise, total_content_depth,
// Unbounded content can still have user specified bounds that require a
// saveLayer to be created to perform the clip.
- options.can_distribute_opacity() && !options.content_is_unbounded());
+ options.can_distribute_opacity() && !options.content_is_unbounded(),
+ backdrop_id //
+ );
}
// |flutter::DlOpReceiver|
@@ -974,6 +977,11 @@
skia_conversions::ToBlendMode(dl_mode), paint_);
}
+void CanvasDlDispatcher::SetBackdropData(
+ std::unordered_map<int64_t, BackdropData> backdrop) {
+ GetCanvas().SetBackdropData(std::move(backdrop));
+}
+
//// Text Frame Dispatcher
TextFrameDispatcher::TextFrameDispatcher(const ContentContext& renderer,
@@ -994,9 +1002,28 @@
void TextFrameDispatcher::saveLayer(const DlRect& bounds,
const flutter::SaveLayerOptions options,
- const flutter::DlImageFilter* backdrop) {
+ const flutter::DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
save();
+ if (backdrop != nullptr && backdrop_id.has_value()) {
+ std::shared_ptr<flutter::DlImageFilter> shared_backdrop =
+ backdrop->shared();
+ std::unordered_map<int64_t, BackdropData>::iterator existing =
+ backdrop_data_.find(backdrop_id.value());
+ if (existing == backdrop_data_.end()) {
+ backdrop_data_[backdrop_id.value()] =
+ BackdropData{.backdrop_count = 1, .last_backdrop = shared_backdrop};
+ } else {
+ BackdropData& data = existing->second;
+ data.backdrop_count++;
+ if (data.all_filters_equal) {
+ data.all_filters_equal = (*data.last_backdrop == *shared_backdrop);
+ data.last_backdrop = shared_backdrop;
+ }
+ }
+ }
+
// This dispatcher does not track enough state to accurately compute
// cull rects with image filters.
auto global_cull_rect = cull_rect_state_.back();
@@ -1192,6 +1219,13 @@
}
}
+std::unordered_map<int64_t, BackdropData>
+TextFrameDispatcher::TakeBackdropData() {
+ std::unordered_map<int64_t, BackdropData> temp;
+ std::swap(temp, backdrop_data_);
+ return temp;
+}
+
std::shared_ptr<Texture> DisplayListToTexture(
const sk_sp<flutter::DisplayList>& display_list,
ISize size,
@@ -1239,6 +1273,7 @@
display_list->max_root_blend_mode(), //
impeller::IRect::MakeSize(size) //
);
+ impeller_dispatcher.SetBackdropData(collector.TakeBackdropData());
display_list->Dispatch(impeller_dispatcher, sk_cull_rect);
impeller_dispatcher.FinishRecording();
@@ -1267,6 +1302,7 @@
display_list->max_root_blend_mode(), //
IRect::RoundOut(ip_cull_rect) //
);
+ impeller_dispatcher.SetBackdropData(collector.TakeBackdropData());
display_list->Dispatch(impeller_dispatcher, cull_rect);
impeller_dispatcher.FinishRecording();
if (reset_host_buffer) {
diff --git a/impeller/display_list/dl_dispatcher.h b/impeller/display_list/dl_dispatcher.h
index 1418229..8302a1f 100644
--- a/impeller/display_list/dl_dispatcher.h
+++ b/impeller/display_list/dl_dispatcher.h
@@ -5,6 +5,8 @@
#ifndef FLUTTER_IMPELLER_DISPLAY_LIST_DL_DISPATCHER_H_
#define FLUTTER_IMPELLER_DISPLAY_LIST_DL_DISPATCHER_H_
+#include <memory>
+
#include "flutter/display_list/dl_op_receiver.h"
#include "flutter/display_list/geometry/dl_geometry_types.h"
#include "flutter/display_list/geometry/dl_path.h"
@@ -73,7 +75,8 @@
const flutter::SaveLayerOptions& options,
uint32_t total_content_depth,
flutter::DlBlendMode max_content_mode,
- const flutter::DlImageFilter* backdrop) override;
+ const flutter::DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
// |flutter::DlOpReceiver|
void restore() override;
@@ -253,6 +256,8 @@
~CanvasDlDispatcher() = default;
+ void SetBackdropData(std::unordered_map<int64_t, BackdropData> backdrop);
+
// |flutter::DlOpReceiver|
void save() override {
// This dispatcher should never be used with the save() variant
@@ -264,7 +269,8 @@
// |flutter::DlOpReceiver|
void saveLayer(const DlRect& bounds,
const flutter::SaveLayerOptions options,
- const flutter::DlImageFilter* backdrop) override {
+ const flutter::DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
// This dispatcher should never be used with the saveLayer() variant
// that does not include the content_depth parameter.
FML_UNREACHABLE();
@@ -299,7 +305,8 @@
void saveLayer(const DlRect& bounds,
const flutter::SaveLayerOptions options,
- const flutter::DlImageFilter* backdrop) override;
+ const flutter::DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
void restore() override;
@@ -353,12 +360,15 @@
// |flutter::DlOpReceiver|
void setImageFilter(const flutter::DlImageFilter* filter) override;
+ std::unordered_map<int64_t, BackdropData> TakeBackdropData();
+
private:
const Rect GetCurrentLocalCullingBounds() const;
const ContentContext& renderer_;
Matrix matrix_;
std::vector<Matrix> stack_;
+ std::unordered_map<int64_t, BackdropData> backdrop_data_;
// note: cull rects are always in the global coordinate space.
std::vector<Rect> cull_rect_state_;
bool has_image_filter_ = false;
diff --git a/impeller/display_list/dl_playground.cc b/impeller/display_list/dl_playground.cc
index eab910d..9a05612 100644
--- a/impeller/display_list/dl_playground.cc
+++ b/impeller/display_list/dl_playground.cc
@@ -45,21 +45,14 @@
wireframe = !wireframe;
context.GetContentContext().SetWireframe(wireframe);
}
-
- auto list = callback();
- TextFrameDispatcher collector(context.GetContentContext(), Matrix(),
- Rect::MakeMaximum());
- list->Dispatch(collector);
-
- CanvasDlDispatcher impeller_dispatcher(
- context.GetContentContext(), render_target,
- list->root_has_backdrop_filter(), list->max_root_blend_mode(),
- IRect::MakeMaximum());
- list->Dispatch(impeller_dispatcher);
- impeller_dispatcher.FinishRecording();
- context.GetContentContext().GetTransientsBuffer().Reset();
- context.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames();
- return true;
+ return RenderToOnscreen(
+ context.GetContentContext(), //
+ render_target, //
+ callback(), //
+ SkIRect::MakeWH(render_target.GetRenderTargetSize().width,
+ render_target.GetRenderTargetSize().height), //
+ /*reset_host_buffer=*/true //
+ );
});
}
diff --git a/impeller/entity/entity_pass_target.cc b/impeller/entity/entity_pass_target.cc
index c92a84a..712645a 100644
--- a/impeller/entity/entity_pass_target.cc
+++ b/impeller/entity/entity_pass_target.cc
@@ -73,4 +73,8 @@
return target_.IsValid();
}
+void EntityPassTarget::RemoveSecondary() {
+ secondary_color_texture_ = nullptr;
+}
+
} // namespace impeller
diff --git a/impeller/entity/entity_pass_target.h b/impeller/entity/entity_pass_target.h
index e82bad5..2adf4ec 100644
--- a/impeller/entity/entity_pass_target.h
+++ b/impeller/entity/entity_pass_target.h
@@ -28,6 +28,9 @@
RenderTarget& GetRenderTarget();
+ /// @brief Remove the cached secondary color texture.
+ void RemoveSecondary();
+
bool IsValid() const;
private:
diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart
index da23f53..d868427 100644
--- a/lib/ui/compositing.dart
+++ b/lib/ui/compositing.dart
@@ -401,6 +401,20 @@
/// the most recent save layer and rendered back to the scene using the indicated
/// [blendMode] prior to rasterizing the child layers.
///
+ /// If [backdropId] is provided and not null, then this value is treated
+ /// as a unique identifier for the backdrop. When the first backdrop filter with
+ /// a given id is processed during rasterization, the state of the backdrop is
+ /// recorded and cached. All subsequent backdrop filters with the same identifier
+ /// will apply their filter to the cached backdrop. The correct usage of the
+ /// backdrop id has the benefit of dramatically improving performance for
+ /// applications with multiple backdrop filters. For example, an application
+ /// that uses a backdrop blur filter for each item in a list view should set
+ /// all filters to have the same backdrop id.
+ ///
+ /// If overlapping backdrop filters use the same backdropId, then each filter
+ /// will apply to the backdrop before the overlapping filter components were
+ /// rendered.
+ ///
/// {@macro dart.ui.sceneBuilder.oldLayer}
///
/// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
@@ -410,6 +424,7 @@
ImageFilter filter, {
BlendMode blendMode = BlendMode.srcOver,
BackdropFilterEngineLayer? oldLayer,
+ int? backdropId,
});
/// Pushes a shader mask operation onto the operation stack.
@@ -772,18 +787,19 @@
BackdropFilterEngineLayer pushBackdropFilter(
ImageFilter filter, {
BlendMode blendMode = BlendMode.srcOver,
+ int? backdropId,
BackdropFilterEngineLayer? oldLayer,
}) {
assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushBackdropFilter'));
final EngineLayer engineLayer = _NativeEngineLayer._();
- _pushBackdropFilter(engineLayer, filter._toNativeImageFilter(), blendMode.index, oldLayer?._nativeLayer);
+ _pushBackdropFilter(engineLayer, filter._toNativeImageFilter(), blendMode.index, backdropId, oldLayer?._nativeLayer);
final BackdropFilterEngineLayer layer = BackdropFilterEngineLayer._(engineLayer);
assert(_debugPushLayer(layer));
return layer;
}
- @Native<Void Function(Pointer<Void>, Handle, Pointer<Void>, Int32, Handle)>(symbol: 'SceneBuilder::pushBackdropFilter')
- external void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter, int blendMode, EngineLayer? oldLayer);
+ @Native<Void Function(Pointer<Void>, Handle, Pointer<Void>, Int32, Handle, Handle)>(symbol: 'SceneBuilder::pushBackdropFilter')
+ external void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter, int blendMode, int? backdropId, EngineLayer? oldLayer);
@override
ShaderMaskEngineLayer pushShaderMask(
diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc
index b89a7f7..a8e3a29 100644
--- a/lib/ui/compositing/scene_builder.cc
+++ b/lib/ui/compositing/scene_builder.cc
@@ -3,7 +3,9 @@
// found in the LICENSE file.
#include "flutter/lib/ui/compositing/scene_builder.h"
+#include <cstdint>
+#include "dart_api.h"
#include "flutter/flow/layers/backdrop_filter_layer.h"
#include "flutter/flow/layers/clip_path_layer.h"
#include "flutter/flow/layers/clip_rect_layer.h"
@@ -13,7 +15,6 @@
#include "flutter/flow/layers/display_list_layer.h"
#include "flutter/flow/layers/image_filter_layer.h"
#include "flutter/flow/layers/layer.h"
-#include "flutter/flow/layers/layer_tree.h"
#include "flutter/flow/layers/opacity_layer.h"
#include "flutter/flow/layers/performance_overlay_layer.h"
#include "flutter/flow/layers/platform_view_layer.h"
@@ -21,13 +22,10 @@
#include "flutter/flow/layers/texture_layer.h"
#include "flutter/flow/layers/transform_layer.h"
#include "flutter/fml/build_config.h"
+#include "flutter/lib/ui/compositing/scene.h"
#include "flutter/lib/ui/floating_point.h"
#include "flutter/lib/ui/painting/matrix.h"
#include "flutter/lib/ui/painting/shader.h"
-#include "third_party/tonic/converter/dart_converter.h"
-#include "third_party/tonic/dart_args.h"
-#include "third_party/tonic/dart_binding_macros.h"
-#include "third_party/tonic/dart_library_natives.h"
namespace flutter {
@@ -43,7 +41,7 @@
void SceneBuilder::pushTransform(Dart_Handle layer_handle,
tonic::Float64List& matrix4,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ const fml::RefPtr<EngineLayer>& old_layer) {
SkM44 sk_matrix = ToSkM44(matrix4);
auto layer = std::make_shared<flutter::TransformLayer>(sk_matrix);
PushLayer(layer);
@@ -51,22 +49,22 @@
matrix4.Release();
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushOffset(Dart_Handle layer_handle,
double dx,
double dy,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ const fml::RefPtr<EngineLayer>& old_layer) {
SkMatrix sk_matrix = SkMatrix::Translate(SafeNarrow(dx), SafeNarrow(dy));
auto layer = std::make_shared<flutter::TransformLayer>(sk_matrix);
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
@@ -75,49 +73,48 @@
double right,
double top,
double bottom,
- int clipBehavior,
- const fml::RefPtr<EngineLayer>& oldLayer) {
- SkRect clipRect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top),
- SafeNarrow(right), SafeNarrow(bottom));
- flutter::Clip clip_behavior = static_cast<flutter::Clip>(clipBehavior);
- auto layer =
- std::make_shared<flutter::ClipRectLayer>(clipRect, clip_behavior);
+ int clip_behavior,
+ const fml::RefPtr<EngineLayer>& old_layer) {
+ SkRect clip_rect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top),
+ SafeNarrow(right), SafeNarrow(bottom));
+ auto layer = std::make_shared<flutter::ClipRectLayer>(
+ clip_rect, static_cast<flutter::Clip>(clip_behavior));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushClipRRect(Dart_Handle layer_handle,
const RRect& rrect,
- int clipBehavior,
- const fml::RefPtr<EngineLayer>& oldLayer) {
- flutter::Clip clip_behavior = static_cast<flutter::Clip>(clipBehavior);
- auto layer =
- std::make_shared<flutter::ClipRRectLayer>(rrect.sk_rrect, clip_behavior);
+ int clip_behavior,
+ const fml::RefPtr<EngineLayer>& old_layer) {
+ auto layer = std::make_shared<flutter::ClipRRectLayer>(
+ rrect.sk_rrect, static_cast<flutter::Clip>(clip_behavior));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushClipPath(Dart_Handle layer_handle,
const CanvasPath* path,
- int clipBehavior,
- const fml::RefPtr<EngineLayer>& oldLayer) {
- flutter::Clip clip_behavior = static_cast<flutter::Clip>(clipBehavior);
- FML_DCHECK(clip_behavior != flutter::Clip::kNone);
- auto layer =
- std::make_shared<flutter::ClipPathLayer>(path->path(), clip_behavior);
+ int clip_behavior,
+ const fml::RefPtr<EngineLayer>& old_layer) {
+ flutter::Clip flutter_clip_behavior =
+ static_cast<flutter::Clip>(clip_behavior);
+ FML_DCHECK(flutter_clip_behavior != flutter::Clip::kNone);
+ auto layer = std::make_shared<flutter::ClipPathLayer>(
+ path->path(), static_cast<flutter::Clip>(flutter_clip_behavior));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
@@ -125,27 +122,27 @@
int alpha,
double dx,
double dy,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ const fml::RefPtr<EngineLayer>& old_layer) {
auto layer = std::make_shared<flutter::OpacityLayer>(
alpha, SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushColorFilter(Dart_Handle layer_handle,
const ColorFilter* color_filter,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ const fml::RefPtr<EngineLayer>& old_layer) {
auto layer =
std::make_shared<flutter::ColorFilterLayer>(color_filter->filter());
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
@@ -153,57 +150,66 @@
const ImageFilter* image_filter,
double dx,
double dy,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ const fml::RefPtr<EngineLayer>& old_layer) {
auto layer = std::make_shared<flutter::ImageFilterLayer>(
image_filter->filter(), SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushBackdropFilter(
Dart_Handle layer_handle,
ImageFilter* filter,
- int blendMode,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ int blend_mode,
+ Dart_Handle backdrop_id,
+ const fml::RefPtr<EngineLayer>& old_layer) {
+ std::optional<int64_t> converted_backdrop_id;
+ if (Dart_IsInteger(backdrop_id)) {
+ int64_t out;
+ Dart_IntegerToInt64(backdrop_id, &out);
+ converted_backdrop_id = out;
+ }
+
auto layer = std::make_shared<flutter::BackdropFilterLayer>(
- filter->filter(), static_cast<DlBlendMode>(blendMode));
+ filter->filter(), static_cast<DlBlendMode>(blend_mode),
+ converted_backdrop_id);
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
void SceneBuilder::pushShaderMask(Dart_Handle layer_handle,
Shader* shader,
- double maskRectLeft,
- double maskRectRight,
- double maskRectTop,
- double maskRectBottom,
- int blendMode,
- int filterQualityIndex,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ double mask_rect_left,
+ double mask_rect_right,
+ double mask_rect_top,
+ double mask_Rect_bottom,
+ int blend_mode,
+ int filter_quality_index,
+ const fml::RefPtr<EngineLayer>& old_layer) {
SkRect rect =
- SkRect::MakeLTRB(SafeNarrow(maskRectLeft), SafeNarrow(maskRectTop),
- SafeNarrow(maskRectRight), SafeNarrow(maskRectBottom));
- auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
+ SkRect::MakeLTRB(SafeNarrow(mask_rect_right), SafeNarrow(mask_rect_right),
+ SafeNarrow(mask_rect_top), SafeNarrow(mask_Rect_bottom));
+ auto sampling = ImageFilter::SamplingFromIndex(filter_quality_index);
auto layer = std::make_shared<flutter::ShaderMaskLayer>(
- shader->shader(sampling), rect, static_cast<DlBlendMode>(blendMode));
+ shader->shader(sampling), rect, static_cast<DlBlendMode>(blend_mode));
PushLayer(layer);
EngineLayer::MakeRetained(layer_handle, layer);
- if (oldLayer && oldLayer->Layer()) {
- layer->AssignOldLayer(oldLayer->Layer().get());
+ if (old_layer && old_layer->Layer()) {
+ layer->AssignOldLayer(old_layer->Layer().get());
}
}
-void SceneBuilder::addRetained(const fml::RefPtr<EngineLayer>& retainedLayer) {
- AddLayer(retainedLayer->Layer());
+void SceneBuilder::addRetained(const fml::RefPtr<EngineLayer>& retained_layer) {
+ AddLayer(retained_layer->Layer());
}
void SceneBuilder::pop() {
@@ -233,13 +239,13 @@
double dy,
double width,
double height,
- int64_t textureId,
+ int64_t texture_id,
bool freeze,
- int filterQualityIndex) {
- auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
+ int filter_quality_index) {
+ auto sampling = ImageFilter::SamplingFromIndex(filter_quality_index);
auto layer = std::make_unique<flutter::TextureLayer>(
SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)),
- SkSize::Make(SafeNarrow(width), SafeNarrow(height)), textureId, freeze,
+ SkSize::Make(SafeNarrow(width), SafeNarrow(height)), texture_id, freeze,
sampling);
AddLayer(std::move(layer));
}
@@ -248,14 +254,14 @@
double dy,
double width,
double height,
- int64_t viewId) {
+ int64_t view_id) {
auto layer = std::make_unique<flutter::PlatformViewLayer>(
SkPoint::Make(SafeNarrow(dx), SafeNarrow(dy)),
- SkSize::Make(SafeNarrow(width), SafeNarrow(height)), viewId);
+ SkSize::Make(SafeNarrow(width), SafeNarrow(height)), view_id);
AddLayer(std::move(layer));
}
-void SceneBuilder::addPerformanceOverlay(uint64_t enabledOptions,
+void SceneBuilder::addPerformanceOverlay(uint64_t enabled_options,
double left,
double right,
double top,
@@ -263,7 +269,7 @@
SkRect rect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top),
SafeNarrow(right), SafeNarrow(bottom));
auto layer =
- std::make_unique<flutter::PerformanceOverlayLayer>(enabledOptions);
+ std::make_unique<flutter::PerformanceOverlayLayer>(enabled_options);
layer->set_paint_bounds(rect);
AddLayer(std::move(layer));
}
diff --git a/lib/ui/compositing/scene_builder.h b/lib/ui/compositing/scene_builder.h
index d13f4d0..717129a 100644
--- a/lib/ui/compositing/scene_builder.h
+++ b/lib/ui/compositing/scene_builder.h
@@ -10,7 +10,6 @@
#include <vector>
#include "flutter/flow/layers/container_layer.h"
-#include "flutter/lib/ui/compositing/scene.h"
#include "flutter/lib/ui/dart_wrapper.h"
#include "flutter/lib/ui/painting/color_filter.h"
#include "flutter/lib/ui/painting/engine_layer.h"
@@ -38,64 +37,65 @@
void pushTransformHandle(Dart_Handle layer_handle,
Dart_Handle matrix4_handle,
- const fml::RefPtr<EngineLayer>& oldLayer) {
+ const fml::RefPtr<EngineLayer>& old_layer) {
tonic::Float64List matrix4(matrix4_handle);
- pushTransform(layer_handle, matrix4, oldLayer);
+ pushTransform(layer_handle, matrix4, old_layer);
}
void pushTransform(Dart_Handle layer_handle,
tonic::Float64List& matrix4,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushOffset(Dart_Handle layer_handle,
double dx,
double dy,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushClipRect(Dart_Handle layer_handle,
double left,
double right,
double top,
double bottom,
- int clipBehavior,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ int clip_behavior,
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushClipRRect(Dart_Handle layer_handle,
const RRect& rrect,
- int clipBehavior,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ int clip_behavior,
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushClipPath(Dart_Handle layer_handle,
const CanvasPath* path,
- int clipBehavior,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ int clip_behavior,
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushOpacity(Dart_Handle layer_handle,
int alpha,
double dx,
double dy,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushColorFilter(Dart_Handle layer_handle,
const ColorFilter* color_filter,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushImageFilter(Dart_Handle layer_handle,
const ImageFilter* image_filter,
double dx,
double dy,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushBackdropFilter(Dart_Handle layer_handle,
ImageFilter* filter,
- int blendMode,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ int blend_mode,
+ Dart_Handle backdrop_id,
+ const fml::RefPtr<EngineLayer>& old_layer);
void pushShaderMask(Dart_Handle layer_handle,
Shader* shader,
- double maskRectLeft,
- double maskRectRight,
- double maskRectTop,
- double maskRectBottom,
- int blendMode,
- int filterQualityIndex,
- const fml::RefPtr<EngineLayer>& oldLayer);
+ double mask_rect_left,
+ double mask_rect_right,
+ double mask_rect_top,
+ double mask_rect_bottom,
+ int blend_mode,
+ int filter_quality_index,
+ const fml::RefPtr<EngineLayer>& old_layer);
- void addRetained(const fml::RefPtr<EngineLayer>& retainedLayer);
+ void addRetained(const fml::RefPtr<EngineLayer>& retained_layer);
void pop();
- void addPerformanceOverlay(uint64_t enabledOptions,
+ void addPerformanceOverlay(uint64_t enabled_options,
double left,
double right,
double top,
@@ -107,15 +107,15 @@
double dy,
double width,
double height,
- int64_t textureId,
+ int64_t texture_id,
bool freeze,
- int filterQuality);
+ int filter_quality);
void addPlatformView(double dx,
double dy,
double width,
double height,
- int64_t viewId);
+ int64_t view_id);
void build(Dart_Handle scene_handle);
diff --git a/lib/ui/compositing/scene_builder_unittests.cc b/lib/ui/compositing/scene_builder_unittests.cc
index 702d83b..cbd2a3b 100644
--- a/lib/ui/compositing/scene_builder_unittests.cc
+++ b/lib/ui/compositing/scene_builder_unittests.cc
@@ -12,6 +12,7 @@
#include "flutter/shell/common/shell_test.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/testing/testing.h"
+#include "lib/ui/compositing/scene.h"
// CREATE_NATIVE_ENTRY is leaky by design
// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
diff --git a/lib/web_ui/lib/compositing.dart b/lib/web_ui/lib/compositing.dart
index 09a4d25..2f0d558 100644
--- a/lib/web_ui/lib/compositing.dart
+++ b/lib/web_ui/lib/compositing.dart
@@ -76,6 +76,7 @@
ImageFilter filter, {
BlendMode blendMode = BlendMode.srcOver,
BackdropFilterEngineLayer? oldLayer,
+ int? backdropId,
});
ShaderMaskEngineLayer pushShaderMask(
Shader shader,
diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart
index 183180e..d2f34bc 100644
--- a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart
+++ b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart
@@ -110,6 +110,7 @@
ui.ImageFilter filter, {
ui.BlendMode blendMode = ui.BlendMode.srcOver,
ui.EngineLayer? oldLayer,
+ int? backdropId,
}) {
return pushLayer<BackdropFilterEngineLayer>(BackdropFilterEngineLayer(
filter,
diff --git a/lib/web_ui/lib/src/engine/html/scene_builder.dart b/lib/web_ui/lib/src/engine/html/scene_builder.dart
index ff63108..88644ad 100644
--- a/lib/web_ui/lib/src/engine/html/scene_builder.dart
+++ b/lib/web_ui/lib/src/engine/html/scene_builder.dart
@@ -240,6 +240,7 @@
ui.ImageFilter filter, {
ui.BlendMode blendMode = ui.BlendMode.srcOver,
ui.BackdropFilterEngineLayer? oldLayer,
+ int? backdropId,
}) {
return _pushSurface<PersistedBackdropFilter>(PersistedBackdropFilter(
oldLayer as PersistedBackdropFilter?, filter));
diff --git a/lib/web_ui/lib/src/engine/scene_builder.dart b/lib/web_ui/lib/src/engine/scene_builder.dart
index af84cb0..37d29e6 100644
--- a/lib/web_ui/lib/src/engine/scene_builder.dart
+++ b/lib/web_ui/lib/src/engine/scene_builder.dart
@@ -131,7 +131,8 @@
ui.BackdropFilterEngineLayer pushBackdropFilter(
ui.ImageFilter filter, {
ui.BlendMode blendMode = ui.BlendMode.srcOver,
- ui.BackdropFilterEngineLayer? oldLayer
+ ui.BackdropFilterEngineLayer? oldLayer,
+ int? backdropId,
}) => pushLayer<BackdropFilterLayer>(
BackdropFilterLayer(),
BackdropFilterOperation(filter, blendMode),
diff --git a/shell/common/dl_op_spy.cc b/shell/common/dl_op_spy.cc
index 19f54d1..77fb209 100644
--- a/shell/common/dl_op_spy.cc
+++ b/shell/common/dl_op_spy.cc
@@ -31,7 +31,8 @@
void DlOpSpy::save() {}
void DlOpSpy::saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) {}
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {}
void DlOpSpy::restore() {}
void DlOpSpy::drawColor(DlColor color, DlBlendMode mode) {
did_draw_ |= !color.isTransparent();
diff --git a/shell/common/dl_op_spy.h b/shell/common/dl_op_spy.h
index 6d3d9c9..82c2dfc 100644
--- a/shell/common/dl_op_spy.h
+++ b/shell/common/dl_op_spy.h
@@ -41,7 +41,8 @@
void save() override;
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override;
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
void restore() override;
void drawColor(DlColor color, DlBlendMode mode) override;
void drawPaint() override;
diff --git a/testing/display_list_testing.cc b/testing/display_list_testing.cc
index d21b586..4f90651 100644
--- a/testing/display_list_testing.cc
+++ b/testing/display_list_testing.cc
@@ -4,6 +4,7 @@
#include "flutter/testing/display_list_testing.h"
+#include <cstdint>
#include <iomanip>
#include "flutter/display_list/display_list.h"
@@ -701,12 +702,17 @@
}
void DisplayListStreamDispatcher::saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) {
startl() << "saveLayer(" << bounds << ", " << options;
if (backdrop) {
os_ << "," << std::endl;
indent(10);
- startl() << "backdrop: ";
+ if (backdrop_id.has_value()) {
+ startl() << "backdrop: " << backdrop_id.value();
+ } else {
+ startl() << "backdrop: (no id)";
+ }
out(backdrop);
outdent(10);
} else {
diff --git a/testing/display_list_testing.h b/testing/display_list_testing.h
index 8dcaa7d..33fcd6b 100644
--- a/testing/display_list_testing.h
+++ b/testing/display_list_testing.h
@@ -110,7 +110,8 @@
void save() override;
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override;
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override;
void restore() override;
void translate(DlScalar tx, DlScalar ty) override;
@@ -397,7 +398,8 @@
void save() override { RecordByType(DisplayListOpType::kSave); }
void saveLayer(const DlRect& bounds,
const SaveLayerOptions options,
- const DlImageFilter* backdrop) override {
+ const DlImageFilter* backdrop,
+ std::optional<int64_t> backdrop_id) override {
if (backdrop) {
RecordByType(DisplayListOpType::kSaveLayerBackdrop);
} else {
diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt
index ef3b466..60d7faf 100644
--- a/testing/impeller_golden_tests_output.txt
+++ b/testing/impeller_golden_tests_output.txt
@@ -254,6 +254,9 @@
impeller_Play_AiksTest_CanRenderBackdropBlurInteractive_Metal.png
impeller_Play_AiksTest_CanRenderBackdropBlurInteractive_OpenGLES.png
impeller_Play_AiksTest_CanRenderBackdropBlurInteractive_Vulkan.png
+impeller_Play_AiksTest_CanRenderBackdropBlurWithSingleBackdropId_Metal.png
+impeller_Play_AiksTest_CanRenderBackdropBlurWithSingleBackdropId_OpenGLES.png
+impeller_Play_AiksTest_CanRenderBackdropBlurWithSingleBackdropId_Vulkan.png
impeller_Play_AiksTest_CanRenderBackdropBlur_Metal.png
impeller_Play_AiksTest_CanRenderBackdropBlur_OpenGLES.png
impeller_Play_AiksTest_CanRenderBackdropBlur_Vulkan.png
@@ -382,6 +385,15 @@
impeller_Play_AiksTest_CanRenderMaskBlurHugeSigma_Metal.png
impeller_Play_AiksTest_CanRenderMaskBlurHugeSigma_OpenGLES.png
impeller_Play_AiksTest_CanRenderMaskBlurHugeSigma_Vulkan.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropIdAndDistinctFilters_Metal.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropIdAndDistinctFilters_OpenGLES.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropIdAndDistinctFilters_Vulkan.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropIdDifferentLayers_Metal.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropIdDifferentLayers_OpenGLES.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropIdDifferentLayers_Vulkan.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropId_Metal.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropId_OpenGLES.png
+impeller_Play_AiksTest_CanRenderMultipleBackdropBlurWithSingleBackdropId_Vulkan.png
impeller_Play_AiksTest_CanRenderNestedClips_Metal.png
impeller_Play_AiksTest_CanRenderNestedClips_OpenGLES.png
impeller_Play_AiksTest_CanRenderNestedClips_Vulkan.png