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

Commit e444009

Browse files
authored
Opacity peephole optimization (#29775)
1 parent 1308455 commit e444009

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+854
-173
lines changed

common/graphics/texture.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class Texture {
2626
const SkRect& bounds,
2727
bool freeze,
2828
GrDirectContext* context,
29-
const SkSamplingOptions& sampling) = 0;
29+
const SkSamplingOptions& sampling,
30+
const SkPaint* paint = nullptr) = 0;
3031

3132
// Called from raster thread.
3233
virtual void OnGrContextCreated() = 0;

flow/display_list.cc

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -978,8 +978,8 @@ static bool CompareOps(uint8_t* ptrA,
978978
return true;
979979
}
980980

981-
void DisplayList::RenderTo(SkCanvas* canvas) const {
982-
DisplayListCanvasDispatcher dispatcher(canvas);
981+
void DisplayList::RenderTo(SkCanvas* canvas, SkScalar opacity) const {
982+
DisplayListCanvasDispatcher dispatcher(canvas, opacity);
983983
Dispatch(dispatcher);
984984
}
985985

@@ -995,19 +995,31 @@ bool DisplayList::Equals(const DisplayList& other) const {
995995
return CompareOps(ptr, ptr + byte_count_, o_ptr, o_ptr + other.byte_count_);
996996
}
997997

998+
DisplayList::DisplayList()
999+
: byte_count_(0),
1000+
op_count_(0),
1001+
nested_byte_count_(0),
1002+
nested_op_count_(0),
1003+
unique_id_(0),
1004+
bounds_({0, 0, 0, 0}),
1005+
bounds_cull_({0, 0, 0, 0}),
1006+
can_apply_group_opacity_(true) {}
1007+
9981008
DisplayList::DisplayList(uint8_t* ptr,
9991009
size_t byte_count,
10001010
int op_count,
10011011
size_t nested_byte_count,
10021012
int nested_op_count,
1003-
const SkRect& cull_rect)
1013+
const SkRect& cull_rect,
1014+
bool can_apply_group_opacity)
10041015
: storage_(ptr),
10051016
byte_count_(byte_count),
10061017
op_count_(op_count),
10071018
nested_byte_count_(nested_byte_count),
10081019
nested_op_count_(nested_op_count),
10091020
bounds_({0, 0, -1, -1}),
1010-
bounds_cull_(cull_rect) {
1021+
bounds_cull_(cull_rect),
1022+
can_apply_group_opacity_(can_apply_group_opacity) {
10111023
static std::atomic<uint32_t> nextID{1};
10121024
do {
10131025
unique_id_ = nextID.fetch_add(+1, std::memory_order_relaxed);
@@ -1057,7 +1069,7 @@ void* DisplayListBuilder::Push(size_t pod, int op_inc, Args&&... args) {
10571069
}
10581070

10591071
sk_sp<DisplayList> DisplayListBuilder::Build() {
1060-
while (save_level_ > 0) {
1072+
while (layer_stack_.size() > 1) {
10611073
restore();
10621074
}
10631075
size_t bytes = used_;
@@ -1067,13 +1079,17 @@ sk_sp<DisplayList> DisplayListBuilder::Build() {
10671079
used_ = allocated_ = op_count_ = 0;
10681080
nested_bytes_ = nested_op_count_ = 0;
10691081
storage_.realloc(bytes);
1082+
bool compatible = layer_stack_.back().is_group_opacity_compatible();
10701083
return sk_sp<DisplayList>(new DisplayList(storage_.release(), bytes, count,
10711084
nested_bytes, nested_count,
1072-
cull_rect_));
1085+
cull_rect_, compatible));
10731086
}
10741087

10751088
DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect)
1076-
: cull_rect_(cull_rect) {}
1089+
: cull_rect_(cull_rect) {
1090+
layer_stack_.emplace_back();
1091+
current_layer_ = &layer_stack_.back();
1092+
}
10771093

10781094
DisplayListBuilder::~DisplayListBuilder() {
10791095
uint8_t* ptr = storage_.get();
@@ -1090,6 +1106,7 @@ void DisplayListBuilder::onSetDither(bool dither) {
10901106
}
10911107
void DisplayListBuilder::onSetInvertColors(bool invert) {
10921108
Push<SetInvertColorsOp>(0, 0, current_invert_colors_ = invert);
1109+
UpdateCurrentOpacityCompatibility();
10931110
}
10941111
void DisplayListBuilder::onSetStrokeCap(SkPaint::Cap cap) {
10951112
Push<SetStrokeCapOp>(0, 0, current_stroke_cap_ = cap);
@@ -1112,6 +1129,7 @@ void DisplayListBuilder::onSetColor(SkColor color) {
11121129
void DisplayListBuilder::onSetBlendMode(SkBlendMode mode) {
11131130
current_blender_ = nullptr;
11141131
Push<SetBlendModeOp>(0, 0, current_blend_mode_ = mode);
1132+
UpdateCurrentOpacityCompatibility();
11151133
}
11161134
void DisplayListBuilder::onSetBlender(sk_sp<SkBlender> blender) {
11171135
// setBlender(nullptr) should be redirected to setBlendMode(SrcOver)
@@ -1126,6 +1144,7 @@ void DisplayListBuilder::onSetBlender(sk_sp<SkBlender> blender) {
11261144
(current_blender_ = blender) //
11271145
? Push<SetBlenderOp>(0, 0, std::move(blender))
11281146
: Push<ClearBlenderOp>(0, 0);
1147+
UpdateCurrentOpacityCompatibility();
11291148
}
11301149
}
11311150
void DisplayListBuilder::onSetShader(sk_sp<SkShader> shader) {
@@ -1142,6 +1161,7 @@ void DisplayListBuilder::onSetColorFilter(sk_sp<SkColorFilter> filter) {
11421161
(current_color_filter_ = filter) //
11431162
? Push<SetColorFilterOp>(0, 0, std::move(filter))
11441163
: Push<ClearColorFilterOp>(0, 0);
1164+
UpdateCurrentOpacityCompatibility();
11451165
}
11461166
void DisplayListBuilder::onSetPathEffect(sk_sp<SkPathEffect> effect) {
11471167
(current_path_effect_ = effect) //
@@ -1228,21 +1248,37 @@ void DisplayListBuilder::setAttributesFromPaint(
12281248
}
12291249

12301250
void DisplayListBuilder::save() {
1231-
save_level_++;
12321251
Push<SaveOp>(0, 1);
1252+
layer_stack_.emplace_back();
1253+
current_layer_ = &layer_stack_.back();
12331254
}
12341255
void DisplayListBuilder::restore() {
1235-
if (save_level_ > 0) {
1256+
if (layer_stack_.size() > 1) {
1257+
// Grab the current layer info before we push the restore
1258+
// on the stack.
1259+
LayerInfo layer_info = layer_stack_.back();
1260+
layer_stack_.pop_back();
1261+
current_layer_ = &layer_stack_.back();
12361262
Push<RestoreOp>(0, 1);
1237-
save_level_--;
1263+
if (!layer_info.has_layer) {
1264+
// For regular save() ops there was no protecting layer so we have to
1265+
// accumulate the values into the enclosing layer.
1266+
if (layer_info.cannot_inherit_opacity) {
1267+
current_layer_->mark_incompatible();
1268+
} else if (layer_info.has_compatible_op) {
1269+
current_layer_->add_compatible_op();
1270+
}
1271+
}
12381272
}
12391273
}
12401274
void DisplayListBuilder::saveLayer(const SkRect* bounds,
12411275
bool restore_with_paint) {
1242-
save_level_++;
12431276
bounds //
12441277
? Push<SaveLayerBoundsOp>(0, 1, *bounds, restore_with_paint)
12451278
: Push<SaveLayerOp>(0, 1, restore_with_paint);
1279+
CheckLayerOpacityCompatibility(restore_with_paint);
1280+
layer_stack_.emplace_back(true);
1281+
current_layer_ = &layer_stack_.back();
12461282
}
12471283

12481284
void DisplayListBuilder::translate(SkScalar tx, SkScalar ty) {
@@ -1356,21 +1392,27 @@ void DisplayListBuilder::clipPath(const SkPath& path,
13561392

13571393
void DisplayListBuilder::drawPaint() {
13581394
Push<DrawPaintOp>(0, 1);
1395+
CheckLayerOpacityCompatibility();
13591396
}
13601397
void DisplayListBuilder::drawColor(SkColor color, SkBlendMode mode) {
13611398
Push<DrawColorOp>(0, 1, color, mode);
1399+
CheckLayerOpacityCompatibility(mode);
13621400
}
13631401
void DisplayListBuilder::drawLine(const SkPoint& p0, const SkPoint& p1) {
13641402
Push<DrawLineOp>(0, 1, p0, p1);
1403+
CheckLayerOpacityCompatibility();
13651404
}
13661405
void DisplayListBuilder::drawRect(const SkRect& rect) {
13671406
Push<DrawRectOp>(0, 1, rect);
1407+
CheckLayerOpacityCompatibility();
13681408
}
13691409
void DisplayListBuilder::drawOval(const SkRect& bounds) {
13701410
Push<DrawOvalOp>(0, 1, bounds);
1411+
CheckLayerOpacityCompatibility();
13711412
}
13721413
void DisplayListBuilder::drawCircle(const SkPoint& center, SkScalar radius) {
13731414
Push<DrawCircleOp>(0, 1, center, radius);
1415+
CheckLayerOpacityCompatibility();
13741416
}
13751417
void DisplayListBuilder::drawRRect(const SkRRect& rrect) {
13761418
if (rrect.isRect()) {
@@ -1379,21 +1421,29 @@ void DisplayListBuilder::drawRRect(const SkRRect& rrect) {
13791421
drawOval(rrect.rect());
13801422
} else {
13811423
Push<DrawRRectOp>(0, 1, rrect);
1424+
CheckLayerOpacityCompatibility();
13821425
}
13831426
}
13841427
void DisplayListBuilder::drawDRRect(const SkRRect& outer,
13851428
const SkRRect& inner) {
13861429
Push<DrawDRRectOp>(0, 1, outer, inner);
1430+
CheckLayerOpacityCompatibility();
13871431
}
13881432
void DisplayListBuilder::drawPath(const SkPath& path) {
13891433
Push<DrawPathOp>(0, 1, path);
1434+
CheckLayerOpacityHairlineCompatibility();
13901435
}
13911436

13921437
void DisplayListBuilder::drawArc(const SkRect& bounds,
13931438
SkScalar start,
13941439
SkScalar sweep,
13951440
bool useCenter) {
13961441
Push<DrawArcOp>(0, 1, bounds, start, sweep, useCenter);
1442+
if (useCenter) {
1443+
CheckLayerOpacityHairlineCompatibility();
1444+
} else {
1445+
CheckLayerOpacityCompatibility();
1446+
}
13971447
}
13981448
void DisplayListBuilder::drawPoints(SkCanvas::PointMode mode,
13991449
uint32_t count,
@@ -1416,10 +1466,19 @@ void DisplayListBuilder::drawPoints(SkCanvas::PointMode mode,
14161466
return;
14171467
}
14181468
CopyV(data_ptr, pts, count);
1469+
// drawPoints treats every point or line (or segment of a polygon)
1470+
// as a completely separate operation meaning we cannot ensure
1471+
// distribution of group opacity without analyzing the mode and the
1472+
// bounds of every sub-primitive.
1473+
// See: https://fiddle.skia.org/c/228459001d2de8db117ce25ef5cedb0c
1474+
UpdateLayerOpacityCompatibility(false);
14191475
}
14201476
void DisplayListBuilder::drawVertices(const sk_sp<SkVertices> vertices,
14211477
SkBlendMode mode) {
14221478
Push<DrawVerticesOp>(0, 1, std::move(vertices), mode);
1479+
// DrawVertices applies its colors to the paint so we have no way
1480+
// of controlling opacity using the current paint attributes.
1481+
UpdateLayerOpacityCompatibility(false);
14231482
}
14241483

14251484
void DisplayListBuilder::drawImage(const sk_sp<SkImage> image,
@@ -1429,6 +1488,7 @@ void DisplayListBuilder::drawImage(const sk_sp<SkImage> image,
14291488
render_with_attributes
14301489
? Push<DrawImageWithAttrOp>(0, 1, std::move(image), point, sampling)
14311490
: Push<DrawImageOp>(0, 1, std::move(image), point, sampling);
1491+
CheckLayerOpacityCompatibility(render_with_attributes);
14321492
}
14331493
void DisplayListBuilder::drawImageRect(const sk_sp<SkImage> image,
14341494
const SkRect& src,
@@ -1438,6 +1498,7 @@ void DisplayListBuilder::drawImageRect(const sk_sp<SkImage> image,
14381498
SkCanvas::SrcRectConstraint constraint) {
14391499
Push<DrawImageRectOp>(0, 1, std::move(image), src, dst, sampling,
14401500
render_with_attributes, constraint);
1501+
CheckLayerOpacityCompatibility(render_with_attributes);
14411502
}
14421503
void DisplayListBuilder::drawImageNine(const sk_sp<SkImage> image,
14431504
const SkIRect& center,
@@ -1448,6 +1509,7 @@ void DisplayListBuilder::drawImageNine(const sk_sp<SkImage> image,
14481509
? Push<DrawImageNineWithAttrOp>(0, 1, std::move(image), center, dst,
14491510
filter)
14501511
: Push<DrawImageNineOp>(0, 1, std::move(image), center, dst, filter);
1512+
CheckLayerOpacityCompatibility(render_with_attributes);
14511513
}
14521514
void DisplayListBuilder::drawImageLattice(const sk_sp<SkImage> image,
14531515
const SkCanvas::Lattice& lattice,
@@ -1469,6 +1531,7 @@ void DisplayListBuilder::drawImageLattice(const sk_sp<SkImage> image,
14691531
filter, render_with_attributes);
14701532
CopyV(pod, lattice.fXDivs, xDivCount, lattice.fYDivs, yDivCount,
14711533
lattice.fColors, cellCount, lattice.fRectTypes, cellCount);
1534+
CheckLayerOpacityCompatibility(render_with_attributes);
14721535
}
14731536
void DisplayListBuilder::drawAtlas(const sk_sp<SkImage> atlas,
14741537
const SkRSXform xform[],
@@ -1503,6 +1566,10 @@ void DisplayListBuilder::drawAtlas(const sk_sp<SkImage> atlas,
15031566
}
15041567
CopyV(data_ptr, xform, count, tex, count);
15051568
}
1569+
// drawAtlas treats each image as a separate operation so we cannot rely
1570+
// on it to distribute the opacity without overlap without checking all
1571+
// of the transforms and texture rectangles.
1572+
UpdateLayerOpacityCompatibility(false);
15061573
}
15071574

15081575
void DisplayListBuilder::drawPicture(const sk_sp<SkPicture> picture,
@@ -1520,6 +1587,7 @@ void DisplayListBuilder::drawPicture(const sk_sp<SkPicture> picture,
15201587
// This behavior is identical to the way SkPicture computes nested op counts.
15211588
nested_op_count_ += picture->approximateOpCount(true) - 1;
15221589
nested_bytes_ += picture->approximateBytesUsed();
1590+
CheckLayerOpacityCompatibility(render_with_attributes);
15231591
}
15241592
void DisplayListBuilder::drawDisplayList(
15251593
const sk_sp<DisplayList> display_list) {
@@ -1532,11 +1600,13 @@ void DisplayListBuilder::drawDisplayList(
15321600
// This behavior is identical to the way SkPicture computes nested op counts.
15331601
nested_op_count_ += display_list->op_count(true) - 1;
15341602
nested_bytes_ += display_list->bytes(true);
1603+
UpdateLayerOpacityCompatibility(display_list->can_apply_group_opacity());
15351604
}
15361605
void DisplayListBuilder::drawTextBlob(const sk_sp<SkTextBlob> blob,
15371606
SkScalar x,
15381607
SkScalar y) {
15391608
Push<DrawTextBlobOp>(0, 1, std::move(blob), x, y);
1609+
CheckLayerOpacityCompatibility();
15401610
}
15411611
void DisplayListBuilder::drawShadow(const SkPath& path,
15421612
const SkColor color,
@@ -1546,6 +1616,7 @@ void DisplayListBuilder::drawShadow(const SkPath& path,
15461616
transparent_occluder //
15471617
? Push<DrawShadowTransparentOccluderOp>(0, 1, path, color, elevation, dpr)
15481618
: Push<DrawShadowOp>(0, 1, path, color, elevation, dpr);
1619+
UpdateLayerOpacityCompatibility(false);
15491620
}
15501621

15511622
// clang-format off

0 commit comments

Comments
 (0)