Skip to content

Commit 0bd729b

Browse files
author
George Wright
authored
Add a DisplayListComplexityCalculator class that calculates the current "complexity score" of a given DisplayList during the Build phase. (flutter#31176)
1 parent 5bbdb7a commit 0bd729b

File tree

12 files changed

+200
-32
lines changed

12 files changed

+200
-32
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ FILE: ../../../flutter/display_list/display_list_canvas_dispatcher.h
5252
FILE: ../../../flutter/display_list/display_list_canvas_recorder.cc
5353
FILE: ../../../flutter/display_list/display_list_canvas_recorder.h
5454
FILE: ../../../flutter/display_list/display_list_canvas_unittests.cc
55+
FILE: ../../../flutter/display_list/display_list_complexity.cc
56+
FILE: ../../../flutter/display_list/display_list_complexity.h
5557
FILE: ../../../flutter/display_list/display_list_dispatcher.cc
5658
FILE: ../../../flutter/display_list/display_list_dispatcher.h
5759
FILE: ../../../flutter/display_list/display_list_flags.cc

display_list/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ source_set("display_list") {
1414
"display_list_canvas_dispatcher.h",
1515
"display_list_canvas_recorder.cc",
1616
"display_list_canvas_recorder.h",
17+
"display_list_complexity.cc",
18+
"display_list_complexity.h",
1719
"display_list_dispatcher.cc",
1820
"display_list_dispatcher.h",
1921
"display_list_flags.cc",

display_list/display_list.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ DisplayList::DisplayList()
3232

3333
DisplayList::DisplayList(uint8_t* ptr,
3434
size_t byte_count,
35-
int op_count,
35+
unsigned int op_count,
3636
size_t nested_byte_count,
37-
int nested_op_count,
37+
unsigned int nested_op_count,
3838
const SkRect& cull_rect,
3939
bool can_apply_group_opacity)
4040
: storage_(ptr),

display_list/display_list.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class DisplayList : public SkRefCnt {
179179
(nested ? nested_byte_count_ : 0);
180180
}
181181

182-
int op_count(bool nested = false) const {
182+
unsigned int op_count(bool nested = false) const {
183183
return op_count_ + (nested ? nested_op_count_ : 0);
184184
}
185185

@@ -203,18 +203,18 @@ class DisplayList : public SkRefCnt {
203203
private:
204204
DisplayList(uint8_t* ptr,
205205
size_t byte_count,
206-
int op_count,
206+
unsigned int op_count,
207207
size_t nested_byte_count,
208-
int nested_op_count,
208+
unsigned int nested_op_count,
209209
const SkRect& cull_rect,
210210
bool can_apply_group_opacity);
211211

212212
std::unique_ptr<uint8_t, SkFunctionWrapper<void(void*), sk_free>> storage_;
213213
size_t byte_count_;
214-
int op_count_;
214+
unsigned int op_count_;
215215

216216
size_t nested_byte_count_;
217-
int nested_op_count_;
217+
unsigned int nested_op_count_;
218218

219219
uint32_t unique_id_;
220220
SkRect bounds_;

display_list/display_list_canvas_unittests.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1732,7 +1732,8 @@ class CanvasCompareTester {
17321732
// of the embedded calls in the display list and so the op counts
17331733
// will not be equal between the two.
17341734
if (!testP.is_draw_display_list()) {
1735-
EXPECT_EQ(display_list->op_count(), sk_picture->approximateOpCount())
1735+
EXPECT_EQ(static_cast<int>(display_list->op_count()),
1736+
sk_picture->approximateOpCount())
17361737
<< info;
17371738
}
17381739

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
// Copyright 2013 The Flutter Authors. All rights reserved.
3+
// Use of this source code is governed by a BSD-style license that can be
4+
// found in the LICENSE file.
5+
6+
#include "flutter/display_list/display_list_complexity.h"
7+
#include "flutter/display_list/display_list.h"
8+
9+
namespace flutter {
10+
11+
DisplayListNaiveComplexityCalculator*
12+
DisplayListNaiveComplexityCalculator::instance_ = nullptr;
13+
14+
DisplayListComplexityCalculator*
15+
DisplayListNaiveComplexityCalculator::GetInstance() {
16+
if (instance_ == nullptr) {
17+
instance_ = new DisplayListNaiveComplexityCalculator();
18+
}
19+
return instance_;
20+
}
21+
22+
DisplayListComplexityCalculator* DisplayListComplexityCalculator::GetForBackend(
23+
GrBackendApi backend) {
24+
switch (backend) {
25+
default:
26+
return DisplayListNaiveComplexityCalculator::GetInstance();
27+
}
28+
}
29+
30+
DisplayListComplexityCalculator*
31+
DisplayListComplexityCalculator::GetForSoftware() {
32+
return DisplayListNaiveComplexityCalculator::GetInstance();
33+
}
34+
35+
} // namespace flutter
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_FLOW_DISPLAY_LIST_COMPLEXITY_H_
6+
#define FLUTTER_FLOW_DISPLAY_LIST_COMPLEXITY_H_
7+
8+
#include "flutter/display_list/display_list.h"
9+
#include "flutter/display_list/types.h"
10+
#include "third_party/skia/include/gpu/GrTypes.h"
11+
12+
namespace flutter {
13+
14+
class DisplayListComplexityCalculator {
15+
public:
16+
static DisplayListComplexityCalculator* GetForSoftware();
17+
static DisplayListComplexityCalculator* GetForBackend(GrBackendApi backend);
18+
19+
virtual ~DisplayListComplexityCalculator() = default;
20+
21+
// Returns a calculated complexity score for a given DisplayList object
22+
virtual unsigned int compute(DisplayList* display_list) = 0;
23+
24+
// Returns whether a given complexity score meets the threshold for
25+
// cacheability for this particular ComplexityCalculator
26+
virtual bool should_be_cached(unsigned int complexity_score) = 0;
27+
};
28+
29+
class DisplayListNaiveComplexityCalculator
30+
: public DisplayListComplexityCalculator {
31+
public:
32+
static DisplayListComplexityCalculator* GetInstance();
33+
34+
unsigned int compute(DisplayList* display_list) override {
35+
return display_list->op_count(true);
36+
}
37+
38+
bool should_be_cached(unsigned int complexity_score) override {
39+
return complexity_score > 5u;
40+
}
41+
42+
private:
43+
DisplayListNaiveComplexityCalculator() {}
44+
static DisplayListNaiveComplexityCalculator* instance_;
45+
};
46+
47+
} // namespace flutter
48+
49+
#endif // FLUTTER_FLOW_DISPLAY_LIST_COMPLEXITY_H_

display_list/display_list_unittests.cc

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ static sk_sp<SkTextBlob> TestBlob2 = MakeTextBlob("TestBlob2");
213213
typedef const std::function<void(DisplayListBuilder&)> DlInvoker;
214214

215215
struct DisplayListInvocation {
216-
int op_count_;
216+
unsigned int op_count_;
217217
size_t byte_count_;
218218

219219
// in some cases, running the sequence through an SkCanvas will result
@@ -226,7 +226,8 @@ struct DisplayListInvocation {
226226
bool supports_group_opacity_ = false;
227227

228228
bool sk_version_matches() {
229-
return (op_count_ == sk_op_count_ && byte_count_ == sk_byte_count_);
229+
return (static_cast<int>(op_count_) == sk_op_count_ &&
230+
byte_count_ == sk_byte_count_);
230231
}
231232

232233
// A negative sk_op_count means "do not test this op".
@@ -240,7 +241,7 @@ struct DisplayListInvocation {
240241

241242
bool supports_group_opacity() { return supports_group_opacity_; }
242243

243-
int op_count() { return op_count_; }
244+
unsigned int op_count() { return op_count_; }
244245
// byte count for the individual ops, no DisplayList overhead
245246
size_t raw_byte_count() { return byte_count_; }
246247
// byte count for the ops with DisplayList overhead, comparable
@@ -797,7 +798,8 @@ TEST(DisplayList, SingleOpDisplayListsRecapturedViaSkCanvasAreEqual) {
797798
dl->RenderTo(&recorder);
798799
sk_sp<DisplayList> sk_copy = recorder.Build();
799800
auto desc = group.op_name + "[variant " + std::to_string(i + 1) + "]";
800-
EXPECT_EQ(sk_copy->op_count(false), group.variants[i].sk_op_count())
801+
EXPECT_EQ(static_cast<int>(sk_copy->op_count(false)),
802+
group.variants[i].sk_op_count())
801803
<< desc;
802804
EXPECT_EQ(sk_copy->bytes(false), group.variants[i].sk_byte_count())
803805
<< desc;
@@ -861,8 +863,8 @@ TEST(DisplayList, FullRotationsAreNop) {
861863
sk_sp<DisplayList> dl = builder.Build();
862864
ASSERT_EQ(dl->bytes(false), sizeof(DisplayList));
863865
ASSERT_EQ(dl->bytes(true), sizeof(DisplayList));
864-
ASSERT_EQ(dl->op_count(false), 0);
865-
ASSERT_EQ(dl->op_count(true), 0);
866+
ASSERT_EQ(dl->op_count(false), 0u);
867+
ASSERT_EQ(dl->op_count(true), 0u);
866868
}
867869

868870
TEST(DisplayList, AllBlendModeNops) {
@@ -872,13 +874,13 @@ TEST(DisplayList, AllBlendModeNops) {
872874
sk_sp<DisplayList> dl = builder.Build();
873875
ASSERT_EQ(dl->bytes(false), sizeof(DisplayList));
874876
ASSERT_EQ(dl->bytes(true), sizeof(DisplayList));
875-
ASSERT_EQ(dl->op_count(false), 0);
876-
ASSERT_EQ(dl->op_count(true), 0);
877+
ASSERT_EQ(dl->op_count(false), 0u);
878+
ASSERT_EQ(dl->op_count(true), 0u);
877879
}
878880

879881
static sk_sp<DisplayList> Build(size_t g_index, size_t v_index) {
880882
DisplayListBuilder builder;
881-
int op_count = 0;
883+
unsigned int op_count = 0;
882884
size_t byte_count = 0;
883885
for (size_t i = 0; i < allGroups.size(); i++) {
884886
DisplayListInvocationGroup& group = allGroups[i];
@@ -1128,18 +1130,20 @@ TEST(DisplayList, NestedOpCountMetricsSameAsSkPicture) {
11281130
outer_builder.drawDisplayList(builder.Build());
11291131

11301132
auto display_list = outer_builder.Build();
1131-
ASSERT_EQ(display_list->op_count(), 1);
1132-
ASSERT_EQ(display_list->op_count(true), 36);
1133+
ASSERT_EQ(display_list->op_count(), 1u);
1134+
ASSERT_EQ(display_list->op_count(true), 36u);
11331135

1134-
ASSERT_EQ(picture->approximateOpCount(), display_list->op_count());
1135-
ASSERT_EQ(picture->approximateOpCount(true), display_list->op_count(true));
1136+
ASSERT_EQ(picture->approximateOpCount(),
1137+
static_cast<int>(display_list->op_count()));
1138+
ASSERT_EQ(picture->approximateOpCount(true),
1139+
static_cast<int>(display_list->op_count(true)));
11361140

11371141
DisplayListCanvasRecorder dl_recorder(SkRect::MakeWH(150, 100));
11381142
picture->playback(&dl_recorder);
11391143

11401144
auto sk_display_list = dl_recorder.Build();
1141-
ASSERT_EQ(display_list->op_count(), 1);
1142-
ASSERT_EQ(display_list->op_count(true), 36);
1145+
ASSERT_EQ(display_list->op_count(), 1u);
1146+
ASSERT_EQ(display_list->op_count(true), 36u);
11431147
}
11441148

11451149
class AttributeRefTester {
@@ -1375,7 +1379,7 @@ TEST(DisplayList, SetMaskBlurSigmaZeroResetsMaskFilter) {
13751379
EXPECT_EQ(builder.getMaskFilter(), nullptr);
13761380
builder.drawRect({30, 30, 40, 40});
13771381
sk_sp<DisplayList> display_list = builder.Build();
1378-
ASSERT_EQ(display_list->op_count(), 2);
1382+
ASSERT_EQ(display_list->op_count(), 2u);
13791383
ASSERT_EQ(display_list->bytes(), sizeof(DisplayList) + 8u + 24u + 8u + 24u);
13801384
}
13811385

@@ -1387,7 +1391,7 @@ TEST(DisplayList, SetMaskFilterNullResetsMaskFilter) {
13871391
EXPECT_EQ(builder.getMaskFilter(), nullptr);
13881392
builder.drawRect({30, 30, 40, 40});
13891393
sk_sp<DisplayList> display_list = builder.Build();
1390-
ASSERT_EQ(display_list->op_count(), 2);
1394+
ASSERT_EQ(display_list->op_count(), 2u);
13911395
ASSERT_EQ(display_list->bytes(), sizeof(DisplayList) + 8u + 24u + 8u + 24u);
13921396
}
13931397

display_list/types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "third_party/skia/include/core/SkShader.h"
2121
#include "third_party/skia/include/core/SkTextBlob.h"
2222
#include "third_party/skia/include/core/SkVertices.h"
23+
#include "third_party/skia/include/gpu/GrTypes.h"
2324
#include "third_party/skia/include/utils/SkShadowUtils.h"
2425

2526
#endif // FLUTTER_DISPLAY_LIST_TYPES_H_

flow/raster_cache.cc

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ static bool IsPictureWorthRasterizing(SkPicture* picture,
8686
return picture->approximateOpCount(true) > 5;
8787
}
8888

89-
static bool IsDisplayListWorthRasterizing(DisplayList* display_list,
90-
bool will_change,
91-
bool is_complex) {
89+
static bool IsDisplayListWorthRasterizing(
90+
DisplayList* display_list,
91+
bool will_change,
92+
bool is_complex,
93+
DisplayListComplexityCalculator* complexity_calculator) {
9294
if (will_change) {
9395
// If the display list is going to change in the future, there is no point
9496
// in doing to extra work to rasterize.
@@ -109,7 +111,8 @@ static bool IsDisplayListWorthRasterizing(DisplayList* display_list,
109111

110112
// TODO(abarth): We should find a better heuristic here that lets us avoid
111113
// wasting memory on trivial layers that are easy to re-rasterize every frame.
112-
return display_list->op_count(true) > 5;
114+
int complexity_score = complexity_calculator->compute(display_list);
115+
return complexity_calculator->should_be_cached(complexity_score);
113116
}
114117

115118
/// @note Procedure doesn't copy all closures.
@@ -273,7 +276,13 @@ bool RasterCache::Prepare(PrerollContext* context,
273276
return false;
274277
}
275278

276-
if (!IsDisplayListWorthRasterizing(display_list, will_change, is_complex)) {
279+
DisplayListComplexityCalculator* complexity_calculator =
280+
context->gr_context ? DisplayListComplexityCalculator::GetForBackend(
281+
context->gr_context->backend())
282+
: DisplayListComplexityCalculator::GetForSoftware();
283+
284+
if (!IsDisplayListWorthRasterizing(display_list, will_change, is_complex,
285+
complexity_calculator)) {
277286
// We only deal with display lists that are worthy of rasterization.
278287
return false;
279288
}

0 commit comments

Comments
 (0)