From 6a782c2750700dcb54f657f0db9e99f221a4a02a Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 16 Aug 2022 12:27:18 -0700 Subject: [PATCH 01/19] initial skeleton of LayerStateStack prototype --- flow/layers/layer.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++ flow/layers/layer.h | 71 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index 8a34b775ef766..305792154c1e6 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -56,6 +56,86 @@ Layer::AutoPrerollSaveLayerState::~AutoPrerollSaveLayerState() { } } +LayerStateStack::LayerStateStack() { + state_stack_.emplace_back(SkM44()); +} + +void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { + if (canvas_) { + canvas_->restoreToCount(canvas_restore_count_); + canvas_ = nullptr; + } + if (canvas) { + canvas_restore_count_ = canvas->getSaveCount(); + canvas_ = canvas; + for (auto& state : state_stack_) { + if (state.is_layer) { + canvas->saveLayer(state.save_bounds(), state.save_skpaint()); + } else { + canvas->save(); + } + canvas->setMatrix(state.matrix); + for (auto& path : state.clip_paths) { + canvas->clipPath(path); + } + } + } +} + +void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { + if (builder_) { + builder_->restoreToCount(builder_restore_count_); + builder_ = nullptr; + } + if (builder) { + builder_restore_count_ = builder->getSaveCount(); + builder_ = builder; + for (auto& state : state_stack_) { + if (state.is_layer) { + builder->saveLayer(state.save_bounds(), state.save_skpaint()); + } else { + builder->save(); + } + builder->transformReset(); + builder->transform(state.matrix); + for (auto& path : state.clip_paths) { + builder->clipPath(path, SkClipOp::kIntersect, false); + } + } + } +} + +void LayerStateStack::setMutatorDelegate(MutatorsStack* mutators) { + // Does a MutatorsStack do restoreToCount? + if (mutators_) { + // builder_->restoreToCount(builder_restore_count_); + mutators_ = nullptr; + } + if (mutators) { + // builder_restore_count_ = mutators->getSaveCount(); + mutators_ = mutators; + } +} + +LayerStateStack::AutoRestore::AutoRestore(LayerStateStack* stack) + : stack_(stack), stack_restore_count_(stack->getSaveCount()) {} + +LayerStateStack::AutoRestore::~AutoRestore() { + stack_->restoreToCount(stack_restore_count_); +} + +void LayerStateStack::save() { + state_stack_.emplace_back(state_stack_.back().matrix); +} + +LayerStateStack::AutoRestore LayerStateStack::autoSave() { + save(); + return AutoRestore(this); +} + +LayerStateStack::RenderState::RenderState(SkM44& incoming_matrix) + : matrix(incoming_matrix) {} + Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, const SkRect& bounds, const SkPaint* paint, diff --git a/flow/layers/layer.h b/flow/layers/layer.h index bb57b430fa3b0..4d7ac3a544061 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -45,6 +45,77 @@ class RasterCacheItem; static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); +class LayerStateStack { + public: + LayerStateStack(); + + void setCanvasDelegate(SkCanvas* canvas); + void setBuilderDelegate(DisplayListBuilder* canvas); + void setMutatorDelegate(MutatorsStack* mutators); + + class AutoRestore { + public: + ~AutoRestore(); + + private: + AutoRestore(LayerStateStack* stack); + friend class LayerStateStack; + + LayerStateStack* stack_; + const int stack_restore_count_; + }; + + void save(); + [[nodiscard]] AutoRestore autoSave(); + void saveLayer(const SkRect* bounds = nullptr, + const DlPaint* paint = nullptr, + const DlImageFilter* backdrop_filter = nullptr); + [[nodiscard]] AutoRestore autoSaveLayer( + const SkRect* bounds = nullptr, + const DlPaint* paint = nullptr, + const DlImageFilter* backdrop_filter = nullptr); + void restore(); + void restoreToCount(int restore_count); + int getSaveCount(); + + void translate(SkScalar tx, SkScalar ty); + void scale(SkScalar sx, SkScalar sy); + void skew(SkScalar sx, SkScalar sy); + void rotate(SkScalar degrees); + void transform(SkM44 matrix); + void transform(SkMatrix matrix); + + void clipRect(SkRect rect, SkClipOp op, bool is_aa); + void clipRRect(SkRect rect, SkClipOp op, bool is_aa); + void clipPath(SkRect rect, SkClipOp op, bool is_aa); + + private: + struct RenderState { + RenderState(SkM44& incoming_matrix); + + SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } + SkPaint* save_skpaint() { FML_DCHECK(false); return nullptr; } + DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } + + bool is_layer; + bool layer_has_bounds; + bool layer_has_paint; + SkRect layer_bounds; + DlPaint layer_paint; + + SkM44 matrix; + std::vector clip_paths; + }; + + std::vector state_stack_; + + SkCanvas* canvas_ = nullptr; + int canvas_restore_count_; + DisplayListBuilder* builder_ = nullptr; + int builder_restore_count_; + MutatorsStack* mutators_ = nullptr; +}; + // This should be an exact copy of the Clip enum in painting.dart. enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer }; From 566f438ab51ce6757c4b1ba7440027ab9cd2bc8e Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 16 Aug 2022 13:31:14 -0700 Subject: [PATCH 02/19] more complete prototype --- flow/layers/layer.cc | 189 ++++++++++++++++++++++++++++++++++++++++++- flow/layers/layer.h | 63 +++++++++++++-- 2 files changed, 240 insertions(+), 12 deletions(-) diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index 305792154c1e6..6e602f51c29fc 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -75,8 +75,8 @@ void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { canvas->save(); } canvas->setMatrix(state.matrix); - for (auto& path : state.clip_paths) { - canvas->clipPath(path); + for (auto& clip : state.clip_ops) { + clip->apply(*canvas); } } } @@ -98,8 +98,8 @@ void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { } builder->transformReset(); builder->transform(state.matrix); - for (auto& path : state.clip_paths) { - builder->clipPath(path, SkClipOp::kIntersect, false); + for (auto& clip : state.clip_ops) { + clip->apply(*builder); } } } @@ -126,6 +126,14 @@ LayerStateStack::AutoRestore::~AutoRestore() { void LayerStateStack::save() { state_stack_.emplace_back(state_stack_.back().matrix); + RenderState& state = state_stack_.back(); + state.is_layer = false; + if (canvas_) { + canvas_->save(); + } + if (builder_) { + builder_->save(); + } } LayerStateStack::AutoRestore LayerStateStack::autoSave() { @@ -133,6 +141,179 @@ LayerStateStack::AutoRestore LayerStateStack::autoSave() { return AutoRestore(this); } +void LayerStateStack::saveLayer(const SkRect* bounds, + const DlPaint* paint, + const DlImageFilter* backdrop_filter) { + state_stack_.emplace_back(state_stack_.back().matrix); + RenderState& state = state_stack_.back(); + state.is_layer = true; + if ((state.layer_has_bounds = (bounds != nullptr))) { + state.layer_bounds = *bounds; + } + if ((state.layer_has_paint = (paint != nullptr))) { + state.layer_paint = *paint; + } + if (canvas_) { + if (backdrop_filter) { + sk_sp sk_filter = backdrop_filter->skia_object(); + canvas_->saveLayer(SkCanvas::SaveLayerRec( + state.save_bounds(), state.save_skpaint(), sk_filter.get(), 0)); + } else { + canvas_->saveLayer(state.save_bounds(), state.save_skpaint()); + } + } + if (builder_) { + builder_->saveLayer(bounds, paint, backdrop_filter); + } +} + +LayerStateStack::AutoRestore LayerStateStack::autoSaveLayer( + const SkRect* bounds, + const DlPaint* paint, + const DlImageFilter* backdrop_filter) { + saveLayer(bounds, paint, backdrop_filter); + return AutoRestore(this); +} + +void LayerStateStack::translate(SkScalar tx, SkScalar ty) { + state_stack_.back().matrix.preTranslate(tx, ty); + if (canvas_) { + canvas_->translate(tx, ty); + } + if (builder_) { + builder_->translate(tx, ty); + } +} + +void LayerStateStack::scale(SkScalar sx, SkScalar sy) { + state_stack_.back().matrix.preScale(sx, sy); + if (canvas_) { + canvas_->scale(sx, sy); + } + if (builder_) { + builder_->scale(sx, sy); + } +} + +void LayerStateStack::skew(SkScalar sx, SkScalar sy) { + SkMatrix m; + m.setSkew(sx, sy); + state_stack_.back().matrix.preConcat(SkM44(m)); + if (canvas_) { + canvas_->skew(sx, sy); + } + if (builder_) { + builder_->skew(sx, sy); + } +} + +void LayerStateStack::rotate(SkScalar degrees) { + SkMatrix m; + m.setRotate(degrees); + state_stack_.back().matrix.preConcat(SkM44(m)); + if (canvas_) { + canvas_->rotate(degrees); + } + if (builder_) { + builder_->rotate(degrees); + } +} + +void LayerStateStack::transform(SkMatrix& matrix) { + state_stack_.back().matrix.preConcat(SkM44(matrix)); + if (canvas_) { + canvas_->concat(matrix); + } + if (builder_) { + builder_->transform(matrix); + } +} + +void LayerStateStack::transform(SkM44& matrix) { + state_stack_.back().matrix.preConcat(matrix); + if (canvas_) { + canvas_->concat(matrix); + } + if (builder_) { + builder_->transform(matrix); + } +} + +void LayerStateStack::clipRect(const SkRect& rect, SkClipOp op, bool is_aa) { + state_stack_.back().clip_ops.push_back( + std::make_unique(rect, op, is_aa)); + if (canvas_) { + canvas_->clipRect(rect, op, is_aa); + } + if (builder_) { + builder_->clipRect(rect, op, is_aa); + } +} + +void LayerStateStack::clipRRect(const SkRRect& rrect, SkClipOp op, bool is_aa) { + state_stack_.back().clip_ops.push_back( + std::make_unique(rrect, op, is_aa)); + if (canvas_) { + canvas_->clipRRect(rrect, op, is_aa); + } + if (builder_) { + builder_->clipRRect(rrect, op, is_aa); + } +} + +void LayerStateStack::clipPath(const SkPath& path, SkClipOp op, bool is_aa) { + state_stack_.back().clip_ops.push_back( + std::make_unique(path, op, is_aa)); + if (canvas_) { + canvas_->clipPath(path, op, is_aa); + } + if (builder_) { + builder_->clipPath(path, op, is_aa); + } +} + +LayerStateStack::ClipEntry::ClipEntry(SkClipOp op, bool is_aa) + : clip_op_(op), is_aa_(is_aa) {} + +LayerStateStack::ClipRectEntry::ClipRectEntry(const SkRect& rect, + SkClipOp op, + bool is_aa) + : ClipEntry(op, is_aa), rect_(rect) {} + +void LayerStateStack::ClipRectEntry::apply(SkCanvas& canvas) const { + canvas.clipRect(rect_, clip_op_, is_aa_); +} + +void LayerStateStack::ClipRectEntry::apply(DisplayListBuilder& builder) const { + builder.clipRect(rect_, clip_op_, is_aa_); +} + +LayerStateStack::ClipRRectEntry::ClipRRectEntry(const SkRRect& rrect, + SkClipOp op, + bool is_aa) + : ClipEntry(op, is_aa), rrect_(rrect) {} + +void LayerStateStack::ClipRRectEntry::apply(SkCanvas& canvas) const { + canvas.clipRRect(rrect_, clip_op_, is_aa_); +} + +void LayerStateStack::ClipRRectEntry::apply(DisplayListBuilder& builder) const { + builder.clipRRect(rrect_, clip_op_, is_aa_); +} + +LayerStateStack::ClipPathEntry::ClipPathEntry(const SkPath& path, + SkClipOp op, + bool is_aa) + : ClipEntry(op, is_aa), path_(path) {} + +void LayerStateStack::ClipPathEntry::apply(SkCanvas& canvas) const { + canvas.clipPath(path_, clip_op_, is_aa_); +} + +void LayerStateStack::ClipPathEntry::apply(DisplayListBuilder& builder) const { + builder.clipPath(path_, clip_op_, is_aa_); +} + LayerStateStack::RenderState::RenderState(SkM44& incoming_matrix) : matrix(incoming_matrix) {} diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 4d7ac3a544061..08d60de3a86e6 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -82,29 +82,76 @@ class LayerStateStack { void scale(SkScalar sx, SkScalar sy); void skew(SkScalar sx, SkScalar sy); void rotate(SkScalar degrees); - void transform(SkM44 matrix); - void transform(SkMatrix matrix); + void transform(SkM44& matrix); + void transform(SkMatrix& matrix); - void clipRect(SkRect rect, SkClipOp op, bool is_aa); - void clipRRect(SkRect rect, SkClipOp op, bool is_aa); - void clipPath(SkRect rect, SkClipOp op, bool is_aa); + void clipRect(const SkRect& rect, SkClipOp op, bool is_aa); + void clipRRect(const SkRRect& rect, SkClipOp op, bool is_aa); + void clipPath(const SkPath& rect, SkClipOp op, bool is_aa); private: + class ClipEntry { + public: + virtual void apply(SkCanvas& canvas) const = 0; + virtual void apply(DisplayListBuilder& builder) const = 0; + + protected: + ClipEntry(SkClipOp op, bool is_aa); + + const SkClipOp clip_op_; + const bool is_aa_; + }; + + class ClipRectEntry : public ClipEntry { + ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa); + + void apply(SkCanvas& canvas) const override; + void apply(DisplayListBuilder& canvas) const override; + + private: + const SkRect rect_; + }; + + class ClipRRectEntry : public ClipEntry { + ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa); + + void apply(SkCanvas& canvas) const override; + void apply(DisplayListBuilder& canvas) const override; + + private: + const SkRRect rrect_; + }; + + class ClipPathEntry : public ClipEntry { + ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa); + + void apply(SkCanvas& canvas) const override; + void apply(DisplayListBuilder& canvas) const override; + + private: + const SkPath path_; + }; + struct RenderState { RenderState(SkM44& incoming_matrix); SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } - SkPaint* save_skpaint() { FML_DCHECK(false); return nullptr; } + SkPaint* save_skpaint() { + FML_DCHECK(false); + return nullptr; + } DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } bool is_layer; + bool layer_has_bounds; - bool layer_has_paint; SkRect layer_bounds; + + bool layer_has_paint; DlPaint layer_paint; SkM44 matrix; - std::vector clip_paths; + std::vector> clip_ops; }; std::vector state_stack_; From 3d4450eed7a6930d587094ba36ca82b92540d781 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 19 Aug 2022 13:10:28 -0700 Subject: [PATCH 03/19] DlPaint to SkPaint conversion --- display_list/display_list_paint.cc | 19 +++++++++++++++++++ display_list/display_list_paint.h | 15 +++++++++++++++ display_list/display_list_utils.cc | 22 +++++++++------------- display_list/display_list_utils.h | 11 +++++++++++ flow/layers/layer.cc | 17 +++++++++++++---- flow/layers/layer.h | 9 ++++++--- 6 files changed, 73 insertions(+), 20 deletions(-) diff --git a/display_list/display_list_paint.cc b/display_list/display_list_paint.cc index d3a0f8c752c29..581df8e81448a 100644 --- a/display_list/display_list_paint.cc +++ b/display_list/display_list_paint.cc @@ -4,6 +4,8 @@ #include "flutter/display_list/display_list_paint.h" +#include "flutter/display_list/display_list_utils.h" + namespace flutter { DlPaint::DlPaint() @@ -34,4 +36,21 @@ bool DlPaint::operator==(DlPaint const& other) const { Equals(maskFilter_, other.maskFilter_); } +void DlPaint::toSkPaint(SkPaint& paint) const { + paint.setAntiAlias(isAntiAlias_); + paint.setDither(isDither_); + paint.setColor(color_); + paint.setBlendMode(getSkBlendMode()); + paint.setStyle(getSkDrawStyle()); + paint.setStrokeCap(getSkStrokeCap()); + paint.setStrokeJoin(getSkStrokeJoin()); + paint.setStrokeWidth(strokeWidth_); + paint.setStrokeMiter(strokeMiter_); + paint.setShader(colorSource_ ? colorSource_->skia_object() : nullptr); + paint.setColorFilter(SkPaintDispatchHelper::MakeColorFilter( + isInvertColors_, colorFilter_.get())); + paint.setImageFilter(imageFilter_->skia_object()); + paint.setMaskFilter(maskFilter_->skia_object()); +} + } // namespace flutter diff --git a/display_list/display_list_paint.h b/display_list/display_list_paint.h index 2892d13685633..bda8d09434f63 100644 --- a/display_list/display_list_paint.h +++ b/display_list/display_list_paint.h @@ -213,6 +213,8 @@ class DlPaint { bool operator==(DlPaint const& other) const; bool operator!=(DlPaint const& other) const { return !(*this == other); } + void toSkPaint(SkPaint& paint) const; + private: #define ASSERT_ENUM_FITS(last_enum, num_bits) \ static_assert(static_cast(last_enum) < (1 << num_bits) && \ @@ -239,6 +241,19 @@ class DlPaint { }; }; + SkBlendMode getSkBlendMode() const { + return static_cast(blendMode_); + } + SkPaint::Style getSkDrawStyle() const { + return static_cast(drawStyle_); + } + SkPaint::Cap getSkStrokeCap() const { + return static_cast(strokeCap_); + } + SkPaint::Join getSkStrokeJoin() const { + return static_cast(strokeJoin_); + } + DlColor color_; float strokeWidth_; float strokeMiter_; diff --git a/display_list/display_list_utils.cc b/display_list/display_list_utils.cc index 58ddba1425c46..b7b35ec941a9b 100644 --- a/display_list/display_list_utils.cc +++ b/display_list/display_list_utils.cc @@ -19,15 +19,6 @@ namespace flutter { -// clang-format off -constexpr float kInvertColorMatrix[20] = { - -1.0, 0, 0, 1.0, 0, - 0, -1.0, 0, 1.0, 0, - 0, 0, -1.0, 1.0, 0, - 1.0, 1.0, 1.0, 1.0, 0 -}; -// clang-format on - void SkPaintDispatchHelper::save_opacity(SkScalar child_opacity) { save_stack_.emplace_back(opacity_); set_opacity(child_opacity); @@ -96,13 +87,18 @@ void SkPaintDispatchHelper::setMaskFilter(const DlMaskFilter* filter) { } sk_sp SkPaintDispatchHelper::makeColorFilter() const { - if (!invert_colors_) { - return color_filter_ ? color_filter_->skia_object() : nullptr; + return MakeColorFilter(invert_colors_, color_filter_.get()); +} + +sk_sp SkPaintDispatchHelper::MakeColorFilter( + bool isInvertColors, const DlColorFilter* color_filter) { + if (!isInvertColors) { + return color_filter ? color_filter->skia_object() : nullptr; } sk_sp invert_filter = SkColorFilters::Matrix(kInvertColorMatrix); - if (color_filter_) { - invert_filter = invert_filter->makeComposed(color_filter_->skia_object()); + if (color_filter) { + invert_filter = invert_filter->makeComposed(color_filter->skia_object()); } return invert_filter; } diff --git a/display_list/display_list_utils.h b/display_list/display_list_utils.h index ff2bad1544fd7..471a7b19c95e0 100644 --- a/display_list/display_list_utils.h +++ b/display_list/display_list_utils.h @@ -174,6 +174,17 @@ class SkPaintDispatchHelper : public virtual Dispatcher { } } + // clang-format off + static constexpr float kInvertColorMatrix[20] = { + -1.0, 0, 0, 1.0, 0, + 0, -1.0, 0, 1.0, 0, + 0, 0, -1.0, 1.0, 0, + 1.0, 1.0, 1.0, 1.0, 0 + }; + // clang-format on + static sk_sp MakeColorFilter( + bool isInvertColors, const DlColorFilter* color_filter); + void setAntiAlias(bool aa) override; void setDither(bool dither) override; void setStyle(DlDrawStyle style) override; diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index 6e602f51c29fc..952d022ad6a77 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -70,7 +70,8 @@ void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { canvas_ = canvas; for (auto& state : state_stack_) { if (state.is_layer) { - canvas->saveLayer(state.save_bounds(), state.save_skpaint()); + SkPaint paint; + canvas->saveLayer(state.save_bounds(), state.save_skpaint(paint)); } else { canvas->save(); } @@ -92,7 +93,14 @@ void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { builder_ = builder; for (auto& state : state_stack_) { if (state.is_layer) { - builder->saveLayer(state.save_bounds(), state.save_skpaint()); + // We do not save the backdrop filter for later playback because + // that filter should only be used to populate the temporary layer + // of the first invocation of saveLayer. Since the filtered backdrop + // appears behind any of the content of the saveLayer, subsequent + // builder objects that are being populated from this state stack + // should performa normal saveLayer with the properties that clip + // or modulate that layers contents. + builder->saveLayer(state.save_bounds(), state.save_dlpaint()); } else { builder->save(); } @@ -154,12 +162,13 @@ void LayerStateStack::saveLayer(const SkRect* bounds, state.layer_paint = *paint; } if (canvas_) { + SkPaint paint; if (backdrop_filter) { sk_sp sk_filter = backdrop_filter->skia_object(); canvas_->saveLayer(SkCanvas::SaveLayerRec( - state.save_bounds(), state.save_skpaint(), sk_filter.get(), 0)); + state.save_bounds(), state.save_skpaint(paint), sk_filter.get(), 0)); } else { - canvas_->saveLayer(state.save_bounds(), state.save_skpaint()); + canvas_->saveLayer(state.save_bounds(), state.save_skpaint(paint)); } } if (builder_) { diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 08d60de3a86e6..a022b70f2b18b 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -136,9 +136,12 @@ class LayerStateStack { RenderState(SkM44& incoming_matrix); SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } - SkPaint* save_skpaint() { - FML_DCHECK(false); - return nullptr; + SkPaint* save_skpaint(SkPaint& paint) { + if (!layer_has_paint) { + return nullptr; + } + layer_paint.toSkPaint(paint); + return &paint; } DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } From 82f7d337be2a7a17685096dfdfe8c3bcecaa2026 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 23 Aug 2022 15:35:29 -0700 Subject: [PATCH 04/19] move LayerStateStack to its own files --- flow/layers/layer.cc | 2 +- flow/layers/layer.h | 240 +++++++++++++------------- flow/layers/layer_state_stack.cc | 279 +++++++++++++++++++++++++++++++ flow/layers/layer_state_stack.h | 140 ++++++++++++++++ 4 files changed, 540 insertions(+), 121 deletions(-) create mode 100644 flow/layers/layer_state_stack.cc create mode 100644 flow/layers/layer_state_stack.h diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index 952d022ad6a77..c4d991c682186 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -126,7 +126,7 @@ void LayerStateStack::setMutatorDelegate(MutatorsStack* mutators) { } LayerStateStack::AutoRestore::AutoRestore(LayerStateStack* stack) - : stack_(stack), stack_restore_count_(stack->getSaveCount()) {} + : stack_(stack), stack_restore_count_(stack->getStackCount()) {} LayerStateStack::AutoRestore::~AutoRestore() { stack_->restoreToCount(stack_restore_count_); diff --git a/flow/layers/layer.h b/flow/layers/layer.h index a022b70f2b18b..9c92715abbdad 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -45,126 +45,126 @@ class RasterCacheItem; static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); -class LayerStateStack { - public: - LayerStateStack(); - - void setCanvasDelegate(SkCanvas* canvas); - void setBuilderDelegate(DisplayListBuilder* canvas); - void setMutatorDelegate(MutatorsStack* mutators); - - class AutoRestore { - public: - ~AutoRestore(); - - private: - AutoRestore(LayerStateStack* stack); - friend class LayerStateStack; - - LayerStateStack* stack_; - const int stack_restore_count_; - }; - - void save(); - [[nodiscard]] AutoRestore autoSave(); - void saveLayer(const SkRect* bounds = nullptr, - const DlPaint* paint = nullptr, - const DlImageFilter* backdrop_filter = nullptr); - [[nodiscard]] AutoRestore autoSaveLayer( - const SkRect* bounds = nullptr, - const DlPaint* paint = nullptr, - const DlImageFilter* backdrop_filter = nullptr); - void restore(); - void restoreToCount(int restore_count); - int getSaveCount(); - - void translate(SkScalar tx, SkScalar ty); - void scale(SkScalar sx, SkScalar sy); - void skew(SkScalar sx, SkScalar sy); - void rotate(SkScalar degrees); - void transform(SkM44& matrix); - void transform(SkMatrix& matrix); - - void clipRect(const SkRect& rect, SkClipOp op, bool is_aa); - void clipRRect(const SkRRect& rect, SkClipOp op, bool is_aa); - void clipPath(const SkPath& rect, SkClipOp op, bool is_aa); - - private: - class ClipEntry { - public: - virtual void apply(SkCanvas& canvas) const = 0; - virtual void apply(DisplayListBuilder& builder) const = 0; - - protected: - ClipEntry(SkClipOp op, bool is_aa); - - const SkClipOp clip_op_; - const bool is_aa_; - }; - - class ClipRectEntry : public ClipEntry { - ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa); - - void apply(SkCanvas& canvas) const override; - void apply(DisplayListBuilder& canvas) const override; - - private: - const SkRect rect_; - }; - - class ClipRRectEntry : public ClipEntry { - ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa); - - void apply(SkCanvas& canvas) const override; - void apply(DisplayListBuilder& canvas) const override; - - private: - const SkRRect rrect_; - }; - - class ClipPathEntry : public ClipEntry { - ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa); - - void apply(SkCanvas& canvas) const override; - void apply(DisplayListBuilder& canvas) const override; - - private: - const SkPath path_; - }; - - struct RenderState { - RenderState(SkM44& incoming_matrix); - - SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } - SkPaint* save_skpaint(SkPaint& paint) { - if (!layer_has_paint) { - return nullptr; - } - layer_paint.toSkPaint(paint); - return &paint; - } - DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } - - bool is_layer; - - bool layer_has_bounds; - SkRect layer_bounds; - - bool layer_has_paint; - DlPaint layer_paint; - - SkM44 matrix; - std::vector> clip_ops; - }; - - std::vector state_stack_; - - SkCanvas* canvas_ = nullptr; - int canvas_restore_count_; - DisplayListBuilder* builder_ = nullptr; - int builder_restore_count_; - MutatorsStack* mutators_ = nullptr; -}; +// class LayerStateStack { +// public: +// LayerStateStack(); + +// void setCanvasDelegate(SkCanvas* canvas); +// void setBuilderDelegate(DisplayListBuilder* canvas); +// void setMutatorDelegate(MutatorsStack* mutators); + +// class AutoRestore { +// public: +// ~AutoRestore(); + +// private: +// AutoRestore(LayerStateStack* stack); +// friend class LayerStateStack; + +// LayerStateStack* stack_; +// const int stack_restore_count_; +// }; + +// [[nodiscard]] AutoRestore autoSave(); +// [[nodiscard]] AutoRestore pushImageFilter(const SkRect* bounds, +// const DlImageFilter* filter); +// [[nodiscard]] AutoRestore pushColorFilter(const SkRect* bounds, +// const DlColorFilter* filter); +// [[nodiscard]] AutoRestore pushBackdropFilter(const SkRect* bounds, +// const DlImageFilter* backdrop); +// void translate(SkScalar tx, SkScalar ty); +// void scale(SkScalar sx, SkScalar sy); +// void skew(SkScalar sx, SkScalar sy); +// void rotate(SkScalar degrees); +// void transform(SkM44& matrix); +// void transform(SkMatrix& matrix); + +// void clipRect(const SkRect& rect, SkClipOp op, bool is_aa); +// void clipRRect(const SkRRect& rect, SkClipOp op, bool is_aa); +// void clipPath(const SkPath& rect, SkClipOp op, bool is_aa); + +// private: +// int getStackCount(); +// void restoreToCount(int restore_count); + +// class StateEntry { +// public: +// virtual void apply(SkCanvas& canvas) const = 0; +// virtual void apply(DisplayListBuilder& canvas) const = 0; +// virtual void apply(MutatorsStack& mutators) const = 0; +// }; + +// class ClipEntry : public StateEntry { +// protected: +// ClipEntry(SkClipOp op, bool is_aa); + +// const SkClipOp clip_op_; +// const bool is_aa_; +// }; + +// class ClipRectEntry : public ClipEntry { +// ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa); + +// void apply(SkCanvas& canvas) const override; +// void apply(DisplayListBuilder& canvas) const override; + +// private: +// const SkRect rect_; +// }; + +// class ClipRRectEntry : public ClipEntry { +// ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa); + +// void apply(SkCanvas& canvas) const override; +// void apply(DisplayListBuilder& canvas) const override; + +// private: +// const SkRRect rrect_; +// }; + +// class ClipPathEntry : public ClipEntry { +// ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa); + +// void apply(SkCanvas& canvas) const override; +// void apply(DisplayListBuilder& canvas) const override; + +// private: +// const SkPath path_; +// }; + +// struct RenderState { +// RenderState(SkM44& incoming_matrix); + +// SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } +// SkPaint* save_skpaint(SkPaint& paint) { +// if (!layer_has_paint) { +// return nullptr; +// } +// layer_paint.toSkPaint(paint); +// return &paint; +// } +// DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } + +// bool is_layer; + +// bool layer_has_bounds; +// SkRect layer_bounds; + +// bool layer_has_paint; +// DlPaint layer_paint; + +// SkM44 matrix; +// std::vector> clip_ops; +// }; + +// std::vector state_stack_; + +// SkCanvas* canvas_ = nullptr; +// int canvas_restore_count_; +// DisplayListBuilder* builder_ = nullptr; +// int builder_restore_count_; +// MutatorsStack* mutators_ = nullptr; +// }; // This should be an exact copy of the Clip enum in painting.dart. enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer }; diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc new file mode 100644 index 0000000000000..a2f3423340f37 --- /dev/null +++ b/flow/layers/layer_state_stack.cc @@ -0,0 +1,279 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/flow/layers/layer_state_stack.h" + +namespace flutter { + +LayerStateStack::LayerStateStack() { + state_stack_.emplace_back(SkM44()); +} + +void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { + if (canvas_) { + canvas_->restoreToCount(canvas_restore_count_); + canvas_ = nullptr; + } + if (canvas) { + canvas_restore_count_ = canvas->getSaveCount(); + canvas_ = canvas; + for (auto& state : state_stack_) { + if (state.is_layer) { + SkPaint paint; + canvas->saveLayer(state.save_bounds(), state.save_skpaint(paint)); + } else { + canvas->save(); + } + canvas->setMatrix(state.matrix); + for (auto& clip : state.clip_ops) { + clip->apply(*canvas); + } + } + } +} + +void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { + if (builder_) { + builder_->restoreToCount(builder_restore_count_); + builder_ = nullptr; + } + if (builder) { + builder_restore_count_ = builder->getSaveCount(); + builder_ = builder; + for (auto& state : state_stack_) { + if (state.is_layer) { + // We do not save the backdrop filter for later playback because + // that filter should only be used to populate the temporary layer + // of the first invocation of saveLayer. Since the filtered backdrop + // appears behind any of the content of the saveLayer, subsequent + // builder objects that are being populated from this state stack + // should performa normal saveLayer with the properties that clip + // or modulate that layers contents. + builder->saveLayer(state.save_bounds(), state.save_dlpaint()); + } else { + builder->save(); + } + builder->transformReset(); + builder->transform(state.matrix); + for (auto& clip : state.clip_ops) { + clip->apply(*builder); + } + } + } +} + +void LayerStateStack::setMutatorDelegate(MutatorsStack* mutators) { + // Does a MutatorsStack do restoreToCount? + if (mutators_) { + // builder_->restoreToCount(builder_restore_count_); + mutators_ = nullptr; + } + if (mutators) { + // builder_restore_count_ = mutators->getSaveCount(); + mutators_ = mutators; + } +} + +LayerStateStack::AutoRestore::AutoRestore(LayerStateStack* stack) + : stack_(stack), stack_restore_count_(stack->getStackCount()) {} + +LayerStateStack::AutoRestore::~AutoRestore() { + stack_->restoreToCount(stack_restore_count_); +} + +void LayerStateStack::save() { + state_stack_.emplace_back(state_stack_.back().matrix); + RenderState& state = state_stack_.back(); + state.is_layer = false; + if (canvas_) { + canvas_->save(); + } + if (builder_) { + builder_->save(); + } +} + +LayerStateStack::AutoRestore LayerStateStack::autoSave() { + save(); + return AutoRestore(this); +} + +void LayerStateStack::saveLayer(const SkRect* bounds, + const DlPaint* paint, + const DlImageFilter* backdrop_filter) { + state_stack_.emplace_back(state_stack_.back().matrix); + RenderState& state = state_stack_.back(); + state.is_layer = true; + if ((state.layer_has_bounds = (bounds != nullptr))) { + state.layer_bounds = *bounds; + } + if ((state.layer_has_paint = (paint != nullptr))) { + state.layer_paint = *paint; + } + if (canvas_) { + SkPaint paint; + if (backdrop_filter) { + sk_sp sk_filter = backdrop_filter->skia_object(); + canvas_->saveLayer(SkCanvas::SaveLayerRec( + state.save_bounds(), state.save_skpaint(paint), sk_filter.get(), 0)); + } else { + canvas_->saveLayer(state.save_bounds(), state.save_skpaint(paint)); + } + } + if (builder_) { + builder_->saveLayer(bounds, paint, backdrop_filter); + } +} + +LayerStateStack::AutoRestore LayerStateStack::autoSaveLayer( + const SkRect* bounds, + const DlPaint* paint, + const DlImageFilter* backdrop_filter) { + saveLayer(bounds, paint, backdrop_filter); + return AutoRestore(this); +} + +void LayerStateStack::translate(SkScalar tx, SkScalar ty) { + state_stack_.back().matrix.preTranslate(tx, ty); + if (canvas_) { + canvas_->translate(tx, ty); + } + if (builder_) { + builder_->translate(tx, ty); + } +} + +void LayerStateStack::scale(SkScalar sx, SkScalar sy) { + state_stack_.back().matrix.preScale(sx, sy); + if (canvas_) { + canvas_->scale(sx, sy); + } + if (builder_) { + builder_->scale(sx, sy); + } +} + +void LayerStateStack::skew(SkScalar sx, SkScalar sy) { + SkMatrix m; + m.setSkew(sx, sy); + state_stack_.back().matrix.preConcat(SkM44(m)); + if (canvas_) { + canvas_->skew(sx, sy); + } + if (builder_) { + builder_->skew(sx, sy); + } +} + +void LayerStateStack::rotate(SkScalar degrees) { + SkMatrix m; + m.setRotate(degrees); + state_stack_.back().matrix.preConcat(SkM44(m)); + if (canvas_) { + canvas_->rotate(degrees); + } + if (builder_) { + builder_->rotate(degrees); + } +} + +void LayerStateStack::transform(SkMatrix& matrix) { + state_stack_.back().matrix.preConcat(SkM44(matrix)); + if (canvas_) { + canvas_->concat(matrix); + } + if (builder_) { + builder_->transform(matrix); + } +} + +void LayerStateStack::transform(SkM44& matrix) { + state_stack_.back().matrix.preConcat(matrix); + if (canvas_) { + canvas_->concat(matrix); + } + if (builder_) { + builder_->transform(matrix); + } +} + +void LayerStateStack::clipRect(const SkRect& rect, SkClipOp op, bool is_aa) { + state_stack_.back().clip_ops.push_back( + std::make_unique(rect, op, is_aa)); + if (canvas_) { + canvas_->clipRect(rect, op, is_aa); + } + if (builder_) { + builder_->clipRect(rect, op, is_aa); + } +} + +void LayerStateStack::clipRRect(const SkRRect& rrect, SkClipOp op, bool is_aa) { + state_stack_.back().clip_ops.push_back( + std::make_unique(rrect, op, is_aa)); + if (canvas_) { + canvas_->clipRRect(rrect, op, is_aa); + } + if (builder_) { + builder_->clipRRect(rrect, op, is_aa); + } +} + +void LayerStateStack::clipPath(const SkPath& path, SkClipOp op, bool is_aa) { + state_stack_.back().clip_ops.push_back( + std::make_unique(path, op, is_aa)); + if (canvas_) { + canvas_->clipPath(path, op, is_aa); + } + if (builder_) { + builder_->clipPath(path, op, is_aa); + } +} + +LayerStateStack::ClipEntry::ClipEntry(SkClipOp op, bool is_aa) + : clip_op_(op), is_aa_(is_aa) {} + +LayerStateStack::ClipRectEntry::ClipRectEntry(const SkRect& rect, + SkClipOp op, + bool is_aa) + : ClipEntry(op, is_aa), rect_(rect) {} + +void LayerStateStack::ClipRectEntry::apply(SkCanvas& canvas) const { + canvas.clipRect(rect_, clip_op_, is_aa_); +} + +void LayerStateStack::ClipRectEntry::apply(DisplayListBuilder& builder) const { + builder.clipRect(rect_, clip_op_, is_aa_); +} + +LayerStateStack::ClipRRectEntry::ClipRRectEntry(const SkRRect& rrect, + SkClipOp op, + bool is_aa) + : ClipEntry(op, is_aa), rrect_(rrect) {} + +void LayerStateStack::ClipRRectEntry::apply(SkCanvas& canvas) const { + canvas.clipRRect(rrect_, clip_op_, is_aa_); +} + +void LayerStateStack::ClipRRectEntry::apply(DisplayListBuilder& builder) const { + builder.clipRRect(rrect_, clip_op_, is_aa_); +} + +LayerStateStack::ClipPathEntry::ClipPathEntry(const SkPath& path, + SkClipOp op, + bool is_aa) + : ClipEntry(op, is_aa), path_(path) {} + +void LayerStateStack::ClipPathEntry::apply(SkCanvas& canvas) const { + canvas.clipPath(path_, clip_op_, is_aa_); +} + +void LayerStateStack::ClipPathEntry::apply(DisplayListBuilder& builder) const { + builder.clipPath(path_, clip_op_, is_aa_); +} + +LayerStateStack::RenderState::RenderState(SkM44& incoming_matrix) + : matrix(incoming_matrix) {} + +} // namespace flutter diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h new file mode 100644 index 0000000000000..0d481413682dc --- /dev/null +++ b/flow/layers/layer_state_stack.h @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FLOW_LAYERS_LAYER_STATE_STACK_H_ +#define FLUTTER_FLOW_LAYERS_LAYER_STATE_STACK_H_ + +#include "flutter/display_list/display_list_builder.h" +#include "layer.h" + +namespace flutter { + +class LayerStateStack { + public: + LayerStateStack(); + + void setCanvasDelegate(SkCanvas* canvas); + void setBuilderDelegate(DisplayListBuilder* canvas); + void setMutatorDelegate(MutatorsStack* mutators); + + class AutoRestore { + public: + ~AutoRestore(); + + private: + AutoRestore(LayerStateStack* stack); + friend class LayerStateStack; + + LayerStateStack* stack_; + const int stack_restore_count_; + }; + + [[nodiscard]] AutoRestore autoSave(); + [[nodiscard]] AutoRestore pushImageFilter(const SkRect* bounds, + const DlImageFilter* filter); + [[nodiscard]] AutoRestore pushColorFilter(const SkRect* bounds, + const DlColorFilter* filter); + [[nodiscard]] AutoRestore pushBackdropFilter(const SkRect* bounds, + const DlImageFilter* backdrop); + void translate(SkScalar tx, SkScalar ty); + void scale(SkScalar sx, SkScalar sy); + void skew(SkScalar sx, SkScalar sy); + void rotate(SkScalar degrees); + void transform(SkM44& matrix); + void transform(SkMatrix& matrix); + + void clipRect(const SkRect& rect, SkClipOp op, bool is_aa); + void clipRRect(const SkRRect& rect, SkClipOp op, bool is_aa); + void clipPath(const SkPath& rect, SkClipOp op, bool is_aa); + + private: + int getStackCount(); + void restoreToCount(int restore_count); + + class StateEntry { + public: + virtual void apply(SkCanvas& canvas) const = 0; + virtual void apply(DisplayListBuilder& canvas) const = 0; + virtual void apply(MutatorsStack& mutators) const = 0; + }; + + class TransformEntry : public StateEntry { + + }; + + class ClipEntry : public StateEntry { + protected: + ClipEntry(SkClipOp op, bool is_aa); + + const SkClipOp clip_op_; + const bool is_aa_; + }; + + class ClipRectEntry : public ClipEntry { + ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa); + + void apply(SkCanvas& canvas) const override; + void apply(DisplayListBuilder& canvas) const override; + + private: + const SkRect rect_; + }; + + class ClipRRectEntry : public ClipEntry { + ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa); + + void apply(SkCanvas& canvas) const override; + void apply(DisplayListBuilder& canvas) const override; + + private: + const SkRRect rrect_; + }; + + class ClipPathEntry : public ClipEntry { + ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa); + + void apply(SkCanvas& canvas) const override; + void apply(DisplayListBuilder& canvas) const override; + + private: + const SkPath path_; + }; + + struct RenderState { + RenderState(SkM44& incoming_matrix); + + SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } + SkPaint* save_skpaint(SkPaint& paint) { + if (!layer_has_paint) { + return nullptr; + } + layer_paint.toSkPaint(paint); + return &paint; + } + DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } + + bool is_layer; + + bool layer_has_bounds; + SkRect layer_bounds; + + bool layer_has_paint; + DlPaint layer_paint; + + SkM44 matrix; + std::vector> clip_ops; + }; + + std::vector state_stack_; + + SkCanvas* canvas_ = nullptr; + int canvas_restore_count_; + DisplayListBuilder* builder_ = nullptr; + int builder_restore_count_; + MutatorsStack* mutators_ = nullptr; +}; + +} // namespace flutter + +#endif // FLUTTER_FLOW_LAYERS_LAYER_STATE_STACK_H_ From 135737fb7558b031ff77c1a61f5e010733fc45e2 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 23 Aug 2022 21:05:59 -0700 Subject: [PATCH 05/19] LayerStackState compiles --- display_list/display_list_paint.cc | 19 -- display_list/display_list_paint.h | 19 +- display_list/display_list_utils.cc | 3 +- display_list/display_list_utils.h | 3 +- flow/layers/layer.cc | 270 ------------------------ flow/layers/layer.h | 121 ----------- flow/layers/layer_state_stack.cc | 316 +++++++++++++---------------- flow/layers/layer_state_stack.h | 176 +++++++++++----- 8 files changed, 267 insertions(+), 660 deletions(-) diff --git a/display_list/display_list_paint.cc b/display_list/display_list_paint.cc index 581df8e81448a..d3a0f8c752c29 100644 --- a/display_list/display_list_paint.cc +++ b/display_list/display_list_paint.cc @@ -4,8 +4,6 @@ #include "flutter/display_list/display_list_paint.h" -#include "flutter/display_list/display_list_utils.h" - namespace flutter { DlPaint::DlPaint() @@ -36,21 +34,4 @@ bool DlPaint::operator==(DlPaint const& other) const { Equals(maskFilter_, other.maskFilter_); } -void DlPaint::toSkPaint(SkPaint& paint) const { - paint.setAntiAlias(isAntiAlias_); - paint.setDither(isDither_); - paint.setColor(color_); - paint.setBlendMode(getSkBlendMode()); - paint.setStyle(getSkDrawStyle()); - paint.setStrokeCap(getSkStrokeCap()); - paint.setStrokeJoin(getSkStrokeJoin()); - paint.setStrokeWidth(strokeWidth_); - paint.setStrokeMiter(strokeMiter_); - paint.setShader(colorSource_ ? colorSource_->skia_object() : nullptr); - paint.setColorFilter(SkPaintDispatchHelper::MakeColorFilter( - isInvertColors_, colorFilter_.get())); - paint.setImageFilter(imageFilter_->skia_object()); - paint.setMaskFilter(maskFilter_->skia_object()); -} - } // namespace flutter diff --git a/display_list/display_list_paint.h b/display_list/display_list_paint.h index bda8d09434f63..1bd6f6bed562b 100644 --- a/display_list/display_list_paint.h +++ b/display_list/display_list_paint.h @@ -166,7 +166,7 @@ class DlPaint { return colorFilter_; } const DlColorFilter* getColorFilterPtr() const { return colorFilter_.get(); } - DlPaint& setColorFilter(std::shared_ptr filter) { + DlPaint& setColorFilter(const std::shared_ptr filter) { colorFilter_ = filter ? filter->shared() : nullptr; return *this; } @@ -179,7 +179,7 @@ class DlPaint { return imageFilter_; } const DlImageFilter* getImageFilterPtr() const { return imageFilter_.get(); } - DlPaint& setImageFilter(std::shared_ptr filter) { + DlPaint& setImageFilter(const std::shared_ptr filter) { imageFilter_ = filter; return *this; } @@ -213,8 +213,6 @@ class DlPaint { bool operator==(DlPaint const& other) const; bool operator!=(DlPaint const& other) const { return !(*this == other); } - void toSkPaint(SkPaint& paint) const; - private: #define ASSERT_ENUM_FITS(last_enum, num_bits) \ static_assert(static_cast(last_enum) < (1 << num_bits) && \ @@ -241,19 +239,6 @@ class DlPaint { }; }; - SkBlendMode getSkBlendMode() const { - return static_cast(blendMode_); - } - SkPaint::Style getSkDrawStyle() const { - return static_cast(drawStyle_); - } - SkPaint::Cap getSkStrokeCap() const { - return static_cast(strokeCap_); - } - SkPaint::Join getSkStrokeJoin() const { - return static_cast(strokeJoin_); - } - DlColor color_; float strokeWidth_; float strokeMiter_; diff --git a/display_list/display_list_utils.cc b/display_list/display_list_utils.cc index b7b35ec941a9b..dc2da62df4020 100644 --- a/display_list/display_list_utils.cc +++ b/display_list/display_list_utils.cc @@ -91,7 +91,8 @@ sk_sp SkPaintDispatchHelper::makeColorFilter() const { } sk_sp SkPaintDispatchHelper::MakeColorFilter( - bool isInvertColors, const DlColorFilter* color_filter) { + bool isInvertColors, + const DlColorFilter* color_filter) { if (!isInvertColors) { return color_filter ? color_filter->skia_object() : nullptr; } diff --git a/display_list/display_list_utils.h b/display_list/display_list_utils.h index 471a7b19c95e0..af7db4c6c5fde 100644 --- a/display_list/display_list_utils.h +++ b/display_list/display_list_utils.h @@ -183,7 +183,8 @@ class SkPaintDispatchHelper : public virtual Dispatcher { }; // clang-format on static sk_sp MakeColorFilter( - bool isInvertColors, const DlColorFilter* color_filter); + bool isInvertColors, + const DlColorFilter* color_filter); void setAntiAlias(bool aa) override; void setDither(bool dither) override; diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index c4d991c682186..8a34b775ef766 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -56,276 +56,6 @@ Layer::AutoPrerollSaveLayerState::~AutoPrerollSaveLayerState() { } } -LayerStateStack::LayerStateStack() { - state_stack_.emplace_back(SkM44()); -} - -void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { - if (canvas_) { - canvas_->restoreToCount(canvas_restore_count_); - canvas_ = nullptr; - } - if (canvas) { - canvas_restore_count_ = canvas->getSaveCount(); - canvas_ = canvas; - for (auto& state : state_stack_) { - if (state.is_layer) { - SkPaint paint; - canvas->saveLayer(state.save_bounds(), state.save_skpaint(paint)); - } else { - canvas->save(); - } - canvas->setMatrix(state.matrix); - for (auto& clip : state.clip_ops) { - clip->apply(*canvas); - } - } - } -} - -void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { - if (builder_) { - builder_->restoreToCount(builder_restore_count_); - builder_ = nullptr; - } - if (builder) { - builder_restore_count_ = builder->getSaveCount(); - builder_ = builder; - for (auto& state : state_stack_) { - if (state.is_layer) { - // We do not save the backdrop filter for later playback because - // that filter should only be used to populate the temporary layer - // of the first invocation of saveLayer. Since the filtered backdrop - // appears behind any of the content of the saveLayer, subsequent - // builder objects that are being populated from this state stack - // should performa normal saveLayer with the properties that clip - // or modulate that layers contents. - builder->saveLayer(state.save_bounds(), state.save_dlpaint()); - } else { - builder->save(); - } - builder->transformReset(); - builder->transform(state.matrix); - for (auto& clip : state.clip_ops) { - clip->apply(*builder); - } - } - } -} - -void LayerStateStack::setMutatorDelegate(MutatorsStack* mutators) { - // Does a MutatorsStack do restoreToCount? - if (mutators_) { - // builder_->restoreToCount(builder_restore_count_); - mutators_ = nullptr; - } - if (mutators) { - // builder_restore_count_ = mutators->getSaveCount(); - mutators_ = mutators; - } -} - -LayerStateStack::AutoRestore::AutoRestore(LayerStateStack* stack) - : stack_(stack), stack_restore_count_(stack->getStackCount()) {} - -LayerStateStack::AutoRestore::~AutoRestore() { - stack_->restoreToCount(stack_restore_count_); -} - -void LayerStateStack::save() { - state_stack_.emplace_back(state_stack_.back().matrix); - RenderState& state = state_stack_.back(); - state.is_layer = false; - if (canvas_) { - canvas_->save(); - } - if (builder_) { - builder_->save(); - } -} - -LayerStateStack::AutoRestore LayerStateStack::autoSave() { - save(); - return AutoRestore(this); -} - -void LayerStateStack::saveLayer(const SkRect* bounds, - const DlPaint* paint, - const DlImageFilter* backdrop_filter) { - state_stack_.emplace_back(state_stack_.back().matrix); - RenderState& state = state_stack_.back(); - state.is_layer = true; - if ((state.layer_has_bounds = (bounds != nullptr))) { - state.layer_bounds = *bounds; - } - if ((state.layer_has_paint = (paint != nullptr))) { - state.layer_paint = *paint; - } - if (canvas_) { - SkPaint paint; - if (backdrop_filter) { - sk_sp sk_filter = backdrop_filter->skia_object(); - canvas_->saveLayer(SkCanvas::SaveLayerRec( - state.save_bounds(), state.save_skpaint(paint), sk_filter.get(), 0)); - } else { - canvas_->saveLayer(state.save_bounds(), state.save_skpaint(paint)); - } - } - if (builder_) { - builder_->saveLayer(bounds, paint, backdrop_filter); - } -} - -LayerStateStack::AutoRestore LayerStateStack::autoSaveLayer( - const SkRect* bounds, - const DlPaint* paint, - const DlImageFilter* backdrop_filter) { - saveLayer(bounds, paint, backdrop_filter); - return AutoRestore(this); -} - -void LayerStateStack::translate(SkScalar tx, SkScalar ty) { - state_stack_.back().matrix.preTranslate(tx, ty); - if (canvas_) { - canvas_->translate(tx, ty); - } - if (builder_) { - builder_->translate(tx, ty); - } -} - -void LayerStateStack::scale(SkScalar sx, SkScalar sy) { - state_stack_.back().matrix.preScale(sx, sy); - if (canvas_) { - canvas_->scale(sx, sy); - } - if (builder_) { - builder_->scale(sx, sy); - } -} - -void LayerStateStack::skew(SkScalar sx, SkScalar sy) { - SkMatrix m; - m.setSkew(sx, sy); - state_stack_.back().matrix.preConcat(SkM44(m)); - if (canvas_) { - canvas_->skew(sx, sy); - } - if (builder_) { - builder_->skew(sx, sy); - } -} - -void LayerStateStack::rotate(SkScalar degrees) { - SkMatrix m; - m.setRotate(degrees); - state_stack_.back().matrix.preConcat(SkM44(m)); - if (canvas_) { - canvas_->rotate(degrees); - } - if (builder_) { - builder_->rotate(degrees); - } -} - -void LayerStateStack::transform(SkMatrix& matrix) { - state_stack_.back().matrix.preConcat(SkM44(matrix)); - if (canvas_) { - canvas_->concat(matrix); - } - if (builder_) { - builder_->transform(matrix); - } -} - -void LayerStateStack::transform(SkM44& matrix) { - state_stack_.back().matrix.preConcat(matrix); - if (canvas_) { - canvas_->concat(matrix); - } - if (builder_) { - builder_->transform(matrix); - } -} - -void LayerStateStack::clipRect(const SkRect& rect, SkClipOp op, bool is_aa) { - state_stack_.back().clip_ops.push_back( - std::make_unique(rect, op, is_aa)); - if (canvas_) { - canvas_->clipRect(rect, op, is_aa); - } - if (builder_) { - builder_->clipRect(rect, op, is_aa); - } -} - -void LayerStateStack::clipRRect(const SkRRect& rrect, SkClipOp op, bool is_aa) { - state_stack_.back().clip_ops.push_back( - std::make_unique(rrect, op, is_aa)); - if (canvas_) { - canvas_->clipRRect(rrect, op, is_aa); - } - if (builder_) { - builder_->clipRRect(rrect, op, is_aa); - } -} - -void LayerStateStack::clipPath(const SkPath& path, SkClipOp op, bool is_aa) { - state_stack_.back().clip_ops.push_back( - std::make_unique(path, op, is_aa)); - if (canvas_) { - canvas_->clipPath(path, op, is_aa); - } - if (builder_) { - builder_->clipPath(path, op, is_aa); - } -} - -LayerStateStack::ClipEntry::ClipEntry(SkClipOp op, bool is_aa) - : clip_op_(op), is_aa_(is_aa) {} - -LayerStateStack::ClipRectEntry::ClipRectEntry(const SkRect& rect, - SkClipOp op, - bool is_aa) - : ClipEntry(op, is_aa), rect_(rect) {} - -void LayerStateStack::ClipRectEntry::apply(SkCanvas& canvas) const { - canvas.clipRect(rect_, clip_op_, is_aa_); -} - -void LayerStateStack::ClipRectEntry::apply(DisplayListBuilder& builder) const { - builder.clipRect(rect_, clip_op_, is_aa_); -} - -LayerStateStack::ClipRRectEntry::ClipRRectEntry(const SkRRect& rrect, - SkClipOp op, - bool is_aa) - : ClipEntry(op, is_aa), rrect_(rrect) {} - -void LayerStateStack::ClipRRectEntry::apply(SkCanvas& canvas) const { - canvas.clipRRect(rrect_, clip_op_, is_aa_); -} - -void LayerStateStack::ClipRRectEntry::apply(DisplayListBuilder& builder) const { - builder.clipRRect(rrect_, clip_op_, is_aa_); -} - -LayerStateStack::ClipPathEntry::ClipPathEntry(const SkPath& path, - SkClipOp op, - bool is_aa) - : ClipEntry(op, is_aa), path_(path) {} - -void LayerStateStack::ClipPathEntry::apply(SkCanvas& canvas) const { - canvas.clipPath(path_, clip_op_, is_aa_); -} - -void LayerStateStack::ClipPathEntry::apply(DisplayListBuilder& builder) const { - builder.clipPath(path_, clip_op_, is_aa_); -} - -LayerStateStack::RenderState::RenderState(SkM44& incoming_matrix) - : matrix(incoming_matrix) {} - Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, const SkRect& bounds, const SkPaint* paint, diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 9c92715abbdad..bb57b430fa3b0 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -45,127 +45,6 @@ class RasterCacheItem; static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); -// class LayerStateStack { -// public: -// LayerStateStack(); - -// void setCanvasDelegate(SkCanvas* canvas); -// void setBuilderDelegate(DisplayListBuilder* canvas); -// void setMutatorDelegate(MutatorsStack* mutators); - -// class AutoRestore { -// public: -// ~AutoRestore(); - -// private: -// AutoRestore(LayerStateStack* stack); -// friend class LayerStateStack; - -// LayerStateStack* stack_; -// const int stack_restore_count_; -// }; - -// [[nodiscard]] AutoRestore autoSave(); -// [[nodiscard]] AutoRestore pushImageFilter(const SkRect* bounds, -// const DlImageFilter* filter); -// [[nodiscard]] AutoRestore pushColorFilter(const SkRect* bounds, -// const DlColorFilter* filter); -// [[nodiscard]] AutoRestore pushBackdropFilter(const SkRect* bounds, -// const DlImageFilter* backdrop); -// void translate(SkScalar tx, SkScalar ty); -// void scale(SkScalar sx, SkScalar sy); -// void skew(SkScalar sx, SkScalar sy); -// void rotate(SkScalar degrees); -// void transform(SkM44& matrix); -// void transform(SkMatrix& matrix); - -// void clipRect(const SkRect& rect, SkClipOp op, bool is_aa); -// void clipRRect(const SkRRect& rect, SkClipOp op, bool is_aa); -// void clipPath(const SkPath& rect, SkClipOp op, bool is_aa); - -// private: -// int getStackCount(); -// void restoreToCount(int restore_count); - -// class StateEntry { -// public: -// virtual void apply(SkCanvas& canvas) const = 0; -// virtual void apply(DisplayListBuilder& canvas) const = 0; -// virtual void apply(MutatorsStack& mutators) const = 0; -// }; - -// class ClipEntry : public StateEntry { -// protected: -// ClipEntry(SkClipOp op, bool is_aa); - -// const SkClipOp clip_op_; -// const bool is_aa_; -// }; - -// class ClipRectEntry : public ClipEntry { -// ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa); - -// void apply(SkCanvas& canvas) const override; -// void apply(DisplayListBuilder& canvas) const override; - -// private: -// const SkRect rect_; -// }; - -// class ClipRRectEntry : public ClipEntry { -// ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa); - -// void apply(SkCanvas& canvas) const override; -// void apply(DisplayListBuilder& canvas) const override; - -// private: -// const SkRRect rrect_; -// }; - -// class ClipPathEntry : public ClipEntry { -// ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa); - -// void apply(SkCanvas& canvas) const override; -// void apply(DisplayListBuilder& canvas) const override; - -// private: -// const SkPath path_; -// }; - -// struct RenderState { -// RenderState(SkM44& incoming_matrix); - -// SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } -// SkPaint* save_skpaint(SkPaint& paint) { -// if (!layer_has_paint) { -// return nullptr; -// } -// layer_paint.toSkPaint(paint); -// return &paint; -// } -// DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } - -// bool is_layer; - -// bool layer_has_bounds; -// SkRect layer_bounds; - -// bool layer_has_paint; -// DlPaint layer_paint; - -// SkM44 matrix; -// std::vector> clip_ops; -// }; - -// std::vector state_stack_; - -// SkCanvas* canvas_ = nullptr; -// int canvas_restore_count_; -// DisplayListBuilder* builder_ = nullptr; -// int builder_restore_count_; -// MutatorsStack* mutators_ = nullptr; -// }; - // This should be an exact copy of the Clip enum in painting.dart. enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer }; diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index a2f3423340f37..2c9e246a2524f 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -5,7 +5,7 @@ #include "flutter/flow/layers/layer_state_stack.h" namespace flutter { - + LayerStateStack::LayerStateStack() { state_stack_.emplace_back(SkM44()); } @@ -19,15 +19,12 @@ void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { canvas_restore_count_ = canvas->getSaveCount(); canvas_ = canvas; for (auto& state : state_stack_) { - if (state.is_layer) { - SkPaint paint; - canvas->saveLayer(state.save_bounds(), state.save_skpaint(paint)); - } else { - canvas->save(); - } - canvas->setMatrix(state.matrix); - for (auto& clip : state.clip_ops) { - clip->apply(*canvas); + if (!state->is_backdrop_filter()) { + // BackdropFilter is only applied on the canvas that + // was present at the time that the backdrop layer was + // first encountered to avoid applying it on every + // platform view embedder overlay. + state->apply(canvas, nullptr); } } } @@ -42,39 +39,17 @@ void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { builder_restore_count_ = builder->getSaveCount(); builder_ = builder; for (auto& state : state_stack_) { - if (state.is_layer) { - // We do not save the backdrop filter for later playback because - // that filter should only be used to populate the temporary layer - // of the first invocation of saveLayer. Since the filtered backdrop - // appears behind any of the content of the saveLayer, subsequent - // builder objects that are being populated from this state stack - // should performa normal saveLayer with the properties that clip - // or modulate that layers contents. - builder->saveLayer(state.save_bounds(), state.save_dlpaint()); - } else { - builder->save(); - } - builder->transformReset(); - builder->transform(state.matrix); - for (auto& clip : state.clip_ops) { - clip->apply(*builder); + if (!state->is_backdrop_filter()) { + // BackdropFilter is only applied on the builder that + // was present at the time that the backdrop layer was + // first encountered to avoid applying it on every + // platform view embedder overlay. + state->apply(nullptr, builder); } } } } -void LayerStateStack::setMutatorDelegate(MutatorsStack* mutators) { - // Does a MutatorsStack do restoreToCount? - if (mutators_) { - // builder_->restoreToCount(builder_restore_count_); - mutators_ = nullptr; - } - if (mutators) { - // builder_restore_count_ = mutators->getSaveCount(); - mutators_ = mutators; - } -} - LayerStateStack::AutoRestore::AutoRestore(LayerStateStack* stack) : stack_(stack), stack_restore_count_(stack->getStackCount()) {} @@ -82,198 +57,179 @@ LayerStateStack::AutoRestore::~AutoRestore() { stack_->restoreToCount(stack_restore_count_); } -void LayerStateStack::save() { - state_stack_.emplace_back(state_stack_.back().matrix); - RenderState& state = state_stack_.back(); - state.is_layer = false; +LayerStateStack::AutoRestore LayerStateStack::save() { + auto ret = LayerStateStack::AutoRestore(this); + state_stack_.emplace_back(std::make_unique()); if (canvas_) { canvas_->save(); } if (builder_) { builder_->save(); } + return ret; } -LayerStateStack::AutoRestore LayerStateStack::autoSave() { - save(); - return AutoRestore(this); +LayerStateStack::AutoRestore LayerStateStack::saveWithImageFilter( + const SkRect* bounds, + const std::shared_ptr filter) { + auto ret = LayerStateStack::AutoRestore(this); + state_stack_.emplace_back(std::make_unique(bounds, filter)); + state_stack_.back()->apply(canvas_, builder_); + return ret; } -void LayerStateStack::saveLayer(const SkRect* bounds, - const DlPaint* paint, - const DlImageFilter* backdrop_filter) { - state_stack_.emplace_back(state_stack_.back().matrix); - RenderState& state = state_stack_.back(); - state.is_layer = true; - if ((state.layer_has_bounds = (bounds != nullptr))) { - state.layer_bounds = *bounds; - } - if ((state.layer_has_paint = (paint != nullptr))) { - state.layer_paint = *paint; - } - if (canvas_) { - SkPaint paint; - if (backdrop_filter) { - sk_sp sk_filter = backdrop_filter->skia_object(); - canvas_->saveLayer(SkCanvas::SaveLayerRec( - state.save_bounds(), state.save_skpaint(paint), sk_filter.get(), 0)); - } else { - canvas_->saveLayer(state.save_bounds(), state.save_skpaint(paint)); - } - } - if (builder_) { - builder_->saveLayer(bounds, paint, backdrop_filter); - } +LayerStateStack::AutoRestore LayerStateStack::saveWithColorFilter( + const SkRect* bounds, + const std::shared_ptr filter) { + auto ret = LayerStateStack::AutoRestore(this); + state_stack_.emplace_back(std::make_unique(bounds, filter)); + state_stack_.back()->apply(canvas_, builder_); + return ret; } -LayerStateStack::AutoRestore LayerStateStack::autoSaveLayer( +LayerStateStack::AutoRestore LayerStateStack::saveWithBackdropFilter( const SkRect* bounds, - const DlPaint* paint, - const DlImageFilter* backdrop_filter) { - saveLayer(bounds, paint, backdrop_filter); - return AutoRestore(this); + const std::shared_ptr filter) { + auto ret = LayerStateStack::AutoRestore(this); + state_stack_.emplace_back( + std::make_unique(bounds, filter)); + state_stack_.back()->apply(canvas_, builder_); + return ret; } void LayerStateStack::translate(SkScalar tx, SkScalar ty) { - state_stack_.back().matrix.preTranslate(tx, ty); - if (canvas_) { - canvas_->translate(tx, ty); - } - if (builder_) { - builder_->translate(tx, ty); - } + state_stack_.emplace_back(std::make_unique(tx, ty)); + state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::scale(SkScalar sx, SkScalar sy) { - state_stack_.back().matrix.preScale(sx, sy); - if (canvas_) { - canvas_->scale(sx, sy); - } - if (builder_) { - builder_->scale(sx, sy); - } +void LayerStateStack::transform(SkMatrix& matrix) { + state_stack_.emplace_back(std::make_unique(matrix)); + state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::skew(SkScalar sx, SkScalar sy) { - SkMatrix m; - m.setSkew(sx, sy); - state_stack_.back().matrix.preConcat(SkM44(m)); - if (canvas_) { - canvas_->skew(sx, sy); - } - if (builder_) { - builder_->skew(sx, sy); - } +void LayerStateStack::transform(SkM44& matrix) { + state_stack_.emplace_back(std::make_unique(matrix)); + state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::rotate(SkScalar degrees) { - SkMatrix m; - m.setRotate(degrees); - state_stack_.back().matrix.preConcat(SkM44(m)); - if (canvas_) { - canvas_->rotate(degrees); - } - if (builder_) { - builder_->rotate(degrees); - } +void LayerStateStack::clipRect(const SkRect& rect, SkClipOp op, bool is_aa) { + state_stack_.emplace_back(std::make_unique(rect, op, is_aa)); + state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::transform(SkMatrix& matrix) { - state_stack_.back().matrix.preConcat(SkM44(matrix)); - if (canvas_) { - canvas_->concat(matrix); - } - if (builder_) { - builder_->transform(matrix); - } +void LayerStateStack::clipRRect(const SkRRect& rrect, SkClipOp op, bool is_aa) { + state_stack_.emplace_back(std::make_unique(rrect, op, is_aa)); + state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::transform(SkM44& matrix) { - state_stack_.back().matrix.preConcat(matrix); - if (canvas_) { - canvas_->concat(matrix); - } - if (builder_) { - builder_->transform(matrix); - } +void LayerStateStack::clipPath(const SkPath& path, SkClipOp op, bool is_aa) { + state_stack_.emplace_back(std::make_unique(path, op, is_aa)); + state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::clipRect(const SkRect& rect, SkClipOp op, bool is_aa) { - state_stack_.back().clip_ops.push_back( - std::make_unique(rect, op, is_aa)); - if (canvas_) { - canvas_->clipRect(rect, op, is_aa); +void LayerStateStack::ImageFilterEntry::apply( + SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas) { + SkPaint paint; + paint.setImageFilter(filter_->skia_object()); + canvas->saveLayer(save_bounds(), &paint); } - if (builder_) { - builder_->clipRect(rect, op, is_aa); + if (builder) { + DlPaint paint; + paint.setImageFilter(filter_); + builder->saveLayer(save_bounds(), &paint); } } -void LayerStateStack::clipRRect(const SkRRect& rrect, SkClipOp op, bool is_aa) { - state_stack_.back().clip_ops.push_back( - std::make_unique(rrect, op, is_aa)); - if (canvas_) { - canvas_->clipRRect(rrect, op, is_aa); +void LayerStateStack::ColorFilterEntry::apply( + SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas) { + SkPaint paint; + paint.setColorFilter(filter_->skia_object()); + canvas->saveLayer(save_bounds(), &paint); } - if (builder_) { - builder_->clipRRect(rrect, op, is_aa); + if (builder) { + DlPaint paint; + paint.setColorFilter(filter_); + builder->saveLayer(save_bounds(), &paint); } } -void LayerStateStack::clipPath(const SkPath& path, SkClipOp op, bool is_aa) { - state_stack_.back().clip_ops.push_back( - std::make_unique(path, op, is_aa)); - if (canvas_) { - canvas_->clipPath(path, op, is_aa); +void LayerStateStack::BackdropFilterEntry::apply( + SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas) { + sk_sp backdrop_filter = filter_->skia_object(); + canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), nullptr, + backdrop_filter.get(), 0}); } - if (builder_) { - builder_->clipPath(path, op, is_aa); + if (builder) { + builder->saveLayer(save_bounds(), nullptr, filter_.get()); } } -LayerStateStack::ClipEntry::ClipEntry(SkClipOp op, bool is_aa) - : clip_op_(op), is_aa_(is_aa) {} - -LayerStateStack::ClipRectEntry::ClipRectEntry(const SkRect& rect, - SkClipOp op, - bool is_aa) - : ClipEntry(op, is_aa), rect_(rect) {} - -void LayerStateStack::ClipRectEntry::apply(SkCanvas& canvas) const { - canvas.clipRect(rect_, clip_op_, is_aa_); +void LayerStateStack::TranslateEntry::apply(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas != nullptr) { + canvas->translate(tx_, ty_); + } + if (builder != nullptr) { + builder->translate(tx_, ty_); + } } -void LayerStateStack::ClipRectEntry::apply(DisplayListBuilder& builder) const { - builder.clipRect(rect_, clip_op_, is_aa_); +void LayerStateStack::TransformMatrixEntry::apply( + SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas != nullptr) { + canvas->concat(matrix_); + } + if (builder != nullptr) { + builder->transform(matrix_); + } } -LayerStateStack::ClipRRectEntry::ClipRRectEntry(const SkRRect& rrect, - SkClipOp op, - bool is_aa) - : ClipEntry(op, is_aa), rrect_(rrect) {} - -void LayerStateStack::ClipRRectEntry::apply(SkCanvas& canvas) const { - canvas.clipRRect(rrect_, clip_op_, is_aa_); +void LayerStateStack::TransformM44Entry::apply( + SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas != nullptr) { + canvas->concat(m44_); + } + if (builder != nullptr) { + builder->transform(m44_); + } } -void LayerStateStack::ClipRRectEntry::apply(DisplayListBuilder& builder) const { - builder.clipRRect(rrect_, clip_op_, is_aa_); +void LayerStateStack::ClipRectEntry::apply(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas != nullptr) { + canvas->clipRect(rect_, clip_op_, is_aa_); + } + if (builder != nullptr) { + builder->clipRect(rect_, clip_op_, is_aa_); + } } -LayerStateStack::ClipPathEntry::ClipPathEntry(const SkPath& path, - SkClipOp op, - bool is_aa) - : ClipEntry(op, is_aa), path_(path) {} - -void LayerStateStack::ClipPathEntry::apply(SkCanvas& canvas) const { - canvas.clipPath(path_, clip_op_, is_aa_); +void LayerStateStack::ClipRRectEntry::apply(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas != nullptr) { + canvas->clipRRect(rrect_, clip_op_, is_aa_); + } + if (builder != nullptr) { + builder->clipRRect(rrect_, clip_op_, is_aa_); + } } -void LayerStateStack::ClipPathEntry::apply(DisplayListBuilder& builder) const { - builder.clipPath(path_, clip_op_, is_aa_); +void LayerStateStack::ClipPathEntry::apply(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas != nullptr) { + canvas->clipPath(path_, clip_op_, is_aa_); + } + if (builder != nullptr) { + builder->clipPath(path_, clip_op_, is_aa_); + } } -LayerStateStack::RenderState::RenderState(SkM44& incoming_matrix) - : matrix(incoming_matrix) {} - } // namespace flutter diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 0d481413682dc..6e868f82dd40b 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -30,17 +30,18 @@ class LayerStateStack { const int stack_restore_count_; }; - [[nodiscard]] AutoRestore autoSave(); - [[nodiscard]] AutoRestore pushImageFilter(const SkRect* bounds, - const DlImageFilter* filter); - [[nodiscard]] AutoRestore pushColorFilter(const SkRect* bounds, - const DlColorFilter* filter); - [[nodiscard]] AutoRestore pushBackdropFilter(const SkRect* bounds, - const DlImageFilter* backdrop); + [[nodiscard]] AutoRestore save(); + [[nodiscard]] AutoRestore saveWithImageFilter( + const SkRect* bounds, + const std::shared_ptr filter); + [[nodiscard]] AutoRestore saveWithColorFilter( + const SkRect* bounds, + const std::shared_ptr filter); + [[nodiscard]] AutoRestore saveWithBackdropFilter( + const SkRect* bounds, + const std::shared_ptr filter); + void translate(SkScalar tx, SkScalar ty); - void scale(SkScalar sx, SkScalar sy); - void skew(SkScalar sx, SkScalar sy); - void rotate(SkScalar degrees); void transform(SkM44& matrix); void transform(SkMatrix& matrix); @@ -54,79 +55,152 @@ class LayerStateStack { class StateEntry { public: - virtual void apply(SkCanvas& canvas) const = 0; - virtual void apply(DisplayListBuilder& canvas) const = 0; - virtual void apply(MutatorsStack& mutators) const = 0; + virtual void apply(SkCanvas* canvas, DisplayListBuilder* builder) const = 0; + virtual bool is_backdrop_filter() const { return false; } + }; + + class SaveEntry : public StateEntry { + public: + SaveEntry() = default; + }; + + class SaveLayerEntry : public StateEntry { + public: + SaveLayerEntry(const SkRect* bounds) + : bounds_(bounds ? *bounds : SkRect::MakeEmpty()), + has_bounds_(bounds != nullptr) {} + + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; + + protected: + const SkRect bounds_; + const bool has_bounds_; + + const SkRect* save_bounds() const { + return has_bounds_ ? &bounds_ : nullptr; + } + }; + + class ImageFilterEntry : public SaveLayerEntry { + public: + ImageFilterEntry(const SkRect* bounds, + const std::shared_ptr filter) + : SaveLayerEntry(bounds), filter_(filter) {} + + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; + + private: + const std::shared_ptr filter_; + }; + + class ColorFilterEntry : public SaveLayerEntry { + public: + ColorFilterEntry(const SkRect* bounds, + const std::shared_ptr filter) + : SaveLayerEntry(bounds), filter_(filter) {} + + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; + + private: + const std::shared_ptr filter_; + }; + + class BackdropFilterEntry : public SaveLayerEntry { + public: + BackdropFilterEntry(const SkRect* bounds, + const std::shared_ptr filter) + : SaveLayerEntry(bounds), filter_(filter) {} + + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; + + bool is_backdrop_filter() const override { return false; } + + private: + const std::shared_ptr filter_; + }; + + class TransformEntry : public StateEntry {}; + + class TranslateEntry : public TransformEntry { + public: + TranslateEntry(SkScalar tx, SkScalar ty) : tx_(tx), ty_(ty) {} + + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; + + private: + const SkScalar tx_; + const SkScalar ty_; + }; + + class TransformMatrixEntry : public TransformEntry { + public: + TransformMatrixEntry(SkMatrix& matrix) : matrix_(matrix) {} + + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; + + private: + const SkMatrix matrix_; }; - class TransformEntry : public StateEntry { - + class TransformM44Entry : public TransformEntry { + public: + TransformM44Entry(SkM44 m44) : m44_(m44) {} + + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; + + private: + const SkM44 m44_; }; class ClipEntry : public StateEntry { protected: - ClipEntry(SkClipOp op, bool is_aa); + ClipEntry(SkClipOp op, bool is_aa) : clip_op_(op), is_aa_(is_aa) {} const SkClipOp clip_op_; const bool is_aa_; }; class ClipRectEntry : public ClipEntry { - ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa); + ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa) + : ClipEntry(op, is_aa), rect_(rect) {} - void apply(SkCanvas& canvas) const override; - void apply(DisplayListBuilder& canvas) const override; + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; private: const SkRect rect_; }; class ClipRRectEntry : public ClipEntry { - ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa); + ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa) + : ClipEntry(op, is_aa), rrect_(rrect) {} - void apply(SkCanvas& canvas) const override; - void apply(DisplayListBuilder& canvas) const override; + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; private: const SkRRect rrect_; }; class ClipPathEntry : public ClipEntry { - ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa); + ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa) + : ClipEntry(op, is_aa), path_(path) {} - void apply(SkCanvas& canvas) const override; - void apply(DisplayListBuilder& canvas) const override; + void apply(SkCanvas* canvas, + DisplayListBuilder* builder) const override = 0; private: const SkPath path_; }; - struct RenderState { - RenderState(SkM44& incoming_matrix); - - SkRect* save_bounds() { return layer_has_bounds ? &layer_bounds : nullptr; } - SkPaint* save_skpaint(SkPaint& paint) { - if (!layer_has_paint) { - return nullptr; - } - layer_paint.toSkPaint(paint); - return &paint; - } - DlPaint* save_dlpaint() { return layer_has_paint ? &layer_paint : nullptr; } - - bool is_layer; - - bool layer_has_bounds; - SkRect layer_bounds; - - bool layer_has_paint; - DlPaint layer_paint; - - SkM44 matrix; - std::vector> clip_ops; - }; - - std::vector state_stack_; + std::vector> state_stack_; SkCanvas* canvas_ = nullptr; int canvas_restore_count_; From cc0de217bb5aebe23306c51a40fb3398273b1617 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Wed, 24 Aug 2022 16:50:14 -0700 Subject: [PATCH 06/19] add restore methods to state entries and migrate layers to state_stack --- flow/BUILD.gn | 2 + flow/layers/backdrop_filter_layer.cc | 28 +--- flow/layers/clip_path_layer.cc | 4 +- flow/layers/clip_path_layer.h | 2 +- flow/layers/clip_path_layer_unittests.cc | 2 +- flow/layers/clip_rect_layer.cc | 4 +- flow/layers/clip_rect_layer.h | 2 +- flow/layers/clip_rect_layer_unittests.cc | 2 +- flow/layers/clip_rrect_layer.cc | 4 +- flow/layers/clip_rrect_layer.h | 2 +- flow/layers/clip_rrect_layer_unittests.cc | 2 +- flow/layers/clip_shape_layer.h | 21 ++- flow/layers/color_filter_layer.cc | 35 ++--- flow/layers/display_list_layer.cc | 101 +++++++------- flow/layers/display_list_raster_cache_item.cc | 2 +- flow/layers/image_filter_layer.cc | 39 ++---- flow/layers/layer.cc | 47 ------- flow/layers/layer.h | 70 +--------- flow/layers/layer_raster_cache_item.cc | 11 +- flow/layers/layer_state_stack.cc | 131 ++++++++++++++---- flow/layers/layer_state_stack.h | 109 +++++++++------ flow/layers/layer_tree.cc | 45 ++---- flow/layers/layer_tree_unittests.cc | 16 ++- flow/layers/opacity_layer.cc | 8 +- flow/layers/performance_overlay_layer.cc | 12 +- .../performance_overlay_layer_unittests.cc | 7 +- flow/layers/physical_shape_layer.cc | 24 ++-- flow/layers/platform_view_layer.cc | 6 +- flow/layers/platform_view_layer_unittests.cc | 4 +- flow/layers/shader_mask_layer.cc | 19 +-- flow/layers/texture_layer.cc | 4 +- flow/layers/transform_layer.cc | 4 +- flow/raster_cache_unittests.cc | 37 +++-- flow/testing/auto_save_layer_unittests.cc | 4 + flow/testing/layer_test.h | 31 ++--- flow/testing/mock_layer.cc | 6 +- flow/testing/mock_raster_cache.cc | 8 +- flow/testing/mock_raster_cache.h | 6 +- shell/common/shell_unittests.cc | 5 +- 39 files changed, 403 insertions(+), 463 deletions(-) diff --git a/flow/BUILD.gn b/flow/BUILD.gn index c42fa8e7ab18c..b1f5f96ada066 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -45,6 +45,8 @@ source_set("flow") { "layers/layer.h", "layers/layer_raster_cache_item.cc", "layers/layer_raster_cache_item.h", + "layers/layer_state_stack.cc", + "layers/layer_state_stack.h", "layers/layer_tree.cc", "layers/layer_tree.h", "layers/offscreen_surface.cc", diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index d52ac787c44c0..bb9d13901fa66 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -54,31 +54,9 @@ void BackdropFilterLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "BackdropFilterLayer::Paint"); FML_DCHECK(needs_painting(context)); - AutoCachePaint save_paint(context); - save_paint.setBlendMode(blend_mode_); - if (context.leaf_nodes_builder) { - // Note that we perform a saveLayer directly on the - // leaf_nodes_builder here similar to how the SkCanvas - // path specifies the kLeafNodesCanvas below. - // See https:://flutter.dev/go/backdrop-filter-with-overlay-canvas - context.leaf_nodes_builder->saveLayer(&paint_bounds(), - save_paint.dl_paint(), filter_.get()); - - PaintChildren(context); - - context.leaf_nodes_builder->restore(); - } else { - auto sk_filter = filter_ ? filter_->skia_object() : nullptr; - Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( - context, - SkCanvas::SaveLayerRec{&paint_bounds(), save_paint.sk_paint(), - sk_filter.get(), 0}, - // BackdropFilter should only happen on the leaf nodes canvas. - // See https:://flutter.dev/go/backdrop-filter-with-overlay-canvas - AutoSaveLayer::SaveMode::kLeafNodesCanvas); - - PaintChildren(context); - } + auto save = context.state_stack.saveWithBackdropFilter(&paint_bounds(), + filter_, blend_mode_); + PaintChildren(context); } } // namespace flutter diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index 51426168e02ce..e79bbaf064def 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -28,8 +28,8 @@ void ClipPathLayer::OnMutatorsStackPushClipShape( mutators_stack.PushClipPath(clip_shape()); } -void ClipPathLayer::OnCanvasClipShape(SkCanvas* canvas) const { - canvas->clipPath(clip_shape(), clip_behavior() != Clip::hardEdge); +void ClipPathLayer::OnStackClipShape(LayerStateStack& stack) const { + stack.clipPath(clip_shape(), clip_behavior() != Clip::hardEdge); } } // namespace flutter diff --git a/flow/layers/clip_path_layer.h b/flow/layers/clip_path_layer.h index c8ff1bad743a6..8b79ca43b31b4 100644 --- a/flow/layers/clip_path_layer.h +++ b/flow/layers/clip_path_layer.h @@ -23,7 +23,7 @@ class ClipPathLayer : public ClipShapeLayer { void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override; - void OnCanvasClipShape(SkCanvas* canvas) const override; + void OnStackClipShape(LayerStateStack& stack) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(ClipPathLayer); diff --git a/flow/layers/clip_path_layer_unittests.cc b/flow/layers/clip_path_layer_unittests.cc index f65af652ce5f5..78c0158f7f0ab 100644 --- a/flow/layers/clip_path_layer_unittests.cc +++ b/flow/layers/clip_path_layer_unittests.cc @@ -77,7 +77,7 @@ TEST_F(ClipPathLayerTest, PaintingCulledLayerDies) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)})); - paint_context().internal_nodes_canvas->clipRect(distant_bounds, false); + paint_context().state_stack.clipRect(distant_bounds, false); EXPECT_FALSE(mock_layer->needs_painting(paint_context())); EXPECT_FALSE(layer->needs_painting(paint_context())); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index e2db2aeac03fc..a0e2af7431d80 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -28,8 +28,8 @@ void ClipRectLayer::OnMutatorsStackPushClipShape( mutators_stack.PushClipRect(clip_shape()); } -void ClipRectLayer::OnCanvasClipShape(SkCanvas* canvas) const { - canvas->clipRect(clip_shape(), clip_behavior() != Clip::hardEdge); +void ClipRectLayer::OnStackClipShape(LayerStateStack& stack) const { + stack.clipRect(clip_shape(), clip_behavior() != Clip::hardEdge); } } // namespace flutter diff --git a/flow/layers/clip_rect_layer.h b/flow/layers/clip_rect_layer.h index 967bd9b349cd7..1e91487653064 100644 --- a/flow/layers/clip_rect_layer.h +++ b/flow/layers/clip_rect_layer.h @@ -22,7 +22,7 @@ class ClipRectLayer : public ClipShapeLayer { void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override; - void OnCanvasClipShape(SkCanvas* canvas) const override; + void OnStackClipShape(LayerStateStack& stack) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(ClipRectLayer); diff --git a/flow/layers/clip_rect_layer_unittests.cc b/flow/layers/clip_rect_layer_unittests.cc index 35ac1fb46f469..e7edef17adb73 100644 --- a/flow/layers/clip_rect_layer_unittests.cc +++ b/flow/layers/clip_rect_layer_unittests.cc @@ -73,7 +73,7 @@ TEST_F(ClipRectLayerTest, PaintingCulledLayerDies) { EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_bounds)})); - paint_context().internal_nodes_canvas->clipRect(distant_bounds, false); + paint_context().state_stack.clipRect(distant_bounds, false); EXPECT_FALSE(mock_layer->needs_painting(paint_context())); EXPECT_FALSE(layer->needs_painting(paint_context())); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 6c1a5cca6cb86..05ab87a5047bd 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -28,8 +28,8 @@ void ClipRRectLayer::OnMutatorsStackPushClipShape( mutators_stack.PushClipRRect(clip_shape()); } -void ClipRRectLayer::OnCanvasClipShape(SkCanvas* canvas) const { - canvas->clipRRect(clip_shape(), clip_behavior() != Clip::hardEdge); +void ClipRRectLayer::OnStackClipShape(LayerStateStack& stack) const { + stack.clipRRect(clip_shape(), clip_behavior() != Clip::hardEdge); } } // namespace flutter diff --git a/flow/layers/clip_rrect_layer.h b/flow/layers/clip_rrect_layer.h index 15c71a732e467..c2b30f4933f37 100644 --- a/flow/layers/clip_rrect_layer.h +++ b/flow/layers/clip_rrect_layer.h @@ -22,7 +22,7 @@ class ClipRRectLayer : public ClipShapeLayer { void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override; - void OnCanvasClipShape(SkCanvas* canvas) const override; + void OnStackClipShape(LayerStateStack& stack) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer); diff --git a/flow/layers/clip_rrect_layer_unittests.cc b/flow/layers/clip_rrect_layer_unittests.cc index 3f47f130ac500..60a063ec83743 100644 --- a/flow/layers/clip_rrect_layer_unittests.cc +++ b/flow/layers/clip_rrect_layer_unittests.cc @@ -77,7 +77,7 @@ TEST_F(ClipRRectLayerTest, PaintingCulledLayerDies) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)})); - paint_context().internal_nodes_canvas->clipRect(distant_bounds, false); + paint_context().state_stack.clipRect(distant_bounds, false); EXPECT_FALSE(mock_layer->needs_painting(paint_context())); EXPECT_FALSE(layer->needs_painting(paint_context())); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index faf4c26d31b6c..ea40f3fec25a1 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -79,23 +79,22 @@ class ClipShapeLayer : public CacheableContainerLayer { void Paint(PaintContext& context) const override { FML_DCHECK(needs_painting(context)); - SkAutoCanvasRestore save(context.internal_nodes_canvas, true); - OnCanvasClipShape(context.internal_nodes_canvas); + auto save = context.state_stack.save(); + OnStackClipShape(context.state_stack); if (!UsesSaveLayer()) { PaintChildren(context); return; } - AutoCachePaint cache_paint(context); - if (context.raster_cache) { - if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { - return; - } - } + // AutoCachePaint cache_paint(context); + // if (context.raster_cache) { + // if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { + // return; + // } + // } - Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create( - context, paint_bounds(), cache_paint.sk_paint()); + auto save_layer = context.state_stack.saveLayer(&paint_bounds()); PaintChildren(context); } @@ -106,7 +105,7 @@ class ClipShapeLayer : public CacheableContainerLayer { protected: virtual const SkRect& clip_shape_bounds() const = 0; virtual void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) = 0; - virtual void OnCanvasClipShape(SkCanvas* canvas) const = 0; + virtual void OnStackClipShape(LayerStateStack& stack) const = 0; virtual ~ClipShapeLayer() = default; const ClipShape& clip_shape() const { return clip_shape_; } diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 02822bf68d612..5211c9733a30c 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -48,29 +48,20 @@ void ColorFilterLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ColorFilterLayer::Paint"); FML_DCHECK(needs_painting(context)); - if (context.raster_cache) { - AutoCachePaint cache_paint(context); - if (layer_raster_cache_item_->IsCacheChildren()) { - cache_paint.setColorFilter(filter_.get()); - } - if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { - return; - } - } + // if (context.raster_cache) { + // AutoCachePaint cache_paint(context); + // if (layer_raster_cache_item_->IsCacheChildren()) { + // cache_paint.setColorFilter(filter_.get()); + // } + // if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { + // return; + // } + // } - AutoCachePaint cache_paint(context); - cache_paint.setColorFilter(filter_.get()); - if (context.leaf_nodes_builder) { - FML_DCHECK(context.builder_multiplexer); - context.builder_multiplexer->saveLayer(&paint_bounds(), - cache_paint.dl_paint()); - PaintChildren(context); - context.builder_multiplexer->restore(); - } else { - Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( - context, paint_bounds(), cache_paint.sk_paint()); - PaintChildren(context); - } + // AutoCachePaint cache_paint(context); + // cache_paint.setColorFilter(filter_.get()); + auto save = context.state_stack.saveWithColorFilter(&paint_bounds(), filter_); + PaintChildren(context); } } // namespace flutter diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 5039feae31c3b..09a92b3d34c15 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -109,58 +109,57 @@ void DisplayListLayer::Paint(PaintContext& context) const { FML_DCHECK(display_list_.skia_object()); FML_DCHECK(needs_painting(context)); - SkAutoCanvasRestore save(context.leaf_nodes_canvas, true); - context.leaf_nodes_canvas->translate(offset_.x(), offset_.y()); - - if (context.raster_cache && display_list_raster_cache_item_) { - AutoCachePaint cache_paint(context); - if (display_list_raster_cache_item_->Draw(context, - cache_paint.sk_paint())) { - TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); - return; - } - } - - if (context.enable_leaf_layer_tracing) { - const auto canvas_size = context.leaf_nodes_canvas->getBaseLayerSize(); - auto offscreen_surface = - std::make_unique(context.gr_context, canvas_size); - - const auto& ctm = context.leaf_nodes_canvas->getTotalMatrix(); - - const auto start_time = fml::TimePoint::Now(); - { - // render display list to offscreen surface. - auto* canvas = offscreen_surface->GetCanvas(); - SkAutoCanvasRestore save(canvas, true); - canvas->clear(SK_ColorTRANSPARENT); - canvas->setMatrix(ctm); - display_list()->RenderTo(canvas, context.inherited_opacity); - canvas->flush(); - } - const fml::TimeDelta offscreen_render_time = - fml::TimePoint::Now() - start_time; - - const SkRect device_bounds = - RasterCacheUtil::GetDeviceBounds(paint_bounds(), ctm); - sk_sp raster_data = offscreen_surface->GetRasterData(true); - LayerSnapshotData snapshot_data(unique_id(), offscreen_render_time, - raster_data, device_bounds); - context.layer_snapshot_store->Add(snapshot_data); - } - - if (context.leaf_nodes_builder) { - AutoCachePaint save_paint(context); - int restore_count = context.leaf_nodes_builder->getSaveCount(); - if (save_paint.dl_paint() != nullptr) { - context.leaf_nodes_builder->saveLayer(&paint_bounds(), - save_paint.dl_paint()); - } - context.leaf_nodes_builder->drawDisplayList(display_list_.skia_object()); - context.leaf_nodes_builder->restoreToCount(restore_count); + auto save = context.state_stack.save(); + context.state_stack.translate(offset_.x(), offset_.y()); + + // if (context.raster_cache && display_list_raster_cache_item_) { + // AutoCachePaint cache_paint(context); + // if (display_list_raster_cache_item_->Draw(context, + // cache_paint.sk_paint())) { + // TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); + // return; + // } + // } + + // if (context.enable_leaf_layer_tracing) { + // const auto canvas_size = context.leaf_nodes_canvas->getBaseLayerSize(); + // auto offscreen_surface = + // std::make_unique(context.gr_context, canvas_size); + + // const auto& ctm = context.leaf_nodes_canvas->getTotalMatrix(); + + // const auto start_time = fml::TimePoint::Now(); + // { + // // render display list to offscreen surface. + // auto* canvas = offscreen_surface->GetCanvas(); + // SkAutoCanvasRestore save(canvas, true); + // canvas->clear(SK_ColorTRANSPARENT); + // canvas->setMatrix(ctm); + // display_list()->RenderTo(canvas, context.inherited_opacity); + // canvas->flush(); + // } + // const fml::TimeDelta offscreen_render_time = + // fml::TimePoint::Now() - start_time; + + // const SkRect device_bounds = + // RasterCacheUtil::GetDeviceBounds(paint_bounds(), ctm); + // sk_sp raster_data = offscreen_surface->GetRasterData(true); + // LayerSnapshotData snapshot_data(unique_id(), offscreen_render_time, + // raster_data, device_bounds); + // context.layer_snapshot_store->Add(snapshot_data); + // } + + if (context.builder) { + // AutoCachePaint save_paint(context); + // int restore_count = context.leaf_nodes_builder->getSaveCount(); + // if (save_paint.dl_paint() != nullptr) { + // context.leaf_nodes_builder->saveLayer(&paint_bounds(), + // save_paint.dl_paint()); + // } + context.builder->drawDisplayList(display_list_.skia_object()); + // context.leaf_nodes_builder->restoreToCount(restore_count); } else { - display_list()->RenderTo(context.leaf_nodes_canvas, - context.inherited_opacity); + display_list()->RenderTo(context.canvas, context.inherited_opacity); } } diff --git a/flow/layers/display_list_raster_cache_item.cc b/flow/layers/display_list_raster_cache_item.cc index 10a64cff3a45e..56b24773ada54 100644 --- a/flow/layers/display_list_raster_cache_item.cc +++ b/flow/layers/display_list_raster_cache_item.cc @@ -121,7 +121,7 @@ void DisplayListRasterCacheItem::PrerollFinalize(PrerollContext* context, bool DisplayListRasterCacheItem::Draw(const PaintContext& context, const SkPaint* paint) const { - return Draw(context, context.leaf_nodes_canvas, paint); + return Draw(context, context.canvas, paint); } bool DisplayListRasterCacheItem::Draw(const PaintContext& context, diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index addccef60d533..e3a8cff5743d3 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -84,32 +84,19 @@ void ImageFilterLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ImageFilterLayer::Paint"); FML_DCHECK(needs_painting(context)); - AutoCachePaint cache_paint(context); - if (context.raster_cache) { - if (layer_raster_cache_item_->IsCacheChildren()) { - cache_paint.setImageFilter(transformed_filter_.get()); - } - if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { - return; - } - } - - cache_paint.setImageFilter(filter_.get()); - if (context.leaf_nodes_builder) { - FML_DCHECK(context.builder_multiplexer); - context.builder_multiplexer->saveLayer(&child_paint_bounds(), - cache_paint.dl_paint()); - PaintChildren(context); - context.builder_multiplexer->restore(); - } else { - // Normally a save_layer is sized to the current layer bounds, but in this - // case the bounds of the child may not be the same as the filtered version - // so we use the bounds of the child container which do not include any - // modifications that the filter might apply. - Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create( - context, child_paint_bounds(), cache_paint.sk_paint()); - PaintChildren(context); - } + // AutoCachePaint cache_paint(context); + // if (context.raster_cache) { + // if (layer_raster_cache_item_->IsCacheChildren()) { + // cache_paint.setImageFilter(transformed_filter_.get()); + // } + // if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { + // return; + // } + // } + + auto save = + context.state_stack.saveWithImageFilter(&child_paint_bounds(), filter_); + PaintChildren(context); } } // namespace flutter diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index 8a34b775ef766..e19af5a13a5b2 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -56,51 +56,4 @@ Layer::AutoPrerollSaveLayerState::~AutoPrerollSaveLayerState() { } } -Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, - const SkRect& bounds, - const SkPaint* paint, - SaveMode save_mode) - : paint_context_(paint_context), - bounds_(bounds), - canvas_(save_mode == SaveMode::kInternalNodesCanvas - ? *(paint_context.internal_nodes_canvas) - : *(paint_context.leaf_nodes_canvas)) { - TRACE_EVENT0("flutter", "Canvas::saveLayer"); - canvas_.saveLayer(bounds_, paint); -} - -Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context, - const SkCanvas::SaveLayerRec& layer_rec, - SaveMode save_mode) - : paint_context_(paint_context), - bounds_(*layer_rec.fBounds), - canvas_(save_mode == SaveMode::kInternalNodesCanvas - ? *(paint_context.internal_nodes_canvas) - : *(paint_context.leaf_nodes_canvas)) { - TRACE_EVENT0("flutter", "Canvas::saveLayer"); - canvas_.saveLayer(layer_rec); -} - -Layer::AutoSaveLayer Layer::AutoSaveLayer::Create( - const PaintContext& paint_context, - const SkRect& bounds, - const SkPaint* paint, - SaveMode save_mode) { - return Layer::AutoSaveLayer(paint_context, bounds, paint, save_mode); -} - -Layer::AutoSaveLayer Layer::AutoSaveLayer::Create( - const PaintContext& paint_context, - const SkCanvas::SaveLayerRec& layer_rec, - SaveMode save_mode) { - return Layer::AutoSaveLayer(paint_context, layer_rec, save_mode); -} - -Layer::AutoSaveLayer::~AutoSaveLayer() { - if (paint_context_.checkerboard_offscreen_layers) { - DrawCheckerboard(&canvas_, bounds_); - } - canvas_.restore(); -} - } // namespace flutter diff --git a/flow/layers/layer.h b/flow/layers/layer.h index bb57b430fa3b0..fe90d2d6bb10d 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -16,6 +16,7 @@ #include "flutter/flow/embedded_views.h" #include "flutter/flow/instrumentation.h" #include "flutter/flow/layer_snapshot_store.h" +#include "flutter/flow/layers/layer_state_stack.h" #include "flutter/flow/raster_cache.h" #include "flutter/fml/build_config.h" #include "flutter/fml/compiler_specific.h" @@ -128,8 +129,8 @@ struct PaintContext { // and applies the operations to all canvases. // The leaf_nodes_canvas is the "current" canvas and is used by leaf // layers. - SkCanvas* internal_nodes_canvas; - SkCanvas* leaf_nodes_canvas; + LayerStateStack& state_stack; + SkCanvas* canvas; GrDirectContext* gr_context; SkColorSpace* dst_color_space; ExternalViewEmbedder* view_embedder; @@ -152,8 +153,7 @@ struct PaintContext { // |saveLayer| with an |SkPaint| initialized to this alphaf value and // a |kSrcOver| blend mode. SkScalar inherited_opacity = SK_Scalar1; - DisplayListBuilder* leaf_nodes_builder = nullptr; - DisplayListBuilderMultiplexer* builder_multiplexer = nullptr; + DisplayListBuilder* builder = nullptr; }; // Represents a single composited layer. Created on the UI thread but then @@ -262,66 +262,6 @@ class Layer { } }; - // Calls SkCanvas::saveLayer and restores the layer upon destruction. Also - // draws a checkerboard over the layer if that is enabled in the PaintContext. - class AutoSaveLayer { - public: - // Indicates which canvas the layer should be saved on. - // - // Usually layers are saved on the internal_nodes_canvas, so that all - // the canvas keep track of the current state of the layer tree. - // In some special cases, layers should only save on the leaf_nodes_canvas, - // See https:://flutter.dev/go/backdrop-filter-with-overlay-canvas for why - // it is the case for Backdrop filter layer. - enum SaveMode { - // The layer is saved on the internal_nodes_canvas. - kInternalNodesCanvas, - // The layer is saved on the leaf_nodes_canvas. - kLeafNodesCanvas - }; - - // Create a layer and save it on the canvas. - // - // The layer is restored from the canvas in destructor. - // - // By default, the layer is saved on and restored from - // `internal_nodes_canvas`. The `save_mode` parameter can be modified to - // save the layer on other canvases. - [[nodiscard]] static AutoSaveLayer Create( - const PaintContext& paint_context, - const SkRect& bounds, - const SkPaint* paint, - SaveMode save_mode = SaveMode::kInternalNodesCanvas); - // Create a layer and save it on the canvas. - // - // The layer is restored from the canvas in destructor. - // - // By default, the layer is saved on and restored from - // `internal_nodes_canvas`. The `save_mode` parameter can be modified to - // save the layer on other canvases. - [[nodiscard]] static AutoSaveLayer Create( - const PaintContext& paint_context, - const SkCanvas::SaveLayerRec& layer_rec, - SaveMode save_mode = SaveMode::kInternalNodesCanvas); - - ~AutoSaveLayer(); - - private: - AutoSaveLayer(const PaintContext& paint_context, - const SkRect& bounds, - const SkPaint* paint, - SaveMode save_mode = SaveMode::kInternalNodesCanvas); - - AutoSaveLayer(const PaintContext& paint_context, - const SkCanvas::SaveLayerRec& layer_rec, - SaveMode save_mode = SaveMode::kInternalNodesCanvas); - - const PaintContext& paint_context_; - const SkRect bounds_; - // The canvas that this layer is saved on and popped from. - SkCanvas& canvas_; - }; - virtual void Paint(PaintContext& context) const = 0; virtual void PaintChildren(PaintContext& context) const { FML_DCHECK(false); } @@ -376,7 +316,7 @@ class Layer { if (paint_bounds_.isEmpty()) { return false; } - return !context.leaf_nodes_canvas->quickReject(paint_bounds_); + return !context.canvas->quickReject(paint_bounds_); } // Propagated unique_id of the first layer in "chain" of replacement layers diff --git a/flow/layers/layer_raster_cache_item.cc b/flow/layers/layer_raster_cache_item.cc index d5ddc17224b5a..57ad0c075f9f1 100644 --- a/flow/layers/layer_raster_cache_item.cc +++ b/flow/layers/layer_raster_cache_item.cc @@ -102,14 +102,11 @@ bool Rasterize(RasterCacheItem::CacheState cache_state, const PaintContext& paint_context, SkCanvas* canvas) { FML_DCHECK(cache_state != RasterCacheItem::CacheState::kNone); - SkISize canvas_size = canvas->getBaseLayerSize(); - SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); - internal_nodes_canvas.setMatrix(canvas->getTotalMatrix()); - internal_nodes_canvas.addCanvas(canvas); + LayerStateStack state_stack; PaintContext context = { // clang-format off - .internal_nodes_canvas = static_cast(&internal_nodes_canvas), - .leaf_nodes_canvas = canvas, + .state_stack = state_stack, + .canvas = canvas, .gr_context = paint_context.gr_context, .dst_color_space = paint_context.dst_color_space, .view_embedder = paint_context.view_embedder, @@ -168,7 +165,7 @@ bool LayerRasterCacheItem::TryToPrepareRasterCache(const PaintContext& context, bool LayerRasterCacheItem::Draw(const PaintContext& context, const SkPaint* paint) const { - return Draw(context, context.leaf_nodes_canvas, paint); + return Draw(context, context.canvas, paint); } bool LayerRasterCacheItem::Draw(const PaintContext& context, diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 2c9e246a2524f..011fcf30026ce 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -6,10 +6,6 @@ namespace flutter { -LayerStateStack::LayerStateStack() { - state_stack_.emplace_back(SkM44()); -} - void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { if (canvas_) { canvas_->restoreToCount(canvas_restore_count_); @@ -60,12 +56,23 @@ LayerStateStack::AutoRestore::~AutoRestore() { LayerStateStack::AutoRestore LayerStateStack::save() { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back(std::make_unique()); - if (canvas_) { - canvas_->save(); - } - if (builder_) { - builder_->save(); - } + state_stack_.back()->apply(canvas_, builder_); + return ret; +} + +LayerStateStack::AutoRestore LayerStateStack::saveLayer(const SkRect* bounds) { + auto ret = LayerStateStack::AutoRestore(this); + state_stack_.emplace_back(std::make_unique(bounds)); + state_stack_.back()->apply(canvas_, builder_); + return ret; +} + +LayerStateStack::AutoRestore LayerStateStack::saveWithOpacity( + const SkRect* bounds, + SkScalar opacity) { + auto ret = LayerStateStack::AutoRestore(this); + state_stack_.emplace_back(std::make_unique(bounds, opacity)); + state_stack_.back()->apply(canvas_, builder_); return ret; } @@ -89,10 +96,11 @@ LayerStateStack::AutoRestore LayerStateStack::saveWithColorFilter( LayerStateStack::AutoRestore LayerStateStack::saveWithBackdropFilter( const SkRect* bounds, - const std::shared_ptr filter) { + const std::shared_ptr filter, + DlBlendMode blend_mode) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( - std::make_unique(bounds, filter)); + std::make_unique(bounds, filter, blend_mode)); state_stack_.back()->apply(canvas_, builder_); return ret; } @@ -102,31 +110,83 @@ void LayerStateStack::translate(SkScalar tx, SkScalar ty) { state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::transform(SkMatrix& matrix) { +void LayerStateStack::transform(const SkMatrix& matrix) { state_stack_.emplace_back(std::make_unique(matrix)); state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::transform(SkM44& matrix) { +void LayerStateStack::transform(const SkM44& matrix) { state_stack_.emplace_back(std::make_unique(matrix)); state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::clipRect(const SkRect& rect, SkClipOp op, bool is_aa) { - state_stack_.emplace_back(std::make_unique(rect, op, is_aa)); +void LayerStateStack::clipRect(const SkRect& rect, bool is_aa) { + state_stack_.emplace_back(std::make_unique(rect, is_aa)); state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::clipRRect(const SkRRect& rrect, SkClipOp op, bool is_aa) { - state_stack_.emplace_back(std::make_unique(rrect, op, is_aa)); +void LayerStateStack::clipRRect(const SkRRect& rrect, bool is_aa) { + state_stack_.emplace_back(std::make_unique(rrect, is_aa)); state_stack_.back()->apply(canvas_, builder_); } -void LayerStateStack::clipPath(const SkPath& path, SkClipOp op, bool is_aa) { - state_stack_.emplace_back(std::make_unique(path, op, is_aa)); +void LayerStateStack::clipPath(const SkPath& path, bool is_aa) { + state_stack_.emplace_back(std::make_unique(path, is_aa)); state_stack_.back()->apply(canvas_, builder_); } +void LayerStateStack::restoreToCount(size_t restore_count) { + while (state_stack_.size() > restore_count) { + state_stack_.back()->restore(canvas_, builder_); + state_stack_.pop_back(); + } +} + +void LayerStateStack::SaveEntry::apply(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas) { + canvas->save(); + } + if (builder) { + builder->save(); + } +} + +void LayerStateStack::SaveEntry::restore(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas) { + canvas->restore(); + } + if (builder) { + builder->restore(); + } + // Draw checkerboard if this was a SaveLayer... +} + +void LayerStateStack::SaveLayerEntry::apply(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas) { + canvas->saveLayer(save_bounds(), nullptr); + } + if (builder) { + builder->saveLayer(save_bounds(), nullptr); + } +} + +void LayerStateStack::OpacityEntry::apply(SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (canvas) { + SkPaint paint; + paint.setAlphaf(opacity_); + canvas->saveLayer(save_bounds(), &paint); + } + if (builder) { + DlPaint paint; + paint.setAlpha(SkScalarRoundToInt(opacity_ * 255)); + builder->saveLayer(save_bounds(), &paint); + } +} + void LayerStateStack::ImageFilterEntry::apply( SkCanvas* canvas, DisplayListBuilder* builder) const { @@ -162,11 +222,24 @@ void LayerStateStack::BackdropFilterEntry::apply( DisplayListBuilder* builder) const { if (canvas) { sk_sp backdrop_filter = filter_->skia_object(); - canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), nullptr, - backdrop_filter.get(), 0}); + if (blend_mode_ != DlBlendMode::kSrcOver) { + SkPaint paint; + paint.setBlendMode(ToSk(blend_mode_)); + canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), &paint, + backdrop_filter.get(), 0}); + } else { + canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), nullptr, + backdrop_filter.get(), 0}); + } } if (builder) { - builder->saveLayer(save_bounds(), nullptr, filter_.get()); + if (blend_mode_ != DlBlendMode::kSrcOver) { + DlPaint paint; + paint.setBlendMode(blend_mode_); + builder->saveLayer(save_bounds(), &paint, filter_.get()); + } else { + builder->saveLayer(save_bounds(), nullptr, filter_.get()); + } } } @@ -205,30 +278,30 @@ void LayerStateStack::TransformM44Entry::apply( void LayerStateStack::ClipRectEntry::apply(SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { - canvas->clipRect(rect_, clip_op_, is_aa_); + canvas->clipRect(rect_, SkClipOp::kIntersect, is_aa_); } if (builder != nullptr) { - builder->clipRect(rect_, clip_op_, is_aa_); + builder->clipRect(rect_, SkClipOp::kIntersect, is_aa_); } } void LayerStateStack::ClipRRectEntry::apply(SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { - canvas->clipRRect(rrect_, clip_op_, is_aa_); + canvas->clipRRect(rrect_, SkClipOp::kIntersect, is_aa_); } if (builder != nullptr) { - builder->clipRRect(rrect_, clip_op_, is_aa_); + builder->clipRRect(rrect_, SkClipOp::kIntersect, is_aa_); } } void LayerStateStack::ClipPathEntry::apply(SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { - canvas->clipPath(path_, clip_op_, is_aa_); + canvas->clipPath(path_, SkClipOp::kIntersect, is_aa_); } if (builder != nullptr) { - builder->clipPath(path_, clip_op_, is_aa_); + builder->clipPath(path_, SkClipOp::kIntersect, is_aa_); } } diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 6e868f82dd40b..ffba5db84783e 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -6,17 +6,15 @@ #define FLUTTER_FLOW_LAYERS_LAYER_STATE_STACK_H_ #include "flutter/display_list/display_list_builder.h" -#include "layer.h" namespace flutter { class LayerStateStack { public: - LayerStateStack(); + LayerStateStack() = default; void setCanvasDelegate(SkCanvas* canvas); void setBuilderDelegate(DisplayListBuilder* canvas); - void setMutatorDelegate(MutatorsStack* mutators); class AutoRestore { public: @@ -27,10 +25,13 @@ class LayerStateStack { friend class LayerStateStack; LayerStateStack* stack_; - const int stack_restore_count_; + const size_t stack_restore_count_; }; [[nodiscard]] AutoRestore save(); + [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds); + [[nodiscard]] AutoRestore saveWithOpacity(const SkRect* bounds, + SkScalar opacity); [[nodiscard]] AutoRestore saveWithImageFilter( const SkRect* bounds, const std::shared_ptr filter); @@ -39,39 +40,46 @@ class LayerStateStack { const std::shared_ptr filter); [[nodiscard]] AutoRestore saveWithBackdropFilter( const SkRect* bounds, - const std::shared_ptr filter); + const std::shared_ptr filter, + DlBlendMode blend_mode); void translate(SkScalar tx, SkScalar ty); - void transform(SkM44& matrix); - void transform(SkMatrix& matrix); + void transform(const SkM44& matrix); + void transform(const SkMatrix& matrix); - void clipRect(const SkRect& rect, SkClipOp op, bool is_aa); - void clipRRect(const SkRRect& rect, SkClipOp op, bool is_aa); - void clipPath(const SkPath& rect, SkClipOp op, bool is_aa); + void clipRect(const SkRect& rect, bool is_aa); + void clipRRect(const SkRRect& rect, bool is_aa); + void clipPath(const SkPath& rect, bool is_aa); private: - int getStackCount(); - void restoreToCount(int restore_count); + size_t getStackCount() { return state_stack_.size(); } + void restoreToCount(size_t restore_count); class StateEntry { public: + virtual ~StateEntry() = default; + virtual void apply(SkCanvas* canvas, DisplayListBuilder* builder) const = 0; + virtual void restore(SkCanvas* canvas, DisplayListBuilder* builder) const {} virtual bool is_backdrop_filter() const { return false; } }; class SaveEntry : public StateEntry { public: SaveEntry() = default; + + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + virtual void restore(SkCanvas* canvas, + DisplayListBuilder* builder) const override; }; - class SaveLayerEntry : public StateEntry { + class SaveLayerEntry : public SaveEntry { public: SaveLayerEntry(const SkRect* bounds) : bounds_(bounds ? *bounds : SkRect::MakeEmpty()), has_bounds_(bounds != nullptr) {} - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; protected: const SkRect bounds_; @@ -82,14 +90,25 @@ class LayerStateStack { } }; + class OpacityEntry : public SaveLayerEntry { + public: + OpacityEntry(const SkRect* bounds, SkScalar opacity) + : SaveLayerEntry(bounds), opacity_(opacity) {} + + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + + private: + const SkScalar opacity_; + }; + class ImageFilterEntry : public SaveLayerEntry { public: ImageFilterEntry(const SkRect* bounds, const std::shared_ptr filter) : SaveLayerEntry(bounds), filter_(filter) {} + ~ImageFilterEntry() override = default; - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const std::shared_ptr filter_; @@ -100,9 +119,9 @@ class LayerStateStack { ColorFilterEntry(const SkRect* bounds, const std::shared_ptr filter) : SaveLayerEntry(bounds), filter_(filter) {} + ~ColorFilterEntry() override = default; - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const std::shared_ptr filter_; @@ -111,16 +130,18 @@ class LayerStateStack { class BackdropFilterEntry : public SaveLayerEntry { public: BackdropFilterEntry(const SkRect* bounds, - const std::shared_ptr filter) - : SaveLayerEntry(bounds), filter_(filter) {} + const std::shared_ptr filter, + DlBlendMode blend_mode) + : SaveLayerEntry(bounds), filter_(filter), blend_mode_(blend_mode) {} + ~BackdropFilterEntry() override = default; - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; bool is_backdrop_filter() const override { return false; } private: const std::shared_ptr filter_; + const DlBlendMode blend_mode_; }; class TransformEntry : public StateEntry {}; @@ -129,8 +150,7 @@ class LayerStateStack { public: TranslateEntry(SkScalar tx, SkScalar ty) : tx_(tx), ty_(ty) {} - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const SkScalar tx_; @@ -139,10 +159,9 @@ class LayerStateStack { class TransformMatrixEntry : public TransformEntry { public: - TransformMatrixEntry(SkMatrix& matrix) : matrix_(matrix) {} + TransformMatrixEntry(const SkMatrix& matrix) : matrix_(matrix) {} - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const SkMatrix matrix_; @@ -150,10 +169,9 @@ class LayerStateStack { class TransformM44Entry : public TransformEntry { public: - TransformM44Entry(SkM44 m44) : m44_(m44) {} + TransformM44Entry(const SkM44& m44) : m44_(m44) {} - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const SkM44 m44_; @@ -161,40 +179,40 @@ class LayerStateStack { class ClipEntry : public StateEntry { protected: - ClipEntry(SkClipOp op, bool is_aa) : clip_op_(op), is_aa_(is_aa) {} + ClipEntry(bool is_aa) : is_aa_(is_aa) {} - const SkClipOp clip_op_; const bool is_aa_; }; class ClipRectEntry : public ClipEntry { - ClipRectEntry(const SkRect& rect, SkClipOp op, bool is_aa) - : ClipEntry(op, is_aa), rect_(rect) {} + public: + ClipRectEntry(const SkRect& rect, bool is_aa) + : ClipEntry(is_aa), rect_(rect) {} - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const SkRect rect_; }; class ClipRRectEntry : public ClipEntry { - ClipRRectEntry(const SkRRect& rrect, SkClipOp op, bool is_aa) - : ClipEntry(op, is_aa), rrect_(rrect) {} + public: + ClipRRectEntry(const SkRRect& rrect, bool is_aa) + : ClipEntry(is_aa), rrect_(rrect) {} - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const SkRRect rrect_; }; class ClipPathEntry : public ClipEntry { - ClipPathEntry(const SkPath& path, SkClipOp op, bool is_aa) - : ClipEntry(op, is_aa), path_(path) {} + public: + ClipPathEntry(const SkPath& path, bool is_aa) + : ClipEntry(is_aa), path_(path) {} + ~ClipPathEntry() override = default; - void apply(SkCanvas* canvas, - DisplayListBuilder* builder) const override = 0; + void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; private: const SkPath path_; @@ -206,7 +224,6 @@ class LayerStateStack { int canvas_restore_count_; DisplayListBuilder* builder_ = nullptr; int builder_restore_count_; - MutatorsStack* mutators_ = nullptr; }; } // namespace flutter diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 3b4907b5336bf..53fc3ad9449b8 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -110,24 +110,12 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, return; } - SkISize canvas_size = frame.canvas()->getBaseLayerSize(); - SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); - internal_nodes_canvas.addCanvas(frame.canvas()); - if (frame.view_embedder() != nullptr) { - auto overlay_canvases = frame.view_embedder()->GetCurrentCanvases(); - for (size_t i = 0; i < overlay_canvases.size(); i++) { - internal_nodes_canvas.addCanvas(overlay_canvases[i]); - } - } DisplayListBuilder* builder = frame.display_list_builder(); - DisplayListBuilderMultiplexer builder_multiplexer; + LayerStateStack state_stack; if (builder) { - builder_multiplexer.addBuilder(builder); - if (frame.view_embedder()) { - for (auto* view_builder : frame.view_embedder()->GetCurrentBuilders()) { - builder_multiplexer.addBuilder(view_builder); - } - } + state_stack.setBuilderDelegate(builder); + } else { + state_stack.setCanvasDelegate(frame.canvas()); } // clear the previous snapshots. @@ -142,8 +130,8 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, ignore_raster_cache ? nullptr : &frame.context().raster_cache(); PaintContext context = { // clang-format off - .internal_nodes_canvas = &internal_nodes_canvas, - .leaf_nodes_canvas = frame.canvas(), + .state_stack = state_stack, + .canvas = frame.canvas(), .gr_context = frame.gr_context(), .dst_color_space = color_space, .view_embedder = frame.view_embedder(), @@ -156,8 +144,7 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, .layer_snapshot_store = snapshot_store, .enable_leaf_layer_tracing = enable_leaf_layer_tracing_, .inherited_opacity = SK_Scalar1, - .leaf_nodes_builder = builder, - .builder_multiplexer = builder ? &builder_multiplexer : nullptr, + .builder = builder // clang-format on }; @@ -177,7 +164,7 @@ sk_sp LayerTree::Flatten( GrDirectContext* gr_context) { TRACE_EVENT0("flutter", "LayerTree::Flatten"); - DisplayListCanvasRecorder builder(bounds); + DisplayListCanvasRecorder recorder(bounds); MutatorsStack unused_stack; const FixedRefreshRateStopwatch unused_stopwatch; @@ -203,16 +190,13 @@ sk_sp LayerTree::Flatten( // clang-format on }; - SkISize canvas_size = builder.getBaseLayerSize(); - SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); - internal_nodes_canvas.addCanvas(&builder); - DisplayListBuilderMultiplexer multiplexer; - multiplexer.addBuilder(builder.builder().get()); + LayerStateStack state_stack; + state_stack.setBuilderDelegate(recorder.builder().get()); PaintContext paint_context = { // clang-format off - .internal_nodes_canvas = &internal_nodes_canvas, - .leaf_nodes_canvas = &builder, + .state_stack = state_stack, + .canvas = &recorder, .gr_context = gr_context, .dst_color_space = nullptr, .view_embedder = nullptr, @@ -224,8 +208,7 @@ sk_sp LayerTree::Flatten( .frame_device_pixel_ratio = device_pixel_ratio_, .layer_snapshot_store = nullptr, .enable_leaf_layer_tracing = false, - .leaf_nodes_builder = builder.builder().get(), - .builder_multiplexer = &multiplexer, + .builder = recorder.builder().get(), // clang-format on }; @@ -239,7 +222,7 @@ sk_sp LayerTree::Flatten( } } - return builder.Build(); + return recorder.Build(); } } // namespace flutter diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index 9eeac5a1f77cd..0581f46e9e1d0 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -234,14 +234,14 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { } TEST_F(LayerTreeTest, PaintContextInitialization) { + LayerStateStack state_stack; FixedRefreshRateStopwatch mock_raster_time; FixedRefreshRateStopwatch mock_ui_time; std::shared_ptr mock_registry; auto expect_defaults = [&mock_raster_time, &mock_ui_time, &mock_registry](const PaintContext& context) { - EXPECT_EQ(context.internal_nodes_canvas, nullptr); - EXPECT_EQ(context.leaf_nodes_canvas, nullptr); + EXPECT_EQ(context.canvas, nullptr); EXPECT_EQ(context.gr_context, nullptr); EXPECT_EQ(context.view_embedder, nullptr); EXPECT_EQ(&context.raster_time, &mock_raster_time); @@ -255,15 +255,17 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { EXPECT_EQ(context.layer_snapshot_store, nullptr); EXPECT_EQ(context.inherited_opacity, SK_Scalar1); - EXPECT_EQ(context.leaf_nodes_builder, nullptr); - EXPECT_EQ(context.builder_multiplexer, nullptr); + EXPECT_EQ(context.builder, nullptr); }; // These 4 initializers are required because they are handled by reference PaintContext context{ - .raster_time = mock_raster_time, - .ui_time = mock_ui_time, - .texture_registry = mock_registry, + // clang-format off + .state_stack = state_stack, + .raster_time = mock_raster_time, + .ui_time = mock_ui_time, + .texture_registry = mock_registry, + // clang-format on }; expect_defaults(context); } diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index e9702629052ca..80ac3f5e80fd9 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -83,8 +83,8 @@ void OpacityLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "OpacityLayer::Paint"); FML_DCHECK(needs_painting(context)); - SkAutoCanvasRestore save(context.internal_nodes_canvas, true); - context.internal_nodes_canvas->translate(offset_.fX, offset_.fY); + auto save = context.state_stack.save(); + context.state_stack.translate(offset_.fX, offset_.fY); SkScalar inherited_opacity = context.inherited_opacity; SkScalar subtree_opacity = opacity() * inherited_opacity; @@ -116,8 +116,8 @@ void OpacityLayer::Paint(PaintContext& context) const { .makeOffset(-offset_.fX, -offset_.fY) .roundOut(&saveLayerBounds); - Layer::AutoSaveLayer save_layer = - Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint); + auto save_layer = + context.state_stack.saveWithOpacity(&saveLayerBounds, subtree_opacity); context.inherited_opacity = SK_Scalar1; PaintChildren(context); context.inherited_opacity = inherited_opacity; diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index d211959a89c52..7d805d03ccda4 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -98,16 +98,16 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) const { SkScalar y = paint_bounds().y() + padding; SkScalar width = paint_bounds().width() - (padding * 2); SkScalar height = paint_bounds().height() / 2; - SkAutoCanvasRestore save(context.leaf_nodes_canvas, true); + + auto save = context.state_stack.save(); VisualizeStopWatch( - context.leaf_nodes_canvas, context.raster_time, x, y, width, - height - padding, options_ & kVisualizeRasterizerStatistics, + context.canvas, context.raster_time, x, y, width, height - padding, + options_ & kVisualizeRasterizerStatistics, options_ & kDisplayRasterizerStatistics, "Raster", font_path_); - VisualizeStopWatch(context.leaf_nodes_canvas, context.ui_time, x, y + height, - width, height - padding, - options_ & kVisualizeEngineStatistics, + VisualizeStopWatch(context.canvas, context.ui_time, x, y + height, width, + height - padding, options_ & kVisualizeEngineStatistics, options_ & kDisplayEngineStatistics, "UI", font_path_); } diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index f7c20d24d2900..fad44a0129b22 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -58,10 +58,13 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { ASSERT_TRUE(surface != nullptr); + LayerStateStack state_stack; + state_stack.setCanvasDelegate(surface->getCanvas()); + flutter::PaintContext paintContext = { // clang-format off - .internal_nodes_canvas = nullptr, - .leaf_nodes_canvas = surface->getCanvas(), + .state_stack = state_stack, + .canvas = surface->getCanvas(), .gr_context = nullptr, .view_embedder = nullptr, .raster_time = mock_stopwatch, diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index 8198d871e8330..074dd7c2e4d57 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -77,12 +77,16 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context, } void PhysicalShapeLayer::Paint(PaintContext& context) const { + // + // Is this layer even used any more ???? + // + TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint"); FML_DCHECK(needs_painting(context)); if (elevation_ != 0) { DisplayListCanvasDispatcher::DrawShadow( - context.leaf_nodes_canvas, path_, shadow_color_, elevation_, + context.canvas, path_, shadow_color_, elevation_, SkColorGetA(color_) != 0xff, context.frame_device_pixel_ratio); } @@ -91,21 +95,21 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { paint.setColor(color_); paint.setAntiAlias(true); if (clip_behavior_ != Clip::antiAliasWithSaveLayer) { - context.leaf_nodes_canvas->drawPath(path_, paint); + context.canvas->drawPath(path_, paint); } - int saveCount = context.internal_nodes_canvas->save(); + int saveCount = context.canvas->save(); switch (clip_behavior_) { case Clip::hardEdge: - context.internal_nodes_canvas->clipPath(path_, false); + context.canvas->clipPath(path_, false); break; case Clip::antiAlias: - context.internal_nodes_canvas->clipPath(path_, true); + context.canvas->clipPath(path_, true); break; case Clip::antiAliasWithSaveLayer: { TRACE_EVENT0("flutter", "Canvas::saveLayer"); - context.internal_nodes_canvas->clipPath(path_, true); - context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr); + context.canvas->clipPath(path_, true); + context.canvas->saveLayer(paint_bounds(), nullptr); } break; case Clip::none: break; @@ -116,16 +120,16 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { // (https://github.com/flutter/flutter/issues/18057#issue-328003931) // using saveLayer, we have to call drawPaint instead of drawPath as // anti-aliased drawPath will always have such artifacts. - context.leaf_nodes_canvas->drawPaint(paint); + context.canvas->drawPaint(paint); } PaintChildren(context); - context.internal_nodes_canvas->restoreToCount(saveCount); + context.canvas->restoreToCount(saveCount); if (UsesSaveLayer()) { if (context.checkerboard_offscreen_layers) { - DrawCheckerboard(context.internal_nodes_canvas, paint_bounds()); + // DrawCheckerboard(context.internal_nodes_canvas, paint_bounds()); } } } diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index 8a46cbbce127c..5b22a8bfd8025 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -39,8 +39,10 @@ void PlatformViewLayer::Paint(PaintContext& context) const { } EmbedderPaintContext embedder_context = context.view_embedder->CompositeEmbeddedView(view_id_); - context.leaf_nodes_canvas = embedder_context.canvas; - context.leaf_nodes_builder = embedder_context.builder; + context.state_stack.setCanvasDelegate(embedder_context.canvas); + context.state_stack.setBuilderDelegate(embedder_context.builder); + context.canvas = embedder_context.canvas; + context.builder = embedder_context.builder; } } // namespace flutter diff --git a/flow/layers/platform_view_layer_unittests.cc b/flow/layers/platform_view_layer_unittests.cc index ecbbe3f39f036..3ea1411fff542 100644 --- a/flow/layers/platform_view_layer_unittests.cc +++ b/flow/layers/platform_view_layer_unittests.cc @@ -32,7 +32,7 @@ TEST_F(PlatformViewLayerTest, NullViewEmbedderDoesntPrerollCompositeOrPaint) { EXPECT_FALSE(layer->subtree_has_platform_view()); layer->Paint(paint_context()); - EXPECT_EQ(paint_context().leaf_nodes_canvas, &mock_canvas()); + EXPECT_EQ(paint_context().canvas, &mock_canvas()); EXPECT_EQ(mock_canvas().draw_calls(), std::vector()); } @@ -67,7 +67,7 @@ TEST_F(PlatformViewLayerTest, ClippedPlatformViewPrerollsAndPaintsNothing) { EXPECT_TRUE(parent_clip_layer->subtree_has_platform_view()); parent_clip_layer->Paint(paint_context()); - EXPECT_EQ(paint_context().leaf_nodes_canvas, &mock_canvas()); + EXPECT_EQ(paint_context().canvas, &mock_canvas()); EXPECT_EQ( mock_canvas().draw_calls(), std::vector( diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index d4a441417e966..0ae572eedb71e 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -56,30 +56,25 @@ void ShaderMaskLayer::Paint(PaintContext& context) const { } auto shader_rect = SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()); - if (context.leaf_nodes_builder) { - context.builder_multiplexer->saveLayer(&paint_bounds(), - cache_paint.dl_paint()); - PaintChildren(context); + auto save = context.state_stack.saveLayer(&paint_bounds()); + PaintChildren(context); + if (context.builder) { DlPaint dl_paint; dl_paint.setBlendMode(blend_mode_); if (color_source_) { dl_paint.setColorSource(color_source_.get()); } - context.leaf_nodes_builder->translate(mask_rect_.left(), mask_rect_.top()); - context.leaf_nodes_builder->drawRect(shader_rect, dl_paint); - context.builder_multiplexer->restore(); + context.builder->translate(mask_rect_.left(), mask_rect_.top()); + context.builder->drawRect(shader_rect, dl_paint); } else { - Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( - context, paint_bounds(), cache_paint.sk_paint()); - PaintChildren(context); SkPaint paint; paint.setBlendMode(ToSk(blend_mode_)); if (color_source_) { paint.setShader(color_source_->skia_object()); } - context.leaf_nodes_canvas->translate(mask_rect_.left(), mask_rect_.top()); - context.leaf_nodes_canvas->drawRect(shader_rect, paint); + context.canvas->translate(mask_rect_.left(), mask_rect_.top()); + context.canvas->drawRect(shader_rect, paint); } } diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index 7ece96ebd4364..afcf0d114e1c6 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -62,8 +62,8 @@ void TextureLayer::Paint(PaintContext& context) const { return; } AutoCachePaint cache_paint(context); - texture->Paint(*context.leaf_nodes_canvas, paint_bounds(), freeze_, - context.gr_context, ToSk(sampling_), cache_paint.sk_paint()); + texture->Paint(*context.canvas, paint_bounds(), freeze_, context.gr_context, + ToSk(sampling_), cache_paint.sk_paint()); } } // namespace flutter diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index f34566a915484..949106c557e2d 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -74,8 +74,8 @@ void TransformLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "TransformLayer::Paint"); FML_DCHECK(needs_painting(context)); - SkAutoCanvasRestore save(context.internal_nodes_canvas, true); - context.internal_nodes_canvas->concat(transform_); + auto save = context.state_stack.save(); + context.state_stack.transform(transform_); PaintChildren(context); } diff --git a/flow/raster_cache_unittests.cc b/flow/raster_cache_unittests.cc index 9a72da8e698ff..b3faec986294c 100644 --- a/flow/raster_cache_unittests.cc +++ b/flow/raster_cache_unittests.cc @@ -29,6 +29,7 @@ TEST(RasterCache, SimpleInitialization) { TEST(RasterCache, MetricsOmitUnpopulatedEntries) { size_t threshold = 2; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -44,7 +45,7 @@ TEST(RasterCache, MetricsOmitUnpopulatedEntries) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -85,6 +86,7 @@ TEST(RasterCache, MetricsOmitUnpopulatedEntries) { TEST(RasterCache, ThresholdIsRespectedForDisplayList) { size_t threshold = 2; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -100,7 +102,7 @@ TEST(RasterCache, ThresholdIsRespectedForDisplayList) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -133,6 +135,7 @@ TEST(RasterCache, ThresholdIsRespectedForDisplayList) { TEST(RasterCache, SetCheckboardCacheImages) { size_t threshold = 1; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -141,7 +144,7 @@ TEST(RasterCache, SetCheckboardCacheImages) { FixedRefreshRateStopwatch raster_time; FixedRefreshRateStopwatch ui_time; PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& paint_context = paint_context_holder.paint_context; auto dummy_draw_function = [](SkCanvas* canvas) {}; bool did_draw_checkerboard = false; @@ -169,6 +172,7 @@ TEST(RasterCache, SetCheckboardCacheImages) { TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForSkPicture) { size_t threshold = 0; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -184,7 +188,7 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForSkPicture) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -198,6 +202,7 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForSkPicture) { TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) { size_t threshold = 0; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -213,7 +218,7 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -228,12 +233,12 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) { TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForSkPicture) { size_t picture_cache_limit_per_frame = 0; + LayerStateStack state_stack; flutter::RasterCache cache(3, picture_cache_limit_per_frame); SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); - ; SkCanvas dummy_canvas; SkPaint paint; @@ -244,7 +249,7 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForSkPicture) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -265,6 +270,7 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForSkPicture) { TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) { size_t picture_cache_limit_per_frame = 0; + LayerStateStack state_stack; flutter::RasterCache cache(3, picture_cache_limit_per_frame); SkMatrix matrix = SkMatrix::I(); @@ -280,7 +286,7 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -304,6 +310,7 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) { TEST(RasterCache, EvitUnusedCacheEntries) { size_t threshold = 1; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -320,7 +327,7 @@ TEST(RasterCache, EvitUnusedCacheEntries) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -410,6 +417,7 @@ TEST(RasterCache, ComputeDeviceRectBasedOnFractionalTranslation) { // triggering any assertions. TEST(RasterCache, DeviceRectRoundOutForDisplayList) { size_t threshold = 1; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkRect logical_rect = SkRect::MakeLTRB(28, 0, 354.56731, 310.288); @@ -430,7 +438,7 @@ TEST(RasterCache, DeviceRectRoundOutForDisplayList) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -456,6 +464,7 @@ TEST(RasterCache, DeviceRectRoundOutForDisplayList) { TEST(RasterCache, NestedOpCountMetricUsedForDisplayList) { size_t threshold = 1; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -473,7 +482,7 @@ TEST(RasterCache, NestedOpCountMetricUsedForDisplayList) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -499,6 +508,7 @@ TEST(RasterCache, NaiveComplexityScoringDisplayList) { DisplayListNaiveComplexityCalculator::GetInstance(); size_t threshold = 1; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrix = SkMatrix::I(); @@ -520,7 +530,7 @@ TEST(RasterCache, NaiveComplexityScoringDisplayList) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -566,6 +576,7 @@ TEST(RasterCache, NaiveComplexityScoringDisplayList) { TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) { size_t threshold = 2; + LayerStateStack state_stack; flutter::RasterCache cache(threshold); SkMatrix matrices[] = { @@ -586,7 +597,7 @@ TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) { PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( &cache, &raster_time, &ui_time, &mutators_stack); PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, &cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; diff --git a/flow/testing/auto_save_layer_unittests.cc b/flow/testing/auto_save_layer_unittests.cc index a44ebdbead301..69bee60f8e7a8 100644 --- a/flow/testing/auto_save_layer_unittests.cc +++ b/flow/testing/auto_save_layer_unittests.cc @@ -9,6 +9,8 @@ namespace flutter { namespace testing { +#if 0 + using AutoSaveLayerTests = LayerTest; TEST_F(AutoSaveLayerTests, SaveLayerOnInternalNodesCanvasByDefault) { @@ -113,5 +115,7 @@ TEST_F(AutoSaveLayerTests, SaveLayerOnlyOnLeafNodesCanvas) { } } +#endif + } // namespace testing } // namespace flutter diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index 60b4536056ab6..7e3daa57ad68b 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -66,8 +66,8 @@ class LayerTestBase : public CanvasTestBase { }, paint_context_{ // clang-format off - .internal_nodes_canvas = TestT::mock_internal_canvas(), - .leaf_nodes_canvas = &TestT::mock_canvas(), + .state_stack = canvas_state_stack_, + .canvas = &TestT::mock_canvas(), .gr_context = nullptr, .view_embedder = nullptr, .raster_time = raster_time_, @@ -79,11 +79,10 @@ class LayerTestBase : public CanvasTestBase { // clang-format on }, display_list_recorder_(kDlBounds), - internal_display_list_canvas_(kDlBounds.width(), kDlBounds.height()), display_list_paint_context_{ // clang-format off - .internal_nodes_canvas = &internal_display_list_canvas_, - .leaf_nodes_canvas = &display_list_recorder_, + .state_stack = display_list_state_stack_, + .canvas = &display_list_recorder_, .gr_context = nullptr, .view_embedder = nullptr, .raster_time = raster_time_, @@ -92,14 +91,13 @@ class LayerTestBase : public CanvasTestBase { .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, - .leaf_nodes_builder = display_list_recorder_.builder().get(), - .builder_multiplexer = &display_list_multiplexer_, + .builder = display_list_recorder_.builder().get(), // clang-format on }, check_board_context_{ // clang-format off - .internal_nodes_canvas = TestT::mock_internal_canvas(), - .leaf_nodes_canvas = &TestT::mock_canvas(), + .state_stack = canvas_state_stack_, + .canvas = &TestT::mock_canvas(), .gr_context = nullptr, .view_embedder = nullptr, .raster_time = raster_time_, @@ -110,9 +108,8 @@ class LayerTestBase : public CanvasTestBase { .frame_device_pixel_ratio = 1.0f, // clang-format on } { - internal_display_list_canvas_.addCanvas(&display_list_recorder_); - display_list_multiplexer_.addBuilder( - display_list_recorder_.builder().get()); + canvas_state_stack_.setCanvasDelegate(&TestT::mock_canvas()); + display_list_state_stack_.setCanvasDelegate(&display_list_recorder_); use_null_raster_cache(); } @@ -184,10 +181,8 @@ class LayerTestBase : public CanvasTestBase { display_list_ = display_list_recorder_.Build(); // null out the canvas and recorder fields of the PaintContext // to prevent future use. - display_list_paint_context_.leaf_nodes_canvas = nullptr; - display_list_paint_context_.internal_nodes_canvas = nullptr; - display_list_paint_context_.leaf_nodes_builder = nullptr; - display_list_paint_context_.builder_multiplexer = nullptr; + display_list_paint_context_.canvas = nullptr; + display_list_paint_context_.builder = nullptr; } return display_list_; } @@ -218,10 +213,10 @@ class LayerTestBase : public CanvasTestBase { std::unique_ptr raster_cache_; PrerollContext preroll_context_; PaintContext paint_context_; + LayerStateStack canvas_state_stack_; DisplayListCanvasRecorder display_list_recorder_; - DisplayListBuilderMultiplexer display_list_multiplexer_; sk_sp display_list_; - SkNWayCanvas internal_display_list_canvas_; + LayerStateStack display_list_state_stack_; PaintContext display_list_paint_context_; PaintContext check_board_context_; LayerSnapshotStore snapshot_store_; diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 618a1d566798f..962bcd1c71c98 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -62,11 +62,11 @@ void MockLayer::Paint(PaintContext& context) const { if (context.inherited_opacity < SK_Scalar1) { SkPaint p; p.setAlphaf(context.inherited_opacity); - context.leaf_nodes_canvas->saveLayer(fake_paint_path_.getBounds(), &p); + context.canvas->saveLayer(fake_paint_path_.getBounds(), &p); } - context.leaf_nodes_canvas->drawPath(fake_paint_path_, fake_paint_); + context.canvas->drawPath(fake_paint_path_, fake_paint_); if (context.inherited_opacity < SK_Scalar1) { - context.leaf_nodes_canvas->restore(); + context.canvas->restore(); } } diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index 33b81c15030b3..c18dca4e0dfbc 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -56,10 +56,11 @@ void MockRasterCache::AddMockPicture(int width, int height) { recorder.drawPath(path, SkPaint()); sk_sp display_list = recorder.Build(); + LayerStateStack state_stack; FixedRefreshRateStopwatch raster_time; FixedRefreshRateStopwatch ui_time; PaintContextHolder holder = - GetSamplePaintContextHolder(this, &raster_time, &ui_time); + GetSamplePaintContextHolder(state_stack, this, &raster_time, &ui_time); holder.paint_context.dst_color_space = color_space_; DisplayListRasterCacheItem display_list_item(display_list.get(), SkPoint(), @@ -117,14 +118,15 @@ PrerollContextHolder GetSamplePrerollContextHolder( } PaintContextHolder GetSamplePaintContextHolder( + LayerStateStack& state_stack, RasterCache* raster_cache, FixedRefreshRateStopwatch* raster_time, FixedRefreshRateStopwatch* ui_time) { sk_sp srgb = SkColorSpace::MakeSRGB(); PaintContextHolder holder = {// clang-format off { - .internal_nodes_canvas = nullptr, - .leaf_nodes_canvas = nullptr, + .state_stack = state_stack, + .canvas = nullptr, .gr_context = nullptr, .dst_color_space = srgb.get(), .view_embedder = nullptr, diff --git a/flow/testing/mock_raster_cache.h b/flow/testing/mock_raster_cache.h index 37742486409bb..6dd7529cd3561 100644 --- a/flow/testing/mock_raster_cache.h +++ b/flow/testing/mock_raster_cache.h @@ -67,6 +67,7 @@ class MockRasterCache : public RasterCache { void AddMockPicture(int width, int height); private: + LayerStateStack mock_state_stack_; MockCanvas mock_canvas_; SkColorSpace* color_space_ = mock_canvas_.imageInfo().colorSpace(); MutatorsStack mutators_stack_; @@ -95,8 +96,8 @@ class MockRasterCache : public RasterCache { PaintContext paint_context_ = { // clang-format off - .internal_nodes_canvas = nullptr, - .leaf_nodes_canvas = nullptr, + .state_stack = mock_state_stack_, + .canvas = nullptr, .gr_context = nullptr, .dst_color_space = color_space_, .view_embedder = nullptr, @@ -128,6 +129,7 @@ PrerollContextHolder GetSamplePrerollContextHolder( MutatorsStack* mutators_stack); PaintContextHolder GetSamplePaintContextHolder( + LayerStateStack& state_stack, RasterCache* raster_cache, FixedRefreshRateStopwatch* raster_time, FixedRefreshRateStopwatch* ui_time); diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index e2193d9be7d24..65829ea7cdb8a 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -2382,10 +2382,11 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { FixedRefreshRateStopwatch raster_time; FixedRefreshRateStopwatch ui_time; MutatorsStack mutators_stack; + LayerStateStack state_stack; PaintContext paint_context = { // clang-format off - .internal_nodes_canvas = nullptr, - .leaf_nodes_canvas = nullptr, + .state_stack = state_stack, + .canvas = nullptr, .gr_context = nullptr, .dst_color_space = nullptr, .view_embedder = nullptr, From f1c49916a346421f59e6710c58f495a33cbf8fd1 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 25 Aug 2022 10:00:08 -0700 Subject: [PATCH 07/19] licenses --- ci/licenses_golden/licenses_flutter | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 41a98a9b6568d..d6aced63f813f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -171,6 +171,8 @@ FILE: ../../../flutter/flow/layers/layer.cc FILE: ../../../flutter/flow/layers/layer.h FILE: ../../../flutter/flow/layers/layer_raster_cache_item.cc FILE: ../../../flutter/flow/layers/layer_raster_cache_item.h +FILE: ../../../flutter/flow/layers/layer_state_stack.cc +FILE: ../../../flutter/flow/layers/layer_state_stack.h FILE: ../../../flutter/flow/layers/layer_tree.cc FILE: ../../../flutter/flow/layers/layer_tree.h FILE: ../../../flutter/flow/layers/layer_tree_unittests.cc From 0a3818b501620c559151e172af33dece24b9b264 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 25 Aug 2022 10:07:23 -0700 Subject: [PATCH 08/19] fix crashes with null filters --- flow/layers/layer_state_stack.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 011fcf30026ce..0aa358779ff60 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -192,7 +192,7 @@ void LayerStateStack::ImageFilterEntry::apply( DisplayListBuilder* builder) const { if (canvas) { SkPaint paint; - paint.setImageFilter(filter_->skia_object()); + paint.setImageFilter(filter_ ? filter_->skia_object() : nullptr); canvas->saveLayer(save_bounds(), &paint); } if (builder) { @@ -207,7 +207,7 @@ void LayerStateStack::ColorFilterEntry::apply( DisplayListBuilder* builder) const { if (canvas) { SkPaint paint; - paint.setColorFilter(filter_->skia_object()); + paint.setColorFilter(filter_ ? filter_->skia_object() : nullptr); canvas->saveLayer(save_bounds(), &paint); } if (builder) { @@ -221,7 +221,8 @@ void LayerStateStack::BackdropFilterEntry::apply( SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { - sk_sp backdrop_filter = filter_->skia_object(); + sk_sp backdrop_filter = + filter_ ? filter_->skia_object() : nullptr; if (blend_mode_ != DlBlendMode::kSrcOver) { SkPaint paint; paint.setBlendMode(ToSk(blend_mode_)); From f5100ac9ed6c5088a08c024e1d7652f6596e7170 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 25 Aug 2022 13:21:34 -0700 Subject: [PATCH 09/19] implement checkerboard --- .../checkerboard_layertree_unittests.cc | 2 - flow/layers/clip_shape_layer.h | 20 ++++--- flow/layers/display_list_layer.cc | 54 ++++++++--------- flow/layers/layer_state_stack.cc | 52 ++++++++++++---- flow/layers/layer_state_stack.h | 60 +++++++++++++------ flow/layers/layer_tree.cc | 2 +- flow/layers/physical_shape_layer.cc | 55 +++++------------ flow/paint_utils.cc | 37 +++++++++--- flow/paint_utils.h | 5 +- flow/raster_cache.cc | 4 +- flow/testing/layer_test.h | 2 +- 11 files changed, 175 insertions(+), 118 deletions(-) diff --git a/flow/layers/checkerboard_layertree_unittests.cc b/flow/layers/checkerboard_layertree_unittests.cc index 1923b77278334..8915af6610506 100644 --- a/flow/layers/checkerboard_layertree_unittests.cc +++ b/flow/layers/checkerboard_layertree_unittests.cc @@ -303,7 +303,6 @@ TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerNotCheckBoard) { const SkPaint clip_paint; SkPaint layer_paint; layer_paint.setColor(SK_ColorGREEN); - layer_paint.setAntiAlias(true); layer->Paint(paint_context()); EXPECT_EQ( mock_canvas().draw_calls(), @@ -342,7 +341,6 @@ TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerCheckBoard) { const SkPaint clip_paint; SkPaint layer_paint; layer_paint.setColor(SK_ColorGREEN); - layer_paint.setAntiAlias(true); layer->Paint(check_board_context()); EXPECT_NE( mock_canvas().draw_calls(), diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index ea40f3fec25a1..08c4a82324b43 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -87,14 +87,18 @@ class ClipShapeLayer : public CacheableContainerLayer { return; } - // AutoCachePaint cache_paint(context); - // if (context.raster_cache) { - // if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { - // return; - // } - // } - - auto save_layer = context.state_stack.saveLayer(&paint_bounds()); + if (context.raster_cache) { + AutoCachePaint cache_paint(context); + if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { + return; + } + } + + // saveWithOpacity optimizes the case where opacity >= 1.0 + // to a simple saveLayer + auto save_layer = context.state_stack.saveWithOpacity( + &paint_bounds(), context.inherited_opacity, + context.checkerboard_offscreen_layers); PaintChildren(context); } diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 09a92b3d34c15..48623f9986c72 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -121,33 +121,33 @@ void DisplayListLayer::Paint(PaintContext& context) const { // } // } - // if (context.enable_leaf_layer_tracing) { - // const auto canvas_size = context.leaf_nodes_canvas->getBaseLayerSize(); - // auto offscreen_surface = - // std::make_unique(context.gr_context, canvas_size); - - // const auto& ctm = context.leaf_nodes_canvas->getTotalMatrix(); - - // const auto start_time = fml::TimePoint::Now(); - // { - // // render display list to offscreen surface. - // auto* canvas = offscreen_surface->GetCanvas(); - // SkAutoCanvasRestore save(canvas, true); - // canvas->clear(SK_ColorTRANSPARENT); - // canvas->setMatrix(ctm); - // display_list()->RenderTo(canvas, context.inherited_opacity); - // canvas->flush(); - // } - // const fml::TimeDelta offscreen_render_time = - // fml::TimePoint::Now() - start_time; - - // const SkRect device_bounds = - // RasterCacheUtil::GetDeviceBounds(paint_bounds(), ctm); - // sk_sp raster_data = offscreen_surface->GetRasterData(true); - // LayerSnapshotData snapshot_data(unique_id(), offscreen_render_time, - // raster_data, device_bounds); - // context.layer_snapshot_store->Add(snapshot_data); - // } + if (context.enable_leaf_layer_tracing) { + const auto canvas_size = context.canvas->getBaseLayerSize(); + auto offscreen_surface = + std::make_unique(context.gr_context, canvas_size); + + const auto& ctm = context.canvas->getTotalMatrix(); + + const auto start_time = fml::TimePoint::Now(); + { + // render display list to offscreen surface. + auto* canvas = offscreen_surface->GetCanvas(); + SkAutoCanvasRestore save(canvas, true); + canvas->clear(SK_ColorTRANSPARENT); + canvas->setMatrix(ctm); + display_list()->RenderTo(canvas, context.inherited_opacity); + canvas->flush(); + } + const fml::TimeDelta offscreen_render_time = + fml::TimePoint::Now() - start_time; + + const SkRect device_bounds = + RasterCacheUtil::GetDeviceBounds(paint_bounds(), ctm); + sk_sp raster_data = offscreen_surface->GetRasterData(true); + LayerSnapshotData snapshot_data(unique_id(), offscreen_render_time, + raster_data, device_bounds); + context.layer_snapshot_store->Add(snapshot_data); + } if (context.builder) { // AutoCachePaint save_paint(context); diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 0aa358779ff60..b17c79944b960 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/flow/layers/layer_state_stack.h" +#include "flutter/flow/paint_utils.h" namespace flutter { @@ -60,36 +61,49 @@ LayerStateStack::AutoRestore LayerStateStack::save() { return ret; } -LayerStateStack::AutoRestore LayerStateStack::saveLayer(const SkRect* bounds) { +LayerStateStack::AutoRestore LayerStateStack::saveLayer(const SkRect* bounds, + bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back(std::make_unique(bounds)); + state_stack_.emplace_back( + std::make_unique(bounds, checkerboard)); state_stack_.back()->apply(canvas_, builder_); return ret; } LayerStateStack::AutoRestore LayerStateStack::saveWithOpacity( const SkRect* bounds, - SkScalar opacity) { + SkScalar opacity, + bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back(std::make_unique(bounds, opacity)); + if (opacity < SK_Scalar1) { + state_stack_.emplace_back( + std::make_unique(bounds, opacity, checkerboard)); + } else { + state_stack_.emplace_back( + std::make_unique(bounds, checkerboard)); + } state_stack_.back()->apply(canvas_, builder_); return ret; } LayerStateStack::AutoRestore LayerStateStack::saveWithImageFilter( const SkRect* bounds, - const std::shared_ptr filter) { + const std::shared_ptr filter, + bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back(std::make_unique(bounds, filter)); + state_stack_.emplace_back( + std::make_unique(bounds, filter, checkerboard)); state_stack_.back()->apply(canvas_, builder_); return ret; } LayerStateStack::AutoRestore LayerStateStack::saveWithColorFilter( const SkRect* bounds, - const std::shared_ptr filter) { + const std::shared_ptr filter, + bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back(std::make_unique(bounds, filter)); + state_stack_.emplace_back( + std::make_unique(bounds, filter, checkerboard)); state_stack_.back()->apply(canvas_, builder_); return ret; } @@ -97,10 +111,11 @@ LayerStateStack::AutoRestore LayerStateStack::saveWithColorFilter( LayerStateStack::AutoRestore LayerStateStack::saveWithBackdropFilter( const SkRect* bounds, const std::shared_ptr filter, - DlBlendMode blend_mode) { + DlBlendMode blend_mode, + bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back( - std::make_unique(bounds, filter, blend_mode)); + state_stack_.emplace_back(std::make_unique( + bounds, filter, blend_mode, checkerboard)); state_stack_.back()->apply(canvas_, builder_); return ret; } @@ -160,7 +175,7 @@ void LayerStateStack::SaveEntry::restore(SkCanvas* canvas, if (builder) { builder->restore(); } - // Draw checkerboard if this was a SaveLayer... + do_checkerboard(canvas, builder); } void LayerStateStack::SaveLayerEntry::apply(SkCanvas* canvas, @@ -173,6 +188,19 @@ void LayerStateStack::SaveLayerEntry::apply(SkCanvas* canvas, } } +void LayerStateStack::SaveLayerEntry::do_checkerboard( + SkCanvas* canvas, + DisplayListBuilder* builder) const { + if (checkerboard_ && has_bounds_) { + if (canvas) { + SkDrawCheckerboard(canvas, bounds_); + } + if (builder) { + DlDrawCheckerboard(builder, bounds_); + } + } +} + void LayerStateStack::OpacityEntry::apply(SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index ffba5db84783e..8e5b3f381337d 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -6,6 +6,7 @@ #define FLUTTER_FLOW_LAYERS_LAYER_STATE_STACK_H_ #include "flutter/display_list/display_list_builder.h" +#include "flutter/display_list/display_list_canvas_recorder.h" namespace flutter { @@ -14,7 +15,13 @@ class LayerStateStack { LayerStateStack() = default; void setCanvasDelegate(SkCanvas* canvas); - void setBuilderDelegate(DisplayListBuilder* canvas); + void setBuilderDelegate(DisplayListBuilder* builder); + void setBuilderDelegate(sk_sp builder) { + setBuilderDelegate(builder.get()); + } + void setBuilderDelegate(DisplayListCanvasRecorder& recorder) { + setBuilderDelegate(recorder.builder().get()); + } class AutoRestore { public: @@ -25,23 +32,28 @@ class LayerStateStack { friend class LayerStateStack; LayerStateStack* stack_; - const size_t stack_restore_count_; + size_t stack_restore_count_; }; [[nodiscard]] AutoRestore save(); - [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds); + [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds, + bool checkerboard = false); [[nodiscard]] AutoRestore saveWithOpacity(const SkRect* bounds, - SkScalar opacity); + SkScalar opacity, + bool checkerboard = false); [[nodiscard]] AutoRestore saveWithImageFilter( const SkRect* bounds, - const std::shared_ptr filter); + const std::shared_ptr filter, + bool checkerboard = false); [[nodiscard]] AutoRestore saveWithColorFilter( const SkRect* bounds, - const std::shared_ptr filter); + const std::shared_ptr filter, + bool checkerboard = false); [[nodiscard]] AutoRestore saveWithBackdropFilter( const SkRect* bounds, const std::shared_ptr filter, - DlBlendMode blend_mode); + DlBlendMode blend_mode, + bool checkerboard = false); void translate(SkScalar tx, SkScalar ty); void transform(const SkM44& matrix); @@ -71,19 +83,28 @@ class LayerStateStack { void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; virtual void restore(SkCanvas* canvas, DisplayListBuilder* builder) const override; + + protected: + virtual void do_checkerboard(SkCanvas* canvas, + DisplayListBuilder* builder) const {} }; class SaveLayerEntry : public SaveEntry { public: - SaveLayerEntry(const SkRect* bounds) + SaveLayerEntry(const SkRect* bounds, bool checkerboard) : bounds_(bounds ? *bounds : SkRect::MakeEmpty()), - has_bounds_(bounds != nullptr) {} + has_bounds_(bounds != nullptr), + checkerboard_(checkerboard) {} void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; protected: const SkRect bounds_; const bool has_bounds_; + const bool checkerboard_; + + void do_checkerboard(SkCanvas* canvas, + DisplayListBuilder* builder) const override; const SkRect* save_bounds() const { return has_bounds_ ? &bounds_ : nullptr; @@ -92,8 +113,8 @@ class LayerStateStack { class OpacityEntry : public SaveLayerEntry { public: - OpacityEntry(const SkRect* bounds, SkScalar opacity) - : SaveLayerEntry(bounds), opacity_(opacity) {} + OpacityEntry(const SkRect* bounds, SkScalar opacity, bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), opacity_(opacity) {} void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; @@ -104,8 +125,9 @@ class LayerStateStack { class ImageFilterEntry : public SaveLayerEntry { public: ImageFilterEntry(const SkRect* bounds, - const std::shared_ptr filter) - : SaveLayerEntry(bounds), filter_(filter) {} + const std::shared_ptr filter, + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} ~ImageFilterEntry() override = default; void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; @@ -117,8 +139,9 @@ class LayerStateStack { class ColorFilterEntry : public SaveLayerEntry { public: ColorFilterEntry(const SkRect* bounds, - const std::shared_ptr filter) - : SaveLayerEntry(bounds), filter_(filter) {} + const std::shared_ptr filter, + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} ~ColorFilterEntry() override = default; void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; @@ -131,8 +154,11 @@ class LayerStateStack { public: BackdropFilterEntry(const SkRect* bounds, const std::shared_ptr filter, - DlBlendMode blend_mode) - : SaveLayerEntry(bounds), filter_(filter), blend_mode_(blend_mode) {} + DlBlendMode blend_mode, + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), + filter_(filter), + blend_mode_(blend_mode) {} ~BackdropFilterEntry() override = default; void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 53fc3ad9449b8..6a7d0bf9e0802 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -191,7 +191,7 @@ sk_sp LayerTree::Flatten( }; LayerStateStack state_stack; - state_stack.setBuilderDelegate(recorder.builder().get()); + state_stack.setBuilderDelegate(recorder); PaintContext paint_context = { // clang-format off diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index 074dd7c2e4d57..ff0f0d65d1c18 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -90,47 +90,24 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { SkColorGetA(color_) != 0xff, context.frame_device_pixel_ratio); } - // Call drawPath without clip if possible for better performance. - SkPaint paint; - paint.setColor(color_); - paint.setAntiAlias(true); - if (clip_behavior_ != Clip::antiAliasWithSaveLayer) { - context.canvas->drawPath(path_, paint); - } - - int saveCount = context.canvas->save(); - switch (clip_behavior_) { - case Clip::hardEdge: - context.canvas->clipPath(path_, false); - break; - case Clip::antiAlias: - context.canvas->clipPath(path_, true); - break; - case Clip::antiAliasWithSaveLayer: { - TRACE_EVENT0("flutter", "Canvas::saveLayer"); - context.canvas->clipPath(path_, true); - context.canvas->saveLayer(paint_bounds(), nullptr); - } break; - case Clip::none: - break; - } - - if (UsesSaveLayer()) { - // If we want to avoid the bleeding edge artifact - // (https://github.com/flutter/flutter/issues/18057#issue-328003931) - // using saveLayer, we have to call drawPaint instead of drawPath as - // anti-aliased drawPath will always have such artifacts. - context.canvas->drawPaint(paint); - } - - PaintChildren(context); - - context.canvas->restoreToCount(saveCount); + auto save = context.state_stack.save(); + if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { + context.state_stack.clipPath(path_, true); + auto saveLayer = context.state_stack.saveLayer( + &paint_bounds(), context.checkerboard_offscreen_layers); + context.canvas->drawColor(color_); + PaintChildren(context); + } else { + SkPaint paint; + paint.setColor(color_); + paint.setAntiAlias(true); - if (UsesSaveLayer()) { - if (context.checkerboard_offscreen_layers) { - // DrawCheckerboard(context.internal_nodes_canvas, paint_bounds()); + // Call drawPath without clip if possible for better performance. + context.canvas->drawPath(path_, paint); + if (clip_behavior_ != Clip::none) { + context.state_stack.clipPath(path_, clip_behavior_ == Clip::antiAlias); } + PaintChildren(context); } } diff --git a/flow/paint_utils.cc b/flow/paint_utils.cc index 016b81f7a5dfe..5c16b6b0be62a 100644 --- a/flow/paint_utils.cc +++ b/flow/paint_utils.cc @@ -24,15 +24,9 @@ sk_sp CreateCheckerboardShader(SkColor c1, SkColor c2, int size) { SkSamplingOptions()); } -void DrawCheckerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) { - SkPaint paint; - paint.setShader(CreateCheckerboardShader(c1, c2, size)); - canvas->drawPaint(paint); -} - } // anonymous namespace -void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect) { +void SkDrawCheckerboard(SkCanvas* canvas, const SkRect& rect) { // Draw a checkerboard canvas->save(); canvas->clipRect(rect); @@ -43,7 +37,9 @@ void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect) { SkColorSetARGB(64, rand() % 256, rand() % 256, rand() % 256); // NOLINTEND(clang-analyzer-security.insecureAPI.rand) - DrawCheckerboard(canvas, checkerboard_color, 0x00000000, 12); + SkPaint paint; + paint.setShader(CreateCheckerboardShader(checkerboard_color, 0x00000000, 12)); + canvas->drawPaint(paint); canvas->restore(); // Stroke the drawn area @@ -54,4 +50,29 @@ void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect) { canvas->drawRect(rect, debugPaint); } +void DlDrawCheckerboard(DisplayListBuilder* builder, const SkRect& rect) { + // Draw a checkerboard + builder->save(); + builder->clipRect(rect, SkClipOp::kIntersect, false); + + // Secure random number generation isn't needed here. + // NOLINTBEGIN(clang-analyzer-security.insecureAPI.rand) + auto checkerboard_color = + SkColorSetARGB(64, rand() % 256, rand() % 256, rand() % 256); + // NOLINTEND(clang-analyzer-security.insecureAPI.rand) + + DlPaint paint; + paint.setColorSource(DlColorSource::From( + CreateCheckerboardShader(checkerboard_color, 0x00000000, 12))); + builder->drawPaint(paint); + builder->restore(); + + // Stroke the drawn area + DlPaint debugPaint; + debugPaint.setStrokeWidth(8); + debugPaint.setColor(DlColor(checkerboard_color).withAlpha(255)); + debugPaint.setDrawStyle(DlDrawStyle::kStroke); + builder->drawRect(rect, debugPaint); +} + } // namespace flutter diff --git a/flow/paint_utils.h b/flow/paint_utils.h index 432dd12811372..cbfd38db0064a 100644 --- a/flow/paint_utils.h +++ b/flow/paint_utils.h @@ -5,13 +5,16 @@ #ifndef FLUTTER_FLOW_PAINT_UTILS_H_ #define FLUTTER_FLOW_PAINT_UTILS_H_ +#include "flutter/display_list/display_list_builder.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkRect.h" namespace flutter { -void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect); +void SkDrawCheckerboard(SkCanvas* canvas, const SkRect& rect); + +void DlDrawCheckerboard(DisplayListBuilder* builder, const SkRect& rect); } // namespace flutter diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index 9b6e72d43c2c8..6087408abf989 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -76,7 +76,7 @@ RasterCache::RasterCache(size_t access_threshold, std::unique_ptr RasterCache::Rasterize( const RasterCache::Context& context, const std::function& draw_function, - const std::function& draw_checkerboard) + const std::function& draw_checkerboard) const { TRACE_EVENT0("flutter", "RasterCachePopulate"); @@ -120,7 +120,7 @@ bool RasterCache::UpdateCacheEntry( Entry& entry = cache_[key]; if (!entry.image) { entry.image = - Rasterize(raster_cache_context, render_function, DrawCheckerboard); + Rasterize(raster_cache_context, render_function, SkDrawCheckerboard); if (entry.image != nullptr) { switch (id.type()) { case RasterCacheKeyType::kDisplayList: { diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index 7e3daa57ad68b..a268df157e07d 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -109,7 +109,7 @@ class LayerTestBase : public CanvasTestBase { // clang-format on } { canvas_state_stack_.setCanvasDelegate(&TestT::mock_canvas()); - display_list_state_stack_.setCanvasDelegate(&display_list_recorder_); + display_list_state_stack_.setBuilderDelegate(display_list_recorder_); use_null_raster_cache(); } From 52fb6a7fb80cf98e247005b2c171d2619a7ea09b Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 26 Aug 2022 14:07:49 -0700 Subject: [PATCH 10/19] review feedback and prototype of opacity inheritance --- flow/layers/layer_state_stack.cc | 182 +++++++++++++++++++------------ flow/layers/layer_state_stack.h | 104 ++++++++++++++---- 2 files changed, 194 insertions(+), 92 deletions(-) diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index b17c79944b960..3573a2ce8601a 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -7,6 +7,9 @@ namespace flutter { +using AutoRestore = LayerStateStack::AutoRestore; +using RenderingAttributes = LayerStateStack::RenderingAttributes; + void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { if (canvas_) { canvas_->restoreToCount(canvas_restore_count_); @@ -16,13 +19,7 @@ void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { canvas_restore_count_ = canvas->getSaveCount(); canvas_ = canvas; for (auto& state : state_stack_) { - if (!state->is_backdrop_filter()) { - // BackdropFilter is only applied on the canvas that - // was present at the time that the backdrop layer was - // first encountered to avoid applying it on every - // platform view embedder overlay. - state->apply(canvas, nullptr); - } + state->apply(&outstanding_, canvas, nullptr); } } } @@ -36,79 +33,84 @@ void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { builder_restore_count_ = builder->getSaveCount(); builder_ = builder; for (auto& state : state_stack_) { - if (!state->is_backdrop_filter()) { - // BackdropFilter is only applied on the builder that - // was present at the time that the backdrop layer was - // first encountered to avoid applying it on every - // platform view embedder overlay. - state->apply(nullptr, builder); - } + state->apply(&outstanding_, nullptr, builder); } } } -LayerStateStack::AutoRestore::AutoRestore(LayerStateStack* stack) +AutoRestore::AutoRestore(LayerStateStack* stack) : stack_(stack), stack_restore_count_(stack->getStackCount()) {} -LayerStateStack::AutoRestore::~AutoRestore() { +AutoRestore::~AutoRestore() { stack_->restoreToCount(stack_restore_count_); } -LayerStateStack::AutoRestore LayerStateStack::save() { +const RenderingAttributes LayerStateStack::applyOutstandingState( + int can_apply_flags) { + SkScalar cur_opacity = outstanding_.opacity; + if (cur_opacity >= SK_Scalar1 || (can_apply_flags & CAN_APPLY_OPACITY) != 0) { + return {cur_opacity}; + } else { + resolve(nullptr, &outstanding_, canvas_, builder_); + outstanding_.opacity = SK_Scalar1; + return {SK_Scalar1}; + } +} + +AutoRestore LayerStateStack::save() { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back(std::make_unique()); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -LayerStateStack::AutoRestore LayerStateStack::saveLayer(const SkRect* bounds, - bool checkerboard) { +AutoRestore LayerStateStack::saveLayer(const SkRect* bounds, + bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( std::make_unique(bounds, checkerboard)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -LayerStateStack::AutoRestore LayerStateStack::saveWithOpacity( - const SkRect* bounds, - SkScalar opacity, - bool checkerboard) { - auto ret = LayerStateStack::AutoRestore(this); +AutoRestore LayerStateStack::saveWithOpacity(const SkRect* bounds, + SkScalar opacity, + bool checkerboard) { + auto ret = AutoRestore(this); if (opacity < SK_Scalar1) { - state_stack_.emplace_back( - std::make_unique(bounds, opacity, checkerboard)); + state_stack_.emplace_back(std::make_unique( + bounds, outstanding_.opacity, opacity, checkerboard)); } else { state_stack_.emplace_back( std::make_unique(bounds, checkerboard)); } - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -LayerStateStack::AutoRestore LayerStateStack::saveWithImageFilter( +AutoRestore LayerStateStack::saveWithImageFilter( const SkRect* bounds, const std::shared_ptr filter, bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( std::make_unique(bounds, filter, checkerboard)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -LayerStateStack::AutoRestore LayerStateStack::saveWithColorFilter( +AutoRestore LayerStateStack::saveWithColorFilter( const SkRect* bounds, const std::shared_ptr filter, bool checkerboard) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( std::make_unique(bounds, filter, checkerboard)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -LayerStateStack::AutoRestore LayerStateStack::saveWithBackdropFilter( +AutoRestore LayerStateStack::saveWithBackdropFilter( const SkRect* bounds, const std::shared_ptr filter, DlBlendMode blend_mode, @@ -116,48 +118,49 @@ LayerStateStack::AutoRestore LayerStateStack::saveWithBackdropFilter( auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back(std::make_unique( bounds, filter, blend_mode, checkerboard)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } void LayerStateStack::translate(SkScalar tx, SkScalar ty) { state_stack_.emplace_back(std::make_unique(tx, ty)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); } void LayerStateStack::transform(const SkMatrix& matrix) { state_stack_.emplace_back(std::make_unique(matrix)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); } void LayerStateStack::transform(const SkM44& matrix) { state_stack_.emplace_back(std::make_unique(matrix)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); } void LayerStateStack::clipRect(const SkRect& rect, bool is_aa) { state_stack_.emplace_back(std::make_unique(rect, is_aa)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); } void LayerStateStack::clipRRect(const SkRRect& rrect, bool is_aa) { state_stack_.emplace_back(std::make_unique(rrect, is_aa)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); } void LayerStateStack::clipPath(const SkPath& path, bool is_aa) { state_stack_.emplace_back(std::make_unique(path, is_aa)); - state_stack_.back()->apply(canvas_, builder_); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); } void LayerStateStack::restoreToCount(size_t restore_count) { while (state_stack_.size() > restore_count) { - state_stack_.back()->restore(canvas_, builder_); + state_stack_.back()->restore(&outstanding_, canvas_, builder_); state_stack_.pop_back(); } } -void LayerStateStack::SaveEntry::apply(SkCanvas* canvas, +void LayerStateStack::SaveEntry::apply(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { canvas->save(); @@ -167,7 +170,8 @@ void LayerStateStack::SaveEntry::apply(SkCanvas* canvas, } } -void LayerStateStack::SaveEntry::restore(SkCanvas* canvas, +void LayerStateStack::SaveEntry::restore(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { canvas->restore(); @@ -178,7 +182,8 @@ void LayerStateStack::SaveEntry::restore(SkCanvas* canvas, do_checkerboard(canvas, builder); } -void LayerStateStack::SaveLayerEntry::apply(SkCanvas* canvas, +void LayerStateStack::SaveLayerEntry::apply(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { canvas->saveLayer(save_bounds(), nullptr); @@ -201,21 +206,36 @@ void LayerStateStack::SaveLayerEntry::do_checkerboard( } } -void LayerStateStack::OpacityEntry::apply(SkCanvas* canvas, +void LayerStateStack::OpacityEntry::apply(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { + attributes->opacity *= opacity_; +} + +void LayerStateStack::OpacityEntry::restore(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const { + attributes->opacity = outstanding_opacity_; +} + +void LayerStateStack::resolve(const SkRect* bounds, + RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) { if (canvas) { SkPaint paint; - paint.setAlphaf(opacity_); - canvas->saveLayer(save_bounds(), &paint); + paint.setAlphaf(attributes->opacity); + canvas->saveLayer(bounds, &paint); } if (builder) { DlPaint paint; - paint.setAlpha(SkScalarRoundToInt(opacity_ * 255)); - builder->saveLayer(save_bounds(), &paint); + paint.setAlpha(SkScalarRoundToInt(attributes->opacity * 255)); + builder->saveLayer(bounds, &paint); } } void LayerStateStack::ImageFilterEntry::apply( + RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { @@ -231,6 +251,7 @@ void LayerStateStack::ImageFilterEntry::apply( } void LayerStateStack::ColorFilterEntry::apply( + RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { @@ -246,33 +267,49 @@ void LayerStateStack::ColorFilterEntry::apply( } void LayerStateStack::BackdropFilterEntry::apply( + RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { sk_sp backdrop_filter = filter_ ? filter_->skia_object() : nullptr; - if (blend_mode_ != DlBlendMode::kSrcOver) { - SkPaint paint; - paint.setBlendMode(ToSk(blend_mode_)); - canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), &paint, - backdrop_filter.get(), 0}); - } else { - canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), nullptr, - backdrop_filter.get(), 0}); - } + SkPaint paint; + paint.setBlendMode(ToSk(blend_mode_)); + canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), &paint, + backdrop_filter.get(), 0}); } if (builder) { - if (blend_mode_ != DlBlendMode::kSrcOver) { - DlPaint paint; - paint.setBlendMode(blend_mode_); - builder->saveLayer(save_bounds(), &paint, filter_.get()); - } else { - builder->saveLayer(save_bounds(), nullptr, filter_.get()); - } + DlPaint paint; + paint.setBlendMode(blend_mode_); + builder->saveLayer(save_bounds(), &paint, filter_.get()); + } +} + +void LayerStateStack::BackdropFilterEntry::reapply( + RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const { + // On the reapply for subsequent overlay layers, we do not + // want to reapply the backdrop filter, but we do need to + // do a saveLayer to encapsulate the contents and match the + // restore that will be forthcoming. Note that this is not + // perfect if the BlendMode is not associative as we will be + // compositing multiple parts of the content in batches. + // Luckily the most common SrcOver is associative. + if (canvas) { + SkPaint paint; + paint.setBlendMode(ToSk(blend_mode_)); + canvas->saveLayer(save_bounds(), &paint); + } + if (builder) { + DlPaint paint; + paint.setBlendMode(blend_mode_); + builder->saveLayer(save_bounds(), &paint); } } -void LayerStateStack::TranslateEntry::apply(SkCanvas* canvas, +void LayerStateStack::TranslateEntry::apply(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { canvas->translate(tx_, ty_); @@ -283,6 +320,7 @@ void LayerStateStack::TranslateEntry::apply(SkCanvas* canvas, } void LayerStateStack::TransformMatrixEntry::apply( + RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { @@ -294,6 +332,7 @@ void LayerStateStack::TransformMatrixEntry::apply( } void LayerStateStack::TransformM44Entry::apply( + RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { @@ -304,7 +343,8 @@ void LayerStateStack::TransformM44Entry::apply( } } -void LayerStateStack::ClipRectEntry::apply(SkCanvas* canvas, +void LayerStateStack::ClipRectEntry::apply(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { canvas->clipRect(rect_, SkClipOp::kIntersect, is_aa_); @@ -314,7 +354,8 @@ void LayerStateStack::ClipRectEntry::apply(SkCanvas* canvas, } } -void LayerStateStack::ClipRRectEntry::apply(SkCanvas* canvas, +void LayerStateStack::ClipRRectEntry::apply(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { canvas->clipRRect(rrect_, SkClipOp::kIntersect, is_aa_); @@ -324,7 +365,8 @@ void LayerStateStack::ClipRRectEntry::apply(SkCanvas* canvas, } } -void LayerStateStack::ClipPathEntry::apply(SkCanvas* canvas, +void LayerStateStack::ClipPathEntry::apply(RenderingAttributes* attributes, + SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas != nullptr) { canvas->clipPath(path_, SkClipOp::kIntersect, is_aa_); diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 8e5b3f381337d..203933da9f989 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -35,6 +35,14 @@ class LayerStateStack { size_t stack_restore_count_; }; + static constexpr int CAN_APPLY_OPACITY = 0x1; + + struct RenderingAttributes { + SkScalar opacity = SK_Scalar1; + }; + + const RenderingAttributes applyOutstandingState(int can_apply_flags = 0); + [[nodiscard]] AutoRestore save(); [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds, bool checkerboard = false); @@ -67,22 +75,40 @@ class LayerStateStack { size_t getStackCount() { return state_stack_.size(); } void restoreToCount(size_t restore_count); + static void resolve(const SkRect* bounds, + RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder); + class StateEntry { public: virtual ~StateEntry() = default; - virtual void apply(SkCanvas* canvas, DisplayListBuilder* builder) const = 0; - virtual void restore(SkCanvas* canvas, DisplayListBuilder* builder) const {} - virtual bool is_backdrop_filter() const { return false; } + virtual void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const = 0; + + virtual void reapply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const { + apply(attributes, canvas, builder); + } + + virtual void restore(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const {} }; class SaveEntry : public StateEntry { public: SaveEntry() = default; - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; - virtual void restore(SkCanvas* canvas, - DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; + void restore(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; protected: virtual void do_checkerboard(SkCanvas* canvas, @@ -96,7 +122,9 @@ class LayerStateStack { has_bounds_(bounds != nullptr), checkerboard_(checkerboard) {} - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; protected: const SkRect bounds_; @@ -113,12 +141,23 @@ class LayerStateStack { class OpacityEntry : public SaveLayerEntry { public: - OpacityEntry(const SkRect* bounds, SkScalar opacity, bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), opacity_(opacity) {} + OpacityEntry(const SkRect* bounds, + SkScalar outstanding_opacity, + SkScalar opacity, + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), + outstanding_opacity_(outstanding_opacity), + opacity_(opacity) {} - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; + void restore(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: + const SkScalar outstanding_opacity_; const SkScalar opacity_; }; @@ -130,7 +169,9 @@ class LayerStateStack { : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} ~ImageFilterEntry() override = default; - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const std::shared_ptr filter_; @@ -144,7 +185,9 @@ class LayerStateStack { : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} ~ColorFilterEntry() override = default; - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const std::shared_ptr filter_; @@ -161,9 +204,13 @@ class LayerStateStack { blend_mode_(blend_mode) {} ~BackdropFilterEntry() override = default; - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; - bool is_backdrop_filter() const override { return false; } + void reapply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const std::shared_ptr filter_; @@ -176,7 +223,9 @@ class LayerStateStack { public: TranslateEntry(SkScalar tx, SkScalar ty) : tx_(tx), ty_(ty) {} - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const SkScalar tx_; @@ -187,7 +236,9 @@ class LayerStateStack { public: TransformMatrixEntry(const SkMatrix& matrix) : matrix_(matrix) {} - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const SkMatrix matrix_; @@ -197,7 +248,9 @@ class LayerStateStack { public: TransformM44Entry(const SkM44& m44) : m44_(m44) {} - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const SkM44 m44_; @@ -215,7 +268,9 @@ class LayerStateStack { ClipRectEntry(const SkRect& rect, bool is_aa) : ClipEntry(is_aa), rect_(rect) {} - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const SkRect rect_; @@ -226,7 +281,9 @@ class LayerStateStack { ClipRRectEntry(const SkRRect& rrect, bool is_aa) : ClipEntry(is_aa), rrect_(rrect) {} - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const SkRRect rrect_; @@ -238,7 +295,9 @@ class LayerStateStack { : ClipEntry(is_aa), path_(path) {} ~ClipPathEntry() override = default; - void apply(SkCanvas* canvas, DisplayListBuilder* builder) const override; + void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; private: const SkPath path_; @@ -247,9 +306,10 @@ class LayerStateStack { std::vector> state_stack_; SkCanvas* canvas_ = nullptr; - int canvas_restore_count_; + int canvas_restore_count_ = 0.0; DisplayListBuilder* builder_ = nullptr; - int builder_restore_count_; + int builder_restore_count_ = 0.0; + RenderingAttributes outstanding_; }; } // namespace flutter From 396560f5234b705d22e1ace9a3d3f4b5a4d424dd Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 26 Aug 2022 14:09:42 -0700 Subject: [PATCH 11/19] actually use new reapply method where appropriate --- flow/layers/layer_state_stack.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 3573a2ce8601a..3dc4a07ffbed5 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -19,7 +19,7 @@ void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { canvas_restore_count_ = canvas->getSaveCount(); canvas_ = canvas; for (auto& state : state_stack_) { - state->apply(&outstanding_, canvas, nullptr); + state->reapply(&outstanding_, canvas, nullptr); } } } @@ -33,7 +33,7 @@ void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { builder_restore_count_ = builder->getSaveCount(); builder_ = builder; for (auto& state : state_stack_) { - state->apply(&outstanding_, nullptr, builder); + state->reapply(&outstanding_, nullptr, builder); } } } From 52b885edb4570694fb8fe4a5ef5d7bee2e3753e2 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 1 Sep 2022 13:01:36 -0700 Subject: [PATCH 12/19] more work on lazy saveLayers --- display_list/display_list_color_filter.h | 11 ++ display_list/display_list_paint.h | 4 + flow/layers/clip_shape_layer.h | 13 +- flow/layers/layer.h | 4 + flow/layers/layer_state_stack.cc | 114 ++++++++++++------ flow/layers/layer_state_stack.h | 145 +++++++++++++++++------ 6 files changed, 213 insertions(+), 78 deletions(-) diff --git a/display_list/display_list_color_filter.h b/display_list/display_list_color_filter.h index 7f03fbf5cb1df..8ac6eba47ee35 100644 --- a/display_list/display_list_color_filter.h +++ b/display_list/display_list_color_filter.h @@ -57,6 +57,11 @@ class DlColorFilter // pixels non-transparent and therefore expand the bounds. virtual bool modifies_transparent_black() const = 0; + // Return a boolean indicating whether the color filtering operation can + // be applied either before or after modulating the pixels with an opacity + // value without changing the operation. + virtual bool can_commute_with_alpha() const { return false; } + // Return a DlBlendColorFilter pointer to this object iff it is a Blend // type of ColorFilter, otherwise return nullptr. virtual const DlBlendColorFilter* asBlend() const { return nullptr; } @@ -150,6 +155,12 @@ class DlMatrixColorFilter final : public DlColorFilter { sk_filter->filterColor(SK_ColorTRANSPARENT) != SK_ColorTRANSPARENT; } + bool can_commute_with_alpha() const override { + return matrix_[3] == 0 && matrix_[8] == 0 && matrix_[13] == 0 && + matrix_[15] == 0 && matrix_[16] == 0 && matrix_[17] == 0 && + (matrix_[18] >= 0.0 && matrix_[18] <= 1.0) && matrix_[19] == 0; + } + std::shared_ptr shared() const override { return std::make_shared(this); } diff --git a/display_list/display_list_paint.h b/display_list/display_list_paint.h index 1bd6f6bed562b..9eb0ad0de2b2a 100644 --- a/display_list/display_list_paint.h +++ b/display_list/display_list_paint.h @@ -104,6 +104,10 @@ class DlPaint { color_.argb = alpha << 24 | (color_.argb & 0x00FFFFFF); return *this; } + DlPaint& setOpacity(SkScalar opacity) { + setAlpha(SkScalarRoundToInt(opacity * 0xff)); + return *this; + } DlBlendMode getBlendMode() const { return static_cast(blendMode_); diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index 08c4a82324b43..e48428f34372a 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -79,7 +79,7 @@ class ClipShapeLayer : public CacheableContainerLayer { void Paint(PaintContext& context) const override { FML_DCHECK(needs_painting(context)); - auto save = context.state_stack.save(); + auto restore = context.state_stack.save(); OnStackClipShape(context.state_stack); if (!UsesSaveLayer()) { @@ -88,17 +88,20 @@ class ClipShapeLayer : public CacheableContainerLayer { } if (context.raster_cache) { + auto restore_apply = context.state_stack.applyState( + &paint_bounds(), LayerStateStack::CALLER_CAN_APPLY_OPACITY); + AutoCachePaint cache_paint(context); - if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { + if (layer_raster_cache_item_->Draw(context, + context.state_stack.sk_paint())) { return; } } // saveWithOpacity optimizes the case where opacity >= 1.0 // to a simple saveLayer - auto save_layer = context.state_stack.saveWithOpacity( - &paint_bounds(), context.inherited_opacity, - context.checkerboard_offscreen_layers); + auto save_layer = context.state_stack.saveLayer( + &child_paint_bounds(), checkerboard_bounds(context)); PaintChildren(context); } diff --git a/flow/layers/layer.h b/flow/layers/layer.h index fe90d2d6bb10d..49da5ae1f9a94 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -292,6 +292,10 @@ class Layer { paint_bounds_ = paint_bounds; } + const SkRect* checkerboard_bounds(PaintContext context) const { + return context.checkerboard_offscreen_layers ? &paint_bounds_ : nullptr; + } + // Determines if the layer has any content. bool is_empty() const { return paint_bounds_.isEmpty(); } diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 3dc4a07ffbed5..70109ec2deef6 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -45,16 +45,39 @@ AutoRestore::~AutoRestore() { stack_->restoreToCount(stack_restore_count_); } -const RenderingAttributes LayerStateStack::applyOutstandingState( - int can_apply_flags) { - SkScalar cur_opacity = outstanding_.opacity; - if (cur_opacity >= SK_Scalar1 || (can_apply_flags & CAN_APPLY_OPACITY) != 0) { - return {cur_opacity}; - } else { - resolve(nullptr, &outstanding_, canvas_, builder_); - outstanding_.opacity = SK_Scalar1; - return {SK_Scalar1}; +static bool needsResolve(RenderingAttributes& outstanding, int flags) { + if (outstanding.opacity < SK_Scalar1 && + (flags & LayerStateStack::CALLER_CAN_APPLY_OPACITY)) { + return true; + } + // Check IF and CF eventually... + return false; +} + +AutoRestore LayerStateStack::applyState(const SkRect& bounds, + int can_apply_flags) { + auto ret = LayerStateStack::AutoRestore(this); + if (needsResolve(outstanding_, can_apply_flags)) { + resolve(bounds); } + return ret; +} + +const SkPaint* LayerStateStack::sk_paint() { + if (needsResolve(outstanding_, 0)) { + temp_sk_paint_.setAlphaf(outstanding_.opacity); + // set IF and CF eventually... + return &temp_sk_paint_; + } + return nullptr; +} + +const DlPaint* LayerStateStack::dl_paint() { + if (outstanding_.opacity < SK_Scalar1) { + temp_dl_paint_.setOpacity(outstanding_.opacity); + return &temp_dl_paint_; + } + return nullptr; } AutoRestore LayerStateStack::save() { @@ -65,24 +88,25 @@ AutoRestore LayerStateStack::save() { } AutoRestore LayerStateStack::saveLayer(const SkRect* bounds, - bool checkerboard) { + const SkRect* checker_bounds) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( - std::make_unique(bounds, checkerboard)); + std::make_unique(bounds, checker_bounds)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } AutoRestore LayerStateStack::saveWithOpacity(const SkRect* bounds, SkScalar opacity, - bool checkerboard) { + const SkRect* checker_bounds) { auto ret = AutoRestore(this); if (opacity < SK_Scalar1) { + pushAttributes(); state_stack_.emplace_back(std::make_unique( - bounds, outstanding_.opacity, opacity, checkerboard)); + bounds, outstanding_.opacity, opacity, checker_bounds)); } else { state_stack_.emplace_back( - std::make_unique(bounds, checkerboard)); + std::make_unique(bounds, checker_bounds)); } state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; @@ -91,10 +115,10 @@ AutoRestore LayerStateStack::saveWithOpacity(const SkRect* bounds, AutoRestore LayerStateStack::saveWithImageFilter( const SkRect* bounds, const std::shared_ptr filter, - bool checkerboard) { + const SkRect* checker_bounds) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( - std::make_unique(bounds, filter, checkerboard)); + std::make_unique(bounds, filter, checker_bounds)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } @@ -102,10 +126,10 @@ AutoRestore LayerStateStack::saveWithImageFilter( AutoRestore LayerStateStack::saveWithColorFilter( const SkRect* bounds, const std::shared_ptr filter, - bool checkerboard) { + const SkRect* checker_bounds) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( - std::make_unique(bounds, filter, checkerboard)); + std::make_unique(bounds, filter, checker_bounds)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } @@ -114,10 +138,10 @@ AutoRestore LayerStateStack::saveWithBackdropFilter( const SkRect* bounds, const std::shared_ptr filter, DlBlendMode blend_mode, - bool checkerboard) { + const SkRect* checker_bounds) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back(std::make_unique( - bounds, filter, blend_mode, checkerboard)); + bounds, filter, blend_mode, checker_bounds)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } @@ -159,6 +183,17 @@ void LayerStateStack::restoreToCount(size_t restore_count) { } } +void LayerStateStack::pushAttributes() { + state_stack_.emplace_back(std::make_unique(outstanding_)); +} + +void LayerStateStack::AttributesEntry::restore( + RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const { + *attributes = attributes_; +} + void LayerStateStack::SaveEntry::apply(RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { @@ -196,12 +231,13 @@ void LayerStateStack::SaveLayerEntry::apply(RenderingAttributes* attributes, void LayerStateStack::SaveLayerEntry::do_checkerboard( SkCanvas* canvas, DisplayListBuilder* builder) const { - if (checkerboard_ && has_bounds_) { + const SkRect* bounds = checkerboard_bounds(); + if (bounds) { if (canvas) { - SkDrawCheckerboard(canvas, bounds_); + SkDrawCheckerboard(canvas, *bounds); } if (builder) { - DlDrawCheckerboard(builder, bounds_); + DlDrawCheckerboard(builder, *bounds); } } } @@ -212,26 +248,26 @@ void LayerStateStack::OpacityEntry::apply(RenderingAttributes* attributes, attributes->opacity *= opacity_; } -void LayerStateStack::OpacityEntry::restore(RenderingAttributes* attributes, - SkCanvas* canvas, - DisplayListBuilder* builder) const { - attributes->opacity = outstanding_opacity_; -} - -void LayerStateStack::resolve(const SkRect* bounds, - RenderingAttributes* attributes, - SkCanvas* canvas, - DisplayListBuilder* builder) { - if (canvas) { +void LayerStateStack::resolve(const SkRect& bounds) { + if (!canvas_ && !builder_) { + return; + } + SkScalar opacity = outstanding_.opacity; + if (opacity >= SK_Scalar1) { + return; + } + pushAttributes(); + if (canvas_) { SkPaint paint; - paint.setAlphaf(attributes->opacity); - canvas->saveLayer(bounds, &paint); + paint.setAlphaf(opacity); + canvas_->saveLayer(bounds, sk_paint()); } - if (builder) { + if (builder_) { DlPaint paint; - paint.setAlpha(SkScalarRoundToInt(attributes->opacity * 255)); - builder->saveLayer(bounds, &paint); + paint.setOpacity(opacity); + builder_->saveLayer(&bounds, dl_paint()); } + outstanding_ = {}; } void LayerStateStack::ImageFilterEntry::apply( diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 203933da9f989..183848574275b 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -35,33 +35,92 @@ class LayerStateStack { size_t stack_restore_count_; }; - static constexpr int CAN_APPLY_OPACITY = 0x1; + static constexpr int CALLER_CAN_APPLY_OPACITY = 0x1; struct RenderingAttributes { + SkRect content_bounds; SkScalar opacity = SK_Scalar1; }; - const RenderingAttributes applyOutstandingState(int can_apply_flags = 0); - + // Apply the outstanding state via saveLayer if necessary, + // respecting the flags representing which potentially + // outstanding attributes the calling layer can apply + // themselves. + // + // A saveLayer may or may not be sent to the delegates depending + // on the outstanding state and the flags supplied by the caller. + // + // An AutoRestore instance will always be returned even if there + // was no saveLayer applied. + [[nodiscard]] AutoRestore applyState(const SkRect& bounds, + int can_apply_flags = 0); + + // Return a pointer to an SkPaint instance representing the + // currently outstanding rendering attributes, or a nullptr + // if there are no outstanding attributes for the caller to + // apply during rendering operations. + const SkPaint* sk_paint(); + + // Return a pointer to an DlPaint instance representing the + // currently outstanding rendering attributes, or a nullptr + // if there are no outstanding attributes for the caller to + // apply during rendering operations. + const DlPaint* dl_paint(); + + // Saves the current state of the state stack until the next + // matching restore call. [[nodiscard]] AutoRestore save(); + + // Saves the state stack and immediately executes a saveLayer + // with all accumulated state onto the canvas or builder to + // be applied at the next matching restore. A saveLayer is + // always executed by this method even if there are no + // outstanding attributes. [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds, - bool checkerboard = false); - [[nodiscard]] AutoRestore saveWithOpacity(const SkRect* bounds, - SkScalar opacity, - bool checkerboard = false); + const SkRect* checker_bounds = nullptr); + + // Records the opacity for application at the next call to + // saveLayer or applyState. A saveLayer may be executed at + // this time if the opacity cannot be batched with other + // outstanding attributes. + [[nodiscard]] AutoRestore saveWithOpacity( + const SkRect* bounds, + SkScalar opacity, + const SkRect* checker_bounds = nullptr); + + // Records the image filter for application at the next call to + // saveLayer or applyState. A saveLayer may be executed at + // this time if the image filter cannot be batched with other + // outstanding attributes. + // (Currently only opacity is recorded for batching) [[nodiscard]] AutoRestore saveWithImageFilter( const SkRect* bounds, const std::shared_ptr filter, - bool checkerboard = false); + const SkRect* checker_bounds = nullptr); + + // Records the color filter for application at the next call to + // saveLayer or applyState. A saveLayer may be executed at + // this time if the color filter cannot be batched with other + // outstanding attributes. + // (Currently only opacity is recorded for batching) [[nodiscard]] AutoRestore saveWithColorFilter( const SkRect* bounds, const std::shared_ptr filter, - bool checkerboard = false); + const SkRect* checker_bounds = nullptr); + + // Saves the state stack and immediately executes a saveLayer + // with the indicated backdrop filter and any outstanding + // state attributes. Since the backdrop filter only applies + // to the pixels alrady on the screen when this call is made, + // the backdrop filter will only be applied to the canvas or + // builder installed at the time that this call is made, and + // subsequent canvas or builder objects that are made delegates + // will only see a saveLayer with the indicated blend_mode. [[nodiscard]] AutoRestore saveWithBackdropFilter( const SkRect* bounds, const std::shared_ptr filter, DlBlendMode blend_mode, - bool checkerboard = false); + const SkRect* checker_bounds = nullptr); void translate(SkScalar tx, SkScalar ty); void transform(const SkM44& matrix); @@ -75,10 +134,16 @@ class LayerStateStack { size_t getStackCount() { return state_stack_.size(); } void restoreToCount(size_t restore_count); - static void resolve(const SkRect* bounds, - RenderingAttributes* attributes, - SkCanvas* canvas, - DisplayListBuilder* builder); + void pushAttributes(); + + void resolve(const SkRect& bounds); + + static std::optional OptionalBounds(const SkRect* bounds) { + return bounds ? std::make_optional(*bounds) : std::nullopt; + } + static const SkRect* BoundsPtr(const std::optional& bounds) { + return bounds.has_value() ? &bounds.value() : nullptr; + } class StateEntry { public: @@ -99,6 +164,18 @@ class LayerStateStack { DisplayListBuilder* builder) const {} }; + class AttributesEntry : public StateEntry { + public: + AttributesEntry(RenderingAttributes attributes) : attributes_(attributes) {} + + void restore(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override; + + private: + const RenderingAttributes attributes_; + }; + class SaveEntry : public StateEntry { public: SaveEntry() = default; @@ -117,25 +194,25 @@ class LayerStateStack { class SaveLayerEntry : public SaveEntry { public: - SaveLayerEntry(const SkRect* bounds, bool checkerboard) - : bounds_(bounds ? *bounds : SkRect::MakeEmpty()), - has_bounds_(bounds != nullptr), - checkerboard_(checkerboard) {} + SaveLayerEntry(const SkRect* bounds, const SkRect* checker_bounds) + : bounds_(OptionalBounds(bounds)), + checkerboard_(OptionalBounds(checker_bounds)) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const override; protected: - const SkRect bounds_; - const bool has_bounds_; - const bool checkerboard_; + const std::optional bounds_; + const std::optional checkerboard_; void do_checkerboard(SkCanvas* canvas, DisplayListBuilder* builder) const override; - const SkRect* save_bounds() const { - return has_bounds_ ? &bounds_ : nullptr; + const SkRect* save_bounds() const { return BoundsPtr(bounds_); } + + const SkRect* checkerboard_bounds() const { + return BoundsPtr(checkerboard_); } }; @@ -144,17 +221,14 @@ class LayerStateStack { OpacityEntry(const SkRect* bounds, SkScalar outstanding_opacity, SkScalar opacity, - bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), + const SkRect* checker_bounds) + : SaveLayerEntry(bounds, checker_bounds), outstanding_opacity_(outstanding_opacity), opacity_(opacity) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const override; - void restore(RenderingAttributes* attributes, - SkCanvas* canvas, - DisplayListBuilder* builder) const override; private: const SkScalar outstanding_opacity_; @@ -165,8 +239,8 @@ class LayerStateStack { public: ImageFilterEntry(const SkRect* bounds, const std::shared_ptr filter, - bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} + const SkRect* checker_bounds) + : SaveLayerEntry(bounds, checker_bounds), filter_(filter) {} ~ImageFilterEntry() override = default; void apply(RenderingAttributes* attributes, @@ -181,8 +255,8 @@ class LayerStateStack { public: ColorFilterEntry(const SkRect* bounds, const std::shared_ptr filter, - bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} + const SkRect* checker_bounds) + : SaveLayerEntry(bounds, checker_bounds), filter_(filter) {} ~ColorFilterEntry() override = default; void apply(RenderingAttributes* attributes, @@ -198,8 +272,8 @@ class LayerStateStack { BackdropFilterEntry(const SkRect* bounds, const std::shared_ptr filter, DlBlendMode blend_mode, - bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), + const SkRect* checker_bounds) + : SaveLayerEntry(bounds, checker_bounds), filter_(filter), blend_mode_(blend_mode) {} ~BackdropFilterEntry() override = default; @@ -310,6 +384,9 @@ class LayerStateStack { DisplayListBuilder* builder_ = nullptr; int builder_restore_count_ = 0.0; RenderingAttributes outstanding_; + + SkPaint temp_sk_paint_; + DlPaint temp_dl_paint_; }; } // namespace flutter From 6c373939aa07cd730b7445c48670f1f3cae0f556 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 1 Sep 2022 22:48:25 -0700 Subject: [PATCH 13/19] more complete opacity inheritance, lots of unit test errors though --- flow/layers/backdrop_filter_layer.cc | 2 +- flow/layers/clip_path_layer_unittests.cc | 44 ++++----- flow/layers/clip_rect_layer_unittests.cc | 44 ++++----- flow/layers/clip_rrect_layer_unittests.cc | 44 ++++----- flow/layers/clip_shape_layer.h | 10 +- flow/layers/color_filter_layer.cc | 3 +- flow/layers/color_filter_layer_unittests.cc | 7 +- flow/layers/container_layer.cc | 25 +++-- flow/layers/container_layer.h | 8 ++ flow/layers/container_layer_unittests.cc | 37 ++++---- flow/layers/display_list_layer.cc | 38 ++++---- flow/layers/display_list_layer_unittests.cc | 13 +-- flow/layers/display_list_raster_cache_item.cc | 2 +- flow/layers/image_filter_layer.cc | 2 +- flow/layers/image_filter_layer_unittests.cc | 7 +- flow/layers/layer.h | 94 +------------------ flow/layers/layer_state_stack.cc | 2 +- flow/layers/layer_state_stack.h | 12 ++- flow/layers/layer_tree.cc | 1 - flow/layers/layer_tree_unittests.cc | 8 +- flow/layers/opacity_layer.cc | 46 ++------- flow/layers/opacity_layer_unittests.cc | 32 +++---- flow/layers/physical_shape_layer.cc | 2 +- flow/layers/physical_shape_layer_unittests.cc | 3 +- flow/layers/platform_view_layer_unittests.cc | 3 +- flow/layers/shader_mask_layer.cc | 12 ++- flow/layers/shader_mask_layer_unittests.cc | 5 +- flow/layers/texture_layer.cc | 6 +- flow/layers/texture_layer_unittests.cc | 4 +- flow/layers/transform_layer.cc | 4 - flow/layers/transform_layer_unittests.cc | 23 ++--- flow/testing/mock_layer.cc | 13 +-- flow/testing/mock_layer_unittests.cc | 7 +- flow/testing/mock_raster_cache.cc | 1 - flow/testing/mock_raster_cache.h | 1 - shell/common/shell_unittests.cc | 1 - 36 files changed, 212 insertions(+), 354 deletions(-) diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index bb9d13901fa66..711d962179674 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -47,7 +47,7 @@ void BackdropFilterLayer::Preroll(PrerollContext* context, PrerollChildren(context, matrix, &child_paint_bounds); child_paint_bounds.join(context->cull_rect); set_paint_bounds(child_paint_bounds); - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } void BackdropFilterLayer::Paint(PaintContext& context) const { diff --git a/flow/layers/clip_path_layer_unittests.cc b/flow/layers/clip_path_layer_unittests.cc index 78c0158f7f0ab..581f247e1265a 100644 --- a/flow/layers/clip_path_layer_unittests.cc +++ b/flow/layers/clip_path_layer_unittests.cc @@ -279,9 +279,9 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); auto mock2 = MockLayer::MakeOpacityCompatible(path2); @@ -289,9 +289,9 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - context->subtree_can_inherit_opacity = false; clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); auto mock3 = MockLayer::MakeOpacityCompatible(path3); @@ -299,9 +299,8 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // ClipRectLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible - context->subtree_can_inherit_opacity = false; clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); { // ClipRectLayer(aa with saveLayer) will always be compatible @@ -311,15 +310,15 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { clip_path_saveLayer->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_path_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the overlapping child and test again, should still be compatible clip_path_saveLayer->Add(mock3); - context->subtree_can_inherit_opacity = false; clip_path_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); } // An incompatible, but non-overlapping child for the following tests @@ -334,17 +333,16 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { clip_path_bad_child->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_path_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); clip_path_bad_child->Add(mock4); // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible - context->subtree_can_inherit_opacity = false; clip_path_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); } { @@ -355,15 +353,15 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { clip_path_saveLayer_bad_child->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_path_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the incompatible child and test again, should still be compatible clip_path_saveLayer_bad_child->Add(mock4); - context->subtree_can_inherit_opacity = false; clip_path_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); } } @@ -383,15 +381,14 @@ TEST_F(ClipPathLayerTest, OpacityInheritancePainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_path_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); @@ -449,15 +446,14 @@ TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_path_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/clip_rect_layer_unittests.cc b/flow/layers/clip_rect_layer_unittests.cc index e7edef17adb73..f11ee5ebea4e8 100644 --- a/flow/layers/clip_rect_layer_unittests.cc +++ b/flow/layers/clip_rect_layer_unittests.cc @@ -272,9 +272,9 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); auto mock2 = MockLayer::MakeOpacityCompatible(path2); @@ -282,9 +282,9 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - context->subtree_can_inherit_opacity = false; clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); auto mock3 = MockLayer::MakeOpacityCompatible(path3); @@ -292,9 +292,8 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // ClipRectLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible - context->subtree_can_inherit_opacity = false; clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); { // ClipRectLayer(aa with saveLayer) will always be compatible @@ -304,15 +303,15 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { clip_rect_saveLayer->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the overlapping child and test again, should still be compatible clip_rect_saveLayer->Add(mock3); - context->subtree_can_inherit_opacity = false; clip_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); } // An incompatible, but non-overlapping child for the following tests @@ -327,17 +326,16 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { clip_rect_bad_child->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); clip_rect_bad_child->Add(mock4); // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible - context->subtree_can_inherit_opacity = false; clip_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); } { @@ -348,15 +346,15 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { clip_rect_saveLayer_bad_child->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the incompatible child and test again, should still be compatible clip_rect_saveLayer_bad_child->Add(mock4); - context->subtree_can_inherit_opacity = false; clip_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); } } @@ -374,15 +372,14 @@ TEST_F(ClipRectLayerTest, OpacityInheritancePainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_rect_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); @@ -438,15 +435,14 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_rect_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/clip_rrect_layer_unittests.cc b/flow/layers/clip_rrect_layer_unittests.cc index 60a063ec83743..a8ea0df1e79bb 100644 --- a/flow/layers/clip_rrect_layer_unittests.cc +++ b/flow/layers/clip_rrect_layer_unittests.cc @@ -278,9 +278,9 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); auto mock2 = MockLayer::MakeOpacityCompatible(path2); @@ -288,9 +288,9 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - context->subtree_can_inherit_opacity = false; clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); auto mock3 = MockLayer::MakeOpacityCompatible(path3); @@ -298,9 +298,8 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // ClipRectLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible - context->subtree_can_inherit_opacity = false; clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); { // ClipRectLayer(aa with saveLayer) will always be compatible @@ -310,15 +309,15 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { clip_r_rect_saveLayer->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_r_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the overlapping child and test again, should still be compatible clip_r_rect_saveLayer->Add(mock3); - context->subtree_can_inherit_opacity = false; clip_r_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); } // An incompatible, but non-overlapping child for the following tests @@ -333,17 +332,16 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { clip_r_rect_bad_child->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_r_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); clip_r_rect_bad_child->Add(mock4); // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible - context->subtree_can_inherit_opacity = false; clip_r_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); } { @@ -354,15 +352,15 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { clip_r_rect_saveLayer_bad_child->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; clip_r_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the incompatible child and test again, should still be compatible clip_r_rect_saveLayer_bad_child->Add(mock4); - context->subtree_can_inherit_opacity = false; clip_r_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); } } @@ -381,15 +379,14 @@ TEST_F(ClipRRectLayerTest, OpacityInheritancePainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_rect_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); @@ -446,15 +443,14 @@ TEST_F(ClipRRectLayerTest, OpacityInheritanceSaveLayerPainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_r_rect_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index e48428f34372a..a6697d2b84253 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -56,10 +56,6 @@ class ClipShapeLayer : public CacheableContainerLayer { Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer()); OnMutatorsStackPushClipShape(context->mutators_stack); - // Collect inheritance information on our children in Preroll so that - // we can pass it along by default. - context->subtree_can_inherit_opacity = true; - SkRect child_paint_bounds = SkRect::MakeEmpty(); PrerollChildren(context, matrix, &child_paint_bounds); if (child_paint_bounds.intersect(clip_shape_bounds())) { @@ -69,7 +65,8 @@ class ClipShapeLayer : public CacheableContainerLayer { // If we use a SaveLayer then we can accept opacity on behalf // of our children and apply it in the saveLayer. if (uses_save_layer) { - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = + LayerStateStack::CALLER_CAN_APPLY_OPACITY; } context->mutators_stack.Pop(); @@ -89,9 +86,8 @@ class ClipShapeLayer : public CacheableContainerLayer { if (context.raster_cache) { auto restore_apply = context.state_stack.applyState( - &paint_bounds(), LayerStateStack::CALLER_CAN_APPLY_OPACITY); + paint_bounds(), LayerStateStack::CALLER_CAN_APPLY_OPACITY); - AutoCachePaint cache_paint(context); if (layer_raster_cache_item_->Draw(context, context.state_stack.sk_paint())) { return; diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 5211c9733a30c..aec3cae3ff75c 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -39,9 +39,10 @@ void ColorFilterLayer::Preroll(PrerollContext* context, AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context, matrix); ContainerLayer::Preroll(context, matrix); + // We always use a saveLayer (or a cached rendering), so we // can always apply opacity in those cases. - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } void ColorFilterLayer::Paint(PaintContext& context) const { diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index 63ac582c5b527..71c549ae71291 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -416,17 +416,18 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { color_filter_layer->Add(mock_layer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; + context->rendering_state_flags = 0; color_filter_layer->Preroll(preroll_context(), initial_transform); // ColorFilterLayer can always inherit opacity whether or not their // children are compatible. - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(color_filter_layer); - context->subtree_can_inherit_opacity = false; + context->rendering_state_flags = 0; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index a37f7d92f4759..4a906eec7ca1b 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -8,7 +8,9 @@ namespace flutter { -ContainerLayer::ContainerLayer() : child_paint_bounds_(SkRect::MakeEmpty()) {} +ContainerLayer::ContainerLayer() + : child_paint_bounds_(SkRect::MakeEmpty()), + children_rendering_state_flags_(0) {} void ContainerLayer::Diff(DiffContext* context, const Layer* old_layer) { auto old_container = static_cast(old_layer); @@ -138,7 +140,8 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, bool child_has_platform_view = false; bool child_has_texture_layer = false; - bool subtree_can_inherit_opacity = context->subtree_can_inherit_opacity; + int children_rendering_state_flags = + LayerStateStack::CALLER_CAN_APPLY_ANYTHING; for (auto& layer : layers_) { // Reset context->has_platform_view and context->has_texture_layer to false @@ -149,18 +152,16 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, // Initialize the "inherit opacity" flag to false and allow the layer to // override the answer during its |Preroll| - context->subtree_can_inherit_opacity = false; + context->rendering_state_flags = 0; layer->Preroll(context, child_matrix); - subtree_can_inherit_opacity = - subtree_can_inherit_opacity && context->subtree_can_inherit_opacity; - if (subtree_can_inherit_opacity && - safe_intersection_test(child_paint_bounds, layer->paint_bounds())) { + children_rendering_state_flags &= context->rendering_state_flags; + if (safe_intersection_test(child_paint_bounds, layer->paint_bounds())) { // This will allow inheritance by a linear sequence of non-overlapping // children, but will fail with a grid or other arbitrary 2D layout. // See https://github.com/flutter/flutter/issues/93899 - subtree_can_inherit_opacity = false; + children_rendering_state_flags = 0; } child_paint_bounds->join(layer->paint_bounds()); @@ -172,8 +173,9 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, context->has_platform_view = child_has_platform_view; context->has_texture_layer = child_has_texture_layer; - context->subtree_can_inherit_opacity = subtree_can_inherit_opacity; + context->rendering_state_flags = children_rendering_state_flags; set_subtree_has_platform_view(child_has_platform_view); + set_children_rendering_state_flags(children_rendering_state_flags); child_paint_bounds_ = *child_paint_bounds; } @@ -184,6 +186,11 @@ void ContainerLayer::PaintChildren(PaintContext& context) const { // layer calls PaintChildren(), though, it may have modified the // PaintContext so the test doesn't work in this "context". + // Apply any outstanding state that the children cannot individually + // and collectively handle. + auto restore = context.state_stack.applyState( + child_paint_bounds(), children_rendering_state_flags()); + // Intentionally not tracing here as there should be no self-time // and the trace event on this common function has a small overhead. for (auto& layer : layers_) { diff --git a/flow/layers/container_layer.h b/flow/layers/container_layer.h index cb3d497aa642a..2824b2999de31 100644 --- a/flow/layers/container_layer.h +++ b/flow/layers/container_layer.h @@ -34,6 +34,13 @@ class ContainerLayer : public Layer { const SkRect& child_paint_bounds() const { return child_paint_bounds_; } + int children_rendering_state_flags() const { + return children_rendering_state_flags_; + } + void set_children_rendering_state_flags(int flags) { + children_rendering_state_flags_ = flags; + } + protected: void PrerollChildren(PrerollContext* context, const SkMatrix& child_matrix, @@ -42,6 +49,7 @@ class ContainerLayer : public Layer { private: std::vector> layers_; SkRect child_paint_bounds_; + int children_rendering_state_flags_; FML_DISALLOW_COPY_AND_ASSIGN(ContainerLayer); }; diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index f1c6df8cdf203..94a3f7ac11c5a 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -460,53 +460,48 @@ TEST_F(ContainerLayerTest, OpacityInheritance) { auto container1 = std::make_shared(); container1->Add(mock1); - // ContainerLayer will not pass through compatibility on its own - // Subclasses must explicitly enable this in their own Preroll + // Single opacity compatible child makes container compatible PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; container1->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); auto mock2 = MockLayer::MakeOpacityCompatible(path2); container1->Add(mock2); - // ContainerLayer will pass through compatibility from multiple - // non-overlapping compatible children if the caller enables it - context->subtree_can_inherit_opacity = true; + // Multiple non-overlapping opacity compatible children are compatible container1->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); auto mock3 = MockLayer::MakeOpacityCompatible(path3); container1->Add(mock3); - // ContainerLayer will not pass through compatibility from multiple - // overlapping children even if they are individually compatible - // and the caller requests it - context->subtree_can_inherit_opacity = true; + // Multiple overlapping individually opacity compatible children result + // in a non-compatible layer container1->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); auto container2 = std::make_shared(); container2->Add(mock1); container2->Add(mock2); - // Double check first two children are compatible and non-overlapping - // if the caller requests it - context->subtree_can_inherit_opacity = true; + // Start again with 2 non-overlapping individually opacity compatible + // children. container2->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path4 = SkPath().addRect({60, 60, 70, 70}); auto mock4 = MockLayer::Make(path4); container2->Add(mock4); - // The third child is non-overlapping, but not compatible so the - // TransformLayer should end up incompatible - context->subtree_can_inherit_opacity = true; + // Add a third child which is not opacity compatible even though it is + // also non-overlapping which will result in an incompatible container. container2->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); } TEST_F(ContainerLayerTest, CollectionCacheableLayer) { SkPath child_path; diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 48623f9986c72..e13848f6f7a8b 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -98,8 +98,8 @@ void DisplayListLayer::Preroll(PrerollContext* context, AutoCache cache = AutoCache(display_list_raster_cache_item_.get(), context, matrix); - if (disp_list->can_apply_group_opacity()) { - context->subtree_can_inherit_opacity = true; + if (disp_list->can_apply_group_opacity() && !context->display_list_enabled) { + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } set_paint_bounds(bounds_); } @@ -112,14 +112,21 @@ void DisplayListLayer::Paint(PaintContext& context) const { auto save = context.state_stack.save(); context.state_stack.translate(offset_.x(), offset_.y()); - // if (context.raster_cache && display_list_raster_cache_item_) { - // AutoCachePaint cache_paint(context); - // if (display_list_raster_cache_item_->Draw(context, - // cache_paint.sk_paint())) { - // TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); - // return; - // } - // } + if (context.raster_cache && display_list_raster_cache_item_) { + if (display_list_raster_cache_item_->Draw(context, + context.state_stack.sk_paint())) { + TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); + return; + } + } + + auto restore = context.state_stack.applyState( + paint_bounds(), + display_list()->can_apply_group_opacity() && !context.builder + ? LayerStateStack::CALLER_CAN_APPLY_OPACITY + : 0); + + SkScalar opacity = context.state_stack.outstanding_opacity(); if (context.enable_leaf_layer_tracing) { const auto canvas_size = context.canvas->getBaseLayerSize(); @@ -135,7 +142,7 @@ void DisplayListLayer::Paint(PaintContext& context) const { SkAutoCanvasRestore save(canvas, true); canvas->clear(SK_ColorTRANSPARENT); canvas->setMatrix(ctm); - display_list()->RenderTo(canvas, context.inherited_opacity); + display_list()->RenderTo(canvas, opacity); canvas->flush(); } const fml::TimeDelta offscreen_render_time = @@ -150,16 +157,9 @@ void DisplayListLayer::Paint(PaintContext& context) const { } if (context.builder) { - // AutoCachePaint save_paint(context); - // int restore_count = context.leaf_nodes_builder->getSaveCount(); - // if (save_paint.dl_paint() != nullptr) { - // context.leaf_nodes_builder->saveLayer(&paint_bounds(), - // save_paint.dl_paint()); - // } context.builder->drawDisplayList(display_list_.skia_object()); - // context.leaf_nodes_builder->restoreToCount(restore_count); } else { - display_list()->RenderTo(context.canvas, context.inherited_opacity); + display_list()->RenderTo(context.canvas, opacity); } } diff --git a/flow/layers/display_list_layer_unittests.cc b/flow/layers/display_list_layer_unittests.cc index ca88583539144..14232828a16a3 100644 --- a/flow/layers/display_list_layer_unittests.cc +++ b/flow/layers/display_list_layer_unittests.cc @@ -109,16 +109,15 @@ TEST_F(DisplayListLayerTest, SimpleDisplayListOpacityInheritance) { EXPECT_TRUE(display_list->can_apply_group_opacity()); auto context = preroll_context(); - context->subtree_can_inherit_opacity = false; display_list_layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint opacity_offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, opacity_offset); opacity_layer->Add(display_list_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); @@ -168,16 +167,14 @@ TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) { EXPECT_FALSE(display_list->can_apply_group_opacity()); auto context = preroll_context(); - context->subtree_can_inherit_opacity = false; display_list_layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); int opacity_alpha = 0x7F; SkPoint opacity_offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, opacity_offset); opacity_layer->Add(display_list_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_FALSE(opacity_layer->children_can_accept_opacity()); @@ -233,9 +230,8 @@ TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) { use_skia_raster_cache(); auto context = preroll_context(); - context->subtree_can_inherit_opacity = false; display_list_layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); // Pump the DisplayListLayer until it is ready to cache its DL display_list_layer->Preroll(preroll_context(), SkMatrix()); @@ -247,7 +243,6 @@ TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) { auto opacity_layer = std::make_shared(opacity_alpha, opacity_offset); opacity_layer->Add(display_list_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/display_list_raster_cache_item.cc b/flow/layers/display_list_raster_cache_item.cc index 56b24773ada54..6b12f9a5bc9f6 100644 --- a/flow/layers/display_list_raster_cache_item.cc +++ b/flow/layers/display_list_raster_cache_item.cc @@ -113,7 +113,7 @@ void DisplayListRasterCacheItem::PrerollFinalize(PrerollContext* context, if (!visible || accesses <= raster_cache->access_threshold()) { cache_state_ = kNone; } else { - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; cache_state_ = kCurrent; } return; diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index e3a8cff5743d3..4c853789dc2a5 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -55,7 +55,7 @@ void ImageFilterLayer::Preroll(PrerollContext* context, // We always paint with a saveLayer (or a cached rendering), // so we can always apply opacity in any of those cases. - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; if (!filter_) { set_paint_bounds(child_bounds); diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 2ad4a7e3e86d6..e2f6e937c2f37 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -446,17 +446,18 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { image_filter_layer->Add(mock_layer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; + context->rendering_state_flags = 0; image_filter_layer->Preroll(preroll_context(), initial_transform); // ImageFilterLayers can always inherit opacity whether or not their // children are compatible. - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(image_filter_layer); - context->subtree_can_inherit_opacity = false; + context->rendering_state_flags = 0; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 49da5ae1f9a94..402158143385e 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -72,42 +72,7 @@ struct PrerollContext { // prescence of a texture layer during Preroll. bool has_texture_layer = false; - // This field indicates whether the subtree rooted at this layer can - // inherit an opacity value and modulate its visibility accordingly. - // - // Any layer is free to ignore this flag. Its value will be false upon - // entry into its Preroll method, it will remain false if it calls - // PrerollChildren on any children it might have, and it will remain - // false upon exit from the Preroll method unless it takes specific - // action compute if it should be true. Thus, this property is "opt-in". - // - // If the value is false when the Preroll method exits, then the - // |PaintContext::inherited_opacity| value should always be set to - // 1.0 when its |Paint| method is called. - // - // Leaf layers need only be concerned with their own rendering and - // can set the value according to whether they can apply the opacity. - // - // For containers, there are 3 ways to interact with this field: - // - // 1. If you need to know whether your children are compatible, then - // set the field to true before you call PrerollChildren. That - // method will then reset the field to false if it detects any - // incompatible children. - // - // 2. If your decision on whether to inherit the opacity depends on - // the answer from the children, then remember the value of the - // field when PrerollChildren returns. (eg. OpacityLayer remembers - // this value to control whether to set the opacity value into the - // |PaintContext::inherited_opacity| field in |Paint| before - // recursing to its children in Paint) - // - // 3. If you want to indicate to your parents that you can accept - // inherited opacity regardless of whether your children were - // compatible then set this field to true before returning - // from your Preroll method. (eg. layers that always apply a - // saveLayer when rendering anyway can apply the opacity there) - bool subtree_can_inherit_opacity = false; + int rendering_state_flags = 0; std::vector* raster_cached_entries; @@ -146,13 +111,6 @@ struct PaintContext { LayerSnapshotStore* layer_snapshot_store = nullptr; bool enable_leaf_layer_tracing = false; - // The following value should be used to modulate the opacity of the - // layer during |Paint|. If the layer does not set the corresponding - // |layer_can_inherit_opacity()| flag, then this value should always - // be |SK_Scalar1|. The value is to be applied as if by using a - // |saveLayer| with an |SkPaint| initialized to this alphaf value and - // a |kSrcOver| blend mode. - SkScalar inherited_opacity = SK_Scalar1; DisplayListBuilder* builder = nullptr; }; @@ -214,54 +172,6 @@ class Layer { bool prev_surface_needs_readback_; }; - class AutoCachePaint { - public: - explicit AutoCachePaint(PaintContext& context) : context_(context) { - needs_paint_ = context.inherited_opacity < SK_Scalar1; - if (needs_paint_) { - sk_paint_.setAlphaf(context.inherited_opacity); - dl_paint_.setAlpha(SkScalarRoundToInt(context.inherited_opacity * 255)); - context.inherited_opacity = SK_Scalar1; - } - } - - ~AutoCachePaint() { context_.inherited_opacity = sk_paint_.getAlphaf(); } - - void setImageFilter(const DlImageFilter* filter) { - sk_paint_.setImageFilter(!filter ? nullptr : filter->skia_object()); - dl_paint_.setImageFilter(filter); - update_needs_paint(); - } - - void setColorFilter(const DlColorFilter* filter) { - sk_paint_.setColorFilter(!filter ? nullptr : filter->skia_object()); - dl_paint_.setColorFilter(filter); - update_needs_paint(); - } - - void setBlendMode(DlBlendMode mode) { - sk_paint_.setBlendMode(ToSk(mode)); - dl_paint_.setBlendMode(mode); - update_needs_paint(); - } - - const SkPaint* sk_paint() { return needs_paint_ ? &sk_paint_ : nullptr; } - const DlPaint* dl_paint() { return needs_paint_ ? &dl_paint_ : nullptr; } - - private: - PaintContext& context_; - SkPaint sk_paint_; - DlPaint dl_paint_; - bool needs_paint_; - - void update_needs_paint() { - needs_paint_ = sk_paint_.getImageFilter() != nullptr || - sk_paint_.getColorFilter() != nullptr || - !sk_paint_.isSrcOver() || - sk_paint_.getAlphaf() < SK_Scalar1; - } - }; - virtual void Paint(PaintContext& context) const = 0; virtual void PaintChildren(PaintContext& context) const { FML_DCHECK(false); } @@ -312,7 +222,7 @@ class Layer { // See https://github.com/flutter/flutter/issues/81419 return true; } - if (context.inherited_opacity == 0) { + if (!context.state_stack.needs_painting()) { return false; } // Workaround for Skia bug (quickReject does not reject empty bounds). diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 70109ec2deef6..83a93751d7010 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -103,7 +103,7 @@ AutoRestore LayerStateStack::saveWithOpacity(const SkRect* bounds, if (opacity < SK_Scalar1) { pushAttributes(); state_stack_.emplace_back(std::make_unique( - bounds, outstanding_.opacity, opacity, checker_bounds)); + bounds, opacity, checker_bounds)); } else { state_stack_.emplace_back( std::make_unique(bounds, checker_bounds)); diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 183848574275b..78f597f755493 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -36,6 +36,7 @@ class LayerStateStack { }; static constexpr int CALLER_CAN_APPLY_OPACITY = 0x1; + static constexpr int CALLER_CAN_APPLY_ANYTHING = 0x1; struct RenderingAttributes { SkRect content_bounds; @@ -55,6 +56,8 @@ class LayerStateStack { [[nodiscard]] AutoRestore applyState(const SkRect& bounds, int can_apply_flags = 0); + SkScalar outstanding_opacity() { return outstanding_.opacity; } + // Return a pointer to an SkPaint instance representing the // currently outstanding rendering attributes, or a nullptr // if there are no outstanding attributes for the caller to @@ -67,6 +70,8 @@ class LayerStateStack { // apply during rendering operations. const DlPaint* dl_paint(); + bool needs_painting() { return outstanding_.opacity > 0; } + // Saves the current state of the state stack until the next // matching restore call. [[nodiscard]] AutoRestore save(); @@ -168,6 +173,10 @@ class LayerStateStack { public: AttributesEntry(RenderingAttributes attributes) : attributes_(attributes) {} + virtual void apply(RenderingAttributes* attributes, + SkCanvas* canvas, + DisplayListBuilder* builder) const override {} + void restore(RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const override; @@ -219,11 +228,9 @@ class LayerStateStack { class OpacityEntry : public SaveLayerEntry { public: OpacityEntry(const SkRect* bounds, - SkScalar outstanding_opacity, SkScalar opacity, const SkRect* checker_bounds) : SaveLayerEntry(bounds, checker_bounds), - outstanding_opacity_(outstanding_opacity), opacity_(opacity) {} void apply(RenderingAttributes* attributes, @@ -231,7 +238,6 @@ class LayerStateStack { DisplayListBuilder* builder) const override; private: - const SkScalar outstanding_opacity_; const SkScalar opacity_; }; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 6a7d0bf9e0802..a1251c279f193 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -143,7 +143,6 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, .frame_device_pixel_ratio = device_pixel_ratio_, .layer_snapshot_store = snapshot_store, .enable_leaf_layer_tracing = enable_leaf_layer_tracing_, - .inherited_opacity = SK_Scalar1, .builder = builder // clang-format on }; diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index 0581f46e9e1d0..2c80ac2fba73d 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -219,8 +219,10 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { EXPECT_EQ(context.has_platform_view, false); EXPECT_EQ(context.has_texture_layer, false); - EXPECT_EQ(context.subtree_can_inherit_opacity, false); + EXPECT_EQ(context.rendering_state_flags, 0); EXPECT_EQ(context.raster_cached_entries, nullptr); + + EXPECT_EQ(context.display_list_enabled, false); }; // These 4 initializers are required because they are handled by reference @@ -239,8 +241,9 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { FixedRefreshRateStopwatch mock_ui_time; std::shared_ptr mock_registry; - auto expect_defaults = [&mock_raster_time, &mock_ui_time, + auto expect_defaults = [&state_stack, &mock_raster_time, &mock_ui_time, &mock_registry](const PaintContext& context) { + EXPECT_EQ(&context.state_stack, &state_stack); EXPECT_EQ(context.canvas, nullptr); EXPECT_EQ(context.gr_context, nullptr); EXPECT_EQ(context.view_embedder, nullptr); @@ -254,7 +257,6 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { EXPECT_EQ(context.enable_leaf_layer_tracing, false); EXPECT_EQ(context.layer_snapshot_store, nullptr); - EXPECT_EQ(context.inherited_opacity, SK_Scalar1); EXPECT_EQ(context.builder, nullptr); }; diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 80ac3f5e80fd9..6c73a97a1d177 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -51,18 +51,15 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); - // Collect inheritance information on our children in Preroll so that - // we can decide whether or not to use a saveLayer in Paint. - context->subtree_can_inherit_opacity = true; - // ContainerLayer will turn the flag off if any children are - // incompatible or if they overlap ContainerLayer::Preroll(context, child_matrix); // We store the inheritance ability of our children for |Paint| - set_children_can_accept_opacity(context->subtree_can_inherit_opacity); + set_children_can_accept_opacity( + (context->rendering_state_flags & + LayerStateStack::CALLER_CAN_APPLY_OPACITY) != 0); // Now we let our parent layers know that we, too, can inherit opacity // regardless of what our children are capable of - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; context->mutators_stack.Pop(); context->mutators_stack.Pop(); @@ -86,41 +83,10 @@ void OpacityLayer::Paint(PaintContext& context) const { auto save = context.state_stack.save(); context.state_stack.translate(offset_.fX, offset_.fY); - SkScalar inherited_opacity = context.inherited_opacity; - SkScalar subtree_opacity = opacity() * inherited_opacity; + auto restore = context.state_stack.saveWithOpacity( + &paint_bounds(), opacity(), checkerboard_bounds(context)); - if (children_can_accept_opacity()) { - context.inherited_opacity = subtree_opacity; - PaintChildren(context); - context.inherited_opacity = inherited_opacity; - return; - } - - SkPaint paint; - paint.setAlphaf(subtree_opacity); - - if (layer_raster_cache_item_->Draw(context, &paint)) { - return; - } - - // Skia may clip the content with saveLayerBounds (although it's not a - // guaranteed clip). So we have to provide a big enough saveLayerBounds. To do - // so, we first remove the offset from paint bounds since it's already in the - // matrix. Then we round out the bounds. - // - // Note that the following lines are only accessible when the raster cache is - // not available (e.g., when we're using the software backend in golden - // tests). - SkRect saveLayerBounds; - paint_bounds() - .makeOffset(-offset_.fX, -offset_.fY) - .roundOut(&saveLayerBounds); - - auto save_layer = - context.state_stack.saveWithOpacity(&saveLayerBounds, subtree_opacity); - context.inherited_opacity = SK_Scalar1; PaintChildren(context); - context.inherited_opacity = inherited_opacity; } } // namespace flutter diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index 6844b9bc50682..18e9263e1d93f 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -179,7 +179,6 @@ TEST_F(OpacityLayerTest, ShouldNotCacheChildren) { opacityLayer->Add(mockLayer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; use_mock_raster_cache(); @@ -194,7 +193,8 @@ TEST_F(OpacityLayerTest, ShouldNotCacheChildren) { opacityLayer->Preroll(preroll_context(), SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); LayerTree::TryToRasterCache(cacheable_items(), &paint_context()); EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0); @@ -466,9 +466,9 @@ TEST_F(OpacityLayerTest, OpacityInheritanceCompatibleChild) { opacityLayer->Add(mockLayer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); } @@ -479,9 +479,9 @@ TEST_F(OpacityLayerTest, OpacityInheritanceIncompatibleChild) { opacityLayer->Add(mockLayer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_FALSE(opacityLayer->children_can_accept_opacity()); } @@ -494,9 +494,9 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughContainer) { opacityLayer->Add(containerLayer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // By default a container layer will not pass opacity through to // its children - specific subclasses will have to enable this // pass through by setting the flag to true themselves before @@ -513,9 +513,9 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughTransform) { opacityLayer->Add(transformLayer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); } @@ -529,9 +529,9 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughImageFilter) { opacityLayer->Add(filterLayer); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); } @@ -546,9 +546,9 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithCompatibleChild) { opacityLayer1->Add(opacityLayer2); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; opacityLayer1->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer1->children_can_accept_opacity()); EXPECT_TRUE(opacityLayer2->children_can_accept_opacity()); @@ -597,9 +597,9 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithIncompatibleChild) { opacityLayer1->Add(opacityLayer2); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; opacityLayer1->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer1->children_can_accept_opacity()); EXPECT_FALSE(opacityLayer2->children_can_accept_opacity()); diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index ff0f0d65d1c18..67a62dab80fc5 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -94,7 +94,7 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { context.state_stack.clipPath(path_, true); auto saveLayer = context.state_stack.saveLayer( - &paint_bounds(), context.checkerboard_offscreen_layers); + &paint_bounds(), checkerboard_bounds(context)); context.canvas->drawColor(color_); PaintChildren(context); } else { diff --git a/flow/layers/physical_shape_layer_unittests.cc b/flow/layers/physical_shape_layer_unittests.cc index 3e41506ea4fad..f1db0375d1ade 100644 --- a/flow/layers/physical_shape_layer_unittests.cc +++ b/flow/layers/physical_shape_layer_unittests.cc @@ -425,9 +425,8 @@ TEST_F(PhysicalShapeLayerTest, OpacityInheritance) { layer_path, Clip::none); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; layer->Preroll(context, SkMatrix()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); } using PhysicalShapeLayerDiffTest = DiffContextTest; diff --git a/flow/layers/platform_view_layer_unittests.cc b/flow/layers/platform_view_layer_unittests.cc index 3ea1411fff542..df37b7d6bbb9c 100644 --- a/flow/layers/platform_view_layer_unittests.cc +++ b/flow/layers/platform_view_layer_unittests.cc @@ -91,9 +91,8 @@ TEST_F(PlatformViewLayerTest, OpacityInheritance) { std::make_shared(layer_offset, layer_size, view_id); PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); } } // namespace testing diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index 0ae572eedb71e..ee4edcb569579 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -40,23 +40,25 @@ void ShaderMaskLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { ContainerLayer::Preroll(context, matrix); // We always paint with a saveLayer (or a cached rendering), // so we can always apply opacity in any of those cases. - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } void ShaderMaskLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ShaderMaskLayer::Paint"); FML_DCHECK(needs_painting(context)); - AutoCachePaint cache_paint(context); - if (context.raster_cache) { - if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { + auto restore = context.state_stack.applyState( + paint_bounds(), + LayerStateStack::CALLER_CAN_APPLY_OPACITY); + + if (layer_raster_cache_item_->Draw(context, context.state_stack.sk_paint())) { return; } } auto shader_rect = SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()); - auto save = context.state_stack.saveLayer(&paint_bounds()); + auto restore = context.state_stack.saveLayer(&paint_bounds()); PaintChildren(context); if (context.builder) { diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index b6412f2497217..f8c6c9d6d9465 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -355,15 +355,14 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { // ShaderMaskLayers can always support opacity despite incompatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; shader_mask_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(shader_mask_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index afcf0d114e1c6..acef7dc8b4526 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -46,7 +46,7 @@ void TextureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(), size_.height())); context->has_texture_layer = true; - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } void TextureLayer::Paint(PaintContext& context) const { @@ -61,9 +61,9 @@ void TextureLayer::Paint(PaintContext& context) const { TRACE_EVENT_INSTANT0("flutter", "null texture"); return; } - AutoCachePaint cache_paint(context); + texture->Paint(*context.canvas, paint_bounds(), freeze_, context.gr_context, - ToSk(sampling_), cache_paint.sk_paint()); + ToSk(sampling_), context.state_stack.sk_paint()); } } // namespace flutter diff --git a/flow/layers/texture_layer_unittests.cc b/flow/layers/texture_layer_unittests.cc index 7d45d1d54e825..fbcedaacf6e65 100644 --- a/flow/layers/texture_layer_unittests.cc +++ b/flow/layers/texture_layer_unittests.cc @@ -128,10 +128,10 @@ TEST_F(TextureLayerTest, OpacityInheritance) { // The texture layer always reports opacity compatibility. PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; context->texture_registry->RegisterTexture(mock_texture); layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); // MockTexture has no actual textur to render into the // PaintContext canvas so we have no way to verify its diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index 949106c557e2d..f05a74b298812 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -56,10 +56,6 @@ void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { context->cull_rect = kGiantRect; } - // Collect inheritance information on our children in Preroll so that - // we can pass it along by default. - context->subtree_can_inherit_opacity = true; - SkRect child_paint_bounds = SkRect::MakeEmpty(); PrerollChildren(context, child_matrix, &child_paint_bounds); diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index e05334c2337eb..752140ae9e245 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -242,9 +242,9 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // TransformLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; transform1->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); auto mock2 = MockLayer::MakeOpacityCompatible(path2); @@ -252,9 +252,9 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // TransformLayer will pass through compatibility from multiple // non-overlapping compatible children - context->subtree_can_inherit_opacity = false; transform1->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); auto mock3 = MockLayer::MakeOpacityCompatible(path3); @@ -262,18 +262,17 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // TransformLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible - context->subtree_can_inherit_opacity = false; transform1->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); auto transform2 = std::make_shared(SkMatrix::Scale(2, 2)); transform2->Add(mock1); transform2->Add(mock2); // Double check first two children are compatible and non-overlapping - context->subtree_can_inherit_opacity = false; transform2->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path4 = SkPath().addRect({60, 60, 70, 70}); auto mock4 = MockLayer::Make(path4); @@ -281,9 +280,8 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible - context->subtree_can_inherit_opacity = false; transform2->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); } TEST_F(TransformLayerTest, OpacityInheritancePainting) { @@ -299,15 +297,14 @@ TEST_F(TransformLayerTest, OpacityInheritancePainting) { // TransformLayer will pass through compatibility from multiple // non-overlapping compatible children PrerollContext* context = preroll_context(); - context->subtree_can_inherit_opacity = false; transform_layer->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(transform_layer); - context->subtree_can_inherit_opacity = false; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 962bcd1c71c98..5ed104a8f9c2b 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -52,22 +52,17 @@ void MockLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { context->surface_needs_readback = true; } if (fake_opacity_compatible_) { - context->subtree_can_inherit_opacity = true; + context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } } void MockLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting(context)); - if (context.inherited_opacity < SK_Scalar1) { - SkPaint p; - p.setAlphaf(context.inherited_opacity); - context.canvas->saveLayer(fake_paint_path_.getBounds(), &p); - } + auto restore = context.state_stack.applyState( + fake_paint_path_.getBounds(), + fake_opacity_compatible_ ? LayerStateStack::CALLER_CAN_APPLY_OPACITY : 0); context.canvas->drawPath(fake_paint_path_, fake_paint_); - if (context.inherited_opacity < SK_Scalar1) { - context.canvas->restore(); - } } void MockCacheableContainerLayer::Preroll(PrerollContext* context, diff --git a/flow/testing/mock_layer_unittests.cc b/flow/testing/mock_layer_unittests.cc index 3323f76d07618..51a8b8b3b7c7f 100644 --- a/flow/testing/mock_layer_unittests.cc +++ b/flow/testing/mock_layer_unittests.cc @@ -83,14 +83,13 @@ TEST_F(MockLayerTest, OpacityInheritance) { PrerollContext* context = preroll_context(); auto mock1 = std::make_shared(path1); - context->subtree_can_inherit_opacity = false; mock1->Preroll(context, SkMatrix::I()); - EXPECT_FALSE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, 0); auto mock2 = MockLayer::MakeOpacityCompatible(path1); - context->subtree_can_inherit_opacity = false; mock2->Preroll(context, SkMatrix::I()); - EXPECT_TRUE(context->subtree_can_inherit_opacity); + EXPECT_EQ(context->rendering_state_flags, + LayerStateStack::CALLER_CAN_APPLY_OPACITY); } } // namespace testing diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index c18dca4e0dfbc..e3baf4493d64f 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -136,7 +136,6 @@ PaintContextHolder GetSamplePaintContextHolder( .raster_cache = raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, - .inherited_opacity = SK_Scalar1, }, // clang-format on srgb}; diff --git a/flow/testing/mock_raster_cache.h b/flow/testing/mock_raster_cache.h index 6dd7529cd3561..5f83b85b3b6f1 100644 --- a/flow/testing/mock_raster_cache.h +++ b/flow/testing/mock_raster_cache.h @@ -107,7 +107,6 @@ class MockRasterCache : public RasterCache { .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, - .inherited_opacity = SK_Scalar1, // clang-format on }; }; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 65829ea7cdb8a..c3a8e625f4df6 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -2396,7 +2396,6 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .raster_cache = &raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, - .inherited_opacity = SK_Scalar1, // clang-format on }; From b8b1f520bebd04ac133bcb7592107f8794c338c6 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 1 Sep 2022 22:52:43 -0700 Subject: [PATCH 14/19] formatting --- flow/layers/layer_state_stack.cc | 4 ++-- flow/layers/layer_state_stack.h | 3 +-- flow/layers/opacity_layer.cc | 8 ++++---- flow/layers/shader_mask_layer.cc | 6 +++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 83a93751d7010..f27393f1c1e13 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -102,8 +102,8 @@ AutoRestore LayerStateStack::saveWithOpacity(const SkRect* bounds, auto ret = AutoRestore(this); if (opacity < SK_Scalar1) { pushAttributes(); - state_stack_.emplace_back(std::make_unique( - bounds, opacity, checker_bounds)); + state_stack_.emplace_back( + std::make_unique(bounds, opacity, checker_bounds)); } else { state_stack_.emplace_back( std::make_unique(bounds, checker_bounds)); diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 78f597f755493..7062c29214469 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -230,8 +230,7 @@ class LayerStateStack { OpacityEntry(const SkRect* bounds, SkScalar opacity, const SkRect* checker_bounds) - : SaveLayerEntry(bounds, checker_bounds), - opacity_(opacity) {} + : SaveLayerEntry(bounds, checker_bounds), opacity_(opacity) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 6c73a97a1d177..9b9de45b16b7d 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -53,9 +53,9 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { ContainerLayer::Preroll(context, child_matrix); // We store the inheritance ability of our children for |Paint| - set_children_can_accept_opacity( - (context->rendering_state_flags & - LayerStateStack::CALLER_CAN_APPLY_OPACITY) != 0); + set_children_can_accept_opacity((context->rendering_state_flags & + LayerStateStack::CALLER_CAN_APPLY_OPACITY) != + 0); // Now we let our parent layers know that we, too, can inherit opacity // regardless of what our children are capable of @@ -84,7 +84,7 @@ void OpacityLayer::Paint(PaintContext& context) const { context.state_stack.translate(offset_.fX, offset_.fY); auto restore = context.state_stack.saveWithOpacity( - &paint_bounds(), opacity(), checkerboard_bounds(context)); + &paint_bounds(), opacity(), checkerboard_bounds(context)); PaintChildren(context); } diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index ee4edcb569579..53c57f670a3f2 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -49,10 +49,10 @@ void ShaderMaskLayer::Paint(PaintContext& context) const { if (context.raster_cache) { auto restore = context.state_stack.applyState( - paint_bounds(), - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + paint_bounds(), LayerStateStack::CALLER_CAN_APPLY_OPACITY); - if (layer_raster_cache_item_->Draw(context, context.state_stack.sk_paint())) { + if (layer_raster_cache_item_->Draw(context, + context.state_stack.sk_paint())) { return; } } From cd6633472eda1cd970ff77f98b4dae8f7941e694 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 5 Sep 2022 14:04:32 -0700 Subject: [PATCH 15/19] rename some fields and minor updates --- flow/layers/backdrop_filter_layer.cc | 2 +- flow/layers/clip_path_layer_unittests.cc | 22 +++--- flow/layers/clip_rect_layer_unittests.cc | 22 +++--- flow/layers/clip_rrect_layer_unittests.cc | 22 +++--- flow/layers/clip_shape_layer.h | 3 +- flow/layers/color_filter_layer.cc | 2 +- flow/layers/color_filter_layer_unittests.cc | 4 +- flow/layers/container_layer.cc | 12 +-- flow/layers/container_layer_unittests.cc | 10 +-- flow/layers/display_list_layer.cc | 2 +- flow/layers/display_list_layer_unittests.cc | 6 +- flow/layers/display_list_raster_cache_item.cc | 2 +- flow/layers/image_filter_layer.cc | 2 +- flow/layers/image_filter_layer_unittests.cc | 4 +- flow/layers/layer.h | 18 ++++- flow/layers/layer_state_stack.cc | 59 +++++++------- flow/layers/layer_state_stack.h | 78 ++++++++++--------- flow/layers/layer_tree_unittests.cc | 2 +- flow/layers/opacity_layer.cc | 4 +- flow/layers/opacity_layer_unittests.cc | 16 ++-- flow/layers/physical_shape_layer_unittests.cc | 2 +- flow/layers/platform_view_layer_unittests.cc | 2 +- flow/layers/shader_mask_layer.cc | 2 +- flow/layers/shader_mask_layer_unittests.cc | 2 +- flow/layers/texture_layer.cc | 2 +- flow/layers/texture_layer_unittests.cc | 2 +- flow/layers/transform_layer_unittests.cc | 12 +-- flow/testing/mock_layer.cc | 2 +- flow/testing/mock_layer_unittests.cc | 4 +- 29 files changed, 165 insertions(+), 157 deletions(-) diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 711d962179674..2530996be65be 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -47,7 +47,7 @@ void BackdropFilterLayer::Preroll(PrerollContext* context, PrerollChildren(context, matrix, &child_paint_bounds); child_paint_bounds.join(context->cull_rect); set_paint_bounds(child_paint_bounds); - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = SAVE_LAYER_RENDER_FLAGS; } void BackdropFilterLayer::Paint(PaintContext& context) const { diff --git a/flow/layers/clip_path_layer_unittests.cc b/flow/layers/clip_path_layer_unittests.cc index 581f247e1265a..94504fa55b4b8 100644 --- a/flow/layers/clip_path_layer_unittests.cc +++ b/flow/layers/clip_path_layer_unittests.cc @@ -280,7 +280,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); @@ -290,7 +290,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); @@ -300,7 +300,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // ClipRectLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); { // ClipRectLayer(aa with saveLayer) will always be compatible @@ -311,13 +311,13 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_path_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the overlapping child and test again, should still be compatible clip_path_saveLayer->Add(mock3); clip_path_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); } @@ -334,7 +334,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_path_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); clip_path_bad_child->Add(mock4); @@ -342,7 +342,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible clip_path_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); } { @@ -354,13 +354,13 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_path_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the incompatible child and test again, should still be compatible clip_path_saveLayer_bad_child->Add(mock4); clip_path_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); } } @@ -382,7 +382,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritancePainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; @@ -447,7 +447,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; diff --git a/flow/layers/clip_rect_layer_unittests.cc b/flow/layers/clip_rect_layer_unittests.cc index f11ee5ebea4e8..7578b0d60b86c 100644 --- a/flow/layers/clip_rect_layer_unittests.cc +++ b/flow/layers/clip_rect_layer_unittests.cc @@ -273,7 +273,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); @@ -283,7 +283,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); @@ -293,7 +293,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // ClipRectLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); { // ClipRectLayer(aa with saveLayer) will always be compatible @@ -304,13 +304,13 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the overlapping child and test again, should still be compatible clip_rect_saveLayer->Add(mock3); clip_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); } @@ -327,7 +327,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); clip_rect_bad_child->Add(mock4); @@ -335,7 +335,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible clip_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); } { @@ -347,13 +347,13 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the incompatible child and test again, should still be compatible clip_rect_saveLayer_bad_child->Add(mock4); clip_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); } } @@ -373,7 +373,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritancePainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; @@ -436,7 +436,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; diff --git a/flow/layers/clip_rrect_layer_unittests.cc b/flow/layers/clip_rrect_layer_unittests.cc index a8ea0df1e79bb..5e362ed5752ce 100644 --- a/flow/layers/clip_rrect_layer_unittests.cc +++ b/flow/layers/clip_rrect_layer_unittests.cc @@ -279,7 +279,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); @@ -289,7 +289,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); @@ -299,7 +299,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // ClipRectLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); { // ClipRectLayer(aa with saveLayer) will always be compatible @@ -310,13 +310,13 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_r_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the overlapping child and test again, should still be compatible clip_r_rect_saveLayer->Add(mock3); clip_r_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); } @@ -333,7 +333,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_r_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); clip_r_rect_bad_child->Add(mock4); @@ -341,7 +341,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible clip_r_rect_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); } { @@ -353,13 +353,13 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_r_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // Now add the incompatible child and test again, should still be compatible clip_r_rect_saveLayer_bad_child->Add(mock4); clip_r_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); } } @@ -380,7 +380,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritancePainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; @@ -444,7 +444,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritanceSaveLayerPainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index a6697d2b84253..999dcdcfc49d7 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -65,8 +65,7 @@ class ClipShapeLayer : public CacheableContainerLayer { // If we use a SaveLayer then we can accept opacity on behalf // of our children and apply it in the saveLayer. if (uses_save_layer) { - context->rendering_state_flags = - LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = SAVE_LAYER_RENDER_FLAGS; } context->mutators_stack.Pop(); diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index aec3cae3ff75c..ee2656215b057 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -42,7 +42,7 @@ void ColorFilterLayer::Preroll(PrerollContext* context, // We always use a saveLayer (or a cached rendering), so we // can always apply opacity in those cases. - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } void ColorFilterLayer::Paint(PaintContext& context) const { diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index 71c549ae71291..9e83b27f1fdbc 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -416,18 +416,16 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { color_filter_layer->Add(mock_layer); PrerollContext* context = preroll_context(); - context->rendering_state_flags = 0; color_filter_layer->Preroll(preroll_context(), initial_transform); // ColorFilterLayer can always inherit opacity whether or not their // children are compatible. - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(color_filter_layer); - context->rendering_state_flags = 0; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 4a906eec7ca1b..5c48a6716aef8 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -140,7 +140,7 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, bool child_has_platform_view = false; bool child_has_texture_layer = false; - int children_rendering_state_flags = + int children_renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_ANYTHING; for (auto& layer : layers_) { @@ -152,16 +152,16 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, // Initialize the "inherit opacity" flag to false and allow the layer to // override the answer during its |Preroll| - context->rendering_state_flags = 0; + context->renderable_state_flags = 0; layer->Preroll(context, child_matrix); - children_rendering_state_flags &= context->rendering_state_flags; + children_renderable_state_flags &= context->renderable_state_flags; if (safe_intersection_test(child_paint_bounds, layer->paint_bounds())) { // This will allow inheritance by a linear sequence of non-overlapping // children, but will fail with a grid or other arbitrary 2D layout. // See https://github.com/flutter/flutter/issues/93899 - children_rendering_state_flags = 0; + children_renderable_state_flags = 0; } child_paint_bounds->join(layer->paint_bounds()); @@ -173,9 +173,9 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, context->has_platform_view = child_has_platform_view; context->has_texture_layer = child_has_texture_layer; - context->rendering_state_flags = children_rendering_state_flags; + context->renderable_state_flags = children_renderable_state_flags; set_subtree_has_platform_view(child_has_platform_view); - set_children_rendering_state_flags(children_rendering_state_flags); + set_children_rendering_state_flags(children_renderable_state_flags); child_paint_bounds_ = *child_paint_bounds; } diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index 94a3f7ac11c5a..3480a62da2cda 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -463,7 +463,7 @@ TEST_F(ContainerLayerTest, OpacityInheritance) { // Single opacity compatible child makes container compatible PrerollContext* context = preroll_context(); container1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); @@ -472,7 +472,7 @@ TEST_F(ContainerLayerTest, OpacityInheritance) { // Multiple non-overlapping opacity compatible children are compatible container1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); @@ -482,7 +482,7 @@ TEST_F(ContainerLayerTest, OpacityInheritance) { // Multiple overlapping individually opacity compatible children result // in a non-compatible layer container1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); auto container2 = std::make_shared(); container2->Add(mock1); @@ -491,7 +491,7 @@ TEST_F(ContainerLayerTest, OpacityInheritance) { // Start again with 2 non-overlapping individually opacity compatible // children. container2->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path4 = SkPath().addRect({60, 60, 70, 70}); @@ -501,7 +501,7 @@ TEST_F(ContainerLayerTest, OpacityInheritance) { // Add a third child which is not opacity compatible even though it is // also non-overlapping which will result in an incompatible container. container2->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); } TEST_F(ContainerLayerTest, CollectionCacheableLayer) { SkPath child_path; diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index e13848f6f7a8b..3aa1be6ab87e5 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -99,7 +99,7 @@ void DisplayListLayer::Preroll(PrerollContext* context, AutoCache cache = AutoCache(display_list_raster_cache_item_.get(), context, matrix); if (disp_list->can_apply_group_opacity() && !context->display_list_enabled) { - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } set_paint_bounds(bounds_); } diff --git a/flow/layers/display_list_layer_unittests.cc b/flow/layers/display_list_layer_unittests.cc index 14232828a16a3..90a67bc06db94 100644 --- a/flow/layers/display_list_layer_unittests.cc +++ b/flow/layers/display_list_layer_unittests.cc @@ -110,7 +110,7 @@ TEST_F(DisplayListLayerTest, SimpleDisplayListOpacityInheritance) { auto context = preroll_context(); display_list_layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; @@ -168,7 +168,7 @@ TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) { auto context = preroll_context(); display_list_layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); int opacity_alpha = 0x7F; SkPoint opacity_offset = SkPoint::Make(10, 10); @@ -231,7 +231,7 @@ TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) { auto context = preroll_context(); display_list_layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); // Pump the DisplayListLayer until it is ready to cache its DL display_list_layer->Preroll(preroll_context(), SkMatrix()); diff --git a/flow/layers/display_list_raster_cache_item.cc b/flow/layers/display_list_raster_cache_item.cc index 6b12f9a5bc9f6..fcfc7a755ad21 100644 --- a/flow/layers/display_list_raster_cache_item.cc +++ b/flow/layers/display_list_raster_cache_item.cc @@ -113,7 +113,7 @@ void DisplayListRasterCacheItem::PrerollFinalize(PrerollContext* context, if (!visible || accesses <= raster_cache->access_threshold()) { cache_state_ = kNone; } else { - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = Layer::RASTER_CACHE_RENDER_FLAGS; cache_state_ = kCurrent; } return; diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 4c853789dc2a5..c3ecbba2c2a2b 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -55,7 +55,7 @@ void ImageFilterLayer::Preroll(PrerollContext* context, // We always paint with a saveLayer (or a cached rendering), // so we can always apply opacity in any of those cases. - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; if (!filter_) { set_paint_bounds(child_bounds); diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index e2f6e937c2f37..1dca76580a369 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -446,18 +446,16 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { image_filter_layer->Add(mock_layer); PrerollContext* context = preroll_context(); - context->rendering_state_flags = 0; image_filter_layer->Preroll(preroll_context(), initial_transform); // ImageFilterLayers can always inherit opacity whether or not their // children are compatible. - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(image_filter_layer); - context->rendering_state_flags = 0; opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 402158143385e..2ced20e7e48a7 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -72,7 +72,11 @@ struct PrerollContext { // prescence of a texture layer during Preroll. bool has_texture_layer = false; - int rendering_state_flags = 0; + // The list of flags that describe which rendering state attributes + // (such as opacity, ColorFilter, ImageFilter) a given layer can + // render itself without requiring the parent to perform a protective + // saveLayer with those attributes. + int renderable_state_flags = 0; std::vector* raster_cached_entries; @@ -118,6 +122,18 @@ struct PaintContext { // subquently used on the Rasterizer thread. class Layer { public: + // The state attribute flags that represent which attributes a + // layer can render if it plans to use a saveLayer call in its + // |Paint| method. + static constexpr int SAVE_LAYER_RENDER_FLAGS = + LayerStateStack::CALLER_CAN_APPLY_OPACITY; + + // The state attribute flags that represent which attributes a + // layer can render if it will be rendering its content/children + // from a cached representation. + static constexpr int RASTER_CACHE_RENDER_FLAGS = + LayerStateStack::CALLER_CAN_APPLY_OPACITY; + Layer(); virtual ~Layer(); diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index f27393f1c1e13..dfdcef604848d 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -10,7 +10,7 @@ namespace flutter { using AutoRestore = LayerStateStack::AutoRestore; using RenderingAttributes = LayerStateStack::RenderingAttributes; -void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { +void LayerStateStack::set_canvas_delegate(SkCanvas* canvas) { if (canvas_) { canvas_->restoreToCount(canvas_restore_count_); canvas_ = nullptr; @@ -18,13 +18,15 @@ void LayerStateStack::setCanvasDelegate(SkCanvas* canvas) { if (canvas) { canvas_restore_count_ = canvas->getSaveCount(); canvas_ = canvas; + RenderingAttributes attributes; for (auto& state : state_stack_) { - state->reapply(&outstanding_, canvas, nullptr); + state->reapply(&attributes, canvas, nullptr); } + FML_DCHECK(attributes == outstanding_); } } -void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { +void LayerStateStack::set_builder_delegate(DisplayListBuilder* builder) { if (builder_) { builder_->restoreToCount(builder_restore_count_); builder_ = nullptr; @@ -32,9 +34,11 @@ void LayerStateStack::setBuilderDelegate(DisplayListBuilder* builder) { if (builder) { builder_restore_count_ = builder->getSaveCount(); builder_ = builder; + RenderingAttributes attributes; for (auto& state : state_stack_) { - state->reapply(&outstanding_, nullptr, builder); + state->reapply(&attributes, nullptr, builder); } + FML_DCHECK(attributes == outstanding_); } } @@ -73,7 +77,7 @@ const SkPaint* LayerStateStack::sk_paint() { } const DlPaint* LayerStateStack::dl_paint() { - if (outstanding_.opacity < SK_Scalar1) { + if (needsResolve(outstanding_, 0)) { temp_dl_paint_.setOpacity(outstanding_.opacity); return &temp_dl_paint_; } @@ -87,61 +91,53 @@ AutoRestore LayerStateStack::save() { return ret; } -AutoRestore LayerStateStack::saveLayer(const SkRect* bounds, - const SkRect* checker_bounds) { +AutoRestore LayerStateStack::saveLayer(const SkRect* bounds) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( - std::make_unique(bounds, checker_bounds)); + std::make_unique(bounds)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -AutoRestore LayerStateStack::saveWithOpacity(const SkRect* bounds, - SkScalar opacity, - const SkRect* checker_bounds) { +AutoRestore LayerStateStack::pushOpacity(const SkRect* bounds, + SkScalar opacity) { auto ret = AutoRestore(this); if (opacity < SK_Scalar1) { pushAttributes(); state_stack_.emplace_back( - std::make_unique(bounds, opacity, checker_bounds)); - } else { - state_stack_.emplace_back( - std::make_unique(bounds, checker_bounds)); + std::make_unique(bounds, opacity)); + state_stack_.back()->apply(&outstanding_, canvas_, builder_); } - state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -AutoRestore LayerStateStack::saveWithImageFilter( +AutoRestore LayerStateStack::pushImageFilter( const SkRect* bounds, - const std::shared_ptr filter, - const SkRect* checker_bounds) { + const std::shared_ptr filter) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( - std::make_unique(bounds, filter, checker_bounds)); + std::make_unique(bounds, filter)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -AutoRestore LayerStateStack::saveWithColorFilter( +AutoRestore LayerStateStack::pushColorFilter( const SkRect* bounds, - const std::shared_ptr filter, - const SkRect* checker_bounds) { + const std::shared_ptr filter) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back( - std::make_unique(bounds, filter, checker_bounds)); + std::make_unique(bounds, filter)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -AutoRestore LayerStateStack::saveWithBackdropFilter( +AutoRestore LayerStateStack::pushBackdropFilter( const SkRect* bounds, const std::shared_ptr filter, - DlBlendMode blend_mode, - const SkRect* checker_bounds) { + DlBlendMode blend_mode) { auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back(std::make_unique( - bounds, filter, blend_mode, checker_bounds)); + bounds, filter, blend_mode)); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } @@ -231,13 +227,12 @@ void LayerStateStack::SaveLayerEntry::apply(RenderingAttributes* attributes, void LayerStateStack::SaveLayerEntry::do_checkerboard( SkCanvas* canvas, DisplayListBuilder* builder) const { - const SkRect* bounds = checkerboard_bounds(); - if (bounds) { + if (do_checkerboard_ && bounds_.has_value()) { if (canvas) { - SkDrawCheckerboard(canvas, *bounds); + SkDrawCheckerboard(canvas, bounds_.value()); } if (builder) { - DlDrawCheckerboard(builder, *bounds); + DlDrawCheckerboard(builder, bounds_.value()); } } } diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 7062c29214469..669b0bd0aef73 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -14,13 +14,21 @@ class LayerStateStack { public: LayerStateStack() = default; - void setCanvasDelegate(SkCanvas* canvas); - void setBuilderDelegate(DisplayListBuilder* builder); - void setBuilderDelegate(sk_sp builder) { - setBuilderDelegate(builder.get()); + bool checkerboard_save_layers() { return do_checkerboard_; } + void set_checkerboard_save_layers(bool checkerboard) { + do_checkerboard_ = checkerboard; } - void setBuilderDelegate(DisplayListCanvasRecorder& recorder) { - setBuilderDelegate(recorder.builder().get()); + + SkCanvas* canvas_delegate() { return canvas_; } + void set_canvas_delegate(SkCanvas* canvas); + void set_builder_delegate(sk_sp builder) { + set_builder_delegate(builder.get()); + } + + DisplayListBuilder* builder_delegate() { return builder_; } + void set_builder_delegate(DisplayListBuilder* builder); + void set_builder_delegate(DisplayListCanvasRecorder& recorder) { + set_builder_delegate(recorder.builder().get()); } class AutoRestore { @@ -39,8 +47,11 @@ class LayerStateStack { static constexpr int CALLER_CAN_APPLY_ANYTHING = 0x1; struct RenderingAttributes { - SkRect content_bounds; SkScalar opacity = SK_Scalar1; + + bool operator==(const RenderingAttributes& other) { + return opacity == other.opacity; + } }; // Apply the outstanding state via saveLayer if necessary, @@ -81,37 +92,31 @@ class LayerStateStack { // be applied at the next matching restore. A saveLayer is // always executed by this method even if there are no // outstanding attributes. - [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds, - const SkRect* checker_bounds = nullptr); + [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds); // Records the opacity for application at the next call to // saveLayer or applyState. A saveLayer may be executed at // this time if the opacity cannot be batched with other // outstanding attributes. - [[nodiscard]] AutoRestore saveWithOpacity( - const SkRect* bounds, - SkScalar opacity, - const SkRect* checker_bounds = nullptr); + [[nodiscard]] AutoRestore pushOpacity(const SkRect* bounds, SkScalar opacity); // Records the image filter for application at the next call to // saveLayer or applyState. A saveLayer may be executed at // this time if the image filter cannot be batched with other // outstanding attributes. // (Currently only opacity is recorded for batching) - [[nodiscard]] AutoRestore saveWithImageFilter( + [[nodiscard]] AutoRestore pushImageFilter( const SkRect* bounds, - const std::shared_ptr filter, - const SkRect* checker_bounds = nullptr); + const std::shared_ptr filter); // Records the color filter for application at the next call to // saveLayer or applyState. A saveLayer may be executed at // this time if the color filter cannot be batched with other // outstanding attributes. // (Currently only opacity is recorded for batching) - [[nodiscard]] AutoRestore saveWithColorFilter( + [[nodiscard]] AutoRestore pushColorFilter( const SkRect* bounds, - const std::shared_ptr filter, - const SkRect* checker_bounds = nullptr); + const std::shared_ptr filter); // Saves the state stack and immediately executes a saveLayer // with the indicated backdrop filter and any outstanding @@ -121,11 +126,10 @@ class LayerStateStack { // builder installed at the time that this call is made, and // subsequent canvas or builder objects that are made delegates // will only see a saveLayer with the indicated blend_mode. - [[nodiscard]] AutoRestore saveWithBackdropFilter( + [[nodiscard]] AutoRestore pushBackdropFilter( const SkRect* bounds, const std::shared_ptr filter, - DlBlendMode blend_mode, - const SkRect* checker_bounds = nullptr); + DlBlendMode blend_mode); void translate(SkScalar tx, SkScalar ty); void transform(const SkM44& matrix); @@ -203,9 +207,8 @@ class LayerStateStack { class SaveLayerEntry : public SaveEntry { public: - SaveLayerEntry(const SkRect* bounds, const SkRect* checker_bounds) - : bounds_(OptionalBounds(bounds)), - checkerboard_(OptionalBounds(checker_bounds)) {} + SaveLayerEntry(const SkRect* bounds, bool checkerboard) + : bounds_(OptionalBounds(bounds)), do_checkerboard_(checkerboard) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, @@ -213,24 +216,20 @@ class LayerStateStack { protected: const std::optional bounds_; - const std::optional checkerboard_; + const bool do_checkerboard_; void do_checkerboard(SkCanvas* canvas, DisplayListBuilder* builder) const override; const SkRect* save_bounds() const { return BoundsPtr(bounds_); } - - const SkRect* checkerboard_bounds() const { - return BoundsPtr(checkerboard_); - } }; class OpacityEntry : public SaveLayerEntry { public: OpacityEntry(const SkRect* bounds, SkScalar opacity, - const SkRect* checker_bounds) - : SaveLayerEntry(bounds, checker_bounds), opacity_(opacity) {} + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), opacity_(opacity) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, @@ -244,8 +243,8 @@ class LayerStateStack { public: ImageFilterEntry(const SkRect* bounds, const std::shared_ptr filter, - const SkRect* checker_bounds) - : SaveLayerEntry(bounds, checker_bounds), filter_(filter) {} + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} ~ImageFilterEntry() override = default; void apply(RenderingAttributes* attributes, @@ -260,8 +259,8 @@ class LayerStateStack { public: ColorFilterEntry(const SkRect* bounds, const std::shared_ptr filter, - const SkRect* checker_bounds) - : SaveLayerEntry(bounds, checker_bounds), filter_(filter) {} + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} ~ColorFilterEntry() override = default; void apply(RenderingAttributes* attributes, @@ -277,8 +276,8 @@ class LayerStateStack { BackdropFilterEntry(const SkRect* bounds, const std::shared_ptr filter, DlBlendMode blend_mode, - const SkRect* checker_bounds) - : SaveLayerEntry(bounds, checker_bounds), + bool checkerboard) + : SaveLayerEntry(bounds, checkerboard), filter_(filter), blend_mode_(blend_mode) {} ~BackdropFilterEntry() override = default; @@ -390,6 +389,9 @@ class LayerStateStack { int builder_restore_count_ = 0.0; RenderingAttributes outstanding_; + bool do_checkerboard_; + friend class SaveLayerEntry; + SkPaint temp_sk_paint_; DlPaint temp_dl_paint_; }; diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index 2c80ac2fba73d..80166ddbd3f10 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -219,7 +219,7 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { EXPECT_EQ(context.has_platform_view, false); EXPECT_EQ(context.has_texture_layer, false); - EXPECT_EQ(context.rendering_state_flags, 0); + EXPECT_EQ(context.renderable_state_flags, 0); EXPECT_EQ(context.raster_cached_entries, nullptr); EXPECT_EQ(context.display_list_enabled, false); diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 9b9de45b16b7d..7077157507798 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -53,13 +53,13 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { ContainerLayer::Preroll(context, child_matrix); // We store the inheritance ability of our children for |Paint| - set_children_can_accept_opacity((context->rendering_state_flags & + set_children_can_accept_opacity((context->renderable_state_flags & LayerStateStack::CALLER_CAN_APPLY_OPACITY) != 0); // Now we let our parent layers know that we, too, can inherit opacity // regardless of what our children are capable of - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; context->mutators_stack.Pop(); context->mutators_stack.Pop(); diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index 18e9263e1d93f..269fd83965708 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -193,7 +193,7 @@ TEST_F(OpacityLayerTest, ShouldNotCacheChildren) { opacityLayer->Preroll(preroll_context(), SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); LayerTree::TryToRasterCache(cacheable_items(), &paint_context()); @@ -467,7 +467,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceCompatibleChild) { PrerollContext* context = preroll_context(); opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); } @@ -480,7 +480,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceIncompatibleChild) { PrerollContext* context = preroll_context(); opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_FALSE(opacityLayer->children_can_accept_opacity()); } @@ -495,7 +495,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughContainer) { PrerollContext* context = preroll_context(); opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // By default a container layer will not pass opacity through to // its children - specific subclasses will have to enable this @@ -514,7 +514,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughTransform) { PrerollContext* context = preroll_context(); opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); } @@ -530,7 +530,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughImageFilter) { PrerollContext* context = preroll_context(); opacityLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); } @@ -547,7 +547,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithCompatibleChild) { PrerollContext* context = preroll_context(); opacityLayer1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer1->children_can_accept_opacity()); EXPECT_TRUE(opacityLayer2->children_can_accept_opacity()); @@ -598,7 +598,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithIncompatibleChild) { PrerollContext* context = preroll_context(); opacityLayer1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); EXPECT_TRUE(opacityLayer1->children_can_accept_opacity()); EXPECT_FALSE(opacityLayer2->children_can_accept_opacity()); diff --git a/flow/layers/physical_shape_layer_unittests.cc b/flow/layers/physical_shape_layer_unittests.cc index f1db0375d1ade..e097e0c50f4a8 100644 --- a/flow/layers/physical_shape_layer_unittests.cc +++ b/flow/layers/physical_shape_layer_unittests.cc @@ -426,7 +426,7 @@ TEST_F(PhysicalShapeLayerTest, OpacityInheritance) { PrerollContext* context = preroll_context(); layer->Preroll(context, SkMatrix()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); } using PhysicalShapeLayerDiffTest = DiffContextTest; diff --git a/flow/layers/platform_view_layer_unittests.cc b/flow/layers/platform_view_layer_unittests.cc index df37b7d6bbb9c..f942ce62bd511 100644 --- a/flow/layers/platform_view_layer_unittests.cc +++ b/flow/layers/platform_view_layer_unittests.cc @@ -92,7 +92,7 @@ TEST_F(PlatformViewLayerTest, OpacityInheritance) { PrerollContext* context = preroll_context(); layer->Preroll(preroll_context(), SkMatrix()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); } } // namespace testing diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index 53c57f670a3f2..1121744cc8677 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -40,7 +40,7 @@ void ShaderMaskLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { ContainerLayer::Preroll(context, matrix); // We always paint with a saveLayer (or a cached rendering), // so we can always apply opacity in any of those cases. - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = SAVE_LAYER_RENDER_FLAGS; } void ShaderMaskLayer::Paint(PaintContext& context) const { diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index f8c6c9d6d9465..e9ab4b3f2a5df 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -356,7 +356,7 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { // ShaderMaskLayers can always support opacity despite incompatible children PrerollContext* context = preroll_context(); shader_mask_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index acef7dc8b4526..fdbb73fc9193c 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -46,7 +46,7 @@ void TextureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(), size_.height())); context->has_texture_layer = true; - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } void TextureLayer::Paint(PaintContext& context) const { diff --git a/flow/layers/texture_layer_unittests.cc b/flow/layers/texture_layer_unittests.cc index fbcedaacf6e65..f71322f3d7299 100644 --- a/flow/layers/texture_layer_unittests.cc +++ b/flow/layers/texture_layer_unittests.cc @@ -130,7 +130,7 @@ TEST_F(TextureLayerTest, OpacityInheritance) { PrerollContext* context = preroll_context(); context->texture_registry->RegisterTexture(mock_texture); layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); // MockTexture has no actual textur to render into the diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index 752140ae9e245..f578c448a75c8 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -243,7 +243,7 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // TransformLayer will pass through compatibility from a compatible child PrerollContext* context = preroll_context(); transform1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path2 = SkPath().addRect({40, 40, 50, 50}); @@ -253,7 +253,7 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // TransformLayer will pass through compatibility from multiple // non-overlapping compatible children transform1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path3 = SkPath().addRect({20, 20, 40, 40}); @@ -263,7 +263,7 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // TransformLayer will not pass through compatibility from multiple // overlapping children even if they are individually compatible transform1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); auto transform2 = std::make_shared(SkMatrix::Scale(2, 2)); transform2->Add(mock1); @@ -271,7 +271,7 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping transform2->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); auto path4 = SkPath().addRect({60, 60, 70, 70}); @@ -281,7 +281,7 @@ TEST_F(TransformLayerTest, OpacityInheritance) { // The third child is non-overlapping, but not compatible so the // TransformLayer should end up incompatible transform2->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); } TEST_F(TransformLayerTest, OpacityInheritancePainting) { @@ -298,7 +298,7 @@ TEST_F(TransformLayerTest, OpacityInheritancePainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); transform_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 5ed104a8f9c2b..25041688cf4db 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -52,7 +52,7 @@ void MockLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { context->surface_needs_readback = true; } if (fake_opacity_compatible_) { - context->rendering_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } } diff --git a/flow/testing/mock_layer_unittests.cc b/flow/testing/mock_layer_unittests.cc index 51a8b8b3b7c7f..49b38c4630607 100644 --- a/flow/testing/mock_layer_unittests.cc +++ b/flow/testing/mock_layer_unittests.cc @@ -84,11 +84,11 @@ TEST_F(MockLayerTest, OpacityInheritance) { auto mock1 = std::make_shared(path1); mock1->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, 0); + EXPECT_EQ(context->renderable_state_flags, 0); auto mock2 = MockLayer::MakeOpacityCompatible(path1); mock2->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->rendering_state_flags, + EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); } From 98d76b9bb4544c3b383739f2dd5c1bcc913035f2 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 6 Sep 2022 00:55:50 -0700 Subject: [PATCH 16/19] switch to new state_stack.save() -> MutatorContext style API --- flow/layers/backdrop_filter_layer.cc | 5 +- flow/layers/clip_path_layer.cc | 5 +- flow/layers/clip_path_layer.h | 3 +- flow/layers/clip_path_layer_unittests.cc | 3 +- flow/layers/clip_rect_layer.cc | 5 +- flow/layers/clip_rect_layer.h | 3 +- flow/layers/clip_rect_layer_unittests.cc | 3 +- flow/layers/clip_rrect_layer.cc | 5 +- flow/layers/clip_rrect_layer.h | 3 +- flow/layers/clip_rrect_layer_unittests.cc | 3 +- flow/layers/clip_shape_layer.h | 13 +- flow/layers/color_filter_layer.cc | 4 +- flow/layers/display_list_layer.cc | 9 +- flow/layers/image_filter_layer.cc | 5 +- flow/layers/layer.h | 4 +- flow/layers/layer_state_stack.cc | 386 +++++++++++------- flow/layers/layer_state_stack.h | 258 +++++++----- flow/layers/layer_tree.cc | 8 +- flow/layers/opacity_layer.cc | 21 +- .../performance_overlay_layer_unittests.cc | 2 +- flow/layers/physical_shape_layer.cc | 11 +- flow/layers/platform_view_layer.cc | 4 +- flow/layers/shader_mask_layer.cc | 7 +- flow/layers/texture_layer.cc | 3 +- flow/layers/transform_layer.cc | 4 +- flow/testing/layer_test.h | 4 +- 26 files changed, 473 insertions(+), 308 deletions(-) diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 2530996be65be..036c14b66328e 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -54,8 +54,9 @@ void BackdropFilterLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "BackdropFilterLayer::Paint"); FML_DCHECK(needs_painting(context)); - auto save = context.state_stack.saveWithBackdropFilter(&paint_bounds(), - filter_, blend_mode_); + auto mutator = context.state_stack.save(); + mutator.applyBackdropFilter(paint_bounds(), filter_, blend_mode_); + PaintChildren(context); } diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index e79bbaf064def..ffe22de7b5470 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -28,8 +28,9 @@ void ClipPathLayer::OnMutatorsStackPushClipShape( mutators_stack.PushClipPath(clip_shape()); } -void ClipPathLayer::OnStackClipShape(LayerStateStack& stack) const { - stack.clipPath(clip_shape(), clip_behavior() != Clip::hardEdge); +void ClipPathLayer::OnStackClipShape( + LayerStateStack::MutatorContext& mutator) const { + mutator.clipPath(clip_shape(), clip_behavior() != Clip::hardEdge); } } // namespace flutter diff --git a/flow/layers/clip_path_layer.h b/flow/layers/clip_path_layer.h index 8b79ca43b31b4..bc691331fe91d 100644 --- a/flow/layers/clip_path_layer.h +++ b/flow/layers/clip_path_layer.h @@ -23,7 +23,8 @@ class ClipPathLayer : public ClipShapeLayer { void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override; - void OnStackClipShape(LayerStateStack& stack) const override; + void OnStackClipShape( + LayerStateStack::MutatorContext& mutator) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(ClipPathLayer); diff --git a/flow/layers/clip_path_layer_unittests.cc b/flow/layers/clip_path_layer_unittests.cc index 94504fa55b4b8..e0ce2283483c2 100644 --- a/flow/layers/clip_path_layer_unittests.cc +++ b/flow/layers/clip_path_layer_unittests.cc @@ -77,7 +77,8 @@ TEST_F(ClipPathLayerTest, PaintingCulledLayerDies) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)})); - paint_context().state_stack.clipRect(distant_bounds, false); + auto mutator = paint_context().state_stack.save(); + mutator.clipRect(distant_bounds, false); EXPECT_FALSE(mock_layer->needs_painting(paint_context())); EXPECT_FALSE(layer->needs_painting(paint_context())); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index a0e2af7431d80..5d29cc403f72d 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -28,8 +28,9 @@ void ClipRectLayer::OnMutatorsStackPushClipShape( mutators_stack.PushClipRect(clip_shape()); } -void ClipRectLayer::OnStackClipShape(LayerStateStack& stack) const { - stack.clipRect(clip_shape(), clip_behavior() != Clip::hardEdge); +void ClipRectLayer::OnStackClipShape( + LayerStateStack::MutatorContext& mutator) const { + mutator.clipRect(clip_shape(), clip_behavior() != Clip::hardEdge); } } // namespace flutter diff --git a/flow/layers/clip_rect_layer.h b/flow/layers/clip_rect_layer.h index 1e91487653064..57d76ae328e19 100644 --- a/flow/layers/clip_rect_layer.h +++ b/flow/layers/clip_rect_layer.h @@ -22,7 +22,8 @@ class ClipRectLayer : public ClipShapeLayer { void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override; - void OnStackClipShape(LayerStateStack& stack) const override; + void OnStackClipShape( + LayerStateStack::MutatorContext& mutator) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(ClipRectLayer); diff --git a/flow/layers/clip_rect_layer_unittests.cc b/flow/layers/clip_rect_layer_unittests.cc index 7578b0d60b86c..3d711b3c7ab5f 100644 --- a/flow/layers/clip_rect_layer_unittests.cc +++ b/flow/layers/clip_rect_layer_unittests.cc @@ -73,7 +73,8 @@ TEST_F(ClipRectLayerTest, PaintingCulledLayerDies) { EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_bounds)})); - paint_context().state_stack.clipRect(distant_bounds, false); + auto mutator = paint_context().state_stack.save(); + mutator.clipRect(distant_bounds, false); EXPECT_FALSE(mock_layer->needs_painting(paint_context())); EXPECT_FALSE(layer->needs_painting(paint_context())); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 05ab87a5047bd..9dbbe71ba90a2 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -28,8 +28,9 @@ void ClipRRectLayer::OnMutatorsStackPushClipShape( mutators_stack.PushClipRRect(clip_shape()); } -void ClipRRectLayer::OnStackClipShape(LayerStateStack& stack) const { - stack.clipRRect(clip_shape(), clip_behavior() != Clip::hardEdge); +void ClipRRectLayer::OnStackClipShape( + LayerStateStack::MutatorContext& mutator) const { + mutator.clipRRect(clip_shape(), clip_behavior() != Clip::hardEdge); } } // namespace flutter diff --git a/flow/layers/clip_rrect_layer.h b/flow/layers/clip_rrect_layer.h index c2b30f4933f37..17d4f29e0950c 100644 --- a/flow/layers/clip_rrect_layer.h +++ b/flow/layers/clip_rrect_layer.h @@ -22,7 +22,8 @@ class ClipRRectLayer : public ClipShapeLayer { void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) override; - void OnStackClipShape(LayerStateStack& stack) const override; + void OnStackClipShape( + LayerStateStack::MutatorContext& mutator) const override; private: FML_DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer); diff --git a/flow/layers/clip_rrect_layer_unittests.cc b/flow/layers/clip_rrect_layer_unittests.cc index 5e362ed5752ce..9575c66903b03 100644 --- a/flow/layers/clip_rrect_layer_unittests.cc +++ b/flow/layers/clip_rrect_layer_unittests.cc @@ -77,7 +77,8 @@ TEST_F(ClipRRectLayerTest, PaintingCulledLayerDies) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)})); - paint_context().state_stack.clipRect(distant_bounds, false); + auto mutator = paint_context().state_stack.save(); + mutator.clipRect(distant_bounds, false); EXPECT_FALSE(mock_layer->needs_painting(paint_context())); EXPECT_FALSE(layer->needs_painting(paint_context())); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index 999dcdcfc49d7..58d55db2599a3 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -75,8 +75,8 @@ class ClipShapeLayer : public CacheableContainerLayer { void Paint(PaintContext& context) const override { FML_DCHECK(needs_painting(context)); - auto restore = context.state_stack.save(); - OnStackClipShape(context.state_stack); + auto mutator = context.state_stack.save(); + OnStackClipShape(mutator); if (!UsesSaveLayer()) { PaintChildren(context); @@ -87,16 +87,16 @@ class ClipShapeLayer : public CacheableContainerLayer { auto restore_apply = context.state_stack.applyState( paint_bounds(), LayerStateStack::CALLER_CAN_APPLY_OPACITY); + SkPaint paint; if (layer_raster_cache_item_->Draw(context, - context.state_stack.sk_paint())) { + context.state_stack.fill(paint))) { return; } } // saveWithOpacity optimizes the case where opacity >= 1.0 // to a simple saveLayer - auto save_layer = context.state_stack.saveLayer( - &child_paint_bounds(), checkerboard_bounds(context)); + mutator.saveLayer(child_paint_bounds()); PaintChildren(context); } @@ -107,7 +107,8 @@ class ClipShapeLayer : public CacheableContainerLayer { protected: virtual const SkRect& clip_shape_bounds() const = 0; virtual void OnMutatorsStackPushClipShape(MutatorsStack& mutators_stack) = 0; - virtual void OnStackClipShape(LayerStateStack& stack) const = 0; + virtual void OnStackClipShape( + LayerStateStack::MutatorContext& mutator) const = 0; virtual ~ClipShapeLayer() = default; const ClipShape& clip_shape() const { return clip_shape_; } diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index ee2656215b057..fad9d6ff484de 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -61,7 +61,9 @@ void ColorFilterLayer::Paint(PaintContext& context) const { // AutoCachePaint cache_paint(context); // cache_paint.setColorFilter(filter_.get()); - auto save = context.state_stack.saveWithColorFilter(&paint_bounds(), filter_); + auto mutator = context.state_stack.save(); + mutator.applyColorFilter(paint_bounds(), filter_); + PaintChildren(context); } diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 3aa1be6ab87e5..04cdbf0c0934a 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -109,12 +109,13 @@ void DisplayListLayer::Paint(PaintContext& context) const { FML_DCHECK(display_list_.skia_object()); FML_DCHECK(needs_painting(context)); - auto save = context.state_stack.save(); - context.state_stack.translate(offset_.x(), offset_.y()); + auto mutator = context.state_stack.save(); + mutator.translate(offset_.x(), offset_.y()); if (context.raster_cache && display_list_raster_cache_item_) { - if (display_list_raster_cache_item_->Draw(context, - context.state_stack.sk_paint())) { + SkPaint paint; + if (display_list_raster_cache_item_->Draw( + context, context.state_stack.fill(paint))) { TRACE_EVENT_INSTANT0("flutter", "raster cache hit"); return; } diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index c3ecbba2c2a2b..aa67137db12ad 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -94,8 +94,9 @@ void ImageFilterLayer::Paint(PaintContext& context) const { // } // } - auto save = - context.state_stack.saveWithImageFilter(&child_paint_bounds(), filter_); + auto mutator = context.state_stack.save(); + mutator.applyImageFilter(child_paint_bounds(), filter_); + PaintChildren(context); } diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 2ced20e7e48a7..7843811275c6a 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -126,7 +126,9 @@ class Layer { // layer can render if it plans to use a saveLayer call in its // |Paint| method. static constexpr int SAVE_LAYER_RENDER_FLAGS = - LayerStateStack::CALLER_CAN_APPLY_OPACITY; + LayerStateStack::CALLER_CAN_APPLY_OPACITY | + LayerStateStack::CALLER_CAN_APPLY_COLOR_FILTER | + LayerStateStack::CALLER_CAN_APPLY_IMAGE_FILTER; // The state attribute flags that represent which attributes a // layer can render if it will be rendering its content/children diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index dfdcef604848d..5182e977334c9 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -8,7 +8,7 @@ namespace flutter { using AutoRestore = LayerStateStack::AutoRestore; -using RenderingAttributes = LayerStateStack::RenderingAttributes; +using MutatorContext = LayerStateStack::MutatorContext; void LayerStateStack::set_canvas_delegate(SkCanvas* canvas) { if (canvas_) { @@ -18,11 +18,7 @@ void LayerStateStack::set_canvas_delegate(SkCanvas* canvas) { if (canvas) { canvas_restore_count_ = canvas->getSaveCount(); canvas_ = canvas; - RenderingAttributes attributes; - for (auto& state : state_stack_) { - state->reapply(&attributes, canvas, nullptr); - } - FML_DCHECK(attributes == outstanding_); + reapply_all(canvas, nullptr); } } @@ -34,153 +30,274 @@ void LayerStateStack::set_builder_delegate(DisplayListBuilder* builder) { if (builder) { builder_restore_count_ = builder->getSaveCount(); builder_ = builder; - RenderingAttributes attributes; - for (auto& state : state_stack_) { - state->reapply(&attributes, nullptr, builder); - } - FML_DCHECK(attributes == outstanding_); + reapply_all(nullptr, builder); + } +} + +void LayerStateStack::reapply_all(SkCanvas* canvas, + DisplayListBuilder* builder) { + // We use a local RenderingAttributes instance so that it can track the + // necessary state changes independently as they occur in the stack. + // Reusing |outstanding_| would wreak havoc on the current state of + // the stack. When we are finished, though, the local attributes + // contents should match the current outstanding_ values; + RenderingAttributes attributes; + for (auto& state : state_stack_) { + state->reapply(&attributes, canvas, builder); } + FML_DCHECK(attributes == outstanding_); } AutoRestore::AutoRestore(LayerStateStack* stack) - : stack_(stack), stack_restore_count_(stack->getStackCount()) {} + : layer_state_stack_(stack), + stack_restore_count_(stack->stack_count()), + attributes_pushed_(stack->outstanding_.pushed) {} AutoRestore::~AutoRestore() { - stack_->restoreToCount(stack_restore_count_); -} - -static bool needsResolve(RenderingAttributes& outstanding, int flags) { - if (outstanding.opacity < SK_Scalar1 && - (flags & LayerStateStack::CALLER_CAN_APPLY_OPACITY)) { - return true; - } - // Check IF and CF eventually... - return false; + layer_state_stack_->restore_to_count(stack_restore_count_); + layer_state_stack_->outstanding_.pushed = attributes_pushed_; } AutoRestore LayerStateStack::applyState(const SkRect& bounds, int can_apply_flags) { - auto ret = LayerStateStack::AutoRestore(this); - if (needsResolve(outstanding_, can_apply_flags)) { - resolve(bounds); + auto ret = AutoRestore(this); + if (needs_save_layer(can_apply_flags)) { + save_layer(bounds); } return ret; } -const SkPaint* LayerStateStack::sk_paint() { - if (needsResolve(outstanding_, 0)) { - temp_sk_paint_.setAlphaf(outstanding_.opacity); - // set IF and CF eventually... - return &temp_sk_paint_; +SkPaint* LayerStateStack::RenderingAttributes::fill(SkPaint& paint) { + SkPaint* ret = nullptr; + if (opacity < SK_Scalar1) { + paint.setAlphaf(std::max(opacity, 0.0f)); + ret = &paint; + } else { + paint.setAlphaf(SK_Scalar1); + } + if (color_filter) { + paint.setColorFilter(color_filter->skia_object()); + ret = &paint; + } else { + paint.setColorFilter(nullptr); + } + if (image_filter) { + paint.setImageFilter(image_filter->skia_object()); + ret = &paint; + } else { + paint.setImageFilter(nullptr); } - return nullptr; + return ret; } -const DlPaint* LayerStateStack::dl_paint() { - if (needsResolve(outstanding_, 0)) { - temp_dl_paint_.setOpacity(outstanding_.opacity); - return &temp_dl_paint_; +DlPaint* LayerStateStack::RenderingAttributes::fill(DlPaint& paint) { + DlPaint* ret = nullptr; + if (opacity < SK_Scalar1) { + paint.setOpacity(std::max(opacity, 0.0f)); + ret = &paint; + } else { + paint.setOpacity(SK_Scalar1); + } + paint.setColorFilter(color_filter); + if (color_filter) { + ret = &paint; + } + paint.setImageFilter(image_filter); + if (image_filter) { + ret = &paint; } - return nullptr; + return ret; } -AutoRestore LayerStateStack::save() { - auto ret = LayerStateStack::AutoRestore(this); +MutatorContext LayerStateStack::save() { + auto ret = MutatorContext(this); state_stack_.emplace_back(std::make_unique()); state_stack_.back()->apply(&outstanding_, canvas_, builder_); return ret; } -AutoRestore LayerStateStack::saveLayer(const SkRect* bounds) { - auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back( - std::make_unique(bounds)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); - return ret; +void MutatorContext::saveLayer(const SkRect& bounds) { + layer_state_stack_->save_layer(bounds); } -AutoRestore LayerStateStack::pushOpacity(const SkRect* bounds, - SkScalar opacity) { - auto ret = AutoRestore(this); +void MutatorContext::applyOpacity(const SkRect& bounds, SkScalar opacity) { if (opacity < SK_Scalar1) { - pushAttributes(); - state_stack_.emplace_back( - std::make_unique(bounds, opacity)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); + layer_state_stack_->push_attributes(); + layer_state_stack_->maybe_save_layer(bounds, opacity); + layer_state_stack_->push_opacity(opacity); } - return ret; } -AutoRestore LayerStateStack::pushImageFilter( - const SkRect* bounds, +void MutatorContext::applyImageFilter( + const SkRect& bounds, const std::shared_ptr filter) { - auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back( - std::make_unique(bounds, filter)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); - return ret; + layer_state_stack_->push_attributes(); + layer_state_stack_->maybe_save_layer(bounds, filter); + layer_state_stack_->push_image_filter(filter); } -AutoRestore LayerStateStack::pushColorFilter( - const SkRect* bounds, +void MutatorContext::applyColorFilter( + const SkRect& bounds, const std::shared_ptr filter) { - auto ret = LayerStateStack::AutoRestore(this); - state_stack_.emplace_back( - std::make_unique(bounds, filter)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); - return ret; + layer_state_stack_->push_attributes(); + layer_state_stack_->maybe_save_layer(bounds, filter); + layer_state_stack_->push_color_filter(filter); +} + +void MutatorContext::applyBackdropFilter( + const SkRect& bounds, + const std::shared_ptr filter, + DlBlendMode blend_mode) { + layer_state_stack_->push_backdrop(bounds, filter, blend_mode); } -AutoRestore LayerStateStack::pushBackdropFilter( - const SkRect* bounds, +void MutatorContext::translate(SkScalar tx, SkScalar ty) { + layer_state_stack_->push_translate(tx, ty); +} + +void MutatorContext::transform(const SkMatrix& matrix) { + layer_state_stack_->push_transform(matrix); +} + +void MutatorContext::transform(const SkM44& m44) { + layer_state_stack_->push_transform(m44); +} + +void MutatorContext::clipRect(const SkRect& rect, bool is_aa) { + layer_state_stack_->push_clip_rect(rect, is_aa); +} + +void MutatorContext::clipRRect(const SkRRect& rrect, bool is_aa) { + layer_state_stack_->push_clip_rrect(rrect, is_aa); +} + +void MutatorContext::clipPath(const SkPath& path, bool is_aa) { + layer_state_stack_->push_clip_path(path, is_aa); +} + +void LayerStateStack::restore_to_count(size_t restore_count) { + while (state_stack_.size() > restore_count) { + state_stack_.back()->restore(&outstanding_, canvas_, builder_); + state_stack_.pop_back(); + } +} + +void LayerStateStack::push_attributes() { + if (!outstanding_.pushed) { + state_stack_.emplace_back(std::make_unique(outstanding_)); + outstanding_.pushed = true; + } +} + +void LayerStateStack::push_opacity(SkScalar opacity) { + state_stack_.emplace_back(std::make_unique(opacity)); + apply_last_entry(); +} + +void LayerStateStack::push_color_filter( + const std::shared_ptr filter) { + state_stack_.emplace_back(std::make_unique(filter)); + apply_last_entry(); +} + +void LayerStateStack::push_image_filter( + const std::shared_ptr filter) { + state_stack_.emplace_back(std::make_unique(filter)); + apply_last_entry(); +} + +void LayerStateStack::push_backdrop( + const SkRect& bounds, const std::shared_ptr filter, DlBlendMode blend_mode) { - auto ret = LayerStateStack::AutoRestore(this); state_stack_.emplace_back(std::make_unique( - bounds, filter, blend_mode)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); - return ret; + bounds, filter, blend_mode, do_checkerboard_)); + apply_last_entry(); } -void LayerStateStack::translate(SkScalar tx, SkScalar ty) { +void LayerStateStack::push_translate(SkScalar tx, SkScalar ty) { state_stack_.emplace_back(std::make_unique(tx, ty)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); + apply_last_entry(); } -void LayerStateStack::transform(const SkMatrix& matrix) { - state_stack_.emplace_back(std::make_unique(matrix)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); +void LayerStateStack::push_transform(const SkM44& m44) { + state_stack_.emplace_back(std::make_unique(m44)); + apply_last_entry(); } -void LayerStateStack::transform(const SkM44& matrix) { - state_stack_.emplace_back(std::make_unique(matrix)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); +void LayerStateStack::push_transform(const SkMatrix& matrix) { + state_stack_.emplace_back(std::make_unique(matrix)); + apply_last_entry(); } -void LayerStateStack::clipRect(const SkRect& rect, bool is_aa) { +void LayerStateStack::push_clip_rect(const SkRect& rect, bool is_aa) { state_stack_.emplace_back(std::make_unique(rect, is_aa)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); + apply_last_entry(); } -void LayerStateStack::clipRRect(const SkRRect& rrect, bool is_aa) { +void LayerStateStack::push_clip_rrect(const SkRRect& rrect, bool is_aa) { state_stack_.emplace_back(std::make_unique(rrect, is_aa)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); + apply_last_entry(); } -void LayerStateStack::clipPath(const SkPath& path, bool is_aa) { +void LayerStateStack::push_clip_path(const SkPath& path, bool is_aa) { state_stack_.emplace_back(std::make_unique(path, is_aa)); - state_stack_.back()->apply(&outstanding_, canvas_, builder_); + apply_last_entry(); } -void LayerStateStack::restoreToCount(size_t restore_count) { - while (state_stack_.size() > restore_count) { - state_stack_.back()->restore(&outstanding_, canvas_, builder_); - state_stack_.pop_back(); +bool LayerStateStack::needs_save_layer(int flags) const { + if (outstanding_.opacity < SK_Scalar1 && + (flags & LayerStateStack::CALLER_CAN_APPLY_OPACITY) == 0) { + return true; + } + if (outstanding_.image_filter && + (flags & LayerStateStack::CALLER_CAN_APPLY_IMAGE_FILTER) == 0) { + return true; + } + if (outstanding_.color_filter && + (flags & LayerStateStack::CALLER_CAN_APPLY_COLOR_FILTER) == 0) { + return true; } + // Check IF and CF eventually... + return false; } -void LayerStateStack::pushAttributes() { - state_stack_.emplace_back(std::make_unique(outstanding_)); +void LayerStateStack::save_layer(const SkRect& bounds) { + state_stack_.emplace_back( + std::make_unique(bounds, do_checkerboard_)); + apply_last_entry(); + outstanding_ = {}; +} + +void LayerStateStack::maybe_save_layer(const SkRect& bounds, int apply_flags) { + if (needs_save_layer(apply_flags)) { + save_layer(bounds); + } +} + +void LayerStateStack::maybe_save_layer(const SkRect& bounds, SkScalar opacity) { + if (outstanding_.color_filter) { + save_layer(bounds); + } +} + +void LayerStateStack::maybe_save_layer( + const SkRect& bounds, + const std::shared_ptr filter) { + if (outstanding_.color_filter || outstanding_.image_filter) { + // TBD: compose the 2 color filters together. + save_layer(bounds); + } +} + +void LayerStateStack::maybe_save_layer( + const SkRect& bounds, + const std::shared_ptr filter) { + if (outstanding_.image_filter || outstanding_.color_filter || + outstanding_.opacity < SK_Scalar1) { + // TBD: compose the 2 image filters together. + save_layer(bounds); + } } void LayerStateStack::AttributesEntry::restore( @@ -217,22 +334,24 @@ void LayerStateStack::SaveLayerEntry::apply(RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { if (canvas) { - canvas->saveLayer(save_bounds(), nullptr); + SkPaint paint; + canvas->saveLayer(bounds_, attributes->fill(paint)); } if (builder) { - builder->saveLayer(save_bounds(), nullptr); + DlPaint paint; + builder->saveLayer(&bounds_, attributes->fill(paint)); } } void LayerStateStack::SaveLayerEntry::do_checkerboard( SkCanvas* canvas, DisplayListBuilder* builder) const { - if (do_checkerboard_ && bounds_.has_value()) { + if (do_checkerboard_) { if (canvas) { - SkDrawCheckerboard(canvas, bounds_.value()); + SkDrawCheckerboard(canvas, bounds_); } if (builder) { - DlDrawCheckerboard(builder, bounds_.value()); + DlDrawCheckerboard(builder, bounds_); } } } @@ -243,58 +362,18 @@ void LayerStateStack::OpacityEntry::apply(RenderingAttributes* attributes, attributes->opacity *= opacity_; } -void LayerStateStack::resolve(const SkRect& bounds) { - if (!canvas_ && !builder_) { - return; - } - SkScalar opacity = outstanding_.opacity; - if (opacity >= SK_Scalar1) { - return; - } - pushAttributes(); - if (canvas_) { - SkPaint paint; - paint.setAlphaf(opacity); - canvas_->saveLayer(bounds, sk_paint()); - } - if (builder_) { - DlPaint paint; - paint.setOpacity(opacity); - builder_->saveLayer(&bounds, dl_paint()); - } - outstanding_ = {}; -} - void LayerStateStack::ImageFilterEntry::apply( RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { - if (canvas) { - SkPaint paint; - paint.setImageFilter(filter_ ? filter_->skia_object() : nullptr); - canvas->saveLayer(save_bounds(), &paint); - } - if (builder) { - DlPaint paint; - paint.setImageFilter(filter_); - builder->saveLayer(save_bounds(), &paint); - } + attributes->image_filter = filter_; } void LayerStateStack::ColorFilterEntry::apply( RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const { - if (canvas) { - SkPaint paint; - paint.setColorFilter(filter_ ? filter_->skia_object() : nullptr); - canvas->saveLayer(save_bounds(), &paint); - } - if (builder) { - DlPaint paint; - paint.setColorFilter(filter_); - builder->saveLayer(save_bounds(), &paint); - } + attributes->color_filter = filter_; } void LayerStateStack::BackdropFilterEntry::apply( @@ -305,14 +384,22 @@ void LayerStateStack::BackdropFilterEntry::apply( sk_sp backdrop_filter = filter_ ? filter_->skia_object() : nullptr; SkPaint paint; - paint.setBlendMode(ToSk(blend_mode_)); - canvas->saveLayer(SkCanvas::SaveLayerRec{save_bounds(), &paint, - backdrop_filter.get(), 0}); + SkPaint* pPaint = attributes->fill(paint); + if (blend_mode_ != DlBlendMode::kSrcOver) { + paint.setBlendMode(ToSk(blend_mode_)); + pPaint = &paint; + } + canvas->saveLayer( + SkCanvas::SaveLayerRec{&bounds_, pPaint, backdrop_filter.get(), 0}); } if (builder) { DlPaint paint; - paint.setBlendMode(blend_mode_); - builder->saveLayer(save_bounds(), &paint, filter_.get()); + DlPaint* pPaint = attributes->fill(paint); + if (blend_mode_ != DlBlendMode::kSrcOver) { + paint.setBlendMode(blend_mode_); + pPaint = &paint; + } + builder->saveLayer(&bounds_, pPaint, filter_.get()); } } @@ -327,16 +414,7 @@ void LayerStateStack::BackdropFilterEntry::reapply( // perfect if the BlendMode is not associative as we will be // compositing multiple parts of the content in batches. // Luckily the most common SrcOver is associative. - if (canvas) { - SkPaint paint; - paint.setBlendMode(ToSk(blend_mode_)); - canvas->saveLayer(save_bounds(), &paint); - } - if (builder) { - DlPaint paint; - paint.setBlendMode(blend_mode_); - builder->saveLayer(save_bounds(), &paint); - } + SaveLayerEntry::apply(attributes, canvas, builder); } void LayerStateStack::TranslateEntry::apply(RenderingAttributes* attributes, diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 669b0bd0aef73..5d1bbd529413a 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -35,23 +35,75 @@ class LayerStateStack { public: ~AutoRestore(); + protected: + LayerStateStack* layer_state_stack_; + private: AutoRestore(LayerStateStack* stack); friend class LayerStateStack; - LayerStateStack* stack_; - size_t stack_restore_count_; + const size_t stack_restore_count_; + const bool attributes_pushed_; }; static constexpr int CALLER_CAN_APPLY_OPACITY = 0x1; - static constexpr int CALLER_CAN_APPLY_ANYTHING = 0x1; + static constexpr int CALLER_CAN_APPLY_COLOR_FILTER = 0x2; + static constexpr int CALLER_CAN_APPLY_IMAGE_FILTER = 0x4; + static constexpr int CALLER_CAN_APPLY_ANYTHING = 0x7; - struct RenderingAttributes { - SkScalar opacity = SK_Scalar1; + class MutatorContext : public AutoRestore { + public: + // Immediately executes a saveLayer with all accumulated state + // onto the canvas or builder to be applied at the next matching + // restore. A saveLayer is always executed by this method even if + // there are no outstanding attributes. + void saveLayer(const SkRect& bounds); + + // Records the opacity for application at the next call to + // saveLayer or applyState. A saveLayer may be executed at + // this time if the opacity cannot be batched with other + // outstanding attributes. + void applyOpacity(const SkRect& bounds, SkScalar opacity); + + // Records the image filter for application at the next call to + // saveLayer or applyState. A saveLayer may be executed at + // this time if the image filter cannot be batched with other + // outstanding attributes. + // (Currently only opacity is recorded for batching) + void applyImageFilter(const SkRect& bounds, + const std::shared_ptr filter); + + // Records the color filter for application at the next call to + // saveLayer or applyState. A saveLayer may be executed at + // this time if the color filter cannot be batched with other + // outstanding attributes. + // (Currently only opacity is recorded for batching) + void applyColorFilter(const SkRect& bounds, + const std::shared_ptr filter); + + // Saves the state stack and immediately executes a saveLayer + // with the indicated backdrop filter and any outstanding + // state attributes. Since the backdrop filter only applies + // to the pixels alrady on the screen when this call is made, + // the backdrop filter will only be applied to the canvas or + // builder installed at the time that this call is made, and + // subsequent canvas or builder objects that are made delegates + // will only see a saveLayer with the indicated blend_mode. + void applyBackdropFilter(const SkRect& bounds, + const std::shared_ptr filter, + DlBlendMode blend_mode); + + void translate(SkScalar tx, SkScalar ty); + void transform(const SkM44& m44); + void transform(const SkMatrix& matrix); + + void clipRect(const SkRect& rect, bool is_aa); + void clipRRect(const SkRRect& rrect, bool is_aa); + void clipPath(const SkPath& path, bool is_aa); - bool operator==(const RenderingAttributes& other) { - return opacity == other.opacity; - } + private: + MutatorContext(LayerStateStack* stack) : AutoRestore(stack) {} + friend class LayerStateStack; }; // Apply the outstanding state via saveLayer if necessary, @@ -60,7 +112,8 @@ class LayerStateStack { // themselves. // // A saveLayer may or may not be sent to the delegates depending - // on the outstanding state and the flags supplied by the caller. + // on how the outstanding state intersects with the flags supplied + // by the caller. // // An AutoRestore instance will always be returned even if there // was no saveLayer applied. @@ -69,83 +122,76 @@ class LayerStateStack { SkScalar outstanding_opacity() { return outstanding_.opacity; } - // Return a pointer to an SkPaint instance representing the - // currently outstanding rendering attributes, or a nullptr - // if there are no outstanding attributes for the caller to - // apply during rendering operations. - const SkPaint* sk_paint(); + const std::shared_ptr outstanding_color_filter() { + return outstanding_.color_filter; + } - // Return a pointer to an DlPaint instance representing the - // currently outstanding rendering attributes, or a nullptr - // if there are no outstanding attributes for the caller to - // apply during rendering operations. - const DlPaint* dl_paint(); + const std::shared_ptr outstanding_image_filter() { + return outstanding_.image_filter; + } + + // Fill the provided paint object with any oustanding attributes and + // return a pointer to it, or return a nullptr if there were no + // outstanding attributes to paint with. + SkPaint* fill(SkPaint& paint) { return outstanding_.fill(paint); } + + // Fill the provided paint object with any oustanding attributes and + // return a pointer to it, or return a nullptr if there were no + // outstanding attributes to paint with. + DlPaint* fill(DlPaint& paint) { return outstanding_.fill(paint); } bool needs_painting() { return outstanding_.opacity > 0; } - // Saves the current state of the state stack until the next - // matching restore call. - [[nodiscard]] AutoRestore save(); - - // Saves the state stack and immediately executes a saveLayer - // with all accumulated state onto the canvas or builder to - // be applied at the next matching restore. A saveLayer is - // always executed by this method even if there are no - // outstanding attributes. - [[nodiscard]] AutoRestore saveLayer(const SkRect* bounds); - - // Records the opacity for application at the next call to - // saveLayer or applyState. A saveLayer may be executed at - // this time if the opacity cannot be batched with other - // outstanding attributes. - [[nodiscard]] AutoRestore pushOpacity(const SkRect* bounds, SkScalar opacity); - - // Records the image filter for application at the next call to - // saveLayer or applyState. A saveLayer may be executed at - // this time if the image filter cannot be batched with other - // outstanding attributes. - // (Currently only opacity is recorded for batching) - [[nodiscard]] AutoRestore pushImageFilter( - const SkRect* bounds, - const std::shared_ptr filter); - - // Records the color filter for application at the next call to - // saveLayer or applyState. A saveLayer may be executed at - // this time if the color filter cannot be batched with other - // outstanding attributes. - // (Currently only opacity is recorded for batching) - [[nodiscard]] AutoRestore pushColorFilter( - const SkRect* bounds, - const std::shared_ptr filter); - - // Saves the state stack and immediately executes a saveLayer - // with the indicated backdrop filter and any outstanding - // state attributes. Since the backdrop filter only applies - // to the pixels alrady on the screen when this call is made, - // the backdrop filter will only be applied to the canvas or - // builder installed at the time that this call is made, and - // subsequent canvas or builder objects that are made delegates - // will only see a saveLayer with the indicated blend_mode. - [[nodiscard]] AutoRestore pushBackdropFilter( - const SkRect* bounds, - const std::shared_ptr filter, - DlBlendMode blend_mode); - - void translate(SkScalar tx, SkScalar ty); - void transform(const SkM44& matrix); - void transform(const SkMatrix& matrix); - - void clipRect(const SkRect& rect, bool is_aa); - void clipRRect(const SkRRect& rect, bool is_aa); - void clipPath(const SkPath& rect, bool is_aa); + // Saves the current state of the state stack and returns a + // MutatorContext which can be used to manipulate the state. + // The state stack will be restored to its current state + // when the MutatorContext object goes out of scope. + [[nodiscard]] MutatorContext save(); private: - size_t getStackCount() { return state_stack_.size(); } - void restoreToCount(size_t restore_count); + size_t stack_count() { return state_stack_.size(); } + void restore_to_count(size_t restore_count); + void reapply_all(SkCanvas* canvas, DisplayListBuilder* builder); - void pushAttributes(); + void apply_last_entry() { + state_stack_.back()->apply(&outstanding_, canvas_, builder_); + } - void resolve(const SkRect& bounds); + // The push methods simply push an associated StateEntry on the stack + // and then apply it to the current canvas and builder. + // --------------------- + void push_attributes(); + void push_opacity(SkScalar opacity); + void push_color_filter(const std::shared_ptr filter); + void push_image_filter(const std::shared_ptr filter); + void push_backdrop(const SkRect& bounds, + const std::shared_ptr filter, + DlBlendMode blend_mode); + + void push_translate(SkScalar tx, SkScalar ty); + void push_transform(const SkM44& matrix); + void push_transform(const SkMatrix& matrix); + + void push_clip_rect(const SkRect& rect, bool is_aa); + void push_clip_rrect(const SkRRect& rrect, bool is_aa); + void push_clip_path(const SkPath& path, bool is_aa); + // --------------------- + + // The maybe/needs_save_layer methods will determine if the indicated + // attribute can be incorporated into the outstanding attributes as is, + // or if the apply_flags are compatible with the outstanding attributes. + // If the oustanding attributes are incompatible with the new attribute + // or the apply flags, then a protective saveLayer will be executed. + // --------------------- + bool needs_save_layer(int flags) const; + void save_layer(const SkRect& bounds); + void maybe_save_layer(const SkRect& bounds, int apply_flags); + void maybe_save_layer(const SkRect& bounds, SkScalar opacity); + void maybe_save_layer(const SkRect& bounds, + const std::shared_ptr filter); + void maybe_save_layer(const SkRect& bounds, + const std::shared_ptr filter); + // --------------------- static std::optional OptionalBounds(const SkRect* bounds) { return bounds ? std::make_optional(*bounds) : std::nullopt; @@ -154,6 +200,22 @@ class LayerStateStack { return bounds.has_value() ? &bounds.value() : nullptr; } + struct RenderingAttributes { + SkScalar opacity = SK_Scalar1; + std::shared_ptr color_filter; + std::shared_ptr image_filter; + bool pushed = false; + + SkPaint* fill(SkPaint& paint); + DlPaint* fill(DlPaint& paint); + + bool operator==(const RenderingAttributes& other) { + return opacity == other.opacity && + Equals(color_filter, other.color_filter) && + Equals(image_filter, other.image_filter); + } + }; + class StateEntry { public: virtual ~StateEntry() = default; @@ -207,29 +269,24 @@ class LayerStateStack { class SaveLayerEntry : public SaveEntry { public: - SaveLayerEntry(const SkRect* bounds, bool checkerboard) - : bounds_(OptionalBounds(bounds)), do_checkerboard_(checkerboard) {} + SaveLayerEntry(const SkRect& bounds, bool checkerboard) + : bounds_(bounds), do_checkerboard_(checkerboard) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, DisplayListBuilder* builder) const override; protected: - const std::optional bounds_; + const SkRect bounds_; const bool do_checkerboard_; void do_checkerboard(SkCanvas* canvas, DisplayListBuilder* builder) const override; - - const SkRect* save_bounds() const { return BoundsPtr(bounds_); } }; - class OpacityEntry : public SaveLayerEntry { + class OpacityEntry : public StateEntry { public: - OpacityEntry(const SkRect* bounds, - SkScalar opacity, - bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), opacity_(opacity) {} + OpacityEntry(SkScalar opacity) : opacity_(opacity) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, @@ -239,12 +296,10 @@ class LayerStateStack { const SkScalar opacity_; }; - class ImageFilterEntry : public SaveLayerEntry { + class ImageFilterEntry : public StateEntry { public: - ImageFilterEntry(const SkRect* bounds, - const std::shared_ptr filter, - bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} + ImageFilterEntry(const std::shared_ptr filter) + : filter_(filter) {} ~ImageFilterEntry() override = default; void apply(RenderingAttributes* attributes, @@ -255,12 +310,10 @@ class LayerStateStack { const std::shared_ptr filter_; }; - class ColorFilterEntry : public SaveLayerEntry { + class ColorFilterEntry : public StateEntry { public: - ColorFilterEntry(const SkRect* bounds, - const std::shared_ptr filter, - bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), filter_(filter) {} + ColorFilterEntry(const std::shared_ptr filter) + : filter_(filter) {} ~ColorFilterEntry() override = default; void apply(RenderingAttributes* attributes, @@ -273,7 +326,7 @@ class LayerStateStack { class BackdropFilterEntry : public SaveLayerEntry { public: - BackdropFilterEntry(const SkRect* bounds, + BackdropFilterEntry(const SkRect& bounds, const std::shared_ptr filter, DlBlendMode blend_mode, bool checkerboard) @@ -293,6 +346,7 @@ class LayerStateStack { private: const std::shared_ptr filter_; const DlBlendMode blend_mode_; + friend class LayerStateStack; }; class TransformEntry : public StateEntry {}; @@ -382,6 +436,7 @@ class LayerStateStack { }; std::vector> state_stack_; + friend class MutatorContext; SkCanvas* canvas_ = nullptr; int canvas_restore_count_ = 0.0; @@ -389,11 +444,8 @@ class LayerStateStack { int builder_restore_count_ = 0.0; RenderingAttributes outstanding_; - bool do_checkerboard_; + bool do_checkerboard_ = false; friend class SaveLayerEntry; - - SkPaint temp_sk_paint_; - DlPaint temp_dl_paint_; }; } // namespace flutter diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index a1251c279f193..0f9727002d033 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -112,10 +112,11 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, DisplayListBuilder* builder = frame.display_list_builder(); LayerStateStack state_stack; + state_stack.set_checkerboard_save_layers(checkerboard_offscreen_layers_); if (builder) { - state_stack.setBuilderDelegate(builder); + state_stack.set_builder_delegate(builder); } else { - state_stack.setCanvasDelegate(frame.canvas()); + state_stack.set_canvas_delegate(frame.canvas()); } // clear the previous snapshots. @@ -190,7 +191,8 @@ sk_sp LayerTree::Flatten( }; LayerStateStack state_stack; - state_stack.setBuilderDelegate(recorder); + state_stack.set_checkerboard_save_layers(false); + state_stack.set_builder_delegate(recorder); PaintContext paint_context = { // clang-format off diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 7077157507798..daa35693396d9 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -80,11 +80,22 @@ void OpacityLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "OpacityLayer::Paint"); FML_DCHECK(needs_painting(context)); - auto save = context.state_stack.save(); - context.state_stack.translate(offset_.fX, offset_.fY); - - auto restore = context.state_stack.saveWithOpacity( - &paint_bounds(), opacity(), checkerboard_bounds(context)); + // Skia may clip the content with saveLayerBounds (although it's not a + // guaranteed clip). So we have to provide a big enough saveLayerBounds. To do + // so, we first remove the offset from paint bounds since it's already in the + // matrix. Then we round out the bounds. + // + // Note that the following lines are only accessible when the raster cache is + // not available (e.g., when we're using the software backend in golden + // tests). + SkRect saveLayerBounds; + paint_bounds() + .makeOffset(-offset_.fX, -offset_.fY) + .roundOut(&saveLayerBounds); + + auto mutator = context.state_stack.save(); + mutator.translate(offset_.fX, offset_.fY); + mutator.applyOpacity(saveLayerBounds, opacity()); PaintChildren(context); } diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index fad44a0129b22..83e893cf0d39f 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -59,7 +59,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { ASSERT_TRUE(surface != nullptr); LayerStateStack state_stack; - state_stack.setCanvasDelegate(surface->getCanvas()); + state_stack.set_canvas_delegate(surface->getCanvas()); flutter::PaintContext paintContext = { // clang-format off diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc index 67a62dab80fc5..9cd5f4d37c3ac 100644 --- a/flow/layers/physical_shape_layer.cc +++ b/flow/layers/physical_shape_layer.cc @@ -73,6 +73,8 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context, paint_bounds.join(child_paint_bounds); } + context->renderable_state_flags = + UsesSaveLayer() ? SAVE_LAYER_RENDER_FLAGS : 0; set_paint_bounds(paint_bounds); } @@ -90,11 +92,10 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { SkColorGetA(color_) != 0xff, context.frame_device_pixel_ratio); } - auto save = context.state_stack.save(); + auto mutator = context.state_stack.save(); if (clip_behavior_ == Clip::antiAliasWithSaveLayer) { - context.state_stack.clipPath(path_, true); - auto saveLayer = context.state_stack.saveLayer( - &paint_bounds(), checkerboard_bounds(context)); + mutator.clipPath(path_, true); + mutator.saveLayer(paint_bounds()); context.canvas->drawColor(color_); PaintChildren(context); } else { @@ -105,7 +106,7 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const { // Call drawPath without clip if possible for better performance. context.canvas->drawPath(path_, paint); if (clip_behavior_ != Clip::none) { - context.state_stack.clipPath(path_, clip_behavior_ == Clip::antiAlias); + mutator.clipPath(path_, clip_behavior_ == Clip::antiAlias); } PaintChildren(context); } diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index 5b22a8bfd8025..efb5df6700631 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -39,8 +39,8 @@ void PlatformViewLayer::Paint(PaintContext& context) const { } EmbedderPaintContext embedder_context = context.view_embedder->CompositeEmbeddedView(view_id_); - context.state_stack.setCanvasDelegate(embedder_context.canvas); - context.state_stack.setBuilderDelegate(embedder_context.builder); + context.state_stack.set_canvas_delegate(embedder_context.canvas); + context.state_stack.set_builder_delegate(embedder_context.builder); context.canvas = embedder_context.canvas; context.builder = embedder_context.builder; } diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index 1121744cc8677..f90bd4c0a6b7f 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -51,14 +51,17 @@ void ShaderMaskLayer::Paint(PaintContext& context) const { auto restore = context.state_stack.applyState( paint_bounds(), LayerStateStack::CALLER_CAN_APPLY_OPACITY); + SkPaint paint; if (layer_raster_cache_item_->Draw(context, - context.state_stack.sk_paint())) { + context.state_stack.fill(paint))) { return; } } auto shader_rect = SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()); - auto restore = context.state_stack.saveLayer(&paint_bounds()); + auto mutator = context.state_stack.save(); + mutator.saveLayer(paint_bounds()); + PaintChildren(context); if (context.builder) { diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index fdbb73fc9193c..543b06e7f19c4 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -62,8 +62,9 @@ void TextureLayer::Paint(PaintContext& context) const { return; } + SkPaint paint; texture->Paint(*context.canvas, paint_bounds(), freeze_, context.gr_context, - ToSk(sampling_), context.state_stack.sk_paint()); + ToSk(sampling_), context.state_stack.fill(paint)); } } // namespace flutter diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index f05a74b298812..0c267544c0c3f 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -70,8 +70,8 @@ void TransformLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "TransformLayer::Paint"); FML_DCHECK(needs_painting(context)); - auto save = context.state_stack.save(); - context.state_stack.transform(transform_); + auto mutator = context.state_stack.save(); + mutator.transform(transform_); PaintChildren(context); } diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index a268df157e07d..24d85cf62aa7e 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -108,8 +108,8 @@ class LayerTestBase : public CanvasTestBase { .frame_device_pixel_ratio = 1.0f, // clang-format on } { - canvas_state_stack_.setCanvasDelegate(&TestT::mock_canvas()); - display_list_state_stack_.setBuilderDelegate(display_list_recorder_); + canvas_state_stack_.set_canvas_delegate(&TestT::mock_canvas()); + display_list_state_stack_.set_builder_delegate(display_list_recorder_); use_null_raster_cache(); } From 68c00618651081060647f42aa028ad3f95781dac Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 6 Sep 2022 01:08:17 -0700 Subject: [PATCH 17/19] fix handling of backdrop filter blend mode in SaveEntries --- flow/layers/layer_state_stack.cc | 34 +++++++++++++++++--------------- flow/layers/layer_state_stack.h | 18 +++++++++-------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 5182e977334c9..ab21703fcaa09 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -67,7 +67,8 @@ AutoRestore LayerStateStack::applyState(const SkRect& bounds, return ret; } -SkPaint* LayerStateStack::RenderingAttributes::fill(SkPaint& paint) { +SkPaint* LayerStateStack::RenderingAttributes::fill(SkPaint& paint, + DlBlendMode mode) { SkPaint* ret = nullptr; if (opacity < SK_Scalar1) { paint.setAlphaf(std::max(opacity, 0.0f)); @@ -87,10 +88,15 @@ SkPaint* LayerStateStack::RenderingAttributes::fill(SkPaint& paint) { } else { paint.setImageFilter(nullptr); } + paint.setBlendMode(ToSk(mode)); + if (mode != DlBlendMode::kSrcOver) { + ret = &paint; + } return ret; } -DlPaint* LayerStateStack::RenderingAttributes::fill(DlPaint& paint) { +DlPaint* LayerStateStack::RenderingAttributes::fill(DlPaint& paint, + DlBlendMode mode) { DlPaint* ret = nullptr; if (opacity < SK_Scalar1) { paint.setOpacity(std::max(opacity, 0.0f)); @@ -106,6 +112,10 @@ DlPaint* LayerStateStack::RenderingAttributes::fill(DlPaint& paint) { if (image_filter) { ret = &paint; } + paint.setBlendMode(mode); + if (mode != DlBlendMode::kSrcOver) { + ret = &paint; + } return ret; } @@ -263,8 +273,8 @@ bool LayerStateStack::needs_save_layer(int flags) const { } void LayerStateStack::save_layer(const SkRect& bounds) { - state_stack_.emplace_back( - std::make_unique(bounds, do_checkerboard_)); + state_stack_.emplace_back(std::make_unique( + bounds, DlBlendMode::kSrcOver, do_checkerboard_)); apply_last_entry(); outstanding_ = {}; } @@ -335,11 +345,11 @@ void LayerStateStack::SaveLayerEntry::apply(RenderingAttributes* attributes, DisplayListBuilder* builder) const { if (canvas) { SkPaint paint; - canvas->saveLayer(bounds_, attributes->fill(paint)); + canvas->saveLayer(bounds_, attributes->fill(paint, blend_mode_)); } if (builder) { DlPaint paint; - builder->saveLayer(&bounds_, attributes->fill(paint)); + builder->saveLayer(&bounds_, attributes->fill(paint, blend_mode_)); } } @@ -384,21 +394,13 @@ void LayerStateStack::BackdropFilterEntry::apply( sk_sp backdrop_filter = filter_ ? filter_->skia_object() : nullptr; SkPaint paint; - SkPaint* pPaint = attributes->fill(paint); - if (blend_mode_ != DlBlendMode::kSrcOver) { - paint.setBlendMode(ToSk(blend_mode_)); - pPaint = &paint; - } + SkPaint* pPaint = attributes->fill(paint, blend_mode_); canvas->saveLayer( SkCanvas::SaveLayerRec{&bounds_, pPaint, backdrop_filter.get(), 0}); } if (builder) { DlPaint paint; - DlPaint* pPaint = attributes->fill(paint); - if (blend_mode_ != DlBlendMode::kSrcOver) { - paint.setBlendMode(blend_mode_); - pPaint = &paint; - } + DlPaint* pPaint = attributes->fill(paint, blend_mode_); builder->saveLayer(&bounds_, pPaint, filter_.get()); } } diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 5d1bbd529413a..73d9aec6043a0 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -206,8 +206,8 @@ class LayerStateStack { std::shared_ptr image_filter; bool pushed = false; - SkPaint* fill(SkPaint& paint); - DlPaint* fill(DlPaint& paint); + SkPaint* fill(SkPaint& paint, DlBlendMode mode = DlBlendMode::kSrcOver); + DlPaint* fill(DlPaint& paint, DlBlendMode mode = DlBlendMode::kSrcOver); bool operator==(const RenderingAttributes& other) { return opacity == other.opacity && @@ -269,8 +269,12 @@ class LayerStateStack { class SaveLayerEntry : public SaveEntry { public: - SaveLayerEntry(const SkRect& bounds, bool checkerboard) - : bounds_(bounds), do_checkerboard_(checkerboard) {} + SaveLayerEntry(const SkRect& bounds, + DlBlendMode blend_mode, + bool checkerboard) + : bounds_(bounds), + blend_mode_(blend_mode), + do_checkerboard_(checkerboard) {} void apply(RenderingAttributes* attributes, SkCanvas* canvas, @@ -278,6 +282,7 @@ class LayerStateStack { protected: const SkRect bounds_; + const DlBlendMode blend_mode_; const bool do_checkerboard_; void do_checkerboard(SkCanvas* canvas, @@ -330,9 +335,7 @@ class LayerStateStack { const std::shared_ptr filter, DlBlendMode blend_mode, bool checkerboard) - : SaveLayerEntry(bounds, checkerboard), - filter_(filter), - blend_mode_(blend_mode) {} + : SaveLayerEntry(bounds, blend_mode, checkerboard), filter_(filter) {} ~BackdropFilterEntry() override = default; void apply(RenderingAttributes* attributes, @@ -345,7 +348,6 @@ class LayerStateStack { private: const std::shared_ptr filter_; - const DlBlendMode blend_mode_; friend class LayerStateStack; }; From b75001a5d9781ea72911b00bc57a01534ded697d Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 6 Sep 2022 12:13:52 -0700 Subject: [PATCH 18/19] fix some unit test issues --- .../checkerboard_layertree_unittests.cc | 16 +++--- flow/layers/clip_path_layer_unittests.cc | 50 +++++++------------ flow/layers/clip_rect_layer_unittests.cc | 46 ++++++----------- flow/layers/clip_rrect_layer_unittests.cc | 31 +++--------- flow/layers/clip_shape_layer.h | 2 +- flow/layers/color_filter_layer_unittests.cc | 11 ++-- flow/layers/container_layer.cc | 2 +- flow/layers/container_layer.h | 3 ++ flow/layers/layer_state_stack.cc | 14 ++---- flow/layers/layer_state_stack.h | 2 - flow/testing/mock_layer.cc | 10 ++-- 11 files changed, 66 insertions(+), 121 deletions(-) diff --git a/flow/layers/checkerboard_layertree_unittests.cc b/flow/layers/checkerboard_layertree_unittests.cc index 8915af6610506..41e73bfe1efea 100644 --- a/flow/layers/checkerboard_layertree_unittests.cc +++ b/flow/layers/checkerboard_layertree_unittests.cc @@ -18,7 +18,7 @@ namespace testing { using CheckerBoardLayerTest = LayerTest; #ifndef NDEBUG -TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerNotCheckBoard) { +TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerNotCheckerBoard) { const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f); const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0); const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0); @@ -68,7 +68,7 @@ TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerNotCheckBoard) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } -TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckBoard) { +TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckerBoard) { const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f); const SkRect cull_bounds = SkRect::MakeXYWH(0.0, 0.0, 2.0, 4.0); const SkRect child_bounds = SkRect::MakeXYWH(2.5, 5.0, 4.5, 4.0); @@ -118,7 +118,7 @@ TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckBoard) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } -TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerNotCheckBoard) { +TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerNotCheckerBoard) { const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f); const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0); const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0); @@ -159,7 +159,7 @@ TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerNotCheckBoard) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } -TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckBoard) { +TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckerBoard) { const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f); const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0); const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0); @@ -200,7 +200,7 @@ TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckBoard) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } -TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerNotCheckBoard) { +TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerNotCheckerBoard) { const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f); const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0); const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0); @@ -241,7 +241,7 @@ TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerNotCheckBoard) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } -TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckBoard) { +TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckerBoard) { const SkMatrix initial_matrix = SkMatrix::Translate(0.5f, 1.0f); const SkRect child_bounds = SkRect::MakeXYWH(1.0, 2.0, 2.0, 2.0); const SkRect layer_bounds = SkRect::MakeXYWH(0.5, 1.0, 5.0, 6.0); @@ -282,7 +282,7 @@ TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckBoard) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } -TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerNotCheckBoard) { +TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerNotCheckerBoard) { constexpr float initial_elevation = 20.0f; SkPath layer_path; layer_path.addRect(0, 0, 8, 8).close(); @@ -320,7 +320,7 @@ TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerNotCheckBoard) { MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); } -TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerCheckBoard) { +TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerCheckerBoard) { constexpr float initial_elevation = 20.0f; SkPath layer_path; layer_path.addRect(0, 0, 8, 8).close(); diff --git a/flow/layers/clip_path_layer_unittests.cc b/flow/layers/clip_path_layer_unittests.cc index e0ce2283483c2..14684de558f6b 100644 --- a/flow/layers/clip_path_layer_unittests.cc +++ b/flow/layers/clip_path_layer_unittests.cc @@ -312,14 +312,12 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_path_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); // Now add the overlapping child and test again, should still be compatible clip_path_saveLayer->Add(mock3); clip_path_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); } // An incompatible, but non-overlapping child for the following tests @@ -355,14 +353,12 @@ TEST_F(ClipPathLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_path_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); // Now add the incompatible child and test again, should still be compatible clip_path_saveLayer_bad_child->Add(mock4); clip_path_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); } } @@ -387,6 +383,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritancePainting) { LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; + DlPaint mock_paint = DlPaint().setAlpha(opacity_alpha); SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_path_layer); @@ -402,22 +399,10 @@ TEST_F(ClipPathLayerTest, OpacityInheritancePainting) { expected_builder.save(); expected_builder.clipPath(layer_clip, SkClipOp::kIntersect, true); /* child layer1 paint */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path1.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path1); - } - expected_builder.restore(); + expected_builder.drawPath(path1, mock_paint); } /* child layer2 paint */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path2.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path2); - } - expected_builder.restore(); + expected_builder.drawPath(path2, mock_paint); } expected_builder.restore(); } @@ -426,7 +411,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritancePainting) { } opacity_layer->Paint(display_list_paint_context()); - EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { @@ -444,14 +429,15 @@ TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { clip_path_layer->Add(mock1); clip_path_layer->Add(mock2); - // ClipRectLayer will pass through compatibility from multiple - // non-overlapping compatible children + // ClipRectLayer will implement compatibility itself for multiple + // overlapping compatible children PrerollContext* context = preroll_context(); clip_path_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); int opacity_alpha = 0x7F; + DlPaint save_layer_paint = DlPaint().setAlpha(opacity_alpha); + DlPaint mock_paint = DlPaint(); SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_path_layer); @@ -466,14 +452,12 @@ TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { /* ClipRectLayer::Paint() */ { expected_builder.save(); expected_builder.clipPath(layer_clip, SkClipOp::kIntersect, true); - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&children_bounds, true); + expected_builder.saveLayer(&children_bounds, &save_layer_paint); /* child layer1 paint */ { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path1); + expected_builder.drawPath(path1, mock_paint); } /* child layer2 paint */ { // - expected_builder.drawPath(path2); + expected_builder.drawPath(path2, mock_paint); } expected_builder.restore(); } @@ -482,7 +466,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { } opacity_layer->Paint(display_list_paint_context()); - EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipPathLayerTest, LayerCached) { diff --git a/flow/layers/clip_rect_layer_unittests.cc b/flow/layers/clip_rect_layer_unittests.cc index 3d711b3c7ab5f..005910a91f757 100644 --- a/flow/layers/clip_rect_layer_unittests.cc +++ b/flow/layers/clip_rect_layer_unittests.cc @@ -305,14 +305,12 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); // Now add the overlapping child and test again, should still be compatible clip_rect_saveLayer->Add(mock3); clip_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); } // An incompatible, but non-overlapping child for the following tests @@ -348,14 +346,12 @@ TEST_F(ClipRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); // Now add the incompatible child and test again, should still be compatible clip_rect_saveLayer_bad_child->Add(mock4); clip_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); } } @@ -378,6 +374,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritancePainting) { LayerStateStack::CALLER_CAN_APPLY_OPACITY); int opacity_alpha = 0x7F; + DlPaint mock_paint = DlPaint().setAlpha(opacity_alpha); SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_rect_layer); @@ -393,22 +390,10 @@ TEST_F(ClipRectLayerTest, OpacityInheritancePainting) { expected_builder.save(); expected_builder.clipRect(clip_rect, SkClipOp::kIntersect, true); /* child layer1 paint */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path1.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path1); - } - expected_builder.restore(); + expected_builder.drawPath(path1, mock_paint); } /* child layer2 paint */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path2.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path2); - } - expected_builder.restore(); + expected_builder.drawPath(path2, mock_paint); } expected_builder.restore(); } @@ -417,7 +402,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritancePainting) { } opacity_layer->Paint(display_list_paint_context()); - EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { @@ -437,10 +422,11 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); int opacity_alpha = 0x7F; + DlPaint save_layer_paint = DlPaint().setAlpha(opacity_alpha); + DlPaint mock_paint; SkPoint offset = SkPoint::Make(10, 10); auto opacity_layer = std::make_shared(opacity_alpha, offset); opacity_layer->Add(clip_rect_layer); @@ -455,14 +441,12 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { /* ClipRectLayer::Paint() */ { expected_builder.save(); expected_builder.clipRect(clip_rect, SkClipOp::kIntersect, true); - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&children_bounds, true); + expected_builder.saveLayer(&children_bounds, &save_layer_paint); /* child layer1 paint */ { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path1); + expected_builder.drawPath(path1, mock_paint); } /* child layer2 paint */ { // - expected_builder.drawPath(path2); + expected_builder.drawPath(path2, mock_paint); } expected_builder.restore(); } @@ -471,7 +455,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { } opacity_layer->Paint(display_list_paint_context()); - EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipRectLayerTest, LayerCached) { diff --git a/flow/layers/clip_rrect_layer_unittests.cc b/flow/layers/clip_rrect_layer_unittests.cc index 9575c66903b03..a25b51f421f84 100644 --- a/flow/layers/clip_rrect_layer_unittests.cc +++ b/flow/layers/clip_rrect_layer_unittests.cc @@ -311,14 +311,12 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_r_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); // Now add the overlapping child and test again, should still be compatible clip_r_rect_saveLayer->Add(mock3); clip_r_rect_saveLayer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); } // An incompatible, but non-overlapping child for the following tests @@ -354,14 +352,12 @@ TEST_F(ClipRRectLayerTest, OpacityInheritance) { // Double check first two children are compatible and non-overlapping clip_r_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); // Now add the incompatible child and test again, should still be compatible clip_r_rect_saveLayer_bad_child->Add(mock4); clip_r_rect_saveLayer_bad_child->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); } } @@ -401,21 +397,11 @@ TEST_F(ClipRRectLayerTest, OpacityInheritancePainting) { expected_builder.clipRRect(clip_r_rect, SkClipOp::kIntersect, true); /* child layer1 paint */ { expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path1.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path1); - } - expected_builder.restore(); + expected_builder.drawPath(path1); } /* child layer2 paint */ { expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path2.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path2); - } - expected_builder.restore(); + expected_builder.drawPath(path2); } expected_builder.restore(); } @@ -424,7 +410,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritancePainting) { } opacity_layer->Paint(display_list_paint_context()); - EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } TEST_F(ClipRRectLayerTest, OpacityInheritanceSaveLayerPainting) { @@ -445,8 +431,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritanceSaveLayerPainting) { // non-overlapping compatible children PrerollContext* context = preroll_context(); clip_r_rect_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index 58d55db2599a3..a880cb6604068 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -96,7 +96,7 @@ class ClipShapeLayer : public CacheableContainerLayer { // saveWithOpacity optimizes the case where opacity >= 1.0 // to a simple saveLayer - mutator.saveLayer(child_paint_bounds()); + mutator.saveLayer(paint_bounds()); PaintChildren(context); } diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index 9e83b27f1fdbc..87dc59f27b39c 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -74,14 +74,9 @@ TEST_F(ColorFilterLayerTest, EmptyFilter) { SkPaint filter_paint; filter_paint.setColorFilter(nullptr); layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, filter_paint, - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + EXPECT_EQ(mock_canvas().draw_calls(), + std::vector({MockCanvas::DrawCall{ + 0, MockCanvas::DrawPathData{child_path, child_paint}}})); } TEST_F(ColorFilterLayerTest, SimpleFilter) { diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 5c48a6716aef8..a02c199504585 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -189,7 +189,7 @@ void ContainerLayer::PaintChildren(PaintContext& context) const { // Apply any outstanding state that the children cannot individually // and collectively handle. auto restore = context.state_stack.applyState( - child_paint_bounds(), children_rendering_state_flags()); + paint_bounds(), children_rendering_state_flags()); // Intentionally not tracing here as there should be no self-time // and the trace event on this common function has a small overhead. diff --git a/flow/layers/container_layer.h b/flow/layers/container_layer.h index 2824b2999de31..a47307f73e6ed 100644 --- a/flow/layers/container_layer.h +++ b/flow/layers/container_layer.h @@ -33,6 +33,9 @@ class ContainerLayer : public Layer { const ContainerLayer* as_container_layer() const override { return this; } const SkRect& child_paint_bounds() const { return child_paint_bounds_; } + void set_child_paint_bounds(const SkRect& bounds) { + child_paint_bounds_ = bounds; + } int children_rendering_state_flags() const { return children_rendering_state_flags_; diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index ab21703fcaa09..89aa6e978cc47 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -49,13 +49,10 @@ void LayerStateStack::reapply_all(SkCanvas* canvas, } AutoRestore::AutoRestore(LayerStateStack* stack) - : layer_state_stack_(stack), - stack_restore_count_(stack->stack_count()), - attributes_pushed_(stack->outstanding_.pushed) {} + : layer_state_stack_(stack), stack_restore_count_(stack->stack_count()) {} AutoRestore::~AutoRestore() { layer_state_stack_->restore_to_count(stack_restore_count_); - layer_state_stack_->outstanding_.pushed = attributes_pushed_; } AutoRestore LayerStateStack::applyState(const SkRect& bounds, @@ -193,10 +190,7 @@ void LayerStateStack::restore_to_count(size_t restore_count) { } void LayerStateStack::push_attributes() { - if (!outstanding_.pushed) { - state_stack_.emplace_back(std::make_unique(outstanding_)); - outstanding_.pushed = true; - } + state_stack_.emplace_back(std::make_unique(outstanding_)); } void LayerStateStack::push_opacity(SkScalar opacity) { @@ -268,7 +262,6 @@ bool LayerStateStack::needs_save_layer(int flags) const { (flags & LayerStateStack::CALLER_CAN_APPLY_COLOR_FILTER) == 0) { return true; } - // Check IF and CF eventually... return false; } @@ -276,7 +269,6 @@ void LayerStateStack::save_layer(const SkRect& bounds) { state_stack_.emplace_back(std::make_unique( bounds, DlBlendMode::kSrcOver, do_checkerboard_)); apply_last_entry(); - outstanding_ = {}; } void LayerStateStack::maybe_save_layer(const SkRect& bounds, int apply_flags) { @@ -351,6 +343,7 @@ void LayerStateStack::SaveLayerEntry::apply(RenderingAttributes* attributes, DlPaint paint; builder->saveLayer(&bounds_, attributes->fill(paint, blend_mode_)); } + *attributes = {}; } void LayerStateStack::SaveLayerEntry::do_checkerboard( @@ -403,6 +396,7 @@ void LayerStateStack::BackdropFilterEntry::apply( DlPaint* pPaint = attributes->fill(paint, blend_mode_); builder->saveLayer(&bounds_, pPaint, filter_.get()); } + *attributes = {}; } void LayerStateStack::BackdropFilterEntry::reapply( diff --git a/flow/layers/layer_state_stack.h b/flow/layers/layer_state_stack.h index 73d9aec6043a0..b9aa834dee2f7 100644 --- a/flow/layers/layer_state_stack.h +++ b/flow/layers/layer_state_stack.h @@ -43,7 +43,6 @@ class LayerStateStack { friend class LayerStateStack; const size_t stack_restore_count_; - const bool attributes_pushed_; }; static constexpr int CALLER_CAN_APPLY_OPACITY = 0x1; @@ -204,7 +203,6 @@ class LayerStateStack { SkScalar opacity = SK_Scalar1; std::shared_ptr color_filter; std::shared_ptr image_filter; - bool pushed = false; SkPaint* fill(SkPaint& paint, DlBlendMode mode = DlBlendMode::kSrcOver); DlPaint* fill(DlPaint& paint, DlBlendMode mode = DlBlendMode::kSrcOver); diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 25041688cf4db..65949460c6c4d 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -59,10 +59,12 @@ void MockLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { void MockLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting(context)); - auto restore = context.state_stack.applyState( - fake_paint_path_.getBounds(), - fake_opacity_compatible_ ? LayerStateStack::CALLER_CAN_APPLY_OPACITY : 0); - context.canvas->drawPath(fake_paint_path_, fake_paint_); + SkPaint paint = fake_paint_; + if (fake_opacity_compatible_) { + paint.setAlphaf(paint.getAlphaf() * + context.state_stack.outstanding_opacity()); + } + context.canvas->drawPath(fake_paint_path_, paint); } void MockCacheableContainerLayer::Preroll(PrerollContext* context, From c60bf8ad550cf0eedbac2de14aa8d0edcebfe2f6 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 6 Sep 2022 14:26:37 -0700 Subject: [PATCH 19/19] layer unit tests now pass --- .../layers/backdrop_filter_layer_unittests.cc | 2 +- .../checkerboard_layertree_unittests.cc | 8 ++-- flow/layers/clip_path_layer_unittests.cc | 4 +- flow/layers/clip_rect_layer_unittests.cc | 4 +- flow/layers/clip_rrect_layer_unittests.cc | 4 +- flow/layers/color_filter_layer_unittests.cc | 10 ++--- flow/layers/container_layer.cc | 2 +- flow/layers/display_list_layer.cc | 12 ++---- flow/layers/display_list_layer_unittests.cc | 19 +++++----- flow/layers/image_filter_layer.cc | 8 ++-- flow/layers/image_filter_layer_unittests.cc | 20 ++++------ flow/layers/layer.h | 6 --- flow/layers/layer_raster_cache_item.cc | 1 - flow/layers/layer_state_stack.cc | 35 +++++++++++------ flow/layers/layer_tree.cc | 4 -- flow/layers/layer_tree_unittests.cc | 2 - flow/layers/opacity_layer_unittests.cc | 36 ++++++------------ .../performance_overlay_layer_unittests.cc | 1 - flow/layers/shader_mask_layer_unittests.cc | 5 +-- flow/layers/transform_layer_unittests.cc | 25 ++++-------- flow/testing/layer_test.h | 38 +++++++++++++++---- flow/testing/mock_raster_cache.cc | 2 - flow/testing/mock_raster_cache.h | 2 - shell/common/shell_unittests.cc | 2 - 24 files changed, 116 insertions(+), 136 deletions(-) diff --git a/flow/layers/backdrop_filter_layer_unittests.cc b/flow/layers/backdrop_filter_layer_unittests.cc index 16cf3bc242232..7d242b89e851f 100644 --- a/flow/layers/backdrop_filter_layer_unittests.cc +++ b/flow/layers/backdrop_filter_layer_unittests.cc @@ -292,7 +292,7 @@ TEST_F(BackdropFilterLayerTest, OpacityInheritance) { parent->Add(layer); clip->Add(parent); - clip->Preroll(preroll_context(), SkMatrix::I()); + clip->Preroll(display_list_preroll_context(), SkMatrix::I()); clip->Paint(display_list_paint_context()); diff --git a/flow/layers/checkerboard_layertree_unittests.cc b/flow/layers/checkerboard_layertree_unittests.cc index 41e73bfe1efea..ec4f7afa8c08d 100644 --- a/flow/layers/checkerboard_layertree_unittests.cc +++ b/flow/layers/checkerboard_layertree_unittests.cc @@ -100,7 +100,7 @@ TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckerBoard) { EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_bounds)})); - layer->Paint(check_board_context()); + layer->Paint(checkerboard_context()); EXPECT_NE( mock_canvas().draw_calls(), @@ -183,7 +183,7 @@ TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckerBoard) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_path)})); - layer->Paint(check_board_context()); + layer->Paint(checkerboard_context()); EXPECT_NE( mock_canvas().draw_calls(), std::vector( @@ -265,7 +265,7 @@ TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckerBoard) { EXPECT_EQ(mock_layer->parent_matrix(), initial_matrix); EXPECT_EQ(mock_layer->parent_mutators(), std::vector({Mutator(layer_rrect)})); - layer->Paint(check_board_context()); + layer->Paint(checkerboard_context()); EXPECT_NE( mock_canvas().draw_calls(), std::vector( @@ -341,7 +341,7 @@ TEST_F(CheckerBoardLayerTest, PhysicalSaveLayerCheckerBoard) { const SkPaint clip_paint; SkPaint layer_paint; layer_paint.setColor(SK_ColorGREEN); - layer->Paint(check_board_context()); + layer->Paint(checkerboard_context()); EXPECT_NE( mock_canvas().draw_calls(), std::vector( diff --git a/flow/layers/clip_path_layer_unittests.cc b/flow/layers/clip_path_layer_unittests.cc index 14684de558f6b..da4e2baf97fff 100644 --- a/flow/layers/clip_path_layer_unittests.cc +++ b/flow/layers/clip_path_layer_unittests.cc @@ -377,7 +377,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritancePainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); clip_path_layer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); @@ -431,7 +431,7 @@ TEST_F(ClipPathLayerTest, OpacityInheritanceSaveLayerPainting) { // ClipRectLayer will implement compatibility itself for multiple // overlapping compatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); clip_path_layer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); diff --git a/flow/layers/clip_rect_layer_unittests.cc b/flow/layers/clip_rect_layer_unittests.cc index 005910a91f757..ba79e7a381464 100644 --- a/flow/layers/clip_rect_layer_unittests.cc +++ b/flow/layers/clip_rect_layer_unittests.cc @@ -368,7 +368,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritancePainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); @@ -420,7 +420,7 @@ TEST_F(ClipRectLayerTest, OpacityInheritanceSaveLayerPainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); diff --git a/flow/layers/clip_rrect_layer_unittests.cc b/flow/layers/clip_rrect_layer_unittests.cc index a25b51f421f84..eb50e9b982b85 100644 --- a/flow/layers/clip_rrect_layer_unittests.cc +++ b/flow/layers/clip_rrect_layer_unittests.cc @@ -375,7 +375,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritancePainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); clip_rect_layer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); @@ -429,7 +429,7 @@ TEST_F(ClipRRectLayerTest, OpacityInheritanceSaveLayerPainting) { // ClipRectLayer will pass through compatibility from multiple // non-overlapping compatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); clip_r_rect_layer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index 87dc59f27b39c..893afc03081fc 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -90,7 +90,7 @@ TEST_F(ColorFilterLayerTest, SimpleFilter) { auto layer = std::make_shared(dl_color_filter); layer->Add(mock_layer); - layer->Preroll(preroll_context(), initial_transform); + layer->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(layer->paint_bounds(), child_bounds); EXPECT_EQ(layer->child_paint_bounds(), child_bounds); EXPECT_TRUE(layer->needs_painting(paint_context())); @@ -132,7 +132,7 @@ TEST_F(ColorFilterLayerTest, MultipleChildren) { SkRect children_bounds = child_path1.getBounds(); children_bounds.join(child_path2.getBounds()); - layer->Preroll(preroll_context(), initial_transform); + layer->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); EXPECT_EQ(layer->paint_bounds(), children_bounds); @@ -186,7 +186,7 @@ TEST_F(ColorFilterLayerTest, Nested) { SkRect children_bounds = child_path1.getBounds(); children_bounds.join(child_path2.getBounds()); - layer1->Preroll(preroll_context(), initial_transform); + layer1->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); EXPECT_EQ(layer1->paint_bounds(), children_bounds); @@ -410,8 +410,8 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { std::make_shared(matrix)); color_filter_layer->Add(mock_layer); - PrerollContext* context = preroll_context(); - color_filter_layer->Preroll(preroll_context(), initial_transform); + PrerollContext* context = display_list_preroll_context(); + color_filter_layer->Preroll(context, initial_transform); // ColorFilterLayer can always inherit opacity whether or not their // children are compatible. EXPECT_EQ(context->renderable_state_flags, diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index a02c199504585..5c48a6716aef8 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -189,7 +189,7 @@ void ContainerLayer::PaintChildren(PaintContext& context) const { // Apply any outstanding state that the children cannot individually // and collectively handle. auto restore = context.state_stack.applyState( - paint_bounds(), children_rendering_state_flags()); + child_paint_bounds(), children_rendering_state_flags()); // Intentionally not tracing here as there should be no self-time // and the trace event on this common function has a small overhead. diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 04cdbf0c0934a..cc754204a9686 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -98,7 +98,7 @@ void DisplayListLayer::Preroll(PrerollContext* context, AutoCache cache = AutoCache(display_list_raster_cache_item_.get(), context, matrix); - if (disp_list->can_apply_group_opacity() && !context->display_list_enabled) { + if (disp_list->can_apply_group_opacity()) { context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; } set_paint_bounds(bounds_); @@ -121,12 +121,6 @@ void DisplayListLayer::Paint(PaintContext& context) const { } } - auto restore = context.state_stack.applyState( - paint_bounds(), - display_list()->can_apply_group_opacity() && !context.builder - ? LayerStateStack::CALLER_CAN_APPLY_OPACITY - : 0); - SkScalar opacity = context.state_stack.outstanding_opacity(); if (context.enable_leaf_layer_tracing) { @@ -158,7 +152,9 @@ void DisplayListLayer::Paint(PaintContext& context) const { } if (context.builder) { - context.builder->drawDisplayList(display_list_.skia_object()); + auto display_list = display_list_.skia_object(); + auto restore = context.state_stack.applyState(display_list->bounds(), 0); + context.builder->drawDisplayList(display_list); } else { display_list()->RenderTo(context.canvas, opacity); } diff --git a/flow/layers/display_list_layer_unittests.cc b/flow/layers/display_list_layer_unittests.cc index 90a67bc06db94..7ab3af42efaca 100644 --- a/flow/layers/display_list_layer_unittests.cc +++ b/flow/layers/display_list_layer_unittests.cc @@ -108,8 +108,8 @@ TEST_F(DisplayListLayerTest, SimpleDisplayListOpacityInheritance) { layer_offset, SkiaGPUObject(display_list, unref_queue()), false, false); EXPECT_TRUE(display_list->can_apply_group_opacity()); - auto context = preroll_context(); - display_list_layer->Preroll(preroll_context(), SkMatrix()); + auto context = display_list_preroll_context(); + display_list_layer->Preroll(context, SkMatrix()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); @@ -125,8 +125,6 @@ TEST_F(DisplayListLayerTest, SimpleDisplayListOpacityInheritance) { child_builder.drawRect(picture_bounds); auto child_display_list = child_builder.Build(); - auto save_layer_bounds = - picture_bounds.makeOffset(layer_offset.fX, layer_offset.fY); DisplayListBuilder expected_builder; /* opacity_layer::Paint() */ { expected_builder.save(); @@ -137,7 +135,7 @@ TEST_F(DisplayListLayerTest, SimpleDisplayListOpacityInheritance) { { expected_builder.translate(layer_offset.fX, layer_offset.fY); expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&save_layer_bounds, true); + expected_builder.saveLayer(&picture_bounds, true); /* display_list contents */ { // expected_builder.drawDisplayList(child_display_list); } @@ -151,7 +149,7 @@ TEST_F(DisplayListLayerTest, SimpleDisplayListOpacityInheritance) { opacity_layer->Paint(display_list_paint_context()); EXPECT_TRUE( - DisplayListsEQ_Verbose(expected_builder.Build(), this->display_list())); + DisplayListsEQ_Verbose(this->display_list(), expected_builder.Build())); } TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) { @@ -166,8 +164,8 @@ TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) { layer_offset, SkiaGPUObject(display_list, unref_queue()), false, false); EXPECT_FALSE(display_list->can_apply_group_opacity()); - auto context = preroll_context(); - display_list_layer->Preroll(preroll_context(), SkMatrix()); + auto context = display_list_preroll_context(); + display_list_layer->Preroll(context, SkMatrix()); EXPECT_EQ(context->renderable_state_flags, 0); int opacity_alpha = 0x7F; @@ -178,6 +176,8 @@ TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) { opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_FALSE(opacity_layer->children_can_accept_opacity()); + // We duplicate the display_list from above to verify that the output + // will still match based on the content of the 2 DisplayLists. DisplayListBuilder child_builder; child_builder.drawRect(picture1_bounds); child_builder.drawRect(picture2_bounds); @@ -187,7 +187,6 @@ TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) { display_list_bounds.join(picture2_bounds); auto save_layer_bounds = display_list_bounds.makeOffset(layer_offset.fX, layer_offset.fY); - save_layer_bounds.roundOut(&save_layer_bounds); DisplayListBuilder expected_builder; /* opacity_layer::Paint() */ { expected_builder.save(); @@ -212,7 +211,7 @@ TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) { opacity_layer->Paint(display_list_paint_context()); EXPECT_TRUE( - DisplayListsEQ_Verbose(expected_builder.Build(), this->display_list())); + DisplayListsEQ_Verbose(this->display_list(), expected_builder.Build())); } TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) { diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index aa67137db12ad..334c2f41f9cd1 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -53,15 +53,15 @@ void ImageFilterLayer::Preroll(PrerollContext* context, SkRect child_bounds = SkRect::MakeEmpty(); PrerollChildren(context, matrix, &child_bounds); - // We always paint with a saveLayer (or a cached rendering), - // so we can always apply opacity in any of those cases. - context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; - if (!filter_) { set_paint_bounds(child_bounds); return; } + // We always paint with a saveLayer (or a cached rendering), + // so we can always apply opacity in any of those cases. + context->renderable_state_flags = LayerStateStack::CALLER_CAN_APPLY_OPACITY; + const SkIRect filter_in_bounds = child_bounds.roundOut(); SkIRect filter_out_bounds; filter_->map_device_bounds(filter_in_bounds, SkMatrix::I(), diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 1dca76580a369..e3a4e86b8300b 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -69,11 +69,7 @@ TEST_F(ImageFilterLayerTest, EmptyFilter) { EXPECT_EQ(mock_canvas().draw_calls(), std::vector({ MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, filter_paint, - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}, + 0, MockCanvas::DrawPathData{child_path, child_paint}}, })); } @@ -91,7 +87,7 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { const SkRect child_rounded_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 21.0f, 22.0f); - layer->Preroll(preroll_context(), initial_transform); + layer->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(layer->paint_bounds(), child_rounded_bounds); EXPECT_EQ(layer->child_paint_bounds(), child_bounds); EXPECT_TRUE(layer->needs_painting(paint_context())); @@ -131,7 +127,7 @@ TEST_F(ImageFilterLayerTest, SimpleFilterBounds) { const SkRect filter_bounds = SkRect::MakeLTRB(10.0f, 12.0f, 42.0f, 44.0f); - layer->Preroll(preroll_context(), initial_transform); + layer->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(layer->paint_bounds(), filter_bounds); EXPECT_EQ(layer->child_paint_bounds(), child_bounds); EXPECT_TRUE(layer->needs_painting(paint_context())); @@ -176,7 +172,7 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) { children_bounds.join(child_path2.getBounds()); SkRect children_rounded_bounds = SkRect::Make(children_bounds.roundOut()); - layer->Preroll(preroll_context(), initial_transform); + layer->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); EXPECT_EQ(layer->paint_bounds(), children_rounded_bounds); @@ -237,7 +233,7 @@ TEST_F(ImageFilterLayerTest, Nested) { const SkRect mock_layer2_rounded_bounds = SkRect::Make(child_path2.getBounds().roundOut()); - layer1->Preroll(preroll_context(), initial_transform); + layer1->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds()); EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds()); EXPECT_EQ(layer1->paint_bounds(), children_rounded_bounds); @@ -445,8 +441,8 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { auto image_filter_layer = std::make_shared(dl_image_filter); image_filter_layer->Add(mock_layer); - PrerollContext* context = preroll_context(); - image_filter_layer->Preroll(preroll_context(), initial_transform); + PrerollContext* context = display_list_preroll_context(); + image_filter_layer->Preroll(context, initial_transform); // ImageFilterLayers can always inherit opacity whether or not their // children are compatible. EXPECT_EQ(context->renderable_state_flags, @@ -481,7 +477,7 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { } opacity_layer->Paint(display_list_paint_context()); - EXPECT_TRUE(DisplayListsEQ_Verbose(expected_builder.Build(), display_list())); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build())); } using ImageFilterLayerDiffTest = DiffContextTest; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 7843811275c6a..e36567500798b 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -62,7 +62,6 @@ struct PrerollContext { const Stopwatch& raster_time; const Stopwatch& ui_time; std::shared_ptr texture_registry; - const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; // These allow us to track properties like elevation, opacity, and the @@ -107,7 +106,6 @@ struct PaintContext { const Stopwatch& ui_time; std::shared_ptr texture_registry; const RasterCache* raster_cache; - const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; // Snapshot store to collect leaf layer snapshots. The store is non-null @@ -220,10 +218,6 @@ class Layer { paint_bounds_ = paint_bounds; } - const SkRect* checkerboard_bounds(PaintContext context) const { - return context.checkerboard_offscreen_layers ? &paint_bounds_ : nullptr; - } - // Determines if the layer has any content. bool is_empty() const { return paint_bounds_.isEmpty(); } diff --git a/flow/layers/layer_raster_cache_item.cc b/flow/layers/layer_raster_cache_item.cc index 57ad0c075f9f1..9f99501c453df 100644 --- a/flow/layers/layer_raster_cache_item.cc +++ b/flow/layers/layer_raster_cache_item.cc @@ -114,7 +114,6 @@ bool Rasterize(RasterCacheItem::CacheState cache_state, .ui_time = paint_context.ui_time, .texture_registry = paint_context.texture_registry, .raster_cache = paint_context.raster_cache, - .checkerboard_offscreen_layers = paint_context.checkerboard_offscreen_layers, .frame_device_pixel_ratio = paint_context.frame_device_pixel_ratio, // clang-format on }; diff --git a/flow/layers/layer_state_stack.cc b/flow/layers/layer_state_stack.cc index 89aa6e978cc47..eb8ea2735d822 100644 --- a/flow/layers/layer_state_stack.cc +++ b/flow/layers/layer_state_stack.cc @@ -138,17 +138,21 @@ void MutatorContext::applyOpacity(const SkRect& bounds, SkScalar opacity) { void MutatorContext::applyImageFilter( const SkRect& bounds, const std::shared_ptr filter) { - layer_state_stack_->push_attributes(); - layer_state_stack_->maybe_save_layer(bounds, filter); - layer_state_stack_->push_image_filter(filter); + if (filter) { + layer_state_stack_->push_attributes(); + layer_state_stack_->maybe_save_layer(bounds, filter); + layer_state_stack_->push_image_filter(filter); + } } void MutatorContext::applyColorFilter( const SkRect& bounds, const std::shared_ptr filter) { - layer_state_stack_->push_attributes(); - layer_state_stack_->maybe_save_layer(bounds, filter); - layer_state_stack_->push_color_filter(filter); + if (filter) { + layer_state_stack_->push_attributes(); + layer_state_stack_->maybe_save_layer(bounds, filter); + layer_state_stack_->push_color_filter(filter); + } } void MutatorContext::applyBackdropFilter( @@ -159,11 +163,17 @@ void MutatorContext::applyBackdropFilter( } void MutatorContext::translate(SkScalar tx, SkScalar ty) { - layer_state_stack_->push_translate(tx, ty); + if (!(tx == 0 || ty == 0)) { + layer_state_stack_->push_translate(tx, ty); + } } void MutatorContext::transform(const SkMatrix& matrix) { - layer_state_stack_->push_transform(matrix); + if (matrix.isTranslate()) { + translate(matrix.getTranslateX(), matrix.getTranslateY()); + } else if (!matrix.isIdentity()) { + layer_state_stack_->push_transform(matrix); + } } void MutatorContext::transform(const SkM44& m44) { @@ -278,7 +288,7 @@ void LayerStateStack::maybe_save_layer(const SkRect& bounds, int apply_flags) { } void LayerStateStack::maybe_save_layer(const SkRect& bounds, SkScalar opacity) { - if (outstanding_.color_filter) { + if (outstanding_.image_filter) { save_layer(bounds); } } @@ -286,7 +296,9 @@ void LayerStateStack::maybe_save_layer(const SkRect& bounds, SkScalar opacity) { void LayerStateStack::maybe_save_layer( const SkRect& bounds, const std::shared_ptr filter) { - if (outstanding_.color_filter || outstanding_.image_filter) { + if (outstanding_.color_filter || outstanding_.image_filter || + (outstanding_.opacity < SK_Scalar1 && + !filter->can_commute_with_alpha())) { // TBD: compose the 2 color filters together. save_layer(bounds); } @@ -295,8 +307,7 @@ void LayerStateStack::maybe_save_layer( void LayerStateStack::maybe_save_layer( const SkRect& bounds, const std::shared_ptr filter) { - if (outstanding_.image_filter || outstanding_.color_filter || - outstanding_.opacity < SK_Scalar1) { + if (outstanding_.image_filter) { // TBD: compose the 2 image filters together. save_layer(bounds); } diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 0f9727002d033..02563a3369890 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -61,7 +61,6 @@ bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame, .raster_time = frame.context().raster_time(), .ui_time = frame.context().ui_time(), .texture_registry = frame.context().texture_registry(), - .checkerboard_offscreen_layers = checkerboard_offscreen_layers_, .frame_device_pixel_ratio = device_pixel_ratio_, .raster_cached_entries = &raster_cache_items_, .display_list_enabled = frame.display_list_builder() != nullptr, @@ -140,7 +139,6 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, .ui_time = frame.context().ui_time(), .texture_registry = frame.context().texture_registry(), .raster_cache = cache, - .checkerboard_offscreen_layers = checkerboard_offscreen_layers_, .frame_device_pixel_ratio = device_pixel_ratio_, .layer_snapshot_store = snapshot_store, .enable_leaf_layer_tracing = enable_leaf_layer_tracing_, @@ -185,7 +183,6 @@ sk_sp LayerTree::Flatten( .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, .texture_registry = texture_registry, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_ // clang-format on }; @@ -205,7 +202,6 @@ sk_sp LayerTree::Flatten( .ui_time = unused_stopwatch, .texture_registry = texture_registry, .raster_cache = nullptr, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_, .layer_snapshot_store = nullptr, .enable_leaf_layer_tracing = false, diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index 80166ddbd3f10..76e28882ac0db 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -213,7 +213,6 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { EXPECT_EQ(&context.raster_time, &mock_raster_time); EXPECT_EQ(&context.ui_time, &mock_ui_time); EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); - EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); EXPECT_EQ(context.has_platform_view, false); @@ -251,7 +250,6 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { EXPECT_EQ(&context.ui_time, &mock_ui_time); EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); EXPECT_EQ(context.raster_cache, nullptr); - EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); EXPECT_EQ(context.enable_leaf_layer_tracing, false); diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index 269fd83965708..fad38379e78fa 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -236,11 +236,7 @@ TEST_F(OpacityLayerTest, FullyOpaque) { MockCanvas::DrawCall{ 1, MockCanvas::ConcatMatrixData{SkM44(layer_transform)}}, MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{opacity_bounds, - opacity_paint, nullptr, 2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, + 1, MockCanvas::DrawPathData{child_path, child_paint}}, MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}}); layer->Paint(paint_context()); EXPECT_EQ(mock_canvas().draw_calls(), expected_draw_calls); @@ -300,7 +296,7 @@ TEST_F(OpacityLayerTest, HalfTransparent) { auto layer = std::make_shared(alpha_half, layer_offset); layer->Add(mock_layer); - layer->Preroll(preroll_context(), initial_transform); + layer->Preroll(display_list_preroll_context(), initial_transform); EXPECT_EQ(mock_layer->paint_bounds(), child_path.getBounds()); EXPECT_EQ(layer->paint_bounds(), expected_layer_bounds); EXPECT_EQ(layer->child_paint_bounds(), child_path.getBounds()); @@ -395,11 +391,10 @@ TEST_F(OpacityLayerTest, Nested) { opacity1_paint.setAlphaf(alpha1 * (1.0 / SK_AlphaOPAQUE)); SkPaint opacity2_paint; opacity2_paint.setAlphaf(alpha2 * (1.0 / SK_AlphaOPAQUE)); - SkRect opacity1_bounds, opacity2_bounds; - expected_layer1_bounds.makeOffset(-layer1_offset.fX, -layer1_offset.fY) - .roundOut(&opacity1_bounds); - expected_layer2_bounds.makeOffset(-layer2_offset.fX, -layer2_offset.fY) - .roundOut(&opacity2_bounds); + SkRect opacity1_bounds = + expected_layer1_bounds.makeOffset(-layer1_offset.fX, -layer1_offset.fY); + SkRect opacity2_bounds = + expected_layer2_bounds.makeOffset(-layer2_offset.fX, -layer2_offset.fY); auto expected_draw_calls = std::vector( {MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, MockCanvas::DrawCall{ @@ -497,11 +492,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughContainer) { opacityLayer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); - // By default a container layer will not pass opacity through to - // its children - specific subclasses will have to enable this - // pass through by setting the flag to true themselves before - // calling their super method ContainerLayer::Preroll(). - EXPECT_FALSE(opacityLayer->children_can_accept_opacity()); + EXPECT_TRUE(opacityLayer->children_can_accept_opacity()); } TEST_F(OpacityLayerTest, OpacityInheritanceThroughTransform) { @@ -545,7 +536,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithCompatibleChild) { opacityLayer2->Add(mockLayer); opacityLayer1->Add(opacityLayer2); - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); opacityLayer1->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); @@ -557,6 +548,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithCompatibleChild) { inheritedOpacity *= 64 * 1.0 / SK_AlphaOPAQUE; saveLayerPaint.setAlphaf(inheritedOpacity); + DlPaint mock_paint = DlPaint().setAlpha(saveLayerPaint.getAlpha()); DisplayListBuilder expected_builder; /* opacityLayer1::Paint */ { expected_builder.save(); @@ -567,13 +559,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithCompatibleChild) { { expected_builder.translate(offset2.fX, offset2.fY); /* mockLayer::Paint */ { - expected_builder.setColor(saveLayerPaint.getAlpha() << 24); - expected_builder.saveLayer(&mockPath.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(mockPath); - } - expected_builder.restore(); + expected_builder.drawPath(mockPath, mock_paint); } } expected_builder.restore(); @@ -596,7 +582,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceNestedWithIncompatibleChild) { opacityLayer2->Add(mockLayer); opacityLayer1->Add(opacityLayer2); - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); opacityLayer1->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index 83e893cf0d39f..a390dd637f7f4 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -71,7 +71,6 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { .ui_time = mock_stopwatch, .texture_registry = nullptr, .raster_cache = nullptr, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, // clang-format on }; diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index e9ab4b3f2a5df..3af230e7d2433 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -354,10 +354,9 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { shader_mask_layer->Add(mock_layer); // ShaderMaskLayers can always support opacity despite incompatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); shader_mask_layer->Preroll(context, SkMatrix::I()); - EXPECT_EQ(context->renderable_state_flags, - LayerStateStack::CALLER_CAN_APPLY_OPACITY); + EXPECT_EQ(context->renderable_state_flags, Layer::SAVE_LAYER_RENDER_FLAGS); int opacity_alpha = 0x7F; SkPoint offset = SkPoint::Make(10, 10); diff --git a/flow/layers/transform_layer_unittests.cc b/flow/layers/transform_layer_unittests.cc index f578c448a75c8..fd13d520cec05 100644 --- a/flow/layers/transform_layer_unittests.cc +++ b/flow/layers/transform_layer_unittests.cc @@ -296,7 +296,7 @@ TEST_F(TransformLayerTest, OpacityInheritancePainting) { // TransformLayer will pass through compatibility from multiple // non-overlapping compatible children - PrerollContext* context = preroll_context(); + PrerollContext* context = display_list_preroll_context(); transform_layer->Preroll(context, SkMatrix::I()); EXPECT_EQ(context->renderable_state_flags, LayerStateStack::CALLER_CAN_APPLY_OPACITY); @@ -308,6 +308,7 @@ TEST_F(TransformLayerTest, OpacityInheritancePainting) { opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); + DlPaint mock_paint = DlPaint().setAlpha(opacity_alpha); DisplayListBuilder expected_builder; /* opacity_layer paint */ { expected_builder.save(); @@ -315,26 +316,16 @@ TEST_F(TransformLayerTest, OpacityInheritancePainting) { expected_builder.translate(offset.fX, offset.fY); /* transform_layer paint */ { expected_builder.save(); - expected_builder.transform(transform); - /* child layer1 paint */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path1.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path1); + { + expected_builder.transform(transform); + /* child layer1 paint */ { + expected_builder.drawPath(path1, mock_paint); } - expected_builder.restore(); - } - /* child layer2 paint */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&path2.getBounds(), true); - { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(path2); + /* child layer2 paint */ { + expected_builder.drawPath(path2, mock_paint); } expected_builder.restore(); } - expected_builder.restore(); } } expected_builder.restore(); diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index 24d85cf62aa7e..ee9b52f442987 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -58,10 +58,10 @@ class LayerTestBase : public CanvasTestBase { .raster_time = raster_time_, .ui_time = ui_time_, .texture_registry = texture_registry_, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .has_platform_view = false, .raster_cached_entries = &cacheable_items_, + .display_list_enabled = false, // clang-format on }, paint_context_{ @@ -74,11 +74,28 @@ class LayerTestBase : public CanvasTestBase { .ui_time = ui_time_, .texture_registry = texture_registry_, .raster_cache = nullptr, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, // clang-format on }, display_list_recorder_(kDlBounds), + display_list_preroll_context_{ + // clang-format off + .raster_cache = nullptr, + .gr_context = nullptr, + .view_embedder = nullptr, + .mutators_stack = mutators_stack_, + .dst_color_space = TestT::mock_color_space(), + .cull_rect = kGiantRect, + .surface_needs_readback = false, + .raster_time = raster_time_, + .ui_time = ui_time_, + .texture_registry = texture_registry_, + .frame_device_pixel_ratio = 1.0f, + .has_platform_view = false, + .raster_cached_entries = &cacheable_items_, + .display_list_enabled = true, + // clang-format on + }, display_list_paint_context_{ // clang-format off .state_stack = display_list_state_stack_, @@ -89,14 +106,13 @@ class LayerTestBase : public CanvasTestBase { .ui_time = ui_time_, .texture_registry = texture_registry_, .raster_cache = nullptr, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .builder = display_list_recorder_.builder().get(), // clang-format on }, - check_board_context_{ + checkerboard_context_{ // clang-format off - .state_stack = canvas_state_stack_, + .state_stack = checkerboard_state_stack_, .canvas = &TestT::mock_canvas(), .gr_context = nullptr, .view_embedder = nullptr, @@ -104,12 +120,13 @@ class LayerTestBase : public CanvasTestBase { .ui_time = ui_time_, .texture_registry = texture_registry_, .raster_cache = nullptr, - .checkerboard_offscreen_layers = true, .frame_device_pixel_ratio = 1.0f, // clang-format on } { canvas_state_stack_.set_canvas_delegate(&TestT::mock_canvas()); display_list_state_stack_.set_builder_delegate(display_list_recorder_); + checkerboard_state_stack_.set_canvas_delegate(&TestT::mock_canvas()); + checkerboard_state_stack_.set_checkerboard_save_layers(true); use_null_raster_cache(); } @@ -170,10 +187,13 @@ class LayerTestBase : public CanvasTestBase { RasterCache* raster_cache() { return raster_cache_.get(); } PrerollContext* preroll_context() { return &preroll_context_; } PaintContext& paint_context() { return paint_context_; } + PrerollContext* display_list_preroll_context() { + return &display_list_preroll_context_; + } PaintContext& display_list_paint_context() { return display_list_paint_context_; } - PaintContext& check_board_context() { return check_board_context_; } + PaintContext& checkerboard_context() { return checkerboard_context_; } LayerSnapshotStore& layer_snapshot_store() { return snapshot_store_; } sk_sp display_list() { @@ -217,8 +237,10 @@ class LayerTestBase : public CanvasTestBase { DisplayListCanvasRecorder display_list_recorder_; sk_sp display_list_; LayerStateStack display_list_state_stack_; + PrerollContext display_list_preroll_context_; PaintContext display_list_paint_context_; - PaintContext check_board_context_; + LayerStateStack checkerboard_state_stack_; + PaintContext checkerboard_context_; LayerSnapshotStore snapshot_store_; std::vector cacheable_items_; diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index e3baf4493d64f..e6f97990d7252 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -105,7 +105,6 @@ PrerollContextHolder GetSamplePrerollContextHolder( .raster_time = *raster_time, .ui_time = *ui_time, .texture_registry = nullptr, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .has_platform_view = false, .has_texture_layer = false, @@ -134,7 +133,6 @@ PaintContextHolder GetSamplePaintContextHolder( .ui_time = *ui_time, .texture_registry = nullptr, .raster_cache = raster_cache, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, }, // clang-format on diff --git a/flow/testing/mock_raster_cache.h b/flow/testing/mock_raster_cache.h index 5f83b85b3b6f1..4fc3d0c534e9d 100644 --- a/flow/testing/mock_raster_cache.h +++ b/flow/testing/mock_raster_cache.h @@ -86,7 +86,6 @@ class MockRasterCache : public RasterCache { .raster_time = raster_time_, .ui_time = ui_time_, .texture_registry = texture_registry_, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .has_platform_view = false, .has_texture_layer = false, @@ -105,7 +104,6 @@ class MockRasterCache : public RasterCache { .ui_time = ui_time_, .texture_registry = texture_registry_, .raster_cache = nullptr, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, // clang-format on }; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index c3a8e625f4df6..217ba9051d489 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -2394,7 +2394,6 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .ui_time = ui_time, .texture_registry = nullptr, .raster_cache = &raster_cache, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, // clang-format on }; @@ -2411,7 +2410,6 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .raster_time = raster_time, .ui_time = ui_time, .texture_registry = nullptr, - .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .has_platform_view = false, .has_texture_layer = false,