diff --git a/display_list/benchmarking/dl_complexity_gl.cc b/display_list/benchmarking/dl_complexity_gl.cc index 44f658bb99146..5da3703b7fbb2 100644 --- a/display_list/benchmarking/dl_complexity_gl.cc +++ b/display_list/benchmarking/dl_complexity_gl.cc @@ -51,7 +51,8 @@ unsigned int DisplayListGLComplexityCalculator::GLHelper::BatchedComplexity() { void DisplayListGLComplexityCalculator::GLHelper::saveLayer( const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) { + const DlImageFilter* backdrop, + std::optional backdrop_id) { if (IsComplex()) { return; } @@ -627,7 +628,8 @@ void DisplayListGLComplexityCalculator::GLHelper::drawDisplayList( 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 d0fcbb98a3bf4..3041f9014102f 100644 --- a/display_list/benchmarking/dl_complexity_gl.h +++ b/display_list/benchmarking/dl_complexity_gl.h @@ -37,7 +37,8 @@ class DisplayListGLComplexityCalculator void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override; + const DlImageFilter* backdrop, + std::optional 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 82f641e6cc123..25fa25a4912a2 100644 --- a/display_list/benchmarking/dl_complexity_metal.cc +++ b/display_list/benchmarking/dl_complexity_metal.cc @@ -65,7 +65,8 @@ DisplayListMetalComplexityCalculator::MetalHelper::BatchedComplexity() { void DisplayListMetalComplexityCalculator::MetalHelper::saveLayer( const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) { + const DlImageFilter* backdrop, + std::optional backdrop_id) { if (IsComplex()) { return; } @@ -571,7 +572,8 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawDisplayList( 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 d11d0ff2a7b02..79dd5c3155be3 100644 --- a/display_list/benchmarking/dl_complexity_metal.h +++ b/display_list/benchmarking/dl_complexity_metal.h @@ -37,7 +37,8 @@ class DisplayListMetalComplexityCalculator void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override; + const DlImageFilter* backdrop, + std::optional 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 0477bf2ae2051..524a5aabf2d87 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -1483,7 +1483,8 @@ class SaveLayerExpector : public virtual DlOpReceiver, void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override { + const DlImageFilter* backdrop, + std::optional backdrop_id) override { FML_UNREACHABLE(); } @@ -1491,7 +1492,8 @@ class SaveLayerExpector : public virtual DlOpReceiver, const SaveLayerOptions& options, uint32_t total_content_depth, DlBlendMode max_content_blend_mode, - const DlImageFilter* backdrop = nullptr) { + const DlImageFilter* backdrop = nullptr, + std::optional 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 @@ class SaveLayerBoundsExpector : public virtual DlOpReceiver, void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override { + const DlImageFilter* backdrop, + std::optional 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 @@ class DepthExpector : public virtual DlOpReceiver, void saveLayer(const DlRect& bounds, SaveLayerOptions options, - const DlImageFilter* backdrop) override { + const DlImageFilter* backdrop, + std::optional 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 @@ class DepthExpector : public virtual DlOpReceiver, const SaveLayerOptions& options, uint32_t total_content_depth, DlBlendMode max_content_mode, - const DlImageFilter* backdrop) override { + const DlImageFilter* backdrop, + std::optional 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 7db556f4afa6f..39953dfd3c54f 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -409,7 +409,8 @@ void DisplayListBuilder::Save() { void DisplayListBuilder::saveLayer(const DlRect& bounds, const SaveLayerOptions in_options, - const DlImageFilter* backdrop) { + const DlImageFilter* backdrop, + std::optional backdrop_id) { SaveLayerOptions options = in_options.without_optimizations(); DisplayListAttributeFlags flags = options.renders_with_attributes() ? kSaveLayerWithPaintFlags @@ -524,7 +525,8 @@ void DisplayListBuilder::saveLayer(const DlRect& bounds, } if (backdrop) { - Push(0, options, record_bounds, backdrop); + Push(0, options, record_bounds, backdrop, + backdrop_id); } else { Push(0, options, record_bounds); } @@ -542,7 +544,8 @@ void DisplayListBuilder::saveLayer(const DlRect& bounds, } void DisplayListBuilder::SaveLayer(std::optional& bounds, const DlPaint* paint, - const DlImageFilter* backdrop) { + const DlImageFilter* backdrop, + std::optional backdrop_id) { SaveLayerOptions options; DlRect temp_bounds; if (bounds.has_value()) { @@ -556,7 +559,7 @@ void DisplayListBuilder::SaveLayer(std::optional& bounds, 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 c7ac9693d0847..58d343d92ab6a 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -54,7 +54,8 @@ class DisplayListBuilder final : public virtual DlCanvas, // |DlCanvas| void SaveLayer(std::optional& bounds, const DlPaint* paint = nullptr, - const DlImageFilter* backdrop = nullptr) override; + const DlImageFilter* backdrop = nullptr, + std::optional backdrop_id = std::nullopt) override; // |DlCanvas| void Restore() override; // |DlCanvas| @@ -354,7 +355,8 @@ class DisplayListBuilder final : public virtual DlCanvas, // |DlOpReceiver| void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override; + const DlImageFilter* backdrop, + std::optional backdrop_id) override; // |DlOpReceiver| void restore() override { Restore(); } diff --git a/display_list/dl_canvas.h b/display_list/dl_canvas.h index ff0ea7e6896f6..80076fc0012b3 100644 --- a/display_list/dl_canvas.h +++ b/display_list/dl_canvas.h @@ -62,7 +62,8 @@ class DlCanvas { virtual void Save() = 0; virtual void SaveLayer(std::optional& bounds, const DlPaint* paint = nullptr, - const DlImageFilter* backdrop = nullptr) = 0; + const DlImageFilter* backdrop = nullptr, + std::optional 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 @@ class DlCanvas { void SaveLayer(const SkRect* bounds, const DlPaint* paint = nullptr, - const DlImageFilter* backdrop = nullptr) { + const DlImageFilter* backdrop = nullptr, + std::optional 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 091ed6f655ec6..79d5d28dcd5a4 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 @@ class DlOpReceiver { // 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 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 backdrop_id = std::nullopt) { + saveLayer(bounds, options, backdrop, backdrop_id); } virtual void restore() = 0; @@ -170,13 +170,17 @@ class DlOpReceiver { // 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 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 592c31e914ca2..189038b37a5fb 100644 --- a/display_list/dl_op_records.h +++ b/display_list/dl_op_records.h @@ -310,19 +310,24 @@ struct SaveLayerBackdropOp final : SaveLayerOpBase { SaveLayerBackdropOp(const SaveLayerOptions& options, const DlRect& rect, - const DlImageFilter* backdrop) - : SaveLayerOpBase(options, rect), backdrop(backdrop->shared()) {} + const DlImageFilter* backdrop, + std::optional backdrop_id) + : SaveLayerOpBase(options, rect), + backdrop(backdrop->shared()), + backdrop_id_(backdrop_id) {} const std::shared_ptr backdrop; + std::optional 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 f98010f56f0bc..1e6b01529429c 100644 --- a/display_list/effects/dl_image_filter.h +++ b/display_list/effects/dl_image_filter.h @@ -281,7 +281,8 @@ class DlBlurImageFilter final : public DlImageFilter { bool equals_(const DlImageFilter& other) const override { FML_DCHECK(other.type() == DlImageFilterType::kBlur); auto that = static_cast(&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 8b19d74c2124f..a190519925af5 100644 --- a/display_list/skia/dl_sk_canvas.cc +++ b/display_list/skia/dl_sk_canvas.cc @@ -54,7 +54,8 @@ void DlSkCanvasAdapter::Save() { void DlSkCanvasAdapter::SaveLayer(std::optional& bounds, const DlPaint* paint, - const DlImageFilter* backdrop) { + const DlImageFilter* backdrop, + std::optional backdrop_id) { sk_sp 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 804752c7f8c56..7047f41a37625 100644 --- a/display_list/skia/dl_sk_canvas.h +++ b/display_list/skia/dl_sk_canvas.h @@ -32,7 +32,8 @@ class DlSkCanvasAdapter final : public virtual DlCanvas { void Save() override; void SaveLayer(std::optional& bounds, const DlPaint* paint = nullptr, - const DlImageFilter* backdrop = nullptr) override; + const DlImageFilter* backdrop = nullptr, + std::optional 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 33b11166cd5ae..45066eb22305f 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 #include "flutter/display_list/dl_blend_mode.h" #include "flutter/display_list/skia/dl_sk_conversions.h" @@ -46,7 +47,8 @@ void DlSkCanvasDispatcher::restore() { } void DlSkCanvasDispatcher::saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) { + const DlImageFilter* backdrop, + std::optional 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 fa5fbdd21259b..1455479a8b22c 100644 --- a/display_list/skia/dl_sk_dispatcher.h +++ b/display_list/skia/dl_sk_dispatcher.h @@ -31,7 +31,8 @@ class DlSkCanvasDispatcher : public virtual DlOpReceiver, void restore() override; void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override; + const DlImageFilter* backdrop, + std::optional 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 05ca54dbd38ae..64ce2a0fef0a0 100644 --- a/display_list/testing/dl_test_snippets.cc +++ b/display_list/testing/dl_test_snippets.cc @@ -327,7 +327,7 @@ std::vector CreateAllSaveRestoreOps() { 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 @@ std::vector CreateAllSaveRestoreOps() { 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 @@ std::vector CreateAllSaveRestoreOps() { 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 @@ std::vector CreateAllSaveRestoreOps() { 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 257d276657b86..fccc04c6ffcee 100644 --- a/display_list/utils/dl_receiver_utils.h +++ b/display_list/utils/dl_receiver_utils.h @@ -82,7 +82,8 @@ class IgnoreDrawDispatchHelper : public virtual DlOpReceiver { void save() override {} void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override {} + const DlImageFilter* backdrop, + std::optional 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 32707c4f77e6d..aec04bafae872 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -8,8 +8,11 @@ namespace flutter { BackdropFilterLayer::BackdropFilterLayer( std::shared_ptr filter, - DlBlendMode blend_mode) - : filter_(std::move(filter)), blend_mode_(blend_mode) {} + DlBlendMode blend_mode, + std::optional 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 @@ void BackdropFilterLayer::Paint(PaintContext& context) const { 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 d17fed110d5e9..180c5a641341a 100644 --- a/flow/layers/backdrop_filter_layer.h +++ b/flow/layers/backdrop_filter_layer.h @@ -13,7 +13,8 @@ namespace flutter { class BackdropFilterLayer : public ContainerLayer { public: BackdropFilterLayer(std::shared_ptr filter, - DlBlendMode blend_mode); + DlBlendMode blend_mode, + std::optional backdrop_id = std::nullopt); void Diff(DiffContext* context, const Layer* old_layer) override; @@ -24,6 +25,7 @@ class BackdropFilterLayer : public ContainerLayer { private: std::shared_ptr filter_; DlBlendMode blend_mode_; + std::optional 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 a3908df25bcbf..15cf79548edde 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -52,7 +52,8 @@ class DummyDelegate : public LayerStateStack::Delegate { void saveLayer(const SkRect& bounds, LayerStateStack::RenderingAttributes& attributes, DlBlendMode blend, - const DlImageFilter* backdrop) override {} + const DlImageFilter* backdrop, + std::optional backdrop_id) override {} void restore() override {} void translate(SkScalar tx, SkScalar ty) override {} @@ -99,10 +100,13 @@ class DlCanvasDelegate : public LayerStateStack::Delegate { void saveLayer(const SkRect& bounds, LayerStateStack::RenderingAttributes& attributes, DlBlendMode blend_mode, - const DlImageFilter* backdrop) override { + const DlImageFilter* backdrop, + std::optional backdrop_id) override { TRACE_EVENT0("flutter", "Canvas::saveLayer"); DlPaint paint; - canvas_->SaveLayer(&bounds, attributes.fill(paint, blend_mode), backdrop); + std::optional rect = ToDlRect(bounds); + canvas_->SaveLayer(rect, attributes.fill(paint, blend_mode), backdrop, + backdrop_id); } void restore() override { canvas_->Restore(); } @@ -157,7 +161,8 @@ class PrerollDelegate : public LayerStateStack::Delegate { void saveLayer(const SkRect& bounds, LayerStateStack::RenderingAttributes& attributes, DlBlendMode blend, - const DlImageFilter* backdrop) override { + const DlImageFilter* backdrop, + std::optional backdrop_id) override { save_stack_.emplace_back(state()); } void restore() override { save_stack_.pop_back(); } @@ -343,13 +348,16 @@ class BackdropFilterEntry : public SaveLayerEntry { BackdropFilterEntry(const SkRect& bounds, const std::shared_ptr& filter, DlBlendMode blend_mode, + std::optional 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 @@ class BackdropFilterEntry : public SaveLayerEntry { private: const std::shared_ptr filter_; + std::optional backdrop_id_; FML_DISALLOW_COPY_ASSIGN_AND_MOVE(BackdropFilterEntry); }; @@ -558,8 +567,9 @@ void MutatorContext::applyColorFilter( void MutatorContext::applyBackdropFilter( const SkRect& bounds, const std::shared_ptr& filter, - DlBlendMode blend_mode) { - layer_state_stack_->push_backdrop(bounds, filter, blend_mode); + DlBlendMode blend_mode, + std::optional 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_image_filter( void LayerStateStack::push_backdrop( const SkRect& bounds, const std::shared_ptr& filter, - DlBlendMode blend_mode) { + DlBlendMode blend_mode, + std::optional backdrop_id) { state_stack_.emplace_back(std::make_unique( - 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 c9e606e86e245..a5cec34ed1cc4 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -197,7 +197,8 @@ class LayerStateStack { // will only see a saveLayer with the indicated blend_mode. void applyBackdropFilter(const SkRect& bounds, const std::shared_ptr& filter, - DlBlendMode blend_mode); + DlBlendMode blend_mode, + std::optional backdrop_id); void translate(SkScalar tx, SkScalar ty); void translate(SkPoint tp) { translate(tp.fX, tp.fY); } @@ -334,7 +335,8 @@ class LayerStateStack { const std::shared_ptr& filter); void push_backdrop(const SkRect& bounds, const std::shared_ptr& filter, - DlBlendMode blend_mode); + DlBlendMode blend_mode, + std::optional backdrop_id); void push_translate(SkScalar tx, SkScalar ty); void push_transform(const SkM44& matrix); @@ -444,10 +446,12 @@ class LayerStateStack { 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 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 c224ac7dee3db..96f852b49f65b 100644 --- a/impeller/display_list/aiks_dl_blur_unittests.cc +++ b/impeller/display_list/aiks_dl_blur_unittests.cc @@ -268,6 +268,87 @@ TEST_P(AiksTest, CanRenderBackdropBlur) { 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, GaussianBlurBackdropTinyMipMap) { } } +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 ae42bf9d69078..6b2ac34a9f315 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 @@ bool AiksPlayground::OpenPlaygroundHere( 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 dedb9c31cf27c..f052634de5b58 100644 --- a/impeller/display_list/canvas.cc +++ b/impeller/display_list/canvas.cc @@ -6,6 +6,7 @@ #include #include +#include #include #include "display_list/effects/dl_color_source.h" @@ -93,11 +94,17 @@ static void ApplyFramebufferBlend(Entity& entity) { /// /// 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 FlipBackdrop( std::vector& 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 @@ static std::shared_ptr FlipBackdrop( 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 @@ static std::shared_ptr FlipBackdrop( msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents)); msaa_backdrop_entity.SetBlendMode(BlendMode::kSource); msaa_backdrop_entity.SetClipDepth(std::numeric_limits::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 @@ static std::shared_ptr FlipBackdrop( // 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 @@ void Canvas::SaveLayer(const Paint& paint, const flutter::DlImageFilter* backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, - bool can_distribute_opacity) { + bool can_distribute_opacity, + std::optional backdrop_id) { TRACE_EVENT0("flutter", "Canvas::saveLayer"); if (IsSkipping()) { return SkipUntilMatchingRestore(total_content_depth); @@ -1055,7 +1065,7 @@ void Canvas::SaveLayer(const Paint& paint, // Backdrop filter state, ignored if there is no BDF. std::shared_ptr 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 @@ void Canvas::SaveLayer(const Paint& paint, 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 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::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 @@ void Canvas::SaveLayer(const Paint& paint, 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 maybe_snapshot = + backdrop_data->shared_filter_snapshot; + if (maybe_snapshot.has_value()) { + Snapshot snapshot = maybe_snapshot.value(); + std::shared_ptr 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 @@ void Canvas::SaveLayer(const Paint& paint, // 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::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::max()); + + backdrop_entity.Render(renderer_, GetCurrentRenderPass()); } bool Canvas::Restore() { @@ -1300,9 +1373,7 @@ bool Canvas::Restore() { return true; } - entity.Render( - renderer_, - *render_passes_.back().inline_pass_context->GetRenderPass(0).pass); + entity.Render(renderer_, GetCurrentRenderPass()); } return true; @@ -1564,19 +1635,24 @@ void Canvas::AddClipEntityToCurrentPass(Entity& entity) { 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 backdrop_data) { + backdrop_data_ = std::move(backdrop_data); } bool Canvas::BlitToOnscreen() { @@ -1642,6 +1718,7 @@ void Canvas::EndReplay() { 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 387cb5c81dc33..f856c8caa47cb 100644 --- a/impeller/display_list/canvas.h +++ b/impeller/display_list/canvas.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #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_slot; + // A single snapshot of the backdrop filter that is used when there are + // multiple backdrops that share an identical filter. + std::optional shared_filter_snapshot; + std::shared_ptr last_backdrop; +}; + struct CanvasStackEntry { Matrix transform; uint32_t clip_depth = 0u; @@ -123,6 +135,10 @@ class Canvas { ~Canvas() = default; + /// @brief Update the backdrop data used to group together backdrop filters + /// within the same layer. + void SetBackdropData(std::unordered_map backdrop_data); + /// @brief Return the culling bounds of the current render target, or nullopt /// if there is no coverage. std::optional GetLocalCoverageLimit() const; @@ -135,7 +151,8 @@ class Canvas { 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 backdrop_id = std::nullopt); bool Restore(); @@ -232,6 +249,7 @@ class Canvas { std::optional initial_cull_rect_; std::vector render_passes_; std::vector save_layer_state_; + std::unordered_map 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 @@ class Canvas { 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 ffdd0c6eca9f8..895a4eb103cad 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -8,14 +8,14 @@ #include #include #include -#include #include #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 @@ void DlDispatcherBase::saveLayer(const DlRect& bounds, const flutter::SaveLayerOptions& options, uint32_t total_content_depth, flutter::DlBlendMode max_content_mode, - const flutter::DlImageFilter* backdrop) { + const flutter::DlImageFilter* backdrop, + std::optional backdrop_id) { AUTO_DEPTH_WATCHER(1u); auto paint = options.renders_with_attributes() ? paint_ : Paint{}; @@ -320,7 +321,9 @@ void DlDispatcherBase::saveLayer(const DlRect& bounds, 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 @@ void CanvasDlDispatcher::drawVertices( skia_conversions::ToBlendMode(dl_mode), paint_); } +void CanvasDlDispatcher::SetBackdropData( + std::unordered_map backdrop) { + GetCanvas().SetBackdropData(std::move(backdrop)); +} + //// Text Frame Dispatcher TextFrameDispatcher::TextFrameDispatcher(const ContentContext& renderer, @@ -994,9 +1002,28 @@ void TextFrameDispatcher::save() { void TextFrameDispatcher::saveLayer(const DlRect& bounds, const flutter::SaveLayerOptions options, - const flutter::DlImageFilter* backdrop) { + const flutter::DlImageFilter* backdrop, + std::optional backdrop_id) { save(); + if (backdrop != nullptr && backdrop_id.has_value()) { + std::shared_ptr shared_backdrop = + backdrop->shared(); + std::unordered_map::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 @@ void TextFrameDispatcher::setImageFilter(const flutter::DlImageFilter* filter) { } } +std::unordered_map +TextFrameDispatcher::TakeBackdropData() { + std::unordered_map temp; + std::swap(temp, backdrop_data_); + return temp; +} + std::shared_ptr DisplayListToTexture( const sk_sp& display_list, ISize size, @@ -1239,6 +1273,7 @@ std::shared_ptr DisplayListToTexture( 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 @@ bool RenderToOnscreen(ContentContext& context, 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 1418229430bf0..8302a1f6b436b 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 + #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 @@ class DlDispatcherBase : public flutter::DlOpReceiver { 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 backdrop_id) override; // |flutter::DlOpReceiver| void restore() override; @@ -253,6 +256,8 @@ class CanvasDlDispatcher : public DlDispatcherBase { ~CanvasDlDispatcher() = default; + void SetBackdropData(std::unordered_map backdrop); + // |flutter::DlOpReceiver| void save() override { // This dispatcher should never be used with the save() variant @@ -264,7 +269,8 @@ class CanvasDlDispatcher : public DlDispatcherBase { // |flutter::DlOpReceiver| void saveLayer(const DlRect& bounds, const flutter::SaveLayerOptions options, - const flutter::DlImageFilter* backdrop) override { + const flutter::DlImageFilter* backdrop, + std::optional 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 @@ class TextFrameDispatcher : public flutter::IgnoreAttributeDispatchHelper, void saveLayer(const DlRect& bounds, const flutter::SaveLayerOptions options, - const flutter::DlImageFilter* backdrop) override; + const flutter::DlImageFilter* backdrop, + std::optional backdrop_id) override; void restore() override; @@ -353,12 +360,15 @@ class TextFrameDispatcher : public flutter::IgnoreAttributeDispatchHelper, // |flutter::DlOpReceiver| void setImageFilter(const flutter::DlImageFilter* filter) override; + std::unordered_map TakeBackdropData(); + private: const Rect GetCurrentLocalCullingBounds() const; const ContentContext& renderer_; Matrix matrix_; std::vector stack_; + std::unordered_map backdrop_data_; // note: cull rects are always in the global coordinate space. std::vector 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 eab910d1f73e4..9a0561230d554 100644 --- a/impeller/display_list/dl_playground.cc +++ b/impeller/display_list/dl_playground.cc @@ -45,21 +45,14 @@ bool DlPlayground::OpenPlaygroundHere(DisplayListPlaygroundCallback callback) { 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 c92a84a76a718..712645a61339f 100644 --- a/impeller/entity/entity_pass_target.cc +++ b/impeller/entity/entity_pass_target.cc @@ -73,4 +73,8 @@ bool EntityPassTarget::IsValid() const { 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 e82bad573874a..2adf4ecaeb50a 100644 --- a/impeller/entity/entity_pass_target.h +++ b/impeller/entity/entity_pass_target.h @@ -28,6 +28,9 @@ class EntityPassTarget { 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 da23f53f06043..d8684270486e6 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -401,6 +401,20 @@ abstract class SceneBuilder { /// 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 @@ abstract class SceneBuilder { ImageFilter filter, { BlendMode blendMode = BlendMode.srcOver, BackdropFilterEngineLayer? oldLayer, + int? backdropId, }); /// Pushes a shader mask operation onto the operation stack. @@ -772,18 +787,19 @@ base class _NativeSceneBuilder extends NativeFieldWrapperClass1 implements Scene 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, Handle, Pointer, Int32, Handle)>(symbol: 'SceneBuilder::pushBackdropFilter') - external void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter, int blendMode, EngineLayer? oldLayer); + @Native, Handle, Pointer, 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 b89a7f7cde99c..a8e3a29f85435 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 +#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 @@ SceneBuilder::~SceneBuilder() = default; void SceneBuilder::pushTransform(Dart_Handle layer_handle, tonic::Float64List& matrix4, - const fml::RefPtr& oldLayer) { + const fml::RefPtr& old_layer) { SkM44 sk_matrix = ToSkM44(matrix4); auto layer = std::make_shared(sk_matrix); PushLayer(layer); @@ -51,22 +49,22 @@ void SceneBuilder::pushTransform(Dart_Handle layer_handle, 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& oldLayer) { + const fml::RefPtr& old_layer) { SkMatrix sk_matrix = SkMatrix::Translate(SafeNarrow(dx), SafeNarrow(dy)); auto layer = std::make_shared(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 @@ void SceneBuilder::pushClipRect(Dart_Handle layer_handle, double right, double top, double bottom, - int clipBehavior, - const fml::RefPtr& oldLayer) { - SkRect clipRect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), - SafeNarrow(right), SafeNarrow(bottom)); - flutter::Clip clip_behavior = static_cast(clipBehavior); - auto layer = - std::make_shared(clipRect, clip_behavior); + int clip_behavior, + const fml::RefPtr& old_layer) { + SkRect clip_rect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), + SafeNarrow(right), SafeNarrow(bottom)); + auto layer = std::make_shared( + clip_rect, static_cast(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& oldLayer) { - flutter::Clip clip_behavior = static_cast(clipBehavior); - auto layer = - std::make_shared(rrect.sk_rrect, clip_behavior); + int clip_behavior, + const fml::RefPtr& old_layer) { + auto layer = std::make_shared( + rrect.sk_rrect, static_cast(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& oldLayer) { - flutter::Clip clip_behavior = static_cast(clipBehavior); - FML_DCHECK(clip_behavior != flutter::Clip::kNone); - auto layer = - std::make_shared(path->path(), clip_behavior); + int clip_behavior, + const fml::RefPtr& old_layer) { + flutter::Clip flutter_clip_behavior = + static_cast(clip_behavior); + FML_DCHECK(flutter_clip_behavior != flutter::Clip::kNone); + auto layer = std::make_shared( + path->path(), static_cast(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 @@ void SceneBuilder::pushOpacity(Dart_Handle layer_handle, int alpha, double dx, double dy, - const fml::RefPtr& oldLayer) { + const fml::RefPtr& old_layer) { auto layer = std::make_shared( 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& oldLayer) { + const fml::RefPtr& old_layer) { auto layer = std::make_shared(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 @@ void SceneBuilder::pushImageFilter(Dart_Handle layer_handle, const ImageFilter* image_filter, double dx, double dy, - const fml::RefPtr& oldLayer) { + const fml::RefPtr& old_layer) { auto layer = std::make_shared( 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& oldLayer) { + int blend_mode, + Dart_Handle backdrop_id, + const fml::RefPtr& old_layer) { + std::optional 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( - filter->filter(), static_cast(blendMode)); + filter->filter(), static_cast(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& 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& 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( - shader->shader(sampling), rect, static_cast(blendMode)); + shader->shader(sampling), rect, static_cast(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& retainedLayer) { - AddLayer(retainedLayer->Layer()); +void SceneBuilder::addRetained(const fml::RefPtr& retained_layer) { + AddLayer(retained_layer->Layer()); } void SceneBuilder::pop() { @@ -233,13 +239,13 @@ void SceneBuilder::addTexture(double dx, 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( 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 @@ void SceneBuilder::addPlatformView(double dx, double dy, double width, double height, - int64_t viewId) { + int64_t view_id) { auto layer = std::make_unique( 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 @@ void SceneBuilder::addPerformanceOverlay(uint64_t enabledOptions, SkRect rect = SkRect::MakeLTRB(SafeNarrow(left), SafeNarrow(top), SafeNarrow(right), SafeNarrow(bottom)); auto layer = - std::make_unique(enabledOptions); + std::make_unique(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 d13f4d0117564..717129a6fd27f 100644 --- a/lib/ui/compositing/scene_builder.h +++ b/lib/ui/compositing/scene_builder.h @@ -10,7 +10,6 @@ #include #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 @@ class SceneBuilder : public RefCountedDartWrappable { void pushTransformHandle(Dart_Handle layer_handle, Dart_Handle matrix4_handle, - const fml::RefPtr& oldLayer) { + const fml::RefPtr& 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& oldLayer); + const fml::RefPtr& old_layer); void pushOffset(Dart_Handle layer_handle, double dx, double dy, - const fml::RefPtr& oldLayer); + const fml::RefPtr& old_layer); void pushClipRect(Dart_Handle layer_handle, double left, double right, double top, double bottom, - int clipBehavior, - const fml::RefPtr& oldLayer); + int clip_behavior, + const fml::RefPtr& old_layer); void pushClipRRect(Dart_Handle layer_handle, const RRect& rrect, - int clipBehavior, - const fml::RefPtr& oldLayer); + int clip_behavior, + const fml::RefPtr& old_layer); void pushClipPath(Dart_Handle layer_handle, const CanvasPath* path, - int clipBehavior, - const fml::RefPtr& oldLayer); + int clip_behavior, + const fml::RefPtr& old_layer); void pushOpacity(Dart_Handle layer_handle, int alpha, double dx, double dy, - const fml::RefPtr& oldLayer); + const fml::RefPtr& old_layer); void pushColorFilter(Dart_Handle layer_handle, const ColorFilter* color_filter, - const fml::RefPtr& oldLayer); + const fml::RefPtr& old_layer); void pushImageFilter(Dart_Handle layer_handle, const ImageFilter* image_filter, double dx, double dy, - const fml::RefPtr& oldLayer); + const fml::RefPtr& old_layer); void pushBackdropFilter(Dart_Handle layer_handle, ImageFilter* filter, - int blendMode, - const fml::RefPtr& oldLayer); + int blend_mode, + Dart_Handle backdrop_id, + const fml::RefPtr& 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& 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& old_layer); - void addRetained(const fml::RefPtr& retainedLayer); + void addRetained(const fml::RefPtr& 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 @@ class SceneBuilder : public RefCountedDartWrappable { 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 702d83bf61417..cbd2a3bfbb946 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 09a4d25300be2..2f0d558f5bb34 100644 --- a/lib/web_ui/lib/compositing.dart +++ b/lib/web_ui/lib/compositing.dart @@ -76,6 +76,7 @@ abstract class SceneBuilder { 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 183180e8a21d2..d2f34bc6a01c8 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 @@ class LayerSceneBuilder implements ui.SceneBuilder { ui.ImageFilter filter, { ui.BlendMode blendMode = ui.BlendMode.srcOver, ui.EngineLayer? oldLayer, + int? backdropId, }) { return pushLayer(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 ff63108231e6e..88644adc0529a 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 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { ui.ImageFilter filter, { ui.BlendMode blendMode = ui.BlendMode.srcOver, ui.BackdropFilterEngineLayer? oldLayer, + int? backdropId, }) { return _pushSurface(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 af84cb00990c6..37d29e66f7fdd 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 @@ class EngineSceneBuilder implements ui.SceneBuilder { ui.BackdropFilterEngineLayer pushBackdropFilter( ui.ImageFilter filter, { ui.BlendMode blendMode = ui.BlendMode.srcOver, - ui.BackdropFilterEngineLayer? oldLayer + ui.BackdropFilterEngineLayer? oldLayer, + int? backdropId, }) => pushLayer( BackdropFilterLayer(), BackdropFilterOperation(filter, blendMode), diff --git a/shell/common/dl_op_spy.cc b/shell/common/dl_op_spy.cc index 19f54d104768f..77fb2092a549a 100644 --- a/shell/common/dl_op_spy.cc +++ b/shell/common/dl_op_spy.cc @@ -31,7 +31,8 @@ void DlOpSpy::setColorSource(const DlColorSource* source) { void DlOpSpy::save() {} void DlOpSpy::saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) {} + const DlImageFilter* backdrop, + std::optional 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 6d3d9c9587f24..82c2dfc55684b 100644 --- a/shell/common/dl_op_spy.h +++ b/shell/common/dl_op_spy.h @@ -41,7 +41,8 @@ class DlOpSpy final : public virtual DlOpReceiver, void save() override; void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override; + const DlImageFilter* backdrop, + std::optional 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 d21b58664451b..4f9065178cbf3 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 #include #include "flutter/display_list/display_list.h" @@ -701,12 +702,17 @@ void DisplayListStreamDispatcher::save() { } void DisplayListStreamDispatcher::saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) { + const DlImageFilter* backdrop, + std::optional 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 8dcaa7de5151d..33fcd6b039dc3 100644 --- a/testing/display_list_testing.h +++ b/testing/display_list_testing.h @@ -110,7 +110,8 @@ class DisplayListStreamDispatcher final : public DlOpReceiver { void save() override; void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override; + const DlImageFilter* backdrop, + std::optional backdrop_id) override; void restore() override; void translate(DlScalar tx, DlScalar ty) override; @@ -397,7 +398,8 @@ class DisplayListGeneralReceiver : public DlOpReceiver { void save() override { RecordByType(DisplayListOpType::kSave); } void saveLayer(const DlRect& bounds, const SaveLayerOptions options, - const DlImageFilter* backdrop) override { + const DlImageFilter* backdrop, + std::optional 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 ef3b466533e9d..60d7faf3a16e8 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -254,6 +254,9 @@ impeller_Play_AiksTest_CanRenderBackdropBlurHugeSigma_Vulkan.png 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_CanRenderLinearGradientWithOverlappingStopsClamp_Vulkan.p 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