diff --git a/display_list/display_list.cc b/display_list/display_list.cc index dfacba0c114f0..363b32d543088 100644 --- a/display_list/display_list.cc +++ b/display_list/display_list.cc @@ -19,6 +19,7 @@ DisplayList::DisplayList() op_count_(0), nested_byte_count_(0), nested_op_count_(0), + total_depth_(0), unique_id_(0), bounds_({0, 0, 0, 0}), can_apply_group_opacity_(true), @@ -27,9 +28,10 @@ DisplayList::DisplayList() DisplayList::DisplayList(DisplayListStorage&& storage, size_t byte_count, - unsigned int op_count, + uint32_t op_count, size_t nested_byte_count, - unsigned int nested_op_count, + uint32_t nested_op_count, + uint32_t total_depth, const SkRect& bounds, bool can_apply_group_opacity, bool is_ui_thread_safe, @@ -40,6 +42,7 @@ DisplayList::DisplayList(DisplayListStorage&& storage, op_count_(op_count), nested_byte_count_(nested_byte_count), nested_op_count_(nested_op_count), + total_depth_(total_depth), unique_id_(next_unique_id()), bounds_(bounds), can_apply_group_opacity_(can_apply_group_opacity), diff --git a/display_list/display_list.h b/display_list/display_list.h index fe12048418972..136b36c883063 100644 --- a/display_list/display_list.h +++ b/display_list/display_list.h @@ -274,10 +274,12 @@ class DisplayList : public SkRefCnt { (nested ? nested_byte_count_ : 0); } - unsigned int op_count(bool nested = false) const { + uint32_t op_count(bool nested = false) const { return op_count_ + (nested ? nested_op_count_ : 0); } + uint32_t total_depth() const { return total_depth_; } + uint32_t unique_id() const { return unique_id_; } const SkRect& bounds() const { return bounds_; } @@ -310,9 +312,10 @@ class DisplayList : public SkRefCnt { private: DisplayList(DisplayListStorage&& ptr, size_t byte_count, - unsigned int op_count, + uint32_t op_count, size_t nested_byte_count, - unsigned int nested_op_count, + uint32_t nested_op_count, + uint32_t total_depth, const SkRect& bounds, bool can_apply_group_opacity, bool is_ui_thread_safe, @@ -325,10 +328,12 @@ class DisplayList : public SkRefCnt { const DisplayListStorage storage_; const size_t byte_count_; - const unsigned int op_count_; + const uint32_t op_count_; const size_t nested_byte_count_; - const unsigned int nested_op_count_; + const uint32_t nested_op_count_; + + const uint32_t total_depth_; const uint32_t unique_id_; const SkRect bounds_; diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index cc1912e877220..1cba278a635f7 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -65,8 +65,9 @@ class DisplayListTestBase : public BaseT { DisplayListBuilder builder; DlOpReceiver& receiver = DisplayListTestBase<::testing::Test>::ToReceiver(builder); - unsigned int op_count = 0; + uint32_t op_count = 0; size_t byte_count = 0; + uint32_t depth = 0; for (size_t i = 0; i < allGroups.size(); i++) { DisplayListInvocationGroup& group = allGroups[i]; size_t j = (i == g_index ? v_index : 0); @@ -76,6 +77,7 @@ class DisplayListTestBase : public BaseT { DisplayListInvocation& invocation = group.variants[j]; op_count += invocation.op_count(); byte_count += invocation.raw_byte_count(); + depth += invocation.depth(); invocation.invoker(receiver); } sk_sp dl = builder.Build(); @@ -92,6 +94,7 @@ class DisplayListTestBase : public BaseT { } EXPECT_EQ(dl->op_count(false), op_count) << name; EXPECT_EQ(dl->bytes(false), byte_count + sizeof(DisplayList)) << name; + EXPECT_EQ(dl->total_depth(), depth) << name; return dl; } @@ -231,6 +234,7 @@ TEST_F(DisplayListTest, EmptyBuild) { auto dl = builder.Build(); EXPECT_EQ(dl->op_count(), 0u); EXPECT_EQ(dl->bytes(), sizeof(DisplayList)); + EXPECT_EQ(dl->total_depth(), 0u); } TEST_F(DisplayListTest, EmptyRebuild) { @@ -526,6 +530,7 @@ TEST_F(DisplayListTest, UnclippedSaveLayerContentAccountsForFilter) { auto display_list = builder.Build(); ASSERT_EQ(display_list->op_count(), 6u); + EXPECT_EQ(display_list->total_depth(), 2u); SkRect result_rect = draw_rect.makeOutset(30.0f, 30.0f); ASSERT_TRUE(result_rect.intersect(clip_rect)); @@ -558,6 +563,7 @@ TEST_F(DisplayListTest, ClippedSaveLayerContentAccountsForFilter) { auto display_list = builder.Build(); ASSERT_EQ(display_list->op_count(), 6u); + EXPECT_EQ(display_list->total_depth(), 2u); SkRect result_rect = draw_rect.makeOutset(30.0f, 30.0f); ASSERT_TRUE(result_rect.intersect(clip_rect)); @@ -573,6 +579,7 @@ TEST_F(DisplayListTest, SingleOpSizes) { auto desc = group.op_name + "(variant " + std::to_string(i + 1) + ")"; ASSERT_EQ(dl->op_count(false), invocation.op_count()) << desc; ASSERT_EQ(dl->bytes(false), invocation.byte_count()) << desc; + EXPECT_EQ(dl->total_depth(), invocation.depth()) << desc; } } } @@ -611,6 +618,7 @@ TEST_F(DisplayListTest, SingleOpDisplayListsRecapturedAreEqual) { ASSERT_EQ(copy->bytes(false), dl->bytes(false)) << desc; ASSERT_EQ(copy->op_count(true), dl->op_count(true)) << desc; ASSERT_EQ(copy->bytes(true), dl->bytes(true)) << desc; + EXPECT_EQ(copy->total_depth(), dl->total_depth()) << desc; ASSERT_EQ(copy->bounds(), dl->bounds()) << desc; ASSERT_TRUE(copy->Equals(*dl)) << desc; ASSERT_TRUE(dl->Equals(*copy)) << desc; @@ -640,6 +648,7 @@ TEST_F(DisplayListTest, SingleOpDisplayListsCompareToEachOther) { ASSERT_EQ(listA->bytes(false), listB->bytes(false)) << desc; ASSERT_EQ(listA->op_count(true), listB->op_count(true)) << desc; ASSERT_EQ(listA->bytes(true), listB->bytes(true)) << desc; + EXPECT_EQ(listA->total_depth(), listB->total_depth()) << desc; ASSERT_EQ(listA->bounds(), listB->bounds()) << desc; ASSERT_TRUE(listA->Equals(*listB)) << desc; ASSERT_TRUE(listB->Equals(*listA)) << desc; @@ -669,7 +678,9 @@ TEST_F(DisplayListTest, SingleOpDisplayListsAreEqualWithOrWithoutRtree) { ASSERT_EQ(dl1->bytes(false), dl2->bytes(false)) << desc; ASSERT_EQ(dl1->op_count(true), dl2->op_count(true)) << desc; ASSERT_EQ(dl1->bytes(true), dl2->bytes(true)) << desc; + EXPECT_EQ(dl1->total_depth(), dl2->total_depth()) << desc; ASSERT_EQ(dl1->bounds(), dl2->bounds()) << desc; + ASSERT_EQ(dl1->total_depth(), dl2->total_depth()) << desc; ASSERT_TRUE(DisplayListsEQ_Verbose(dl1, dl2)) << desc; ASSERT_TRUE(DisplayListsEQ_Verbose(dl2, dl2)) << desc; ASSERT_EQ(dl1->rtree().get(), nullptr) << desc; @@ -691,6 +702,7 @@ TEST_F(DisplayListTest, FullRotationsAreNop) { ASSERT_EQ(dl->bytes(true), sizeof(DisplayList)); ASSERT_EQ(dl->op_count(false), 0u); ASSERT_EQ(dl->op_count(true), 0u); + EXPECT_EQ(dl->total_depth(), 0u); } TEST_F(DisplayListTest, AllBlendModeNops) { @@ -702,6 +714,7 @@ TEST_F(DisplayListTest, AllBlendModeNops) { ASSERT_EQ(dl->bytes(true), sizeof(DisplayList)); ASSERT_EQ(dl->op_count(false), 0u); ASSERT_EQ(dl->op_count(true), 0u); + EXPECT_EQ(dl->total_depth(), 0u); } TEST_F(DisplayListTest, DisplayListsWithVaryingOpComparisons) { @@ -933,13 +946,15 @@ TEST_F(DisplayListTest, NestedOpCountMetricsSameAsSkPicture) { receiver.drawRect(SkRect::MakeXYWH(x, y, 80, 80)); } } + DisplayListBuilder outer_builder(SkRect::MakeWH(150, 100)); DlOpReceiver& outer_receiver = ToReceiver(outer_builder); outer_receiver.drawDisplayList(builder.Build()); - auto display_list = outer_builder.Build(); + ASSERT_EQ(display_list->op_count(), 1u); ASSERT_EQ(display_list->op_count(true), 36u); + EXPECT_EQ(display_list->total_depth(), 37u); ASSERT_EQ(picture->approximateOpCount(), static_cast(display_list->op_count())); @@ -1556,6 +1571,7 @@ TEST_F(DisplayListTest, FlutterSvgIssue661BoundsWereEmpty) { EXPECT_EQ(display_list->bounds().roundOut(), SkIRect::MakeWH(100, 100)); EXPECT_EQ(display_list->op_count(), 19u); EXPECT_EQ(display_list->bytes(), sizeof(DisplayList) + 400u); + EXPECT_EQ(display_list->total_depth(), 3u); } TEST_F(DisplayListTest, TranslateAffectsCurrentTransform) { @@ -3084,11 +3100,13 @@ TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCCW) { TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { auto run_tests = [](const std::string& name, void init(DisplayListBuilder & builder, DlPaint & paint), - uint32_t expected_op_count = 0u) { + uint32_t expected_op_count = 0u, + uint32_t expected_total_depth = 0u) { auto run_one_test = [init](const std::string& name, void build(DisplayListBuilder & builder, DlPaint & paint), - uint32_t expected_op_count = 0u) { + uint32_t expected_op_count = 0u, + uint32_t expected_total_depth = 0u) { DisplayListBuilder builder; DlPaint paint; init(builder, paint); @@ -3098,6 +3116,7 @@ TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { FML_LOG(ERROR) << *list; } ASSERT_EQ(list->op_count(), expected_op_count) << name; + EXPECT_EQ(list->total_depth(), expected_total_depth) << name; ASSERT_TRUE(list->bounds().isEmpty()) << name; }; run_one_test( @@ -3105,19 +3124,19 @@ TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { [](DisplayListBuilder& builder, DlPaint& paint) { builder.DrawColor(paint.getColor(), paint.getBlendMode()); }, - expected_op_count); + expected_op_count, expected_total_depth); run_one_test( name + " DrawPaint", [](DisplayListBuilder& builder, DlPaint& paint) { builder.DrawPaint(paint); }, - expected_op_count); + expected_op_count, expected_total_depth); run_one_test( name + " DrawRect", [](DisplayListBuilder& builder, DlPaint& paint) { builder.DrawRect({10, 10, 20, 20}, paint); }, - expected_op_count); + expected_op_count, expected_total_depth); run_one_test( name + " Other Draw Ops", [](DisplayListBuilder& builder, DlPaint& paint) { @@ -3155,7 +3174,7 @@ TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { builder.DrawShadow(kTestPath1, paint.getColor(), 1, true, 1); } }, - expected_op_count); + expected_op_count, expected_total_depth); run_one_test( name + " SaveLayer", [](DisplayListBuilder& builder, DlPaint& paint) { @@ -3163,7 +3182,7 @@ TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { builder.DrawRect({10, 10, 20, 20}, DlPaint()); builder.Restore(); }, - expected_op_count); + expected_op_count, expected_total_depth); run_one_test( name + " inside Save", [](DisplayListBuilder& builder, DlPaint& paint) { @@ -3171,7 +3190,7 @@ TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { builder.DrawRect({10, 10, 20, 20}, paint); builder.Restore(); }, - expected_op_count); + expected_op_count, expected_total_depth); }; run_tests("transparent color", // [](DisplayListBuilder& builder, DlPaint& paint) { @@ -3230,7 +3249,7 @@ TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { builder.SaveLayer(nullptr, nullptr); paint.setBlendMode(DlBlendMode::kDst); }, - 2u); + 2u, 1u); run_tests("DrawImage inside Culled SaveLayer", // [](DisplayListBuilder& builder, DlPaint& paint) { DlPaint save_paint; @@ -3781,5 +3800,87 @@ TEST_F(DisplayListTest, SaveLayerBoundsClipDetectionSimpleClippedRect) { EXPECT_TRUE(expector.all_bounds_checked()); } +class DepthExpector : public virtual DlOpReceiver, + virtual IgnoreAttributeDispatchHelper, + virtual IgnoreTransformDispatchHelper, + virtual IgnoreClipDispatchHelper, + virtual IgnoreDrawDispatchHelper { + public: + explicit DepthExpector(std::vector expectations) + : depth_expectations_(std::move(expectations)) {} + + void save() override { + // This method should not be called since we override the variant with + // the total_content_depth parameter. + FAIL() << "save(no depth parameter) method should not be called"; + } + + void save(uint32_t total_content_depth) override { + ASSERT_LT(index_, depth_expectations_.size()); + EXPECT_EQ(depth_expectations_[index_], total_content_depth) + << "at index " << index_; + index_++; + } + + void saveLayer(const SkRect& bounds, + SaveLayerOptions options, + const DlImageFilter* backdrop) override { + // This method should not be called since we override the variant with + // the total_content_depth parameter. + FAIL() << "saveLayer(no depth parameter) method should not be called"; + } + + void saveLayer(const SkRect& bounds, + const SaveLayerOptions& options, + uint32_t total_content_depth, + const DlImageFilter* backdrop) override { + ASSERT_LT(index_, depth_expectations_.size()); + EXPECT_EQ(depth_expectations_[index_], total_content_depth) + << "at index " << index_; + index_++; + } + + private: + size_t index_ = 0; + std::vector depth_expectations_; +}; + +TEST_F(DisplayListTest, SaveContentDepthTest) { + DisplayListBuilder child_builder; + child_builder.DrawRect({10, 10, 20, 20}, DlPaint()); // depth 1 + auto child = child_builder.Build(); + + DisplayListBuilder builder; + builder.DrawRect({10, 10, 20, 20}, DlPaint()); // depth 1 + + builder.Save(); // covers depth 1->9 + { + builder.Translate(5, 5); + builder.DrawRect({10, 10, 20, 20}, DlPaint()); // depth 2 + + builder.DrawDisplayList(child, 1.0f); // depth 3 (content) + 4 (self) + + builder.SaveLayer(nullptr, nullptr); // covers depth 5->6 + { + builder.DrawRect({12, 12, 22, 22}, DlPaint()); // depth 5 + builder.DrawRect({14, 14, 24, 24}, DlPaint()); // depth 6 + } + builder.Restore(); // layer is restored with depth 7 + + builder.DrawRect({16, 16, 26, 26}, DlPaint()); // depth 8 + builder.DrawRect({18, 18, 28, 28}, DlPaint()); // depth 9 + } + builder.Restore(); + + builder.DrawRect({16, 16, 26, 26}, DlPaint()); // depth 10 + builder.DrawRect({18, 18, 28, 28}, DlPaint()); // depth 11 + auto display_list = builder.Build(); + + EXPECT_EQ(display_list->total_depth(), 11u); + + DepthExpector expector({8, 2}); + display_list->Dispatch(expector); +} + } // namespace testing } // namespace flutter diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index de079b9ccb124..0910708304db6 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -40,7 +40,7 @@ static constexpr inline bool is_power_of_two(int value) { } template -void* DisplayListBuilder::Push(size_t pod, int render_op_inc, Args&&... args) { +void* DisplayListBuilder::Push(size_t pod, Args&&... args) { size_t size = SkAlignPtr(sizeof(T) + pod); FML_DCHECK(size < (1 << 24)); if (used_ + size > allocated_) { @@ -58,7 +58,8 @@ void* DisplayListBuilder::Push(size_t pod, int render_op_inc, Args&&... args) { new (op) T{std::forward(args)...}; op->type = T::kType; op->size = size; - render_op_count_ += render_op_inc; + render_op_count_ += T::kRenderOpInc; + depth_ += T::kDepthInc; op_index_++; return op + 1; } @@ -72,6 +73,7 @@ sk_sp DisplayListBuilder::Build() { int count = render_op_count_; size_t nested_bytes = nested_bytes_; int nested_count = nested_op_count_; + uint32_t total_depth = depth_; bool compatible = current_layer_->is_group_opacity_compatible(); bool is_safe = is_ui_thread_safe_; bool affects_transparency = current_layer_->affects_transparent_layer(); @@ -81,6 +83,7 @@ sk_sp DisplayListBuilder::Build() { used_ = allocated_ = render_op_count_ = op_index_ = 0; nested_bytes_ = nested_op_count_ = 0; + depth_ = 0; is_ui_thread_safe_ = true; storage_.realloc(bytes); layer_stack_.pop_back(); @@ -90,9 +93,10 @@ sk_sp DisplayListBuilder::Build() { layer_tracker_.reset(); current_ = DlPaint(); - return sk_sp(new DisplayList( - std::move(storage_), bytes, count, nested_bytes, nested_count, bounds, - compatible, is_safe, affects_transparency, std::move(rtree))); + return sk_sp( + new DisplayList(std::move(storage_), bytes, count, nested_bytes, + nested_count, total_depth, bounds, compatible, is_safe, + affects_transparency, std::move(rtree))); } DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect, @@ -126,47 +130,47 @@ SkImageInfo DisplayListBuilder::GetImageInfo() const { void DisplayListBuilder::onSetAntiAlias(bool aa) { current_.setAntiAlias(aa); - Push(0, 0, aa); + Push(0, aa); } void DisplayListBuilder::onSetInvertColors(bool invert) { current_.setInvertColors(invert); - Push(0, 0, invert); + Push(0, invert); UpdateCurrentOpacityCompatibility(); } void DisplayListBuilder::onSetStrokeCap(DlStrokeCap cap) { current_.setStrokeCap(cap); - Push(0, 0, cap); + Push(0, cap); } void DisplayListBuilder::onSetStrokeJoin(DlStrokeJoin join) { current_.setStrokeJoin(join); - Push(0, 0, join); + Push(0, join); } void DisplayListBuilder::onSetDrawStyle(DlDrawStyle style) { current_.setDrawStyle(style); - Push(0, 0, style); + Push(0, style); } void DisplayListBuilder::onSetStrokeWidth(float width) { current_.setStrokeWidth(width); - Push(0, 0, width); + Push(0, width); } void DisplayListBuilder::onSetStrokeMiter(float limit) { current_.setStrokeMiter(limit); - Push(0, 0, limit); + Push(0, limit); } void DisplayListBuilder::onSetColor(DlColor color) { current_.setColor(color); - Push(0, 0, color); + Push(0, color); } void DisplayListBuilder::onSetBlendMode(DlBlendMode mode) { current_.setBlendMode(mode); - Push(0, 0, mode); + Push(0, mode); UpdateCurrentOpacityCompatibility(); } void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { if (source == nullptr) { current_.setColorSource(nullptr); - Push(0, 0); + Push(0); } else { current_.setColorSource(source->shared()); is_ui_thread_safe_ = is_ui_thread_safe_ && source->isUIThreadSafe(); @@ -180,20 +184,20 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { case DlColorSourceType::kImage: { const DlImageColorSource* image_source = source->asImage(); FML_DCHECK(image_source); - Push(0, 0, image_source); + Push(0, image_source); break; } case DlColorSourceType::kLinearGradient: { const DlLinearGradientColorSource* linear = source->asLinearGradient(); FML_DCHECK(linear); - void* pod = Push(linear->size(), 0); + void* pod = Push(linear->size()); new (pod) DlLinearGradientColorSource(linear); break; } case DlColorSourceType::kRadialGradient: { const DlRadialGradientColorSource* radial = source->asRadialGradient(); FML_DCHECK(radial); - void* pod = Push(radial->size(), 0); + void* pod = Push(radial->size()); new (pod) DlRadialGradientColorSource(radial); break; } @@ -201,28 +205,28 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { const DlConicalGradientColorSource* conical = source->asConicalGradient(); FML_DCHECK(conical); - void* pod = Push(conical->size(), 0); + void* pod = Push(conical->size()); new (pod) DlConicalGradientColorSource(conical); break; } case DlColorSourceType::kSweepGradient: { const DlSweepGradientColorSource* sweep = source->asSweepGradient(); FML_DCHECK(sweep); - void* pod = Push(sweep->size(), 0); + void* pod = Push(sweep->size()); new (pod) DlSweepGradientColorSource(sweep); break; } case DlColorSourceType::kRuntimeEffect: { const DlRuntimeEffectColorSource* effect = source->asRuntimeEffect(); FML_DCHECK(effect); - Push(0, 0, effect); + Push(0, effect); break; } #ifdef IMPELLER_ENABLE_3D case DlColorSourceType::kScene: { const DlSceneColorSource* scene = source->asScene(); FML_DCHECK(scene); - Push(0, 0, scene); + Push(0, scene); break; } #endif // IMPELLER_ENABLE_3D @@ -232,42 +236,42 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) { if (filter == nullptr) { current_.setImageFilter(nullptr); - Push(0, 0); + Push(0); } else { current_.setImageFilter(filter->shared()); switch (filter->type()) { case DlImageFilterType::kBlur: { const DlBlurImageFilter* blur_filter = filter->asBlur(); FML_DCHECK(blur_filter); - void* pod = Push(blur_filter->size(), 0); + void* pod = Push(blur_filter->size()); new (pod) DlBlurImageFilter(blur_filter); break; } case DlImageFilterType::kDilate: { const DlDilateImageFilter* dilate_filter = filter->asDilate(); FML_DCHECK(dilate_filter); - void* pod = Push(dilate_filter->size(), 0); + void* pod = Push(dilate_filter->size()); new (pod) DlDilateImageFilter(dilate_filter); break; } case DlImageFilterType::kErode: { const DlErodeImageFilter* erode_filter = filter->asErode(); FML_DCHECK(erode_filter); - void* pod = Push(erode_filter->size(), 0); + void* pod = Push(erode_filter->size()); new (pod) DlErodeImageFilter(erode_filter); break; } case DlImageFilterType::kMatrix: { const DlMatrixImageFilter* matrix_filter = filter->asMatrix(); FML_DCHECK(matrix_filter); - void* pod = Push(matrix_filter->size(), 0); + void* pod = Push(matrix_filter->size()); new (pod) DlMatrixImageFilter(matrix_filter); break; } case DlImageFilterType::kCompose: case DlImageFilterType::kLocalMatrix: case DlImageFilterType::kColorFilter: { - Push(0, 0, filter); + Push(0, filter); break; } } @@ -276,31 +280,31 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) { void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) { if (filter == nullptr) { current_.setColorFilter(nullptr); - Push(0, 0); + Push(0); } else { current_.setColorFilter(filter->shared()); switch (filter->type()) { case DlColorFilterType::kBlend: { const DlBlendColorFilter* blend_filter = filter->asBlend(); FML_DCHECK(blend_filter); - void* pod = Push(blend_filter->size(), 0); + void* pod = Push(blend_filter->size()); new (pod) DlBlendColorFilter(blend_filter); break; } case DlColorFilterType::kMatrix: { const DlMatrixColorFilter* matrix_filter = filter->asMatrix(); FML_DCHECK(matrix_filter); - void* pod = Push(matrix_filter->size(), 0); + void* pod = Push(matrix_filter->size()); new (pod) DlMatrixColorFilter(matrix_filter); break; } case DlColorFilterType::kSrgbToLinearGamma: { - void* pod = Push(filter->size(), 0); + void* pod = Push(filter->size()); new (pod) DlSrgbToLinearGammaColorFilter(); break; } case DlColorFilterType::kLinearToSrgbGamma: { - void* pod = Push(filter->size(), 0); + void* pod = Push(filter->size()); new (pod) DlLinearToSrgbGammaColorFilter(); break; } @@ -311,13 +315,13 @@ void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) { void DisplayListBuilder::onSetPathEffect(const DlPathEffect* effect) { if (effect == nullptr) { current_.setPathEffect(nullptr); - Push(0, 0); + Push(0); } else { current_.setPathEffect(effect->shared()); switch (effect->type()) { case DlPathEffectType::kDash: { const DlDashPathEffect* dash_effect = effect->asDash(); - void* pod = Push(dash_effect->size(), 0); + void* pod = Push(dash_effect->size()); new (pod) DlDashPathEffect(dash_effect); break; } @@ -327,14 +331,14 @@ void DisplayListBuilder::onSetPathEffect(const DlPathEffect* effect) { void DisplayListBuilder::onSetMaskFilter(const DlMaskFilter* filter) { if (filter == nullptr) { current_.setMaskFilter(nullptr); - Push(0, 0); + Push(0); } else { current_.setMaskFilter(filter->shared()); switch (filter->type()) { case DlMaskFilterType::kBlur: { const DlBlurMaskFilter* blur_filter = filter->asBlur(); FML_DCHECK(blur_filter); - void* pod = Push(blur_filter->size(), 0); + void* pod = Push(blur_filter->size()); new (pod) DlBlurMaskFilter(blur_filter); break; } @@ -384,8 +388,9 @@ void DisplayListBuilder::SetAttributesFromPaint( void DisplayListBuilder::checkForDeferredSave() { if (current_layer_->has_deferred_save_op_) { size_t save_offset_ = used_; - Push(0, 1); + Push(0); current_layer_->save_offset_ = save_offset_; + current_layer_->start_depth_ = depth_; current_layer_->has_deferred_save_op_ = false; } } @@ -429,7 +434,14 @@ void DisplayListBuilder::Restore() { if (!current_layer_->has_deferred_save_op_) { op->restore_index = op_index_; - Push(0, 1); + op->total_content_depth = depth_ - current_layer_->start_depth_; + Push(0); + if (current_layer_->is_save_layer()) { + // A saveLayer will usually do a final copy to the main buffer in + // addition to its content, but that is accounted for outside of + // the total content depth computed above. + depth_++; + } } std::shared_ptr filter = current_layer_->filter(); @@ -595,11 +607,11 @@ void DisplayListBuilder::saveLayer(const SkRect& bounds, FML_DCHECK(unclipped); } CheckLayerOpacityCompatibility(true); - layer_stack_.emplace_back(save_layer_offset); + layer_stack_.emplace_back(save_layer_offset, depth_); layer_stack_.back().filter_ = current_.getImageFilter(); } else { CheckLayerOpacityCompatibility(false); - layer_stack_.emplace_back(save_layer_offset); + layer_stack_.emplace_back(save_layer_offset, depth_); } current_layer_ = &layer_stack_.back(); current_layer_->is_save_layer_ = true; @@ -636,9 +648,9 @@ void DisplayListBuilder::saveLayer(const SkRect& bounds, // when we tested the PaintResult. [[maybe_unused]] bool unclipped = AccumulateUnbounded(); FML_DCHECK(unclipped); - Push(0, 1, options, record_bounds, backdrop); + Push(0, options, record_bounds, backdrop); } else { - Push(0, 1, options, record_bounds); + Push(0, options, record_bounds); } if (options.renders_with_attributes()) { @@ -696,7 +708,7 @@ void DisplayListBuilder::Translate(SkScalar tx, SkScalar ty) { if (SkScalarIsFinite(tx) && SkScalarIsFinite(ty) && (tx != 0.0 || ty != 0.0)) { checkForDeferredSave(); - Push(0, 1, tx, ty); + Push(0, tx, ty); tracker_.translate(tx, ty); if (layer_tracker_) { layer_tracker_->translate(tx, ty); @@ -707,7 +719,7 @@ void DisplayListBuilder::Scale(SkScalar sx, SkScalar sy) { if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) && (sx != 1.0 || sy != 1.0)) { checkForDeferredSave(); - Push(0, 1, sx, sy); + Push(0, sx, sy); tracker_.scale(sx, sy); if (layer_tracker_) { layer_tracker_->scale(sx, sy); @@ -717,7 +729,7 @@ void DisplayListBuilder::Scale(SkScalar sx, SkScalar sy) { void DisplayListBuilder::Rotate(SkScalar degrees) { if (SkScalarMod(degrees, 360.0) != 0.0) { checkForDeferredSave(); - Push(0, 1, degrees); + Push(0, degrees); tracker_.rotate(degrees); if (layer_tracker_) { layer_tracker_->rotate(degrees); @@ -728,7 +740,7 @@ void DisplayListBuilder::Skew(SkScalar sx, SkScalar sy) { if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) && (sx != 0.0 || sy != 0.0)) { checkForDeferredSave(); - Push(0, 1, sx, sy); + Push(0, sx, sy); tracker_.skew(sx, sy); if (layer_tracker_) { layer_tracker_->skew(sx, sy); @@ -750,7 +762,7 @@ void DisplayListBuilder::Transform2DAffine( Translate(mxt, myt); } else { checkForDeferredSave(); - Push(0, 1, + Push(0, mxx, mxy, mxt, myx, myy, myt); tracker_.transform2DAffine(mxx, mxy, mxt, @@ -779,7 +791,7 @@ void DisplayListBuilder::TransformFullPerspective( SkScalarsAreFinite(mzx, mzy) && SkScalarsAreFinite(mzz, mzt) && SkScalarsAreFinite(mwx, mwy) && SkScalarsAreFinite(mwz, mwt)) { checkForDeferredSave(); - Push(0, 1, + Push(0, mxx, mxy, mxz, mxt, myx, myy, myz, myt, mzx, mzy, mzz, mzt, @@ -799,7 +811,7 @@ void DisplayListBuilder::TransformFullPerspective( // clang-format on void DisplayListBuilder::TransformReset() { checkForDeferredSave(); - Push(0, 0); + Push(0); if (layer_tracker_) { // The matrices in layer_tracker_ and tracker_ are similar, but // start at a different base transform. The tracker_ potentially @@ -852,10 +864,10 @@ void DisplayListBuilder::ClipRect(const SkRect& rect, checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: - Push(0, 1, rect, is_aa); + Push(0, rect, is_aa); break; case ClipOp::kDifference: - Push(0, 1, rect, is_aa); + Push(0, rect, is_aa); break; } } @@ -873,10 +885,10 @@ void DisplayListBuilder::ClipRRect(const SkRRect& rrect, checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: - Push(0, 1, rrect, is_aa); + Push(0, rrect, is_aa); break; case ClipOp::kDifference: - Push(0, 1, rrect, is_aa); + Push(0, rrect, is_aa); break; } } @@ -909,10 +921,10 @@ void DisplayListBuilder::ClipPath(const SkPath& path, checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: - Push(0, 1, path, is_aa); + Push(0, path, is_aa); break; case ClipOp::kDifference: - Push(0, 1, path, is_aa); + Push(0, path, is_aa); break; } } @@ -924,7 +936,7 @@ bool DisplayListBuilder::QuickReject(const SkRect& bounds) const { void DisplayListBuilder::drawPaint() { OpResult result = PaintResult(current_, kDrawPaintFlags); if (result != OpResult::kNoEffect && AccumulateUnbounded()) { - Push(0, 1); + Push(0); CheckLayerOpacityCompatibility(); UpdateLayerResult(result); } @@ -936,7 +948,7 @@ void DisplayListBuilder::DrawPaint(const DlPaint& paint) { void DisplayListBuilder::DrawColor(DlColor color, DlBlendMode mode) { OpResult result = PaintResult(DlPaint(color).setBlendMode(mode)); if (result != OpResult::kNoEffect && AccumulateUnbounded()) { - Push(0, 1, color, mode); + Push(0, color, mode); CheckLayerOpacityCompatibility(mode); UpdateLayerResult(result); } @@ -948,7 +960,7 @@ void DisplayListBuilder::drawLine(const SkPoint& p0, const SkPoint& p1) { : kDrawHVLineFlags; OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds, flags)) { - Push(0, 1, p0, p1); + Push(0, p0, p1); CheckLayerOpacityCompatibility(); UpdateLayerResult(result); } @@ -964,7 +976,7 @@ void DisplayListBuilder::drawRect(const SkRect& rect) { OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(rect.makeSorted(), flags)) { - Push(0, 1, rect); + Push(0, rect); CheckLayerOpacityCompatibility(); UpdateLayerResult(result); } @@ -978,7 +990,7 @@ void DisplayListBuilder::drawOval(const SkRect& bounds) { OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds.makeSorted(), flags)) { - Push(0, 1, bounds); + Push(0, bounds); CheckLayerOpacityCompatibility(); UpdateLayerResult(result); } @@ -994,7 +1006,7 @@ void DisplayListBuilder::drawCircle(const SkPoint& center, SkScalar radius) { SkRect bounds = SkRect::MakeLTRB(center.fX - radius, center.fY - radius, center.fX + radius, center.fY + radius); if (AccumulateOpBounds(bounds, flags)) { - Push(0, 1, center, radius); + Push(0, center, radius); CheckLayerOpacityCompatibility(); UpdateLayerResult(result); } @@ -1016,7 +1028,7 @@ void DisplayListBuilder::drawRRect(const SkRRect& rrect) { OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(rrect.getBounds(), flags)) { - Push(0, 1, rrect); + Push(0, rrect); CheckLayerOpacityCompatibility(); UpdateLayerResult(result); } @@ -1032,7 +1044,7 @@ void DisplayListBuilder::drawDRRect(const SkRRect& outer, OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(outer.getBounds(), flags)) { - Push(0, 1, outer, inner); + Push(0, outer, inner); CheckLayerOpacityCompatibility(); UpdateLayerResult(result); } @@ -1051,7 +1063,7 @@ void DisplayListBuilder::drawPath(const SkPath& path) { ? AccumulateUnbounded() : AccumulateOpBounds(path.getBounds(), flags); if (is_visible) { - Push(0, 1, path); + Push(0, path); CheckLayerOpacityHairlineCompatibility(); UpdateLayerResult(result); } @@ -1075,7 +1087,7 @@ void DisplayListBuilder::drawArc(const SkRect& bounds, // angles are and then also consider the quadrants swept and // the center if specified. if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds, flags)) { - Push(0, 1, bounds, start, sweep, useCenter); + Push(0, bounds, start, sweep, useCenter); if (useCenter) { CheckLayerOpacityHairlineCompatibility(); } else { @@ -1132,13 +1144,13 @@ void DisplayListBuilder::drawPoints(PointMode mode, void* data_ptr; switch (mode) { case PointMode::kPoints: - data_ptr = Push(bytes, 1, count); + data_ptr = Push(bytes, count); break; case PointMode::kLines: - data_ptr = Push(bytes, 1, count); + data_ptr = Push(bytes, count); break; case PointMode::kPolygon: - data_ptr = Push(bytes, 1, count); + data_ptr = Push(bytes, count); break; default: FML_UNREACHABLE(); @@ -1166,7 +1178,7 @@ void DisplayListBuilder::drawVertices(const DlVertices* vertices, OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(vertices->bounds(), flags)) { - void* pod = Push(vertices->size(), 1, mode); + void* pod = Push(vertices->size(), mode); new (pod) DlVertices(vertices); // DrawVertices applies its colors to the paint so we have no way // of controlling opacity using the current paint attributes. @@ -1198,8 +1210,8 @@ void DisplayListBuilder::drawImage(const sk_sp image, image->width(), image->height()); if (AccumulateOpBounds(bounds, flags)) { render_with_attributes - ? Push(0, 1, image, point, sampling) - : Push(0, 1, image, point, sampling); + ? Push(0, image, point, sampling) + : Push(0, image, point, sampling); CheckLayerOpacityCompatibility(render_with_attributes); UpdateLayerResult(result); is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); @@ -1228,8 +1240,8 @@ void DisplayListBuilder::drawImageRect(const sk_sp image, : kDrawImageRectFlags; OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(dst, flags)) { - Push(0, 1, image, src, dst, sampling, - render_with_attributes, constraint); + Push(0, image, src, dst, sampling, render_with_attributes, + constraint); CheckLayerOpacityCompatibility(render_with_attributes); UpdateLayerResult(result); is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); @@ -1260,8 +1272,8 @@ void DisplayListBuilder::drawImageNine(const sk_sp image, OpResult result = PaintResult(current_, flags); if (result != OpResult::kNoEffect && AccumulateOpBounds(dst, flags)) { render_with_attributes - ? Push(0, 1, image, center, dst, filter) - : Push(0, 1, image, center, dst, filter); + ? Push(0, image, center, dst, filter) + : Push(0, image, center, dst, filter); CheckLayerOpacityCompatibility(render_with_attributes); UpdateLayerResult(result); is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); @@ -1316,21 +1328,21 @@ void DisplayListBuilder::drawAtlas(const sk_sp atlas, bytes += count * sizeof(DlColor); if (cull_rect != nullptr) { data_ptr = - Push(bytes, 1, atlas, count, mode, sampling, true, + Push(bytes, atlas, count, mode, sampling, true, *cull_rect, render_with_attributes); } else { - data_ptr = Push(bytes, 1, atlas, count, mode, sampling, true, + data_ptr = Push(bytes, atlas, count, mode, sampling, true, render_with_attributes); } CopyV(data_ptr, xform, count, tex, count, colors, count); } else { if (cull_rect != nullptr) { data_ptr = - Push(bytes, 1, atlas, count, mode, sampling, false, + Push(bytes, atlas, count, mode, sampling, false, *cull_rect, render_with_attributes); } else { - data_ptr = Push(bytes, 1, atlas, count, mode, sampling, - false, render_with_attributes); + data_ptr = Push(bytes, atlas, count, mode, sampling, false, + render_with_attributes); } CopyV(data_ptr, xform, count, tex, count); } @@ -1397,8 +1409,19 @@ void DisplayListBuilder::DrawDisplayList(const sk_sp display_list, } DlPaint current_paint = current_; - Push(0, 1, display_list, + Push(0, display_list, opacity < SK_Scalar1 ? opacity : SK_Scalar1); + + // This depth increment accounts for every draw call in the child + // DisplayList and is in addition to the implicit depth increment + // that was performed when we pushed the DrawDisplayListOp. The + // eventual dispatcher can use or ignore the implicit depth increment + // as it sees fit depending on whether it needs to do rendering + // before or after the drawDisplayList op, but it must be accounted + // for if the depth value accounting is to remain consistent between + // the recording and dispatching process. + depth_ += display_list->total_depth(); + is_ui_thread_safe_ = is_ui_thread_safe_ && display_list->isUIThreadSafe(); // Not really necessary if the developer is interacting with us via // our attribute-state-less DlCanvas methods, but this avoids surprises @@ -1438,7 +1461,7 @@ void DisplayListBuilder::drawTextBlob(const sk_sp blob, unclipped = true; #endif // OS_FUCHSIA if (unclipped) { - Push(0, 1, blob, x, y); + Push(0, blob, x, y); // There is no way to query if the glyphs of a text blob overlap and // there are no current guarantees from either Skia or Impeller that // they will protect overlapping glyphs from the effects of overdraw @@ -1477,7 +1500,7 @@ void DisplayListBuilder::drawTextFrame( unclipped = true; #endif // OS_FUCHSIA if (unclipped) { - Push(0, 1, text_frame, x, y); + Push(0, text_frame, x, y); // There is no way to query if the glyphs of a text blob overlap and // there are no current guarantees from either Skia or Impeller that // they will protect overlapping glyphs from the effects of overdraw @@ -1508,9 +1531,9 @@ void DisplayListBuilder::DrawShadow(const SkPath& path, DlCanvas::ComputeShadowBounds(path, elevation, dpr, GetTransform()); if (AccumulateOpBounds(shadow_bounds, kDrawShadowFlags)) { transparent_occluder // - ? Push(0, 1, path, color, elevation, + ? Push(0, path, color, elevation, dpr) - : Push(0, 1, path, color, elevation, dpr); + : Push(0, path, color, elevation, dpr); UpdateLayerOpacityCompatibility(false); UpdateLayerResult(result); } diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index a1742f3a4305a..9e27a66393398 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -488,17 +488,18 @@ class DisplayListBuilder final : public virtual DlCanvas, DisplayListStorage storage_; size_t used_ = 0; size_t allocated_ = 0; - int render_op_count_ = 0; + uint32_t render_op_count_ = 0; + uint32_t depth_ = 0; int op_index_ = 0; // bytes and ops from |drawPicture| and |drawDisplayList| size_t nested_bytes_ = 0; - int nested_op_count_ = 0; + uint32_t nested_op_count_ = 0; bool is_ui_thread_safe_ = true; template - void* Push(size_t extra, int op_inc, Args&&... args); + void* Push(size_t extra, Args&&... args); void intersect(const SkRect& rect); @@ -510,7 +511,8 @@ class DisplayListBuilder final : public virtual DlCanvas, class SaveInfo { public: - explicit SaveInfo(size_t save_offset = 0) : save_offset_(save_offset) {} + explicit SaveInfo(size_t save_offset = 0, uint32_t start_depth = 0) + : save_offset_(save_offset), start_depth_(start_depth) {} // The offset into the memory buffer where the save DLOp record // for this save() call is placed. This may be needed if the @@ -587,6 +589,7 @@ class DisplayListBuilder final : public virtual DlCanvas, private: size_t save_offset_; + uint32_t start_depth_; bool is_save_layer_ = false; bool cannot_inherit_opacity_ = false; bool has_compatible_op_ = false; diff --git a/display_list/dl_op_receiver.h b/display_list/dl_op_receiver.h index 2eec9358273a7..68781fe26a2d2 100644 --- a/display_list/dl_op_receiver.h +++ b/display_list/dl_op_receiver.h @@ -38,6 +38,52 @@ class DisplayList; /// Unlike DlCanvas, this interface has attribute state which is global across /// an entire DisplayList (not affected by save/restore). /// +/// DISPLAYLIST DEPTH TRACKING +/// +/// Each rendering call in the DisplayList stream is assumed to have a "depth" +/// value relative to the beginning of its DisplayList. The depth value is +/// implicitly allocated during recording and only reported in 2 places so +/// it is important for a dispatcher to perform the same internal allocations +/// if it is to make sense of the information reported by the save/saveLayer +/// calls. This depth value is maintained as follows: +/// +/// - The absolute depth value is never reported, only the total depth +/// size of the entire DisplayList or one of its save/restore pairs +/// is reported. Since the DisplayList might be dispatched recursively +/// due to embedded drawDisplayList calls, these depth size values +/// will often be relative to things like: +/// - the start of a given save/saveLayer group +/// - the start of a DisplayList dispatch or recursion +/// as such, only totals for groups of DisplayList dispatched calls +/// will be reported. These totals will be reported in: +/// - the `DisplayList::total_depth()` method reporting the total +/// depth accumulated for every operation in the DisplayList +/// - the save/saveLayer dispatch calls will report the total +/// depth accumulated for every call until their corresponding +/// restore call. +/// - The depth value is incremented for every drawing operation, including: +/// - all draw* calls (including drawDisplayList) +/// - drawDisplayList will also accumulate the total_depth() of the +/// DisplayList object it is drawing (in other words it will skip enough +/// depth values for each drawing call in the child). +/// This bump is in addition to the depth value it records for being +/// a rendering operation. Some implementations may need to surround +/// the actual drawDisplayList with a protective saveLayer, but others +/// may not - so the implicit depth value assigned to the drawDisplayList +/// call itself may go unused, but must be accounted for. +/// - a saveLayer call will also increment the depth value just like a +/// rendering call. This is in addition to the depth of its content. +/// It is doing so to reserve a depth for the drawing operation that +/// copies its layer back to the parent. +/// - Each save() or saveLayer() call will report the total depth of all +/// rendering calls within its content (recorded before the corresponding +/// restore) and report this total during dispatch. This information might +/// be needed to assign depths to the clip operations that occur within +/// its content. As there is no enclosing saveLayer/restore pair around +/// the root of a DisplayList, the total depth of the DisplayList can +/// be used to determine the appropriate clip depths for any clip ops +/// appearing before the first save/saveLayer or after the last restore. +/// /// @see DlSkCanvasDispatcher /// @see impeller::DlDispatcher /// @see DlOpSpy @@ -118,6 +164,9 @@ class DlOpReceiver { // All of the following methods are nearly 1:1 with their counterparts // in |SkCanvas| and have the same behavior and output. virtual void save() = 0; + // Optional variant of save() that passes the total depth count of + // all rendering operations that occur until the next restore() call. + virtual void save(uint32_t total_content_depth) { save(); } // The |options| parameter can specify whether the existing rendering // attributes will be applied to the save layer surface while rendering // it back to the current surface. If the flag is false then this method @@ -137,6 +186,14 @@ class DlOpReceiver { virtual void saveLayer(const SkRect& bounds, const SaveLayerOptions options, const DlImageFilter* backdrop = nullptr) = 0; + // Optional variant of saveLayer() that passes the total depth count of + // all rendering operations that occur until the next restore() call. + virtual void saveLayer(const SkRect& bounds, + const SaveLayerOptions& options, + uint32_t total_content_depth, + const DlImageFilter* backdrop = nullptr) { + saveLayer(bounds, options, backdrop); + } virtual void restore() = 0; // --------------------------------------------------------------------- diff --git a/display_list/dl_op_records.h b/display_list/dl_op_records.h index bcd895a1fcad7..3f8d70af1ce5d 100644 --- a/display_list/dl_op_records.h +++ b/display_list/dl_op_records.h @@ -96,6 +96,9 @@ enum class DisplayListCompare { // of data for "free" and works best when it packs well into an 8-byte // aligned size. struct DLOp { + static constexpr uint32_t kDepthInc = 0; + static constexpr uint32_t kRenderOpInc = 0; + DisplayListOpType type : 8; uint32_t size : 24; @@ -105,17 +108,17 @@ struct DLOp { }; // 4 byte header + 4 byte payload packs into minimum 8 bytes -#define DEFINE_SET_BOOL_OP(name) \ - struct Set##name##Op final : DLOp { \ - static const auto kType = DisplayListOpType::kSet##name; \ - \ - explicit Set##name##Op(bool value) : value(value) {} \ - \ - const bool value; \ - \ - void dispatch(DispatchContext& ctx) const { \ - ctx.receiver.set##name(value); \ - } \ +#define DEFINE_SET_BOOL_OP(name) \ + struct Set##name##Op final : DLOp { \ + static constexpr auto kType = DisplayListOpType::kSet##name; \ + \ + explicit Set##name##Op(bool value) : value(value) {} \ + \ + const bool value; \ + \ + void dispatch(DispatchContext& ctx) const { \ + ctx.receiver.set##name(value); \ + } \ }; DEFINE_SET_BOOL_OP(AntiAlias) DEFINE_SET_BOOL_OP(InvertColors) @@ -124,7 +127,7 @@ DEFINE_SET_BOOL_OP(InvertColors) // 4 byte header + 4 byte payload packs into minimum 8 bytes #define DEFINE_SET_ENUM_OP(name) \ struct SetStroke##name##Op final : DLOp { \ - static const auto kType = DisplayListOpType::kSetStroke##name; \ + static constexpr auto kType = DisplayListOpType::kSetStroke##name; \ \ explicit SetStroke##name##Op(DlStroke##name value) : value(value) {} \ \ @@ -140,7 +143,7 @@ DEFINE_SET_ENUM_OP(Join) // 4 byte header + 4 byte payload packs into minimum 8 bytes struct SetStyleOp final : DLOp { - static const auto kType = DisplayListOpType::kSetStyle; + static constexpr auto kType = DisplayListOpType::kSetStyle; explicit SetStyleOp(DlDrawStyle style) : style(style) {} @@ -152,7 +155,7 @@ struct SetStyleOp final : DLOp { }; // 4 byte header + 4 byte payload packs into minimum 8 bytes struct SetStrokeWidthOp final : DLOp { - static const auto kType = DisplayListOpType::kSetStrokeWidth; + static constexpr auto kType = DisplayListOpType::kSetStrokeWidth; explicit SetStrokeWidthOp(float width) : width(width) {} @@ -164,7 +167,7 @@ struct SetStrokeWidthOp final : DLOp { }; // 4 byte header + 4 byte payload packs into minimum 8 bytes struct SetStrokeMiterOp final : DLOp { - static const auto kType = DisplayListOpType::kSetStrokeMiter; + static constexpr auto kType = DisplayListOpType::kSetStrokeMiter; explicit SetStrokeMiterOp(float limit) : limit(limit) {} @@ -177,7 +180,7 @@ struct SetStrokeMiterOp final : DLOp { // 4 byte header + 4 byte payload packs into minimum 8 bytes struct SetColorOp final : DLOp { - static const auto kType = DisplayListOpType::kSetColor; + static constexpr auto kType = DisplayListOpType::kSetColor; explicit SetColorOp(DlColor color) : color(color) {} @@ -187,7 +190,7 @@ struct SetColorOp final : DLOp { }; // 4 byte header + 4 byte payload packs into minimum 8 bytes struct SetBlendModeOp final : DLOp { - static const auto kType = DisplayListOpType::kSetBlendMode; + static constexpr auto kType = DisplayListOpType::kSetBlendMode; explicit SetBlendModeOp(DlBlendMode mode) : mode(mode) {} @@ -206,7 +209,7 @@ struct SetBlendModeOp final : DLOp { // 4 and 8 bytes unused #define DEFINE_SET_CLEAR_DLATTR_OP(name, sk_name, field) \ struct Clear##name##Op final : DLOp { \ - static const auto kType = DisplayListOpType::kClear##name; \ + static constexpr auto kType = DisplayListOpType::kClear##name; \ \ Clear##name##Op() {} \ \ @@ -215,7 +218,7 @@ struct SetBlendModeOp final : DLOp { } \ }; \ struct SetPod##name##Op final : DLOp { \ - static const auto kType = DisplayListOpType::kSetPod##name; \ + static constexpr auto kType = DisplayListOpType::kSetPod##name; \ \ SetPod##name##Op() {} \ \ @@ -234,7 +237,7 @@ DEFINE_SET_CLEAR_DLATTR_OP(PathEffect, PathEffect, effect) // 4 byte header + 80 bytes for the embedded DlImageColorSource // uses 84 total bytes (4 bytes unused) struct SetImageColorSourceOp : DLOp { - static const auto kType = DisplayListOpType::kSetImageColorSource; + static constexpr auto kType = DisplayListOpType::kSetImageColorSource; explicit SetImageColorSourceOp(const DlImageColorSource* source) : source(source->image(), @@ -253,7 +256,7 @@ struct SetImageColorSourceOp : DLOp { // 56 bytes: 4 byte header, 4 byte padding, 8 for vtable, 8 * 2 for sk_sps, 24 // for the std::vector. struct SetRuntimeEffectColorSourceOp : DLOp { - static const auto kType = DisplayListOpType::kSetRuntimeEffectColorSource; + static constexpr auto kType = DisplayListOpType::kSetRuntimeEffectColorSource; explicit SetRuntimeEffectColorSourceOp( const DlRuntimeEffectColorSource* source) @@ -275,7 +278,7 @@ struct SetRuntimeEffectColorSourceOp : DLOp { #ifdef IMPELLER_ENABLE_3D struct SetSceneColorSourceOp : DLOp { - static const auto kType = DisplayListOpType::kSetSceneColorSource; + static constexpr auto kType = DisplayListOpType::kSetSceneColorSource; explicit SetSceneColorSourceOp(const DlSceneColorSource* source) : source(source->scene_node(), source->camera_matrix()) {} @@ -295,7 +298,7 @@ struct SetSceneColorSourceOp : DLOp { // 4 byte header + 16 byte payload uses 24 total bytes (4 bytes unused) struct SetSharedImageFilterOp : DLOp { - static const auto kType = DisplayListOpType::kSetSharedImageFilter; + static constexpr auto kType = DisplayListOpType::kSetSharedImageFilter; explicit SetSharedImageFilterOp(const DlImageFilter* filter) : filter(filter->shared()) {} @@ -315,16 +318,20 @@ struct SetSharedImageFilterOp : DLOp { // The base struct for all save() and saveLayer() ops // 4 byte header + 8 byte payload packs into 16 bytes (4 bytes unused) struct SaveOpBase : DLOp { + static constexpr uint32_t kDepthInc = 0; + static constexpr uint32_t kRenderOpInc = 1; + SaveOpBase() : options(), restore_index(0) {} explicit SaveOpBase(const SaveLayerOptions& options) - : options(options), restore_index(0) {} + : options(options), restore_index(0), total_content_depth(0) {} // options parameter is only used by saveLayer operations, but since // it packs neatly into the empty space created by laying out the 64-bit // offsets, it can be stored for free and defaulted to 0 for save operations. SaveLayerOptions options; int restore_index; + uint32_t total_content_depth; inline bool save_needed(DispatchContext& ctx) const { bool needed = ctx.next_render_index <= restore_index; @@ -335,13 +342,13 @@ struct SaveOpBase : DLOp { }; // 16 byte SaveOpBase with no additional data (options is unsed here) struct SaveOp final : SaveOpBase { - static const auto kType = DisplayListOpType::kSave; + static constexpr auto kType = DisplayListOpType::kSave; SaveOp() : SaveOpBase() {} void dispatch(DispatchContext& ctx) const { if (save_needed(ctx)) { - ctx.receiver.save(); + ctx.receiver.save(total_content_depth); } } }; @@ -355,20 +362,20 @@ struct SaveLayerOpBase : SaveOpBase { }; // 32 byte SaveLayerOpBase with no additional data struct SaveLayerOp final : SaveLayerOpBase { - static const auto kType = DisplayListOpType::kSaveLayer; + static constexpr auto kType = DisplayListOpType::kSaveLayer; SaveLayerOp(const SaveLayerOptions& options, const SkRect& rect) : SaveLayerOpBase(options, rect) {} void dispatch(DispatchContext& ctx) const { if (save_needed(ctx)) { - ctx.receiver.saveLayer(rect, options); + ctx.receiver.saveLayer(rect, options, total_content_depth); } } }; // 32 byte SaveLayerOpBase + 16 byte payload packs into minimum 48 bytes struct SaveLayerBackdropOp final : SaveLayerOpBase { - static const auto kType = DisplayListOpType::kSaveLayerBackdrop; + static constexpr auto kType = DisplayListOpType::kSaveLayerBackdrop; SaveLayerBackdropOp(const SaveLayerOptions& options, const SkRect& rect, @@ -379,7 +386,8 @@ struct SaveLayerBackdropOp final : SaveLayerOpBase { void dispatch(DispatchContext& ctx) const { if (save_needed(ctx)) { - ctx.receiver.saveLayer(rect, options, backdrop.get()); + ctx.receiver.saveLayer(rect, options, total_content_depth, + backdrop.get()); } } @@ -392,7 +400,9 @@ struct SaveLayerBackdropOp final : SaveLayerOpBase { }; // 4 byte header + no payload uses minimum 8 bytes (4 bytes unused) struct RestoreOp final : DLOp { - static const auto kType = DisplayListOpType::kRestore; + static constexpr auto kType = DisplayListOpType::kRestore; + static constexpr uint32_t kDepthInc = 0; + static constexpr uint32_t kRenderOpInc = 1; RestoreOp() {} @@ -407,6 +417,9 @@ struct RestoreOp final : DLOp { }; struct TransformClipOpBase : DLOp { + static constexpr uint32_t kDepthInc = 0; + static constexpr uint32_t kRenderOpInc = 1; + inline bool op_needed(const DispatchContext& context) const { return context.next_render_index <= context.next_restore_index; } @@ -414,7 +427,7 @@ struct TransformClipOpBase : DLOp { // 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes // (4 bytes unused) struct TranslateOp final : TransformClipOpBase { - static const auto kType = DisplayListOpType::kTranslate; + static constexpr auto kType = DisplayListOpType::kTranslate; TranslateOp(SkScalar tx, SkScalar ty) : tx(tx), ty(ty) {} @@ -430,7 +443,7 @@ struct TranslateOp final : TransformClipOpBase { // 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes // (4 bytes unused) struct ScaleOp final : TransformClipOpBase { - static const auto kType = DisplayListOpType::kScale; + static constexpr auto kType = DisplayListOpType::kScale; ScaleOp(SkScalar sx, SkScalar sy) : sx(sx), sy(sy) {} @@ -445,7 +458,7 @@ struct ScaleOp final : TransformClipOpBase { }; // 4 byte header + 4 byte payload packs into minimum 8 bytes struct RotateOp final : TransformClipOpBase { - static const auto kType = DisplayListOpType::kRotate; + static constexpr auto kType = DisplayListOpType::kRotate; explicit RotateOp(SkScalar degrees) : degrees(degrees) {} @@ -460,7 +473,7 @@ struct RotateOp final : TransformClipOpBase { // 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes // (4 bytes unused) struct SkewOp final : TransformClipOpBase { - static const auto kType = DisplayListOpType::kSkew; + static constexpr auto kType = DisplayListOpType::kSkew; SkewOp(SkScalar sx, SkScalar sy) : sx(sx), sy(sy) {} @@ -476,7 +489,7 @@ struct SkewOp final : TransformClipOpBase { // 4 byte header + 24 byte payload uses 28 bytes but is rounded up to 32 bytes // (4 bytes unused) struct Transform2DAffineOp final : TransformClipOpBase { - static const auto kType = DisplayListOpType::kTransform2DAffine; + static constexpr auto kType = DisplayListOpType::kTransform2DAffine; // clang-format off Transform2DAffineOp(SkScalar mxx, SkScalar mxy, SkScalar mxt, @@ -497,7 +510,7 @@ struct Transform2DAffineOp final : TransformClipOpBase { // 4 byte header + 64 byte payload uses 68 bytes which is rounded up to 72 bytes // (4 bytes unused) struct TransformFullPerspectiveOp final : TransformClipOpBase { - static const auto kType = DisplayListOpType::kTransformFullPerspective; + static constexpr auto kType = DisplayListOpType::kTransformFullPerspective; // clang-format off TransformFullPerspectiveOp( @@ -528,7 +541,7 @@ struct TransformFullPerspectiveOp final : TransformClipOpBase { // 4 byte header with no payload. struct TransformResetOp final : TransformClipOpBase { - static const auto kType = DisplayListOpType::kTransformReset; + static constexpr auto kType = DisplayListOpType::kTransformReset; TransformResetOp() = default; @@ -549,22 +562,22 @@ struct TransformResetOp final : TransformClipOpBase { // the header, but the Windows compiler keeps wanting to expand that // packing into more bytes than needed (even when they are declared as // packed bit fields!) -#define DEFINE_CLIP_SHAPE_OP(shapetype, clipop) \ - struct Clip##clipop##shapetype##Op final : TransformClipOpBase { \ - static const auto kType = DisplayListOpType::kClip##clipop##shapetype; \ - \ - Clip##clipop##shapetype##Op(Sk##shapetype shape, bool is_aa) \ - : is_aa(is_aa), shape(shape) {} \ - \ - const bool is_aa; \ - const Sk##shapetype shape; \ - \ - void dispatch(DispatchContext& ctx) const { \ - if (op_needed(ctx)) { \ - ctx.receiver.clip##shapetype(shape, DlCanvas::ClipOp::k##clipop, \ - is_aa); \ - } \ - } \ +#define DEFINE_CLIP_SHAPE_OP(shapetype, clipop) \ + struct Clip##clipop##shapetype##Op final : TransformClipOpBase { \ + static constexpr auto kType = DisplayListOpType::kClip##clipop##shapetype; \ + \ + Clip##clipop##shapetype##Op(Sk##shapetype shape, bool is_aa) \ + : is_aa(is_aa), shape(shape) {} \ + \ + const bool is_aa; \ + const Sk##shapetype shape; \ + \ + void dispatch(DispatchContext& ctx) const { \ + if (op_needed(ctx)) { \ + ctx.receiver.clip##shapetype(shape, DlCanvas::ClipOp::k##clipop, \ + is_aa); \ + } \ + } \ }; DEFINE_CLIP_SHAPE_OP(Rect, Intersect) DEFINE_CLIP_SHAPE_OP(RRect, Intersect) @@ -574,7 +587,7 @@ DEFINE_CLIP_SHAPE_OP(RRect, Difference) #define DEFINE_CLIP_PATH_OP(clipop) \ struct Clip##clipop##PathOp final : TransformClipOpBase { \ - static const auto kType = DisplayListOpType::kClip##clipop##Path; \ + static constexpr auto kType = DisplayListOpType::kClip##clipop##Path; \ \ Clip##clipop##PathOp(const SkPath& path, bool is_aa) \ : is_aa(is_aa), cached_path(path) {} \ @@ -605,6 +618,9 @@ DEFINE_CLIP_PATH_OP(Difference) #undef DEFINE_CLIP_PATH_OP struct DrawOpBase : DLOp { + static constexpr uint32_t kDepthInc = 1; + static constexpr uint32_t kRenderOpInc = 1; + inline bool op_needed(const DispatchContext& ctx) const { return ctx.cur_index >= ctx.next_render_index; } @@ -612,7 +628,7 @@ struct DrawOpBase : DLOp { // 4 byte header + no payload uses minimum 8 bytes (4 bytes unused) struct DrawPaintOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawPaint; + static constexpr auto kType = DisplayListOpType::kDrawPaint; DrawPaintOp() {} @@ -625,7 +641,7 @@ struct DrawPaintOp final : DrawOpBase { // 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes // (4 bytes unused) struct DrawColorOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawColor; + static constexpr auto kType = DisplayListOpType::kDrawColor; DrawColorOp(DlColor color, DlBlendMode mode) : color(color), mode(mode) {} @@ -646,7 +662,7 @@ struct DrawColorOp final : DrawOpBase { // SkRRect is 52 more bytes, which packs efficiently into 56 bytes total #define DEFINE_DRAW_1ARG_OP(op_name, arg_type, arg_name) \ struct Draw##op_name##Op final : DrawOpBase { \ - static const auto kType = DisplayListOpType::kDraw##op_name; \ + static constexpr auto kType = DisplayListOpType::kDraw##op_name; \ \ explicit Draw##op_name##Op(arg_type arg_name) : arg_name(arg_name) {} \ \ @@ -666,7 +682,7 @@ DEFINE_DRAW_1ARG_OP(RRect, SkRRect, rrect) // 4 byte header + 128 byte payload uses 132 bytes but is rounded // up to 136 bytes (4 bytes unused) struct DrawPathOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawPath; + static constexpr auto kType = DisplayListOpType::kDrawPath; explicit DrawPathOp(const SkPath& path) : cached_path(path) {} @@ -694,21 +710,21 @@ struct DrawPathOp final : DrawOpBase { // SkPoint + SkScalar is 12 more bytes, packing efficiently into 16 bytes total // 2 x SkRRect is 104 more bytes, using 108 and rounding up to 112 bytes total // (4 bytes unused) -#define DEFINE_DRAW_2ARG_OP(op_name, type1, name1, type2, name2) \ - struct Draw##op_name##Op final : DrawOpBase { \ - static const auto kType = DisplayListOpType::kDraw##op_name; \ - \ - Draw##op_name##Op(type1 name1, type2 name2) \ - : name1(name1), name2(name2) {} \ - \ - const type1 name1; \ - const type2 name2; \ - \ - void dispatch(DispatchContext& ctx) const { \ - if (op_needed(ctx)) { \ - ctx.receiver.draw##op_name(name1, name2); \ - } \ - } \ +#define DEFINE_DRAW_2ARG_OP(op_name, type1, name1, type2, name2) \ + struct Draw##op_name##Op final : DrawOpBase { \ + static constexpr auto kType = DisplayListOpType::kDraw##op_name; \ + \ + Draw##op_name##Op(type1 name1, type2 name2) \ + : name1(name1), name2(name2) {} \ + \ + const type1 name1; \ + const type2 name2; \ + \ + void dispatch(DispatchContext& ctx) const { \ + if (op_needed(ctx)) { \ + ctx.receiver.draw##op_name(name1, name2); \ + } \ + } \ }; DEFINE_DRAW_2ARG_OP(Line, SkPoint, p0, SkPoint, p1) DEFINE_DRAW_2ARG_OP(Circle, SkPoint, center, SkScalar, radius) @@ -717,7 +733,7 @@ DEFINE_DRAW_2ARG_OP(DRRect, SkRRect, outer, SkRRect, inner) // 4 byte header + 28 byte payload packs efficiently into 32 bytes struct DrawArcOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawArc; + static constexpr auto kType = DisplayListOpType::kDrawArc; DrawArcOp(SkRect bounds, SkScalar start, SkScalar sweep, bool center) : bounds(bounds), start(start), sweep(sweep), center(center) {} @@ -742,7 +758,7 @@ struct DrawArcOp final : DrawOpBase { // the fixed payload beyond the 8 bytes #define DEFINE_DRAW_POINTS_OP(name, mode) \ struct Draw##name##Op final : DrawOpBase { \ - static const auto kType = DisplayListOpType::kDraw##name; \ + static constexpr auto kType = DisplayListOpType::kDraw##name; \ \ explicit Draw##name##Op(uint32_t count) : count(count) {} \ \ @@ -768,7 +784,7 @@ DEFINE_DRAW_POINTS_OP(Polygon, kPolygon); // indices so the alignment can be up to 6 bytes off leading to // up to 6 bytes of overhead struct DrawVerticesOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawVertices; + static constexpr auto kType = DisplayListOpType::kDrawVertices; explicit DrawVerticesOp(DlBlendMode mode) : mode(mode) {} @@ -787,7 +803,7 @@ struct DrawVerticesOp final : DrawOpBase { // (4 bytes unused) #define DEFINE_DRAW_IMAGE_OP(name, with_attributes) \ struct name##Op final : DrawOpBase { \ - static const auto kType = DisplayListOpType::k##name; \ + static constexpr auto kType = DisplayListOpType::k##name; \ \ name##Op(const sk_sp& image, \ const SkPoint& point, \ @@ -818,7 +834,7 @@ DEFINE_DRAW_IMAGE_OP(DrawImageWithAttr, true) // 4 byte header + 72 byte payload uses 76 bytes but is rounded up to 80 bytes // (4 bytes unused) struct DrawImageRectOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawImageRect; + static constexpr auto kType = DisplayListOpType::kDrawImageRect; DrawImageRectOp(const sk_sp& image, const SkRect& src, @@ -860,7 +876,7 @@ struct DrawImageRectOp final : DrawOpBase { // 4 byte header + 44 byte payload packs efficiently into 48 bytes #define DEFINE_DRAW_IMAGE_NINE_OP(name, render_with_attributes) \ struct name##Op final : DrawOpBase { \ - static const auto kType = DisplayListOpType::k##name; \ + static constexpr auto kType = DisplayListOpType::k##name; \ \ name##Op(const sk_sp& image, \ const SkIRect& center, \ @@ -940,7 +956,7 @@ struct DrawAtlasBaseOp : DrawOpBase { // Packs into 48 bytes as per DrawAtlasBaseOp // with array data following the struct also as per DrawAtlasBaseOp struct DrawAtlasOp final : DrawAtlasBaseOp { - static const auto kType = DisplayListOpType::kDrawAtlas; + static constexpr auto kType = DisplayListOpType::kDrawAtlas; DrawAtlasOp(const sk_sp& atlas, int count, @@ -981,7 +997,7 @@ struct DrawAtlasOp final : DrawAtlasBaseOp { // of 56 bytes for the Culled drawAtlas. // Also with array data following the struct as per DrawAtlasBaseOp struct DrawAtlasCulledOp final : DrawAtlasBaseOp { - static const auto kType = DisplayListOpType::kDrawAtlasCulled; + static constexpr auto kType = DisplayListOpType::kDrawAtlasCulled; DrawAtlasCulledOp(const sk_sp& atlas, int count, @@ -1025,7 +1041,7 @@ struct DrawAtlasCulledOp final : DrawAtlasBaseOp { // 4 byte header + ptr aligned payload uses 12 bytes round up to 16 // (4 bytes unused) struct DrawDisplayListOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawDisplayList; + static constexpr auto kType = DisplayListOpType::kDrawDisplayList; explicit DrawDisplayListOp(const sk_sp& display_list, SkScalar opacity) @@ -1051,7 +1067,7 @@ struct DrawDisplayListOp final : DrawOpBase { // 4 byte header + 8 payload bytes + an aligned pointer take 24 bytes // (4 unused to align the pointer) struct DrawTextBlobOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawTextBlob; + static constexpr auto kType = DisplayListOpType::kDrawTextBlob; DrawTextBlobOp(const sk_sp& blob, SkScalar x, SkScalar y) : x(x), y(y), blob(blob) {} @@ -1068,7 +1084,7 @@ struct DrawTextBlobOp final : DrawOpBase { }; struct DrawTextFrameOp final : DrawOpBase { - static const auto kType = DisplayListOpType::kDrawTextFrame; + static constexpr auto kType = DisplayListOpType::kDrawTextFrame; DrawTextFrameOp(const std::shared_ptr& text_frame, SkScalar x, @@ -1089,7 +1105,7 @@ struct DrawTextFrameOp final : DrawOpBase { // 4 byte header + 140 byte payload packs evenly into 140 bytes #define DEFINE_DRAW_SHADOW_OP(name, transparent_occluder) \ struct Draw##name##Op final : DrawOpBase { \ - static const auto kType = DisplayListOpType::kDraw##name; \ + static constexpr auto kType = DisplayListOpType::kDraw##name; \ \ Draw##name##Op(const SkPath& path, \ DlColor color, \ diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc index 4757833f99ef6..bd6e75da64b0e 100644 --- a/display_list/testing/dl_test_snippets.cc +++ b/display_list/testing/dl_test_snippets.cc @@ -49,146 +49,145 @@ std::vector CreateAllAttributesOps() { return { {"SetAntiAlias", { - {0, 8, 0, 0, [](DlOpReceiver& r) { r.setAntiAlias(true); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setAntiAlias(false); }}, + {0, 8, 0, [](DlOpReceiver& r) { r.setAntiAlias(true); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setAntiAlias(false); }}, }}, {"SetInvertColors", { - {0, 8, 0, 0, [](DlOpReceiver& r) { r.setInvertColors(true); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setInvertColors(false); }}, + {0, 8, 0, [](DlOpReceiver& r) { r.setInvertColors(true); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setInvertColors(false); }}, }}, {"SetStrokeCap", { - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kRound); }}, - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kSquare); }}, - {0, 0, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kButt); }}, }}, {"SetStrokeJoin", { - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kBevel); }}, - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kRound); }}, - {0, 0, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kMiter); }}, }}, {"SetStyle", { - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setDrawStyle(DlDrawStyle::kStroke); }}, - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setDrawStyle(DlDrawStyle::kStrokeAndFill); }}, - {0, 0, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.setDrawStyle(DlDrawStyle::kFill); }}, }}, {"SetStrokeWidth", { - {0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(1.0); }}, - {0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(5.0); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(0.0); }}, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeWidth(1.0); }}, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeWidth(5.0); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(0.0); }}, }}, {"SetStrokeMiter", { - {0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(0.0); }}, - {0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(5.0); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(4.0); }}, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeMiter(0.0); }}, + {0, 8, 0, [](DlOpReceiver& r) { r.setStrokeMiter(5.0); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(4.0); }}, }}, {"SetColor", { - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorGREEN)); }}, - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorBLUE)); }}, - {0, 0, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorBLACK)); }}, }}, {"SetBlendMode", { - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kSrcIn); }}, - {0, 8, 0, 0, + {0, 8, 0, [](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kDstIn); }}, - {0, 0, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kSrcOver); }}, }}, {"SetColorSource", { - {0, 96, 0, 0, - [](DlOpReceiver& r) { r.setColorSource(&kTestSource1); }}, + {0, 96, 0, [](DlOpReceiver& r) { r.setColorSource(&kTestSource1); }}, // stop_count * (sizeof(float) + sizeof(uint32_t)) = 80 - {0, 80 + 6 * 4, 0, 0, + {0, 80 + 6 * 4, 0, [](DlOpReceiver& r) { r.setColorSource(kTestSource2.get()); }}, - {0, 80 + 6 * 4, 0, 0, + {0, 80 + 6 * 4, 0, [](DlOpReceiver& r) { r.setColorSource(kTestSource3.get()); }}, - {0, 88 + 6 * 4, 0, 0, + {0, 88 + 6 * 4, 0, [](DlOpReceiver& r) { r.setColorSource(kTestSource4.get()); }}, - {0, 80 + 6 * 4, 0, 0, + {0, 80 + 6 * 4, 0, [](DlOpReceiver& r) { r.setColorSource(kTestSource5.get()); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setColorSource(nullptr); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setColorSource(nullptr); }}, }}, {"SetImageFilter", { - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestBlurImageFilter1); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestBlurImageFilter2); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestBlurImageFilter3); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestBlurImageFilter4); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestDilateImageFilter1); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestDilateImageFilter2); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestDilateImageFilter3); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestErodeImageFilter1); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestErodeImageFilter2); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestErodeImageFilter3); }}, - {0, 64, 0, 0, + {0, 64, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestMatrixImageFilter1); }}, - {0, 64, 0, 0, + {0, 64, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestMatrixImageFilter2); }}, - {0, 64, 0, 0, + {0, 64, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestMatrixImageFilter3); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestComposeImageFilter1); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestComposeImageFilter2); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestComposeImageFilter3); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestCFImageFilter1); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter(&kTestCFImageFilter2); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setImageFilter(nullptr); }}, - {0, 24, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.setImageFilter(nullptr); }}, + {0, 24, 0, [](DlOpReceiver& r) { r.setImageFilter( kTestBlurImageFilter1 @@ -198,52 +197,52 @@ std::vector CreateAllAttributesOps() { }}, {"SetColorFilter", { - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter1); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter2); }}, - {0, 24, 0, 0, + {0, 24, 0, [](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter3); }}, - {0, 96, 0, 0, + {0, 96, 0, [](DlOpReceiver& r) { r.setColorFilter(&kTestMatrixColorFilter1); }}, - {0, 96, 0, 0, + {0, 96, 0, [](DlOpReceiver& r) { r.setColorFilter(&kTestMatrixColorFilter2); }}, - {0, 16, 0, 0, + {0, 16, 0, [](DlOpReceiver& r) { r.setColorFilter(DlSrgbToLinearGammaColorFilter::kInstance.get()); }}, - {0, 16, 0, 0, + {0, 16, 0, [](DlOpReceiver& r) { r.setColorFilter(DlLinearToSrgbGammaColorFilter::kInstance.get()); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setColorFilter(nullptr); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setColorFilter(nullptr); }}, }}, {"SetPathEffect", { // sizeof(DlDashPathEffect) + 2 * sizeof(SkScalar) - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setPathEffect(kTestPathEffect1.get()); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setPathEffect(kTestPathEffect2.get()); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setPathEffect(nullptr); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setPathEffect(nullptr); }}, }}, {"SetMaskFilter", { - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter1); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter2); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter3); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter4); }}, - {0, 32, 0, 0, + {0, 32, 0, [](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter5); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.setMaskFilter(nullptr); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.setMaskFilter(nullptr); }}, }}, }; } @@ -252,15 +251,6 @@ std::vector CreateAllSaveRestoreOps() { return { {"Save(Layer)+Restore", { - {5, 128, 5, 128, - [](DlOpReceiver& r) { - r.saveLayer(nullptr, SaveLayerOptions::kNoAttributes, - &kTestCFImageFilter1); - r.clipRect({0, 0, 25, 25}, DlCanvas::ClipOp::kIntersect, true); - r.drawRect({5, 5, 15, 15}); - r.drawRect({10, 10, 20, 20}); - r.restore(); - }}, // There are many reasons that save and restore can elide content, // including whether or not there are any draw operations between // them, whether or not there are any state changes to restore, and @@ -268,7 +258,7 @@ std::vector CreateAllSaveRestoreOps() { // attributes to be distributed to the children. To prevent those // cases we include at least one clip operation and 2 overlapping // rendering primitives between each save/restore pair. - {5, 96, 5, 96, + {5, 96, 2, [](DlOpReceiver& r) { r.save(); r.clipRect({0, 0, 25, 25}, DlCanvas::ClipOp::kIntersect, true); @@ -276,7 +266,7 @@ std::vector CreateAllSaveRestoreOps() { r.drawRect({10, 10, 20, 20}); r.restore(); }}, - {5, 112, 5, 112, + {5, 112, 3, [](DlOpReceiver& r) { r.saveLayer(nullptr, SaveLayerOptions::kNoAttributes); r.clipRect({0, 0, 25, 25}, DlCanvas::ClipOp::kIntersect, true); @@ -284,7 +274,7 @@ std::vector CreateAllSaveRestoreOps() { r.drawRect({10, 10, 20, 20}); r.restore(); }}, - {5, 112, 5, 112, + {5, 112, 3, [](DlOpReceiver& r) { r.saveLayer(nullptr, SaveLayerOptions::kWithAttributes); r.clipRect({0, 0, 25, 25}, DlCanvas::ClipOp::kIntersect, true); @@ -292,7 +282,7 @@ std::vector CreateAllSaveRestoreOps() { r.drawRect({10, 10, 20, 20}); r.restore(); }}, - {5, 112, 5, 112, + {5, 112, 3, [](DlOpReceiver& r) { r.saveLayer(&kTestBounds, SaveLayerOptions::kNoAttributes); r.clipRect({0, 0, 25, 25}, DlCanvas::ClipOp::kIntersect, true); @@ -300,7 +290,7 @@ std::vector CreateAllSaveRestoreOps() { r.drawRect({10, 10, 20, 20}); r.restore(); }}, - {5, 112, 5, 112, + {5, 112, 3, [](DlOpReceiver& r) { r.saveLayer(&kTestBounds, SaveLayerOptions::kWithAttributes); r.clipRect({0, 0, 25, 25}, DlCanvas::ClipOp::kIntersect, true); @@ -308,16 +298,16 @@ std::vector CreateAllSaveRestoreOps() { r.drawRect({10, 10, 20, 20}); r.restore(); }}, - // backdrop variants - using the TestCFImageFilter because it can be - // reconstituted in the DL->SkCanvas->DL stream - // {5, 104, 5, 104, [](DlOpReceiver& r) { - // r.saveLayer(nullptr, SaveLayerOptions::kNoAttributes, - // &kTestCFImageFilter1); r.clipRect({0, 0, 25, 25}, - // SkClipOp::kIntersect, true); r.drawRect({5, 5, 15, 15}); - // r.drawRect({10, 10, 20, 20}); - // r.restore(); - // }}, - {5, 128, 5, 128, + {5, 128, 3, + [](DlOpReceiver& r) { + r.saveLayer(nullptr, SaveLayerOptions::kNoAttributes, + &kTestCFImageFilter1); + r.clipRect({0, 0, 25, 25}, DlCanvas::ClipOp::kIntersect, true); + r.drawRect({5, 5, 15, 15}); + r.drawRect({10, 10, 20, 20}); + r.restore(); + }}, + {5, 128, 3, [](DlOpReceiver& r) { r.saveLayer(nullptr, SaveLayerOptions::kWithAttributes, &kTestCFImageFilter1); @@ -326,7 +316,7 @@ std::vector CreateAllSaveRestoreOps() { r.drawRect({10, 10, 20, 20}); r.restore(); }}, - {5, 128, 5, 128, + {5, 128, 3, [](DlOpReceiver& r) { r.saveLayer(&kTestBounds, SaveLayerOptions::kNoAttributes, &kTestCFImageFilter1); @@ -335,7 +325,7 @@ std::vector CreateAllSaveRestoreOps() { r.drawRect({10, 10, 20, 20}); r.restore(); }}, - {5, 128, 5, 128, + {5, 128, 3, [](DlOpReceiver& r) { r.saveLayer(&kTestBounds, SaveLayerOptions::kWithAttributes, &kTestCFImageFilter1); @@ -352,60 +342,55 @@ std::vector CreateAllTransformOps() { return { {"Translate", { - // cv.translate(0, 0) is ignored - {1, 16, 1, 16, [](DlOpReceiver& r) { r.translate(10, 10); }}, - {1, 16, 1, 16, [](DlOpReceiver& r) { r.translate(10, 15); }}, - {1, 16, 1, 16, [](DlOpReceiver& r) { r.translate(15, 10); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.translate(0, 0); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.translate(10, 10); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.translate(10, 15); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.translate(15, 10); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.translate(0, 0); }}, }}, {"Scale", { - // cv.scale(1, 1) is ignored - {1, 16, 1, 16, [](DlOpReceiver& r) { r.scale(2, 2); }}, - {1, 16, 1, 16, [](DlOpReceiver& r) { r.scale(2, 3); }}, - {1, 16, 1, 16, [](DlOpReceiver& r) { r.scale(3, 2); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.scale(1, 1); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.scale(2, 2); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.scale(2, 3); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.scale(3, 2); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.scale(1, 1); }}, }}, {"Rotate", { - // cv.rotate(0) is ignored, otherwise expressed as concat(rotmatrix) - {1, 8, 1, 32, [](DlOpReceiver& r) { r.rotate(30); }}, - {1, 8, 1, 32, [](DlOpReceiver& r) { r.rotate(45); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.rotate(0); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.rotate(360); }}, + {1, 8, 0, [](DlOpReceiver& r) { r.rotate(30); }}, + {1, 8, 0, [](DlOpReceiver& r) { r.rotate(45); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.rotate(0); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.rotate(360); }}, }}, {"Skew", { - // cv.skew(0, 0) is ignored, otherwise expressed as - // concat(skewmatrix) - {1, 16, 1, 32, [](DlOpReceiver& r) { r.skew(0.1, 0.1); }}, - {1, 16, 1, 32, [](DlOpReceiver& r) { r.skew(0.1, 0.2); }}, - {1, 16, 1, 32, [](DlOpReceiver& r) { r.skew(0.2, 0.1); }}, - {0, 0, 0, 0, [](DlOpReceiver& r) { r.skew(0, 0); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.skew(0.1, 0.1); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.skew(0.1, 0.2); }}, + {1, 16, 0, [](DlOpReceiver& r) { r.skew(0.2, 0.1); }}, + {0, 0, 0, [](DlOpReceiver& r) { r.skew(0, 0); }}, }}, {"Transform2DAffine", { - {1, 32, 1, 32, + {1, 32, 0, [](DlOpReceiver& r) { r.transform2DAffine(0, 1, 12, 1, 0, 33); }}, // r.transform(identity) is ignored - {0, 0, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.transform2DAffine(1, 0, 0, 0, 1, 0); }}, }}, {"TransformFullPerspective", { - {1, 72, 1, 72, + {1, 72, 0, [](DlOpReceiver& r) { r.transformFullPerspective(0, 1, 0, 12, 1, 0, 0, 33, 3, 2, 5, 29, 0, 0, 0, 12); }}, // r.transform(2D affine) is reduced to 2x3 - {1, 32, 1, 32, + {1, 32, 0, [](DlOpReceiver& r) { r.transformFullPerspective(2, 1, 0, 4, 1, 3, 0, 5, 0, 0, 1, 0, 0, 0, 0, 1); }}, // r.transform(identity) is ignored - {0, 0, 0, 0, + {0, 0, 0, [](DlOpReceiver& r) { r.transformFullPerspective(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); @@ -418,85 +403,85 @@ std::vector CreateAllClipOps() { return { {"ClipRect", { - {1, 24, 1, 24, + {1, 24, 0, [](DlOpReceiver& r) { r.clipRect(kTestBounds, DlCanvas::ClipOp::kIntersect, true); }}, - {1, 24, 1, 24, + {1, 24, 0, [](DlOpReceiver& r) { r.clipRect(kTestBounds.makeOffset(1, 1), DlCanvas::ClipOp::kIntersect, true); }}, - {1, 24, 1, 24, + {1, 24, 0, [](DlOpReceiver& r) { r.clipRect(kTestBounds, DlCanvas::ClipOp::kIntersect, false); }}, - {1, 24, 1, 24, + {1, 24, 0, [](DlOpReceiver& r) { r.clipRect(kTestBounds, DlCanvas::ClipOp::kDifference, true); }}, - {1, 24, 1, 24, + {1, 24, 0, [](DlOpReceiver& r) { r.clipRect(kTestBounds, DlCanvas::ClipOp::kDifference, false); }}, }}, {"ClipRRect", { - {1, 64, 1, 64, + {1, 64, 0, [](DlOpReceiver& r) { r.clipRRect(kTestRRect, DlCanvas::ClipOp::kIntersect, true); }}, - {1, 64, 1, 64, + {1, 64, 0, [](DlOpReceiver& r) { r.clipRRect(kTestRRect.makeOffset(1, 1), DlCanvas::ClipOp::kIntersect, true); }}, - {1, 64, 1, 64, + {1, 64, 0, [](DlOpReceiver& r) { r.clipRRect(kTestRRect, DlCanvas::ClipOp::kIntersect, false); }}, - {1, 64, 1, 64, + {1, 64, 0, [](DlOpReceiver& r) { r.clipRRect(kTestRRect, DlCanvas::ClipOp::kDifference, true); }}, - {1, 64, 1, 64, + {1, 64, 0, [](DlOpReceiver& r) { r.clipRRect(kTestRRect, DlCanvas::ClipOp::kDifference, false); }}, }}, {"ClipPath", { - {1, 40, 1, 40, + {1, 40, 0, [](DlOpReceiver& r) { r.clipPath(kTestPath1, DlCanvas::ClipOp::kIntersect, true); }}, - {1, 40, 1, 40, + {1, 40, 0, [](DlOpReceiver& r) { r.clipPath(kTestPath2, DlCanvas::ClipOp::kIntersect, true); }}, - {1, 40, 1, 40, + {1, 40, 0, [](DlOpReceiver& r) { r.clipPath(kTestPath3, DlCanvas::ClipOp::kIntersect, true); }}, - {1, 40, 1, 40, + {1, 40, 0, [](DlOpReceiver& r) { r.clipPath(kTestPath1, DlCanvas::ClipOp::kIntersect, false); }}, - {1, 40, 1, 40, + {1, 40, 0, [](DlOpReceiver& r) { r.clipPath(kTestPath1, DlCanvas::ClipOp::kDifference, true); }}, - {1, 40, 1, 40, + {1, 40, 0, [](DlOpReceiver& r) { r.clipPath(kTestPath1, DlCanvas::ClipOp::kDifference, false); }}, // clipPath(rect) becomes clipRect - {1, 24, 1, 24, + {1, 24, 0, [](DlOpReceiver& r) { r.clipPath(kTestPathRect, DlCanvas::ClipOp::kIntersect, true); }}, // clipPath(oval) becomes clipRRect - {1, 64, 1, 64, + {1, 64, 0, [](DlOpReceiver& r) { r.clipPath(kTestPathOval, DlCanvas::ClipOp::kIntersect, true); }}, @@ -508,108 +493,106 @@ std::vector CreateAllRenderingOps() { return { {"DrawPaint", { - {1, 8, 1, 8, [](DlOpReceiver& r) { r.drawPaint(); }}, + {1, 8, 1, [](DlOpReceiver& r) { r.drawPaint(); }}, }}, {"DrawColor", { - // cv.drawColor becomes cv.drawPaint(paint) - {1, 16, 1, 24, + {1, 16, 1, [](DlOpReceiver& r) { r.drawColor(DlColor(SK_ColorBLUE), DlBlendMode::kSrcIn); }}, - {1, 16, 1, 24, + {1, 16, 1, [](DlOpReceiver& r) { r.drawColor(DlColor(SK_ColorBLUE), DlBlendMode::kDstOut); }}, - {1, 16, 1, 24, + {1, 16, 1, [](DlOpReceiver& r) { r.drawColor(DlColor(SK_ColorCYAN), DlBlendMode::kSrcIn); }}, }}, {"DrawLine", { - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawLine({0, 0}, {10, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawLine({0, 1}, {10, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawLine({0, 0}, {20, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawLine({0, 0}, {10, 20}); }}, }}, {"DrawRect", { - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawRect({0, 0, 10, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawRect({0, 1, 10, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawRect({0, 0, 20, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawRect({0, 0, 10, 20}); }}, }}, {"DrawOval", { - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawOval({0, 0, 10, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawOval({0, 1, 10, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawOval({0, 0, 20, 10}); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawOval({0, 0, 10, 20}); }}, }}, {"DrawCircle", { - // cv.drawCircle becomes cv.drawOval - {1, 16, 1, 24, + {1, 16, 1, [](DlOpReceiver& r) { r.drawCircle({0, 0}, 10); }}, - {1, 16, 1, 24, + {1, 16, 1, [](DlOpReceiver& r) { r.drawCircle({0, 5}, 10); }}, - {1, 16, 1, 24, + {1, 16, 1, [](DlOpReceiver& r) { r.drawCircle({0, 0}, 20); }}, }}, {"DrawRRect", { - {1, 56, 1, 56, [](DlOpReceiver& r) { r.drawRRect(kTestRRect); }}, - {1, 56, 1, 56, + {1, 56, 1, [](DlOpReceiver& r) { r.drawRRect(kTestRRect); }}, + {1, 56, 1, [](DlOpReceiver& r) { r.drawRRect(kTestRRect.makeOffset(5, 5)); }}, }}, {"DrawDRRect", { - {1, 112, 1, 112, + {1, 112, 1, [](DlOpReceiver& r) { r.drawDRRect(kTestRRect, kTestInnerRRect); }}, - {1, 112, 1, 112, + {1, 112, 1, [](DlOpReceiver& r) { r.drawDRRect(kTestRRect.makeOffset(5, 5), kTestInnerRRect.makeOffset(4, 4)); @@ -617,45 +600,45 @@ std::vector CreateAllRenderingOps() { }}, {"DrawPath", { - {1, 40, 1, 40, [](DlOpReceiver& r) { r.drawPath(kTestPath1); }}, - {1, 40, 1, 40, [](DlOpReceiver& r) { r.drawPath(kTestPath2); }}, - {1, 40, 1, 40, [](DlOpReceiver& r) { r.drawPath(kTestPath3); }}, - {1, 40, 1, 40, [](DlOpReceiver& r) { r.drawPath(kTestPathRect); }}, - {1, 40, 1, 40, [](DlOpReceiver& r) { r.drawPath(kTestPathOval); }}, + {1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath1); }}, + {1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath2); }}, + {1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath3); }}, + {1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathRect); }}, + {1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathOval); }}, }}, {"DrawArc", { - {1, 32, 1, 32, + {1, 32, 1, [](DlOpReceiver& r) { r.drawArc(kTestBounds, 45, 270, false); }}, - {1, 32, 1, 32, + {1, 32, 1, [](DlOpReceiver& r) { r.drawArc(kTestBounds.makeOffset(1, 1), 45, 270, false); }}, - {1, 32, 1, 32, + {1, 32, 1, [](DlOpReceiver& r) { r.drawArc(kTestBounds, 30, 270, false); }}, - {1, 32, 1, 32, + {1, 32, 1, [](DlOpReceiver& r) { r.drawArc(kTestBounds, 45, 260, false); }}, - {1, 32, 1, 32, + {1, 32, 1, [](DlOpReceiver& r) { r.drawArc(kTestBounds, 45, 270, true); }}, }}, {"DrawPoints", { - {1, 8 + TestPointCount * 8, 1, 8 + TestPointCount * 8, + {1, 8 + TestPointCount * 8, 1, [](DlOpReceiver& r) { r.drawPoints(DlCanvas::PointMode::kPoints, TestPointCount, kTestPoints); }}, - {1, 8 + (TestPointCount - 1) * 8, 1, 8 + (TestPointCount - 1) * 8, + {1, 8 + (TestPointCount - 1) * 8, 1, [](DlOpReceiver& r) { r.drawPoints(DlCanvas::PointMode::kPoints, TestPointCount - 1, kTestPoints); }}, - {1, 8 + TestPointCount * 8, 1, 8 + TestPointCount * 8, + {1, 8 + TestPointCount * 8, 1, [](DlOpReceiver& r) { r.drawPoints(DlCanvas::PointMode::kLines, TestPointCount, kTestPoints); }}, - {1, 8 + TestPointCount * 8, 1, 8 + TestPointCount * 8, + {1, 8 + TestPointCount * 8, 1, [](DlOpReceiver& r) { r.drawPoints(DlCanvas::PointMode::kPolygon, TestPointCount, kTestPoints); @@ -663,46 +646,46 @@ std::vector CreateAllRenderingOps() { }}, {"DrawVertices", { - {1, 112, 1, 16, + {1, 112, 1, [](DlOpReceiver& r) { r.drawVertices(TestVertices1.get(), DlBlendMode::kSrcIn); }}, - {1, 112, 1, 16, + {1, 112, 1, [](DlOpReceiver& r) { r.drawVertices(TestVertices1.get(), DlBlendMode::kDstIn); }}, - {1, 112, 1, 16, + {1, 112, 1, [](DlOpReceiver& r) { r.drawVertices(TestVertices2.get(), DlBlendMode::kSrcIn); }}, }}, {"DrawImage", { - {1, 24, -1, 48, + {1, 24, 1, [](DlOpReceiver& r) { r.drawImage(TestImage1, {10, 10}, kNearestSampling, false); }}, - {1, 24, -1, 48, + {1, 24, 1, [](DlOpReceiver& r) { r.drawImage(TestImage1, {10, 10}, kNearestSampling, true); }}, - {1, 24, -1, 48, + {1, 24, 1, [](DlOpReceiver& r) { r.drawImage(TestImage1, {20, 10}, kNearestSampling, false); }}, - {1, 24, -1, 48, + {1, 24, 1, [](DlOpReceiver& r) { r.drawImage(TestImage1, {10, 20}, kNearestSampling, false); }}, - {1, 24, -1, 48, + {1, 24, 1, [](DlOpReceiver& r) { r.drawImage(TestImage1, {10, 10}, kLinearSampling, false); }}, - {1, 24, -1, 48, + {1, 24, 1, [](DlOpReceiver& r) { r.drawImage(TestImage2, {10, 10}, kNearestSampling, false); }}, - {1, 24, -1, 48, + {1, 24, 1, [](DlOpReceiver& r) { auto dl_image = DlImage::Make(TestSkImage); r.drawImage(dl_image, {10, 10}, kNearestSampling, false); @@ -710,49 +693,49 @@ std::vector CreateAllRenderingOps() { }}, {"DrawImageRect", { - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { r.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80}, kNearestSampling, false, DlCanvas::SrcRectConstraint::kFast); }}, - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { r.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80}, kNearestSampling, true, DlCanvas::SrcRectConstraint::kFast); }}, - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { r.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80}, kNearestSampling, false, DlCanvas::SrcRectConstraint::kStrict); }}, - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { r.drawImageRect(TestImage1, {10, 10, 25, 20}, {10, 10, 80, 80}, kNearestSampling, false, DlCanvas::SrcRectConstraint::kFast); }}, - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { r.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 85, 80}, kNearestSampling, false, DlCanvas::SrcRectConstraint::kFast); }}, - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { r.drawImageRect(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80}, kLinearSampling, false, DlCanvas::SrcRectConstraint::kFast); }}, - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { r.drawImageRect(TestImage2, {10, 10, 15, 15}, {10, 10, 80, 80}, kNearestSampling, false, DlCanvas::SrcRectConstraint::kFast); }}, - {1, 56, -1, 80, + {1, 56, 1, [](DlOpReceiver& r) { auto dl_image = DlImage::Make(TestSkImage); r.drawImageRect(dl_image, {10, 10, 15, 15}, {10, 10, 80, 80}, @@ -762,39 +745,37 @@ std::vector CreateAllRenderingOps() { }}, {"DrawImageNine", { - // SkCanvas::drawImageNine is immediately converted to - // drawImageLattice - {1, 48, -1, 80, + {1, 48, 1, [](DlOpReceiver& r) { r.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80}, DlFilterMode::kNearest, false); }}, - {1, 48, -1, 80, + {1, 48, 1, [](DlOpReceiver& r) { r.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80}, DlFilterMode::kNearest, true); }}, - {1, 48, -1, 80, + {1, 48, 1, [](DlOpReceiver& r) { r.drawImageNine(TestImage1, {10, 10, 25, 20}, {10, 10, 80, 80}, DlFilterMode::kNearest, false); }}, - {1, 48, -1, 80, + {1, 48, 1, [](DlOpReceiver& r) { r.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 85, 80}, DlFilterMode::kNearest, false); }}, - {1, 48, -1, 80, + {1, 48, 1, [](DlOpReceiver& r) { r.drawImageNine(TestImage1, {10, 10, 20, 20}, {10, 10, 80, 80}, DlFilterMode::kLinear, false); }}, - {1, 48, -1, 80, + {1, 48, 1, [](DlOpReceiver& r) { r.drawImageNine(TestImage2, {10, 10, 15, 15}, {10, 10, 80, 80}, DlFilterMode::kNearest, false); }}, - {1, 48, -1, 80, + {1, 48, 1, [](DlOpReceiver& r) { auto dl_image = DlImage::Make(TestSkImage); r.drawImageNine(dl_image, {10, 10, 15, 15}, {10, 10, 80, 80}, @@ -803,7 +784,7 @@ std::vector CreateAllRenderingOps() { }}, {"DrawAtlas", { - {1, 48 + 32 + 8, -1, 48 + 32 + 32, + {1, 48 + 32 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; @@ -811,14 +792,14 @@ std::vector CreateAllRenderingOps() { DlBlendMode::kSrcIn, kNearestSampling, nullptr, false); }}, - {1, 48 + 32 + 8, -1, 48 + 32 + 32, + {1, 48 + 32 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; r.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn, kNearestSampling, nullptr, true); }}, - {1, 48 + 32 + 8, -1, 48 + 32 + 32, + {1, 48 + 32 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{0, 1, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; @@ -826,7 +807,7 @@ std::vector CreateAllRenderingOps() { DlBlendMode::kSrcIn, kNearestSampling, nullptr, false); }}, - {1, 48 + 32 + 8, -1, 48 + 32 + 32, + {1, 48 + 32 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 25, 30, 30}}; @@ -834,14 +815,14 @@ std::vector CreateAllRenderingOps() { DlBlendMode::kSrcIn, kNearestSampling, nullptr, false); }}, - {1, 48 + 32 + 8, -1, 48 + 32 + 32, + {1, 48 + 32 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; r.drawAtlas(TestImage1, xforms, texs, nullptr, 2, DlBlendMode::kSrcIn, kLinearSampling, nullptr, false); }}, - {1, 48 + 32 + 8, -1, 48 + 32 + 32, + {1, 48 + 32 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; @@ -849,7 +830,7 @@ std::vector CreateAllRenderingOps() { DlBlendMode::kDstIn, kNearestSampling, nullptr, false); }}, - {1, 64 + 32 + 8, -1, 64 + 32 + 32, + {1, 64 + 32 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; @@ -858,7 +839,7 @@ std::vector CreateAllRenderingOps() { DlBlendMode::kSrcIn, kNearestSampling, &cull_rect, false); }}, - {1, 48 + 32 + 8 + 8, -1, 48 + 32 + 32 + 8, + {1, 48 + 32 + 8 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; @@ -867,7 +848,7 @@ std::vector CreateAllRenderingOps() { DlBlendMode::kSrcIn, kNearestSampling, nullptr, false); }}, - {1, 64 + 32 + 8 + 8, -1, 64 + 32 + 32 + 8, + {1, 64 + 32 + 8 + 8, 1, [](DlOpReceiver& r) { static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}}; @@ -877,7 +858,7 @@ std::vector CreateAllRenderingOps() { DlBlendMode::kSrcIn, kNearestSampling, &cull_rect, false); }}, - {1, 48 + 32 + 8, -1, 48 + 32 + 32, + {1, 48 + 32 + 8, 1, [](DlOpReceiver& r) { auto dl_image = DlImage::Make(TestSkImage); static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}}; @@ -889,67 +870,59 @@ std::vector CreateAllRenderingOps() { }}, {"DrawDisplayList", { - // cv.drawDL does not exist - {1, 16, -1, 16, + {1, 16, 2, [](DlOpReceiver& r) { r.drawDisplayList(TestDisplayList1, 1.0); }}, - {1, 16, -1, 16, + {1, 16, 2, [](DlOpReceiver& r) { r.drawDisplayList(TestDisplayList1, 0.5); }}, - {1, 16, -1, 16, + {1, 16, 2, [](DlOpReceiver& r) { r.drawDisplayList(TestDisplayList2, 1.0); }}, - {1, 16, -1, 16, + {1, 16, 2, [](DlOpReceiver& r) { r.drawDisplayList(MakeTestDisplayList(10, 10, SK_ColorRED), 1.0); }}, }}, {"DrawTextBlob", { - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawTextBlob(GetTestTextBlob(1), 10, 10); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawTextBlob(GetTestTextBlob(1), 20, 10); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawTextBlob(GetTestTextBlob(1), 10, 20); }}, - {1, 24, 1, 24, + {1, 24, 1, [](DlOpReceiver& r) { r.drawTextBlob(GetTestTextBlob(2), 10, 10); }}, }}, - // The -1 op counts below are to indicate to the framework not to test - // SkCanvas conversion of these ops as it converts the operation into a - // format that is not exposed publicly and so we cannot recapture the - // operation. - // See: https://bugs.chromium.org/p/skia/issues/detail?id=12125 {"DrawShadow", { - // cv shadows are turned into an opaque ShadowRec which is not - // exposed - {1, 48, -1, 48, + {1, 48, 1, [](DlOpReceiver& r) { r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 1.0, false, 1.0); }}, - {1, 48, -1, 48, + {1, 48, 1, [](DlOpReceiver& r) { r.drawShadow(kTestPath2, DlColor(SK_ColorGREEN), 1.0, false, 1.0); }}, - {1, 48, -1, 48, + {1, 48, 1, [](DlOpReceiver& r) { r.drawShadow(kTestPath1, DlColor(SK_ColorBLUE), 1.0, false, 1.0); }}, - {1, 48, -1, 48, + {1, 48, 1, [](DlOpReceiver& r) { r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 2.0, false, 1.0); }}, - {1, 48, -1, 48, + {1, 48, 1, [](DlOpReceiver& r) { r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 1.0, true, 1.0); }}, - {1, 48, -1, 48, + {1, 48, 1, [](DlOpReceiver& r) { r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 1.0, false, 2.5); }}, diff --git a/display_list/testing/dl_test_snippets.h b/display_list/testing/dl_test_snippets.h index aa3bf23619a83..4a2b725b86b82 100644 --- a/display_list/testing/dl_test_snippets.h +++ b/display_list/testing/dl_test_snippets.h @@ -228,14 +228,10 @@ SkFont CreateTestFontOfSize(SkScalar scalar); sk_sp GetTestTextBlob(int index); struct DisplayListInvocation { - unsigned int op_count_; + uint32_t op_count_; size_t byte_count_; - // in some cases, running the sequence through an SkCanvas will result - // in fewer ops/bytes. Attribute invocations are recorded in an SkPaint - // and not forwarded on, and SkCanvas culls unused save/restore/transforms. - int sk_op_count_; - size_t sk_byte_count_; + uint32_t depth_; DlInvoker invoker; bool supports_group_opacity_ = false; @@ -244,20 +240,16 @@ struct DisplayListInvocation { bool supports_group_opacity() { return supports_group_opacity_; } - unsigned int op_count() { return op_count_; } + uint32_t op_count() { return op_count_; } // byte count for the individual ops, no DisplayList overhead size_t raw_byte_count() { return byte_count_; } // byte count for the ops with DisplayList overhead, comparable // to |DisplayList.byte_count(). size_t byte_count() { return sizeof(DisplayList) + byte_count_; } - void Invoke(DlOpReceiver& builder) { invoker(builder); } + uint32_t depth() { return depth_; } - // sk_sp Build() { - // DisplayListBuilder builder; - // invoker(builder.asReceiver()); - // return builder.Build(); - // } + void Invoke(DlOpReceiver& builder) { invoker(builder); } }; struct DisplayListInvocationGroup {