Skip to content

Commit f6ea618

Browse files
author
George Wright
authored
Tweak drawTextBlob cost based on multiple draw calls and update the benchmark accordingly (#31561)
1 parent 749794a commit f6ea618

7 files changed

+107
-125
lines changed

display_list/display_list_benchmarks.cc

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,48 +1182,20 @@ void BM_DrawTextBlob(benchmark::State& state,
11821182
DisplayListOpFlags::kDrawTextBlobFlags);
11831183
AnnotateAttributes(attributes, state, DisplayListOpFlags::kDrawTextBlobFlags);
11841184

1185-
size_t glyph_runs = state.range(0);
1185+
size_t draw_calls = state.range(0);
11861186
size_t canvas_size = kFixedCanvasSize;
11871187
canvas_provider->InitializeSurface(canvas_size, canvas_size);
11881188
auto canvas = canvas_provider->GetSurface()->getCanvas();
11891189

1190-
// We're just using plain Latin-1 where glyph count == character count
1191-
const char* string_fragment = "This text has exactly 32 glyphs.";
1192-
size_t fragment_length = strlen(string_fragment);
1193-
state.SetComplexityN(glyph_runs * fragment_length);
1194-
1195-
// TODO(gw280): different fonts
1196-
SkFont font;
1197-
1198-
auto blob_fragment = SkTextBlob::MakeFromString(string_fragment, font);
1199-
auto bounds = blob_fragment->bounds();
1200-
1201-
// Calculate the approximate number of these glyph runs we can fit on a single
1202-
// canvas.
1203-
size_t x_count_max = canvas_size / bounds.width();
1204-
size_t y_count_max = canvas_size / bounds.height();
1205-
size_t remaining_runs = glyph_runs;
1206-
1207-
SkTextBlobBuilder blob_builder;
1208-
size_t current_y = 0;
1209-
while (remaining_runs > 0) {
1210-
size_t runs_this_pass = std::min(x_count_max, remaining_runs);
1211-
auto buffer = blob_builder.allocRun(
1212-
font, runs_this_pass * fragment_length, 0,
1213-
((current_y % y_count_max) + 1) * bounds.height());
1214-
for (size_t i = 0; i < runs_this_pass; i++) {
1215-
font.textToGlyphs(string_fragment, fragment_length, SkTextEncoding::kUTF8,
1216-
buffer.glyphs + (i * fragment_length), fragment_length);
1217-
}
1218-
remaining_runs -= runs_this_pass;
1219-
current_y++;
1220-
}
1221-
1222-
auto blob = blob_builder.make();
1190+
state.counters["DrawCallCount_Varies"] = draw_calls;
1191+
state.counters["GlyphCount"] = draw_calls;
1192+
char character[2] = {'A', '\0'};
12231193

1224-
state.counters["DrawCallCount"] = 1;
1225-
state.counters["GlyphCount"] = glyph_runs * fragment_length;
1226-
builder.drawTextBlob(blob, 0.0f, 0.0f);
1194+
for (size_t i = 0; i < draw_calls; i++) {
1195+
character[0] = 'A' + (i % 26);
1196+
auto blob = SkTextBlob::MakeFromString(character, SkFont());
1197+
builder.drawTextBlob(blob, 50.0f, 50.0f);
1198+
}
12271199

12281200
auto display_list = builder.Build();
12291201

@@ -1233,7 +1205,7 @@ void BM_DrawTextBlob(benchmark::State& state,
12331205
}
12341206

12351207
auto filename = canvas_provider->BackendName() + "-DrawTextBlob-" +
1236-
std::to_string(glyph_runs * fragment_length) + ".png";
1208+
std::to_string(draw_calls) + ".png";
12371209
canvas_provider->Snapshot(filename);
12381210
}
12391211

display_list/display_list_complexity_gl.cc

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,36 @@ DisplayListGLComplexityCalculator::GetInstance() {
2525
return instance_;
2626
}
2727

