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

Commit 9bb0a59

Browse files
authored
Reland "add non-rendering operation culling to DisplayListBuilder" (#41463) (#42584)
This reverts commit 2553def. Fixes flutter/flutter#125338 This PR should fix the blendmode/color analysis that caused failures for #41463 as well as the bounds failures for inverted rectangles that caused failures for #42330 (incorporating the fix from #42556). The description from the [previous PR](#41463) updated with the new name of the DL property: --------------------------------- This optimization avoids recording unnecessary render operations that will not affect the output and also eliminates the need for "draw detection" mechanisms like `DlOpSpy` and `CanvasSpy` by remembering if any non-transparent operations were included. The `DlOpSpy` unit tests were updated to check if the results from that object match the new `DisplayList::modifies_transparent_black()` method. Fixes flutter/flutter#125338 In addition, this change will unblock some other Issues: - flutter/flutter#125318 - flutter/flutter#125403
1 parent 788437e commit 9bb0a59

20 files changed

+1267
-311
lines changed

display_list/benchmarking/dl_complexity_unittests.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ TEST(DisplayListComplexity, DrawAtlas) {
423423
std::vector<SkRSXform> xforms;
424424
for (int i = 0; i < 10; i++) {
425425
rects.push_back(SkRect::MakeXYWH(0, 0, 10, 10));
426-
xforms.push_back(SkRSXform::Make(0, 0, 0, 0));
426+
xforms.push_back(SkRSXform::Make(1, 0, 0, 0));
427427
}
428428

429429
DisplayListBuilder builder;

display_list/display_list.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ DisplayList::DisplayList()
2222
unique_id_(0),
2323
bounds_({0, 0, 0, 0}),
2424
can_apply_group_opacity_(true),
25-
is_ui_thread_safe_(true) {}
25+
is_ui_thread_safe_(true),
26+
modifies_transparent_black_(false) {}
2627

2728
DisplayList::DisplayList(DisplayListStorage&& storage,
2829
size_t byte_count,
@@ -32,6 +33,7 @@ DisplayList::DisplayList(DisplayListStorage&& storage,
3233
const SkRect& bounds,
3334
bool can_apply_group_opacity,
3435
bool is_ui_thread_safe,
36+
bool modifies_transparent_black,
3537
sk_sp<const DlRTree> rtree)
3638
: storage_(std::move(storage)),
3739
byte_count_(byte_count),
@@ -42,6 +44,7 @@ DisplayList::DisplayList(DisplayListStorage&& storage,
4244
bounds_(bounds),
4345
can_apply_group_opacity_(can_apply_group_opacity),
4446
is_ui_thread_safe_(is_ui_thread_safe),
47+
modifies_transparent_black_(modifies_transparent_black),
4548
rtree_(std::move(rtree)) {}
4649

4750
DisplayList::~DisplayList() {

display_list/display_list.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,19 @@ class DisplayList : public SkRefCnt {
265265
bool can_apply_group_opacity() const { return can_apply_group_opacity_; }
266266
bool isUIThreadSafe() const { return is_ui_thread_safe_; }
267267

268+
/// @brief Indicates if there are any rendering operations in this
269+
/// DisplayList that will modify a surface of transparent black
270+
/// pixels.
271+
///
272+
/// This condition can be used to determine whether to create a cleared
273+
/// surface, render a DisplayList into it, and then composite the
274+
/// result into a scene. It is not uncommon for code in the engine to
275+
/// come across such degenerate DisplayList objects when slicing up a
276+
/// frame between platform views.
277+
bool modifies_transparent_black() const {
278+
return modifies_transparent_black_;
279+
}
280+
268281
private:
269282
DisplayList(DisplayListStorage&& ptr,
270283
size_t byte_count,
@@ -274,6 +287,7 @@ class DisplayList : public SkRefCnt {
274287
const SkRect& bounds,
275288
bool can_apply_group_opacity,
276289
bool is_ui_thread_safe,
290+
bool modifies_transparent_black,
277291
sk_sp<const DlRTree> rtree);
278292

279293
static uint32_t next_unique_id();
@@ -292,6 +306,8 @@ class DisplayList : public SkRefCnt {
292306

293307
const bool can_apply_group_opacity_;
294308
const bool is_ui_thread_safe_;
309+
const bool modifies_transparent_black_;
310+
295311
const sk_sp<const DlRTree> rtree_;
296312

297313
void Dispatch(DlOpReceiver& ctx,

display_list/display_list_unittests.cc

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "flutter/testing/testing.h"
2323

2424
#include "third_party/skia/include/core/SkPictureRecorder.h"
25+
#include "third_party/skia/include/core/SkRSXform.h"
2526
#include "third_party/skia/include/core/SkSurface.h"
2627

2728
namespace flutter {
@@ -3016,5 +3017,164 @@ TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCCW) {
30163017
check_inverted_bounds(renderer, "DrawRoundRectPath Counter-Clockwise");
30173018
}
30183019

3020+
TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) {
3021+
auto run_tests = [](const std::string& name,
3022+
void init(DisplayListBuilder & builder, DlPaint & paint),
3023+
uint32_t expected_op_count = 0u) {
3024+
auto run_one_test =
3025+
[init](const std::string& name,
3026+
void build(DisplayListBuilder & builder, DlPaint & paint),
3027+
uint32_t expected_op_count = 0u) {
3028+
DisplayListBuilder builder;
3029+
DlPaint paint;
3030+
init(builder, paint);
3031+
build(builder, paint);
3032+
auto list = builder.Build();
3033+
if (list->op_count() != expected_op_count) {
3034+
FML_LOG(ERROR) << *list;
3035+
}
3036+
ASSERT_EQ(list->op_count(), expected_op_count) << name;
3037+
ASSERT_TRUE(list->bounds().isEmpty()) << name;
3038+
};
3039+
run_one_test(
3040+
name + " DrawColor",
3041+
[](DisplayListBuilder& builder, DlPaint& paint) {
3042+
builder.DrawColor(paint.getColor(), paint.getBlendMode());
3043+
},
3044+
expected_op_count);
3045+
run_one_test(
3046+
name + " DrawPaint",
3047+
[](DisplayListBuilder& builder, DlPaint& paint) {
3048+
builder.DrawPaint(paint);
3049+
},
3050+
expected_op_count);
3051+
run_one_test(
3052+
name + " DrawRect",
3053+
[](DisplayListBuilder& builder, DlPaint& paint) {
3054+
builder.DrawRect({10, 10, 20, 20}, paint);
3055+
},
3056+
expected_op_count);
3057+
run_one_test(
3058+
name + " Other Draw Ops",
3059+
[](DisplayListBuilder& builder, DlPaint& paint) {
3060+
builder.DrawLine({10, 10}, {20, 20}, paint);
3061+
builder.DrawOval({10, 10, 20, 20}, paint);
3062+
builder.DrawCircle({50, 50}, 20, paint);
3063+
builder.DrawRRect(SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5), paint);
3064+
builder.DrawDRRect(SkRRect::MakeRectXY({5, 5, 100, 100}, 5, 5),
3065+
SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5),
3066+
paint);
3067+
builder.DrawPath(kTestPath1, paint);
3068+
builder.DrawArc({10, 10, 20, 20}, 45, 90, true, paint);
3069+
SkPoint pts[] = {{10, 10}, {20, 20}};
3070+
builder.DrawPoints(PointMode::kLines, 2, pts, paint);
3071+
builder.DrawVertices(TestVertices1, DlBlendMode::kSrcOver, paint);
3072+
builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear,
3073+
&paint);
3074+
builder.DrawImageRect(TestImage1, SkRect{0.0f, 0.0f, 10.0f, 10.0f},
3075+
SkRect{10.0f, 10.0f, 25.0f, 25.0f},
3076+
DlImageSampling::kLinear, &paint);
3077+
builder.DrawImageNine(TestImage1, {10, 10, 20, 20},
3078+
{10, 10, 100, 100}, DlFilterMode::kLinear,
3079+
&paint);
3080+
SkRSXform xforms[] = {{1, 0, 10, 10}, {0, 1, 10, 10}};
3081+
SkRect rects[] = {{10, 10, 20, 20}, {10, 20, 30, 20}};
3082+
builder.DrawAtlas(TestImage1, xforms, rects, nullptr, 2,
3083+
DlBlendMode::kSrcOver, DlImageSampling::kLinear,
3084+
nullptr, &paint);
3085+
builder.DrawTextBlob(TestBlob1, 10, 10, paint);
3086+
3087+
// Dst mode eliminates most rendering ops except for
3088+
// the following two, so we'll prune those manually...
3089+
if (paint.getBlendMode() != DlBlendMode::kDst) {
3090+
builder.DrawDisplayList(TestDisplayList1, paint.getOpacity());
3091+
builder.DrawShadow(kTestPath1, paint.getColor(), 1, true, 1);
3092+
}
3093+
},
3094+
expected_op_count);
3095+
run_one_test(
3096+
name + " SaveLayer",
3097+
[](DisplayListBuilder& builder, DlPaint& paint) {
3098+
builder.SaveLayer(nullptr, &paint, nullptr);
3099+
builder.DrawRect({10, 10, 20, 20}, DlPaint());
3100+
builder.Restore();
3101+
},
3102+
expected_op_count);
3103+
run_one_test(
3104+
name + " inside Save",
3105+
[](DisplayListBuilder& builder, DlPaint& paint) {
3106+
builder.Save();
3107+
builder.DrawRect({10, 10, 20, 20}, paint);
3108+
builder.Restore();
3109+
},
3110+
expected_op_count);
3111+
};
3112+
run_tests("transparent color", //
3113+
[](DisplayListBuilder& builder, DlPaint& paint) {
3114+
paint.setColor(DlColor::kTransparent());
3115+
});
3116+
run_tests("0 alpha", //
3117+
[](DisplayListBuilder& builder, DlPaint& paint) {
3118+
// The transparent test above already tested transparent
3119+
// black (all 0s), we set White color here so we can test
3120+
// the case of all 1s with a 0 alpha
3121+
paint.setColor(DlColor::kWhite());
3122+
paint.setAlpha(0);
3123+
});
3124+
run_tests("BlendMode::kDst", //
3125+
[](DisplayListBuilder& builder, DlPaint& paint) {
3126+
paint.setBlendMode(DlBlendMode::kDst);
3127+
});
3128+
run_tests("Empty rect clip", //
3129+
[](DisplayListBuilder& builder, DlPaint& paint) {
3130+
builder.ClipRect(SkRect::MakeEmpty(), ClipOp::kIntersect, false);
3131+
});
3132+
run_tests("Empty rrect clip", //
3133+
[](DisplayListBuilder& builder, DlPaint& paint) {
3134+
builder.ClipRRect(SkRRect::MakeEmpty(), ClipOp::kIntersect,
3135+
false);
3136+
});
3137+
run_tests("Empty path clip", //
3138+
[](DisplayListBuilder& builder, DlPaint& paint) {
3139+
builder.ClipPath(SkPath(), ClipOp::kIntersect, false);
3140+
});
3141+
run_tests("Transparent SaveLayer", //
3142+
[](DisplayListBuilder& builder, DlPaint& paint) {
3143+
DlPaint save_paint;
3144+
save_paint.setColor(DlColor::kTransparent());
3145+
builder.SaveLayer(nullptr, &save_paint);
3146+
});
3147+
run_tests("0 alpha SaveLayer", //
3148+
[](DisplayListBuilder& builder, DlPaint& paint) {
3149+
DlPaint save_paint;
3150+
// The transparent test above already tested transparent
3151+
// black (all 0s), we set White color here so we can test
3152+
// the case of all 1s with a 0 alpha
3153+
save_paint.setColor(DlColor::kWhite());
3154+
save_paint.setAlpha(0);
3155+
builder.SaveLayer(nullptr, &save_paint);
3156+
});
3157+
run_tests("Dst blended SaveLayer", //
3158+
[](DisplayListBuilder& builder, DlPaint& paint) {
3159+
DlPaint save_paint;
3160+
save_paint.setBlendMode(DlBlendMode::kDst);
3161+
builder.SaveLayer(nullptr, &save_paint);
3162+
});
3163+
run_tests(
3164+
"Nop inside SaveLayer",
3165+
[](DisplayListBuilder& builder, DlPaint& paint) {
3166+
builder.SaveLayer(nullptr, nullptr);
3167+
paint.setBlendMode(DlBlendMode::kDst);
3168+
},
3169+
2u);
3170+
run_tests("DrawImage inside Culled SaveLayer", //
3171+
[](DisplayListBuilder& builder, DlPaint& paint) {
3172+
DlPaint save_paint;
3173+
save_paint.setColor(DlColor::kTransparent());
3174+
builder.SaveLayer(nullptr, &save_paint);
3175+
builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear);
3176+
});
3177+
}
3178+
30193179
} // namespace testing
30203180
} // namespace flutter

0 commit comments

Comments
 (0)