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

Commit 5d3edd2

Browse files
flarzanderso
authored andcommitted
Cached DisplayList opacity inheritance fix (#39690)
* only indicate opacity inheritance when DL is actually cached * unit test * use CacheInfo struct to simplify return values
1 parent ada363e commit 5d3edd2

File tree

7 files changed

+91
-17
lines changed

7 files changed

+91
-17
lines changed

display_list/display_list.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,15 @@ static bool CompareOps(uint8_t* ptrA,
186186
return true;
187187
}
188188

189-
void DisplayList::RenderTo(DisplayListBuilder* builder,
190-
SkScalar opacity) const {
191-
// TODO(100983): Opacity is not respected and attributes are not reset.
189+
void DisplayList::RenderTo(DisplayListBuilder* builder) const {
192190
if (!builder) {
193191
return;
194192
}
195193
Dispatch(*builder);
196194
}
197195

198196
void DisplayList::RenderTo(SkCanvas* canvas, SkScalar opacity) const {
197+
FML_DCHECK(can_apply_group_opacity() || opacity >= SK_Scalar1);
199198
DisplayListCanvasDispatcher dispatcher(canvas, opacity);
200199
Dispatch(dispatcher);
201200
}

display_list/display_list.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@ class DisplayList : public SkRefCnt {
229229
Dispatch(ctx, ptr, ptr + byte_count_);
230230
}
231231

232-
void RenderTo(DisplayListBuilder* builder,
233-
SkScalar opacity = SK_Scalar1) const;
232+
void RenderTo(DisplayListBuilder* builder) const;
234233

235234
void RenderTo(SkCanvas* canvas, SkScalar opacity = SK_Scalar1) const;
236235

flow/layers/display_list_layer_unittests.cc

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "flutter/flow/layers/display_list_layer.h"
88

99
#include "flutter/display_list/display_list_builder.h"
10+
#include "flutter/flow/layers/layer_tree.h"
1011
#include "flutter/flow/testing/diff_context_test.h"
1112
#include "flutter/flow/testing/skia_gpu_object_layer_test.h"
1213
#include "flutter/fml/macros.h"
@@ -249,6 +250,8 @@ TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) {
249250
display_list_layer->Preroll(preroll_context());
250251
display_list_layer->Preroll(preroll_context());
251252
display_list_layer->Preroll(preroll_context());
253+
LayerTree::TryToRasterCache(*preroll_context()->raster_cached_entries,
254+
&paint_context(), false);
252255

253256
int opacity_alpha = 0x7F;
254257
SkPoint opacity_offset = SkPoint::Make(10, 10);
@@ -516,5 +519,69 @@ TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
516519
ASSERT_TRUE(raster_cache_item->Draw(paint_context(), nullptr));
517520
}
518521

522+
TEST_F(DisplayListLayerTest, OverflowCachedDisplayListOpacityInheritance) {
523+
use_mock_raster_cache();
524+
PrerollContext* context = preroll_context();
525+
int per_frame =
526+
RasterCacheUtil::kDefaultPictureAndDispLayListCacheLimitPerFrame;
527+
int layer_count = per_frame + 1;
528+
SkPoint opacity_offset = {10, 10};
529+
auto opacity_layer = std::make_shared<OpacityLayer>(0.5f, opacity_offset);
530+
std::shared_ptr<DisplayListLayer> layers[layer_count];
531+
for (int i = 0; i < layer_count; i++) {
532+
DisplayListBuilder builder(false);
533+
builder.drawRect({0, 0, 100, 100});
534+
builder.drawRect({50, 50, 100, 100});
535+
auto display_list = builder.Build();
536+
ASSERT_FALSE(display_list->can_apply_group_opacity());
537+
SkPoint offset = {i * 200.0f, 0};
538+
539+
layers[i] = std::make_shared<DisplayListLayer>(
540+
offset, SkiaGPUObject(display_list, unref_queue()), true, false);
541+
opacity_layer->Add(layers[i]);
542+
}
543+
for (size_t j = 0; j < context->raster_cache->access_threshold(); j++) {
544+
context->raster_cache->BeginFrame();
545+
for (int i = 0; i < layer_count; i++) {
546+
context->renderable_state_flags = 0;
547+
layers[i]->Preroll(context);
548+
ASSERT_EQ(context->renderable_state_flags, 0) << "pass " << (j + 1);
549+
}
550+
}
551+
opacity_layer->Preroll(context);
552+
ASSERT_FALSE(opacity_layer->children_can_accept_opacity());
553+
LayerTree::TryToRasterCache(*context->raster_cached_entries, &paint_context(),
554+
false);
555+
context->raster_cached_entries->clear();
556+
context->raster_cache->BeginFrame();
557+
for (int i = 0; i < per_frame; i++) {
558+
context->renderable_state_flags = 0;
559+
layers[i]->Preroll(context);
560+
ASSERT_EQ(context->renderable_state_flags,
561+
LayerStateStack::kCallerCanApplyOpacity)
562+
<< "layer " << (i + 1);
563+
}
564+
for (int i = per_frame; i < layer_count; i++) {
565+
context->renderable_state_flags = 0;
566+
layers[i]->Preroll(context);
567+
ASSERT_EQ(context->renderable_state_flags, 0) << "layer " << (i + 1);
568+
}
569+
opacity_layer->Preroll(context);
570+
ASSERT_FALSE(opacity_layer->children_can_accept_opacity());
571+
LayerTree::TryToRasterCache(*context->raster_cached_entries, &paint_context(),
572+
false);
573+
context->raster_cached_entries->clear();
574+
context->raster_cache->BeginFrame();
575+
for (int i = 0; i < layer_count; i++) {
576+
context->renderable_state_flags = 0;
577+
layers[i]->Preroll(context);
578+
ASSERT_EQ(context->renderable_state_flags,
579+
LayerStateStack::kCallerCanApplyOpacity)
580+
<< "layer " << (i + 1);
581+
}
582+
opacity_layer->Preroll(context);
583+
ASSERT_TRUE(opacity_layer->children_can_accept_opacity());
584+
}
585+
519586
} // namespace testing
520587
} // namespace flutter

