Skip to content

Commit

Permalink
Cached DisplayList opacity inheritance fix (#39690)
Browse files Browse the repository at this point in the history
* only indicate opacity inheritance when DL is actually cached

* unit test

* use CacheInfo struct to simplify return values
  • Loading branch information
flar committed Feb 17, 2023
1 parent f6bb7ae commit 27696d2
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 17 deletions.
5 changes: 2 additions & 3 deletions display_list/display_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,7 @@ static bool CompareOps(uint8_t* ptrA,
return true;
}

void DisplayList::RenderTo(DisplayListBuilder* builder,
SkScalar opacity) const {
// TODO(100983): Opacity is not respected and attributes are not reset.
void DisplayList::RenderTo(DisplayListBuilder* builder) const {
if (!builder) {
return;
}
Expand All @@ -308,6 +306,7 @@ void DisplayList::RenderTo(DisplayListBuilder* builder,
}

void DisplayList::RenderTo(SkCanvas* canvas, SkScalar opacity) const {
FML_DCHECK(can_apply_group_opacity() || opacity >= SK_Scalar1);
DisplayListCanvasDispatcher dispatcher(canvas, opacity);
if (has_rtree()) {
Dispatch(dispatcher, canvas->getLocalClipBounds());
Expand Down
3 changes: 1 addition & 2 deletions display_list/display_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,7 @@ class DisplayList : public SkRefCnt {
void Dispatch(Dispatcher& ctx) const;
void Dispatch(Dispatcher& ctx, const SkRect& cull_rect) const;

void RenderTo(DisplayListBuilder* builder,
SkScalar opacity = SK_Scalar1) const;
void RenderTo(DisplayListBuilder* builder) const;

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

Expand Down
67 changes: 67 additions & 0 deletions flow/layers/display_list_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "flutter/flow/layers/display_list_layer.h"

#include "flutter/display_list/display_list_builder.h"
#include "flutter/flow/layers/layer_tree.h"
#include "flutter/flow/testing/diff_context_test.h"
#include "flutter/flow/testing/skia_gpu_object_layer_test.h"
#include "flutter/fml/macros.h"
Expand Down Expand Up @@ -249,6 +250,8 @@ TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) {
display_list_layer->Preroll(preroll_context());
display_list_layer->Preroll(preroll_context());
display_list_layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(*preroll_context()->raster_cached_entries,
&paint_context(), false);

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

TEST_F(DisplayListLayerTest, OverflowCachedDisplayListOpacityInheritance) {
use_mock_raster_cache();
PrerollContext* context = preroll_context();
int per_frame =
RasterCacheUtil::kDefaultPictureAndDispLayListCacheLimitPerFrame;
int layer_count = per_frame + 1;
SkPoint opacity_offset = {10, 10};
auto opacity_layer = std::make_shared<OpacityLayer>(0.5f, opacity_offset);
std::shared_ptr<DisplayListLayer> layers[layer_count];
for (int i = 0; i < layer_count; i++) {
DisplayListBuilder builder(false);
builder.drawRect({0, 0, 100, 100});
builder.drawRect({50, 50, 100, 100});
auto display_list = builder.Build();
ASSERT_FALSE(display_list->can_apply_group_opacity());
SkPoint offset = {i * 200.0f, 0};

layers[i] = std::make_shared<DisplayListLayer>(
offset, SkiaGPUObject(display_list, unref_queue()), true, false);
opacity_layer->Add(layers[i]);
}
for (size_t j = 0; j < context->raster_cache->access_threshold(); j++) {
context->raster_cache->BeginFrame();
for (int i = 0; i < layer_count; i++) {
context->renderable_state_flags = 0;
layers[i]->Preroll(context);
ASSERT_EQ(context->renderable_state_flags, 0) << "pass " << (j + 1);
}
}
opacity_layer->Preroll(context);
ASSERT_FALSE(opacity_layer->children_can_accept_opacity());
LayerTree::TryToRasterCache(*context->raster_cached_entries, &paint_context(),
false);
context->raster_cached_entries->clear();
context->raster_cache->BeginFrame();
for (int i = 0; i < per_frame; i++) {
context->renderable_state_flags = 0;
layers[i]->Preroll(context);
ASSERT_EQ(context->renderable_state_flags,
LayerStateStack::kCallerCanApplyOpacity)
<< "layer " << (i + 1);
}
for (int i = per_frame; i < layer_count; i++) {
context->renderable_state_flags = 0;
layers[i]->Preroll(context);
ASSERT_EQ(context->renderable_state_flags, 0) << "layer " << (i + 1);
}
opacity_layer->Preroll(context);
ASSERT_FALSE(opacity_layer->children_can_accept_opacity());
LayerTree::TryToRasterCache(*context->raster_cached_entries, &paint_context(),
false);
context->raster_cached_entries->clear();
context->raster_cache->BeginFrame();
for (int i = 0; i < layer_count; i++) {
context->renderable_state_flags = 0;
layers[i]->Preroll(context);
ASSERT_EQ(context->renderable_state_flags,
LayerStateStack::kCallerCanApplyOpacity)
<< "layer " << (i + 1);
}
opacity_layer->Preroll(context);
ASSERT_TRUE(opacity_layer->children_can_accept_opacity());
}

} // namespace testing
} // namespace flutter
11 changes: 8 additions & 3 deletions flow/layers/display_list_raster_cache_item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,16 @@ void DisplayListRasterCacheItem::PrerollFinalize(PrerollContext* context,
auto* raster_cache = context->raster_cache;
SkRect bounds = display_list_->bounds().makeOffset(offset_.x(), offset_.y());
bool visible = !context->state_stack.content_culled(bounds);
int accesses = raster_cache->MarkSeen(key_id_, matrix, visible);
if (!visible || accesses <= raster_cache->access_threshold()) {
RasterCache::CacheInfo cache_info =
raster_cache->MarkSeen(key_id_, matrix, visible);
if (!visible ||
cache_info.accesses_since_visible <= raster_cache->access_threshold()) {
cache_state_ = kNone;
} else {
context->renderable_state_flags |= LayerStateStack::kCallerCanApplyOpacity;
if (cache_info.has_image) {
context->renderable_state_flags |=
LayerStateStack::kCallerCanApplyOpacity;
}
cache_state_ = kCurrent;
}
return;
Expand Down
8 changes: 4 additions & 4 deletions flow/raster_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,17 @@ bool RasterCache::UpdateCacheEntry(
return entry.image != nullptr;
}

int RasterCache::MarkSeen(const RasterCacheKeyID& id,
const SkMatrix& matrix,
bool visible) const {
RasterCache::CacheInfo RasterCache::MarkSeen(const RasterCacheKeyID& id,
const SkMatrix& matrix,
bool visible) const {
RasterCacheKey key = RasterCacheKey(id, matrix);
Entry& entry = cache_[key];
entry.encountered_this_frame = true;
entry.visible_this_frame = visible;
if (visible || entry.accesses_since_visible > 0) {
entry.accesses_since_visible++;
}
return entry.accesses_since_visible;
return {entry.accesses_since_visible, entry.image != nullptr};
}

int RasterCache::GetAccessCount(const RasterCacheKeyID& id,
Expand Down
12 changes: 8 additions & 4 deletions flow/raster_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ class RasterCache {
const SkRect& logical_rect;
const char* flow_type;
};
struct CacheInfo {
const size_t accesses_since_visible;
const bool has_image;
};

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

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

/**
* Returns the access count (i.e. accesses_since_visible) for the given
Expand Down
2 changes: 1 addition & 1 deletion flow/testing/mock_raster_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void MockRasterCache::AddMockPicture(int width, int height) {

DisplayListRasterCacheItem display_list_item(display_list.get(), SkPoint(),
true, false);
for (int i = 0; i < access_threshold(); i++) {
for (size_t i = 0; i < access_threshold(); i++) {
AutoCache(&display_list_item, &preroll_context_, ctm);
}
RasterCache::Context r_context = {
Expand Down

0 comments on commit 27696d2

Please sign in to comment.