28-
unsigned int
29-
DisplayListGLComplexityCalculator::GLHelper::SaveLayerComplexity() {
28+
unsigned int DisplayListGLComplexityCalculator::GLHelper::BatchedComplexity() {
3029
// Calculate the impact of saveLayer.
3130
unsigned int save_layer_complexity;
32-
if (SaveLayerCount() == 0) {
31+
if (save_layer_count_ == 0) {
3332
save_layer_complexity = 0;
3433
} else {
3534
// m = 1/5
3635
// c = 10
37-
save_layer_complexity = (SaveLayerCount() + 50) * 40000;
36+
save_layer_complexity = (save_layer_count_ + 50) * 40000;
3837
}
3938

40-
return save_layer_complexity;
39+
unsigned int draw_text_blob_complexity;
40+
if (draw_text_blob_count_ == 0) {
41+
draw_text_blob_complexity = 0;
42+
} else {
43+
// m = 1/240
44+
// c = 0.25
45+
draw_text_blob_complexity = (draw_text_blob_count_ + 60) * 2500 / 3;
46+
}
47+
48+
return save_layer_complexity + draw_text_blob_complexity;
49+
}
50+
51+
void DisplayListGLComplexityCalculator::GLHelper::saveLayer(
52+
const SkRect* bounds,
53+
const SaveLayerOptions options) {
54+
if (IsComplex()) {
55+
return;
56+
}
57+
save_layer_count_++;
4158
}
4259

4360
void DisplayListGLComplexityCalculator::GLHelper::drawLine(const SkPoint& p0,
@@ -611,33 +628,13 @@ void DisplayListGLComplexityCalculator::GLHelper::drawTextBlob(
611628
if (IsComplex()) {
612629
return;
613630
}
614-
// There are two classes here, hairline vs non-hairline.
615-
// Hairline scales loglinearly with the number of glyphs.
616-
// Non-hairline scales linearly.
617631

618-
// Unfortunately there is currently no way for us to figure out the glyph
619-
// count from an SkTextBlob. We will need to figure out a better solution
620-
// here, but for now just use a placeholder value of 100 glyphs.
621-
unsigned int glyph_count = 100;
632+
// DrawTextBlob has a high fixed cost, but if we call it multiple times
633+
// per frame, that fixed cost is greatly reduced per subsequent call. This
634+
// is likely because there is batching being done in SkCanvas.
622635

623-
// These values were worked out by creating a straight line graph (y=mx+c)
624-
// approximately matching the measured data, normalising the data so that
625-
// 0.0005ms resulted in a score of 100 then simplifying down the formula.
626-
unsigned int complexity;
627-
if (IsHairline() && Style() == SkPaint::Style::kStroke_Style) {
628-
// If hairlines are on, we hit a degenerative case within Skia that causes
629-
// our time to skyrocket.
630-
//
631-
// m = 1/65
632-
// c = 1
633-
complexity = (glyph_count + 65) * 40000 / 13;
634-
} else {
635-
// m = 1/3500
636-
// c = 0.5
637-
complexity = (glyph_count + 1750) * 40 / 7;
638-
}
639-
640-
AccumulateComplexity(complexity);
636+
// Increment draw_text_blob_count_ and calculate the cost at the end.
637+
draw_text_blob_count_++;
641638
}
642639

643640
void DisplayListGLComplexityCalculator::GLHelper::drawShadow(

display_list/display_list_complexity_gl.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ class DisplayListGLComplexityCalculator
3232
private:
3333
class GLHelper : public ComplexityCalculatorHelper {
3434
public:
35-
GLHelper(unsigned int ceiling) : ComplexityCalculatorHelper(ceiling) {}
35+
GLHelper(unsigned int ceiling)
36+
: ComplexityCalculatorHelper(ceiling),
37+
save_layer_count_(0),
38+
draw_text_blob_count_(0) {}
39+
40+
void saveLayer(const SkRect* bounds,
41+
const SaveLayerOptions options) override;
3642

3743
void drawLine(const SkPoint& p0, const SkPoint& p1) override;
3844
void drawRect(const SkRect& rect) override;
@@ -75,7 +81,11 @@ class DisplayListGLComplexityCalculator
7581
bool render_with_attributes,
7682
SkCanvas::SrcRectConstraint constraint) override;
7783

78-
unsigned int SaveLayerComplexity() override;
84+
unsigned int BatchedComplexity() override;
85+
86+
private:
87+
unsigned int save_layer_count_;
88+
unsigned int draw_text_blob_count_;
7989
};
8090

8191
DisplayListGLComplexityCalculator()

display_list/display_list_complexity_helper.h

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,7 @@ class ComplexityCalculatorHelper
9696
public virtual IgnoreTransformDispatchHelper {
9797
public:
9898
ComplexityCalculatorHelper(unsigned int ceiling)
99-
: is_complex_(false),
100-
ceiling_(ceiling),
101-
save_layer_count_(0),
102-
complexity_score_(0) {}
99+
: is_complex_(false), ceiling_(ceiling), complexity_score_(0) {}
103100

104101
virtual ~ComplexityCalculatorHelper() = default;
105102

@@ -131,14 +128,6 @@ class ComplexityCalculatorHelper
131128
current_paint_.setStrokeWidth(width);
132129
}
133130

134-
void saveLayer(const SkRect* bounds,
135-
const SaveLayerOptions options) override {
136-
if (IsComplex()) {
137-
return;
138-
}
139-
save_layer_count_++;
140-
}
141-
142131
void drawColor(SkColor color, SkBlendMode mode) override {
143132
if (IsComplex()) {
144133
return;
@@ -221,15 +210,16 @@ class ComplexityCalculatorHelper
221210
return Ceiling();
222211
}
223212

224-
// Calculate the impact of saveLayer.
225-
unsigned int save_layer_complexity = SaveLayerComplexity();
213+
// Calculate the impact of any draw ops where the complexity is dependent
214+
// on the number of calls made.
215+
unsigned int batched_complexity = BatchedComplexity();
226216

227217
// Check for overflow
228-
if (Ceiling() - complexity_score_ < save_layer_complexity) {
218+
if (Ceiling() - complexity_score_ < batched_complexity) {
229219
return Ceiling();
230220
}
231221

232-
return complexity_score_ + save_layer_complexity;
222+
return complexity_score_ + batched_complexity;
233223
}
234224

235225
protected:
@@ -248,7 +238,6 @@ class ComplexityCalculatorHelper
248238
inline SkPaint::Style Style() { return current_paint_.getStyle(); }
249239
inline bool IsComplex() { return is_complex_; }
250240
inline unsigned int Ceiling() { return ceiling_; }
251-
inline unsigned int SaveLayerCount() { return save_layer_count_; }
252241
inline unsigned int CurrentComplexityScore() { return complexity_score_; }
253242

254243
unsigned int CalculatePathComplexity(const SkPath& path,
@@ -285,7 +274,10 @@ class ComplexityCalculatorHelper
285274
bool render_with_attributes,
286275
SkCanvas::SrcRectConstraint constraint) = 0;
287276

288-
virtual unsigned int SaveLayerComplexity() = 0;
277+
// This calculates and returns the cost of draw calls which are batched and
278+
// thus have a time cost proportional to the number of draw calls made, such
279+
// as saveLayer and drawTextBlob.
280+
virtual unsigned int BatchedComplexity() = 0;
289281

290282
private:
291283
SkPaint current_paint_;
@@ -296,7 +288,6 @@ class ComplexityCalculatorHelper
296288
bool is_complex_;
297289
unsigned int ceiling_;
298290

299-
unsigned int save_layer_count_;
300291
unsigned int complexity_score_;
301292
};
302293

display_list/display_list_complexity_metal.cc

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,45 @@ DisplayListMetalComplexityCalculator::GetInstance() {
2626
}
2727

2828
unsigned int
29-
DisplayListMetalComplexityCalculator::MetalHelper::SaveLayerComplexity() {
29+
DisplayListMetalComplexityCalculator::MetalHelper::BatchedComplexity() {
3030
// Calculate the impact of saveLayer.
3131
unsigned int save_layer_complexity;
32-
if (SaveLayerCount() == 0) {
32+
if (save_layer_count_ == 0) {
3333
save_layer_complexity = 0;
3434
} else {
3535
// saveLayer seems to have two trends; if the count is < 200,
3636
// then the individual cost of a saveLayer is higher than if
3737
// the count is > 200.
38-
if (SaveLayerCount() > 200) {
38+
if (save_layer_count_ > 200) {
3939
// m = 1/5
4040
// c = 1
41-
save_layer_complexity = (SaveLayerCount() + 5) * 40000;
41+
save_layer_complexity = (save_layer_count_ + 5) * 40000;
4242
} else {
4343
// m = 1/2
4444
// c = 1
45-
save_layer_complexity = (SaveLayerCount() + 2) * 100000;
45+
save_layer_complexity = (save_layer_count_ + 2) * 100000;
4646
}
4747
}
4848

49-
return save_layer_complexity;
49+
unsigned int draw_text_blob_complexity;
50+
if (draw_text_blob_count_ == 0) {
51+
draw_text_blob_complexity = 0;
52+
} else {
53+
// m = 1/240
54+
// c = 0.75
55+
draw_text_blob_complexity = (draw_text_blob_count_ + 180) * 2500 / 3;
56+
}
57+
58+
return save_layer_complexity + draw_text_blob_complexity;
59+
}
60+
61+
void DisplayListMetalComplexityCalculator::MetalHelper::saveLayer(
62+
const SkRect* bounds,
63+
const SaveLayerOptions options) {
64+
if (IsComplex()) {
65+
return;
66+
}
67+
save_layer_count_++;
5068
}
5169

5270
void DisplayListMetalComplexityCalculator::MetalHelper::drawLine(
@@ -552,36 +570,13 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawTextBlob(
552570
if (IsComplex()) {
553571
return;
554572
}
555-
// There are two classes here, hairline vs non-hairline.
556-
//
557-
// Hairline scales loglinearly with the number of glyphs.
558-
// Non-hairline scales linearly.
559573

560-
// Unfortunately there is currently no way for us to figure out the glyph
561-
// count from an SkTextBlob. We will need to figure out a better solution
562-
// here, but for now just use a placeholder value of 100 glyphs.
563-
unsigned int glyph_count = 100;
574+
// DrawTextBlob has a high fixed cost, but if we call it multiple times
575+
// per frame, that fixed cost is greatly reduced per subsequent call. This
576+
// is likely because there is batching being done in SkCanvas.
564577

565-
// These values were worked out by creating a straight line graph (y=mx+c)
566-
// approximately matching the measured data, normalising the data so that
567-
// 0.0005ms resulted in a score of 100 then simplifying down the formula.
568-
unsigned int complexity;
569-
if (IsHairline() && Style() == SkPaint::Style::kStroke_Style) {
570-
// If hairlines are on, we hit a degenerative case within Skia that causes
571-
// our time to skyrocket.
572-
//
573-
// m = 1/3000
574-
// c = 1.75
575-
// x = glyph_count * log2(glyph_count)
576-
unsigned int x = glyph_count * log(glyph_count);
577-
complexity = (x + 5250) * 200 / 3;
578-
} else {
579-
// m = 1/5000
580-
// c = 0.75
581-
complexity = 40 * (glyph_count + 3750);
582-
}
583-
584-
AccumulateComplexity(complexity);
578+
// Increment draw_text_blob_count_ and calculate the cost at the end.
579+
draw_text_blob_count_++;
585580
}
586581

587582
void DisplayListMetalComplexityCalculator::MetalHelper::drawShadow(

display_list/display_list_complexity_metal.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ class DisplayListMetalComplexityCalculator
3232
private:
3333
class MetalHelper : public ComplexityCalculatorHelper {
3434
public:
35-
MetalHelper(unsigned int ceiling) : ComplexityCalculatorHelper(ceiling) {}
35+
MetalHelper(unsigned int ceiling)
36+
: ComplexityCalculatorHelper(ceiling),
37+
save_layer_count_(0),
38+
draw_text_blob_count_(0) {}
39+
40+
void saveLayer(const SkRect* bounds,
41+
const SaveLayerOptions options) override;
3642

3743
void drawLine(const SkPoint& p0, const SkPoint& p1) override;
3844
void drawRect(const SkRect& rect) override;
@@ -75,7 +81,11 @@ class DisplayListMetalComplexityCalculator
7581
bool render_with_attributes,
7682
SkCanvas::SrcRectConstraint constraint) override;
7783

78-
unsigned int SaveLayerComplexity() override;
84+
unsigned int BatchedComplexity() override;
85+
86+
private:
87+
unsigned int save_layer_count_;
88+
unsigned int draw_text_blob_count_;
7989
};
8090

8191
DisplayListMetalComplexityCalculator()

display_list/display_list_complexity_unittests.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,16 @@ TEST(DisplayListComplexity, DrawTextBlob) {
304304
builder.drawTextBlob(text_blob, 0.0f, 0.0f);
305305
auto display_list = builder.Build();
306306

307+
DisplayListBuilder builder_multiple;
308+
builder_multiple.drawTextBlob(text_blob, 0.0f, 0.0f);
309+
builder_multiple.drawTextBlob(text_blob, 0.0f, 0.0f);
310+
auto display_list_multiple = builder_multiple.Build();
311+
307312
auto calculators = AccumulatorCalculators();
308313
for (auto calculator : calculators) {
309314
ASSERT_NE(calculator->Compute(display_list.get()), 0u);
315+
ASSERT_GT(calculator->Compute(display_list_multiple.get()),
316+
calculator->Compute(display_list.get()));
310317
}
311318
}
312319

0 commit comments

Comments
 (0)