flow/layers/display_list_raster_cache_item.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,16 @@ void DisplayListRasterCacheItem::PrerollFinalize(PrerollContext* context,
109109
// it great than the threshold. Otherwise we only increase the entry
110110
// access_count.
111111
bool visible = !context->state_stack.content_culled(bounds);
112-
int accesses = raster_cache->MarkSeen(key_id_, matrix, visible);
113-
if (!visible || accesses <= raster_cache->access_threshold()) {
112+
RasterCache::CacheInfo cache_info =
113+
raster_cache->MarkSeen(key_id_, matrix, visible);
114+
if (!visible ||
115+
cache_info.accesses_since_visible <= raster_cache->access_threshold()) {
114116
cache_state_ = kNone;
115117
} else {
116-
context->renderable_state_flags |= LayerStateStack::kCallerCanApplyOpacity;
118+
if (cache_info.has_image) {
119+
context->renderable_state_flags |=
120+
LayerStateStack::kCallerCanApplyOpacity;
121+
}
117122
cache_state_ = kCurrent;
118123
}
119124
return;

flow/raster_cache.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,17 @@ bool RasterCache::UpdateCacheEntry(
109109
return entry.image != nullptr;
110110
}
111111

112-
int RasterCache::MarkSeen(const RasterCacheKeyID& id,
113-
const SkMatrix& matrix,
114-
bool visible) const {
112+
RasterCache::CacheInfo RasterCache::MarkSeen(const RasterCacheKeyID& id,
113+
const SkMatrix& matrix,
114+
bool visible) const {
115115
RasterCacheKey key = RasterCacheKey(id, matrix);
116116
Entry& entry = cache_[key];
117117
entry.encountered_this_frame = true;
118118
entry.visible_this_frame = visible;
119119
if (visible || entry.accesses_since_visible > 0) {
120120
entry.accesses_since_visible++;
121121
}
122-
return entry.accesses_since_visible;
122+
return {entry.accesses_since_visible, entry.image != nullptr};
123123
}
124124

125125
int RasterCache::GetAccessCount(const RasterCacheKeyID& id,

flow/raster_cache.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ class RasterCache {
121121
const SkRect& logical_rect;
122122
const char* flow_type;
123123
};
124+
struct CacheInfo {
125+
const size_t accesses_since_visible;
126+
const bool has_image;
127+
};
124128

125129
std::unique_ptr<RasterCacheResult> Rasterize(
126130
const RasterCache::Context& context,
@@ -203,7 +207,7 @@ class RasterCache {
203207
* If the number is one, then it must be prepared and drawn on 1 frame
204208
* and it will then be cached on the next frame if it is prepared.
205209
*/
206-
int access_threshold() const { return access_threshold_; }
210+
size_t access_threshold() const { return access_threshold_; }
207211

208212
bool GenerateNewCacheInThisFrame() const {
209213
// Disabling caching when access_threshold is zero is historic behavior.
@@ -221,9 +225,9 @@ class RasterCache {
221225
* @return the number of times the entry has been hit since it was created.
222226
* For a new entry that will be 1 if it is visible, or zero if non-visible.
223227
*/
224-
int MarkSeen(const RasterCacheKeyID& id,
225-
const SkMatrix& matrix,
226-
bool visible) const;
228+
CacheInfo MarkSeen(const RasterCacheKeyID& id,
229+
const SkMatrix& matrix,
230+
bool visible) const;
227231

228232
/**
229233
* Returns the access count (i.e. accesses_since_visible) for the given

flow/testing/mock_raster_cache.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void MockRasterCache::AddMockPicture(int width, int height) {
6565

6666
DisplayListRasterCacheItem display_list_item(display_list.get(), SkPoint(),
6767
true, false);
68-
for (int i = 0; i < access_threshold(); i++) {
68+
for (size_t i = 0; i < access_threshold(); i++) {
6969
AutoCache(&display_list_item, &preroll_context_, ctm);
7070
}
7171
RasterCache::Context r_context = {

0 commit comments

Comments
 (0)