Lazily allocate RasterCacheItems only when caching is enabled (flutter/engine#45211)

Fixes https://github.com/flutter/flutter/issues/133377

The default allocation of RasterCacheItems in the layer tree was showing up in profiles of apps running on Impeller which don't actually use the raster cache.

In order to eliminate the overhead of those allocations, RasterCacheItems are now lazily allocated only when the layers encounter an actual raster_cache during the Preroll phase.
This commit is contained in:
Jim Graham 2023-08-31 13:32:06 -07:00 committed by GitHub
parent e92e5cd6a9
commit 8cbaba6a03
22 changed files with 567 additions and 200 deletions

View File

@ -6,31 +6,39 @@
namespace flutter {
AutoCache::AutoCache(RasterCacheItem* raster_cache_item,
AutoCache::AutoCache(CacheableLayer& cacheable_layer,
PrerollContext* context,
const SkMatrix& matrix)
: raster_cache_item_(raster_cache_item),
context_(context),
matrix_(matrix) {
if (IsCacheEnabled()) {
raster_cache_item->PrerollSetup(context, matrix);
bool caching_enabled) {
if (context->raster_cache && caching_enabled) {
raster_cache_item_ = cacheable_layer.realize_raster_cache_item();
if (raster_cache_item_) {
context_ = context;
matrix_ = context->state_stack.transform_3x3();
raster_cache_item_->PrerollSetup(context_, matrix_);
}
} else {
cacheable_layer.disable_raster_cache_item();
}
}
bool AutoCache::IsCacheEnabled() {
return raster_cache_item_ && context_ && context_->raster_cache;
}
AutoCache::~AutoCache() {
if (IsCacheEnabled()) {
if (raster_cache_item_) {
raster_cache_item_->PrerollFinalize(context_, matrix_);
}
}
CacheableContainerLayer::CacheableContainerLayer(int layer_cached_threshold,
bool can_cache_children) {
layer_raster_cache_item_ = LayerRasterCacheItem::Make(
this, layer_cached_threshold, can_cache_children);
RasterCacheItem* CacheableContainerLayer::realize_raster_cache_item() {
if (!layer_raster_cache_item_) {
layer_raster_cache_item_ = LayerRasterCacheItem::Make(
this, layer_cache_threshold_, can_cache_children_);
}
return layer_raster_cache_item_.get();
}
void CacheableContainerLayer::disable_raster_cache_item() {
if (layer_raster_cache_item_) {
layer_raster_cache_item_->reset_cache_state();
}
}
} // namespace flutter

View File

@ -9,39 +9,62 @@
#include "flutter/flow/layers/container_layer.h"
#include "flutter/flow/layers/layer_raster_cache_item.h"
#include "flutter/flow/raster_cache_util.h"
namespace flutter {
class CacheableLayer {
protected:
virtual RasterCacheItem* realize_raster_cache_item() = 0;
virtual void disable_raster_cache_item() = 0;
friend class AutoCache;
};
class AutoCache {
public:
AutoCache(RasterCacheItem* raster_cache_item,
AutoCache(CacheableLayer& item_provider,
PrerollContext* context,
const SkMatrix& matrix);
bool caching_enabled = true);
void ShouldNotBeCached() { raster_cache_item_ = nullptr; }
~AutoCache();
private:
inline bool IsCacheEnabled();
RasterCacheItem* raster_cache_item_ = nullptr;
PrerollContext* context_ = nullptr;
const SkMatrix matrix_;
SkMatrix matrix_;
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(AutoCache);
};
class CacheableContainerLayer : public ContainerLayer {
class CacheableContainerLayer : public ContainerLayer, public CacheableLayer {
public:
explicit CacheableContainerLayer(
int layer_cached_threshold =
RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer,
bool can_cache_children = false);
bool can_cache_children = false)
: layer_cache_threshold_(layer_cached_threshold),
can_cache_children_(can_cache_children) {}
const LayerRasterCacheItem* raster_cache_item() const {
return layer_raster_cache_item_.get();
}
void MarkCanCacheChildren(bool can_cache_children) {
if (layer_raster_cache_item_) {
layer_raster_cache_item_->MarkCanCacheChildren(can_cache_children);
}
}
protected:
RasterCacheItem* realize_raster_cache_item() override;
virtual void disable_raster_cache_item() override;
std::unique_ptr<LayerRasterCacheItem> layer_raster_cache_item_;
int layer_cache_threshold_;
bool can_cache_children_;
};
} // namespace flutter

View File

@ -519,31 +519,74 @@ TEST_F(ClipPathLayerTest, LayerCached) {
use_mock_raster_cache();
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
const auto* clip_cache_item = layer->raster_cache_item();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(clip_cache_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kCurrent);
DlPaint paint;
EXPECT_TRUE(raster_cache()->Draw(clip_cache_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
TEST_F(ClipPathLayerTest, NullRasterCacheResetsRasterCacheItem) {
auto path1 = SkPath().addRect({10, 10, 30, 30});
auto mock1 = MockLayer::MakeOpacityCompatible(path1);
auto layer_clip = SkPath()
.addRect(SkRect::MakeLTRB(5, 5, 25, 25))
.addOval(SkRect::MakeLTRB(20, 20, 40, 50));
auto layer =
std::make_shared<ClipPathLayer>(layer_clip, Clip::antiAliasWithSaveLayer);
layer->Add(mock1);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
int limit = RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer;
for (int i = 1; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kNone);
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(ClipPathLayerTest, EmptyClipDoesNotCullPlatformView) {
const SkPoint view_offset = SkPoint::Make(0.0f, 0.0f);
const SkSize view_size = SkSize::Make(8.0f, 8.0f);

View File

@ -499,30 +499,71 @@ TEST_F(ClipRectLayerTest, LayerCached) {
use_mock_raster_cache();
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
const auto* clip_cache_item = layer->raster_cache_item();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(clip_cache_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kCurrent);
DlPaint paint;
EXPECT_TRUE(raster_cache()->Draw(clip_cache_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
TEST_F(ClipRectLayerTest, NullRasterCacheResetsRasterCacheItem) {
auto path1 = SkPath().addRect({10, 10, 30, 30});
auto mock1 = MockLayer::MakeOpacityCompatible(path1);
SkRect clip_rect = SkRect::MakeWH(500, 500);
auto layer =
std::make_shared<ClipRectLayer>(clip_rect, Clip::antiAliasWithSaveLayer);
layer->Add(mock1);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
int limit = RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer;
for (int i = 1; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kNone);
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(ClipRectLayerTest, EmptyClipDoesNotCullPlatformView) {
const SkPoint view_offset = SkPoint::Make(0.0f, 0.0f);
const SkSize view_size = SkSize::Make(8.0f, 8.0f);

View File

@ -512,29 +512,72 @@ TEST_F(ClipRRectLayerTest, LayerCached) {
use_mock_raster_cache();
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
const auto* clip_cache_item = layer->raster_cache_item();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(clip_cache_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kCurrent);
EXPECT_TRUE(raster_cache()->Draw(clip_cache_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
TEST_F(ClipRRectLayerTest, NullRasterCacheResetsRasterCacheItem) {
auto path1 = SkPath().addRect({10, 10, 30, 30});
DlPaint paint = DlPaint();
auto mock1 = MockLayer::MakeOpacityCompatible(path1);
SkRect clip_rect = SkRect::MakeWH(500, 500);
SkRRect clip_rrect = SkRRect::MakeRectXY(clip_rect, 20, 20);
auto layer = std::make_shared<ClipRRectLayer>(clip_rrect,
Clip::antiAliasWithSaveLayer);
layer->Add(mock1);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
int limit = RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer;
for (int i = 1; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kNone);
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(ClipRRectLayerTest, NoSaveLayerShouldNotCache) {
auto path1 = SkPath().addRect({10, 10, 30, 30});
@ -551,24 +594,23 @@ TEST_F(ClipRRectLayerTest, NoSaveLayerShouldNotCache) {
use_mock_raster_cache();
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
const auto* clip_cache_item = layer->raster_cache_item();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(clip_cache_item->cache_state(), RasterCacheItem::CacheState::kNone);
EXPECT_EQ(layer->raster_cache_item(), nullptr);
}
TEST_F(ClipRRectLayerTest, EmptyClipDoesNotCullPlatformView) {

View File

@ -48,9 +48,7 @@ class ClipShapeLayer : public CacheableContainerLayer {
// We can use the raster_cache for children only when the use_save_layer is
// true so if use_save_layer is false we pass the layer_raster_item is
// nullptr which mean we don't do raster cache logic.
AutoCache cache =
AutoCache(uses_save_layer ? layer_raster_cache_item_.get() : nullptr,
context, context->state_stack.transform_3x3());
AutoCache cache(*this, context, uses_save_layer);
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(

View File

@ -39,8 +39,7 @@ void ColorFilterLayer::Diff(DiffContext* context, const Layer* old_layer) {
void ColorFilterLayer::Preroll(PrerollContext* context) {
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context);
AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context,
context->state_stack.transform_3x3());
AutoCache cache(*this, context);
ContainerLayer::Preroll(context);

View File

@ -271,27 +271,25 @@ TEST_F(ColorFilterLayerTest, CacheChild) {
other_canvas.Transform(other_transform);
use_mock_raster_cache();
const auto* cacheable_color_filter_item = layer->raster_cache_item();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_color_filter_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_color_filter_item->GetId().has_value());
EXPECT_EQ(layer->raster_cache_item(), nullptr);
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(cacheable_color_filter_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kChildren);
EXPECT_EQ(
cacheable_color_filter_item->GetId().value(),
layer->raster_cache_item()->GetId().value(),
RasterCacheKeyID(RasterCacheKeyID::LayerChildrenIds(layer.get()).value(),
RasterCacheKeyType::kLayerChildren));
EXPECT_FALSE(raster_cache()->Draw(
cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
@ -317,30 +315,65 @@ TEST_F(ColorFilterLayerTest, CacheChildren) {
use_mock_raster_cache();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
const auto* cacheable_color_filter_item = layer->raster_cache_item();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_color_filter_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_color_filter_item->GetId().has_value());
EXPECT_EQ(layer->raster_cache_item(), nullptr);
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(cacheable_color_filter_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kChildren);
EXPECT_EQ(
cacheable_color_filter_item->GetId().value(),
layer->raster_cache_item()->GetId().value(),
RasterCacheKeyID(RasterCacheKeyID::LayerChildrenIds(layer.get()).value(),
RasterCacheKeyType::kLayerChildren));
EXPECT_FALSE(raster_cache()->Draw(
cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
TEST_F(ColorFilterLayerTest, NullRasterCacheResetsRasterCacheItem) {
auto layer_filter = DlSrgbToLinearGammaColorFilter::instance;
const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
DlPaint paint = DlPaint();
auto mock_layer = std::make_shared<MockLayer>(child_path);
auto layer = std::make_shared<ColorFilterLayer>(layer_filter);
layer->Add(mock_layer);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
int limit = RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer;
for (int i = 1; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kChildren);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(ColorFilterLayerTest, CacheColorFilterLayerSelf) {
auto layer_filter = DlSrgbToLinearGammaColorFilter::instance;
auto initial_transform = SkMatrix::Translate(50.0, 25.5);
@ -362,25 +395,28 @@ TEST_F(ColorFilterLayerTest, CacheColorFilterLayerSelf) {
use_mock_raster_cache();
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
const auto* cacheable_color_filter_item = layer->raster_cache_item();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
// frame 1.
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
layer->Paint(paint_context());
// frame 2.
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
// ColorFilterLayer default cache children.
EXPECT_EQ(cacheable_color_filter_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kChildren);
EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(
cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
layer->Paint(paint_context());
// frame 3.
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
layer->Paint(paint_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
@ -389,14 +425,14 @@ TEST_F(ColorFilterLayerTest, CacheColorFilterLayerSelf) {
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)2);
// ColorFilterLayer default cache itself.
EXPECT_EQ(cacheable_color_filter_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kCurrent);
EXPECT_EQ(cacheable_color_filter_item->GetId(),
EXPECT_EQ(layer->raster_cache_item()->GetId(),
RasterCacheKeyID(layer->unique_id(), RasterCacheKeyType::kLayer));
EXPECT_TRUE(raster_cache()->Draw(cacheable_color_filter_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(
cacheable_color_filter_item->GetId().value(), other_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
}
TEST_F(ColorFilterLayerTest, OpacityInheritance) {

View File

@ -19,11 +19,26 @@ DisplayListLayer::DisplayListLayer(const SkPoint& offset,
sk_sp<DisplayList> display_list,
bool is_complex,
bool will_change)
: offset_(offset), display_list_(std::move(display_list)) {
: offset_(offset),
display_list_(std::move(display_list)),
is_complex_(is_complex),
will_change_(will_change) {
if (display_list_) {
bounds_ = display_list_->bounds().makeOffset(offset_.x(), offset_.y());
}
}
RasterCacheItem* DisplayListLayer::realize_raster_cache_item() {
if (!display_list_raster_cache_item_) {
display_list_raster_cache_item_ = DisplayListRasterCacheItem::Make(
display_list_, offset_, is_complex, will_change);
display_list_, offset_, is_complex_, will_change_);
}
return display_list_raster_cache_item_.get();
}
void DisplayListLayer::disable_raster_cache_item() {
if (display_list_raster_cache_item_) {
display_list_raster_cache_item_->reset_cache_state();
}
}
@ -95,8 +110,7 @@ bool DisplayListLayer::Compare(DiffContext::Statistics& statistics,
void DisplayListLayer::Preroll(PrerollContext* context) {
DisplayList* disp_list = display_list();
AutoCache cache = AutoCache(display_list_raster_cache_item_.get(), context,
context->state_stack.transform_3x3());
AutoCache cache(*this, context);
if (disp_list->can_apply_group_opacity()) {
context->renderable_state_flags = LayerStateStack::kCallerCanApplyOpacity;
}

View File

@ -8,13 +8,14 @@
#include <memory>
#include "flutter/display_list/display_list.h"
#include "flutter/flow/layers/cacheable_layer.h"
#include "flutter/flow/layers/display_list_raster_cache_item.h"
#include "flutter/flow/layers/layer.h"
#include "flutter/flow/raster_cache_item.h"
namespace flutter {
class DisplayListLayer : public Layer {
class DisplayListLayer : public Layer, public CacheableLayer {
public:
static constexpr size_t kMaxBytesToCompare = 10000;
@ -47,12 +48,18 @@ class DisplayListLayer : public Layer {
}
private:
RasterCacheItem* realize_raster_cache_item() override;
void disable_raster_cache_item() override;
std::unique_ptr<DisplayListRasterCacheItem> display_list_raster_cache_item_;
friend class AutoCache;
SkPoint offset_;
SkRect bounds_;
sk_sp<DisplayList> display_list_;
bool is_complex_;
bool will_change_;
static bool Compare(DiffContext::Statistics& statistics,
const DisplayListLayer* l1,

View File

@ -474,6 +474,46 @@ TEST_F(DisplayListLayerTest, NoLayerTreeSnapshotsWhenDisabledByDefault) {
EXPECT_EQ(0u, snapshot_store.Size());
}
TEST_F(DisplayListLayerTest, NullRasterCacheResetsRasterCacheItem) {
const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
DisplayListBuilder builder;
builder.DrawRect(picture_bounds, DlPaint());
auto display_list = builder.Build();
auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
true, false);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
size_t limit = raster_cache()->access_threshold();
for (size_t i = 0; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kNone);
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
@ -485,9 +525,10 @@ TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
true, false);
auto raster_cache_item = layer->raster_cache_item();
use_mock_raster_cache();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
// First Preroll the DisplayListLayer a few times where it does not intersect
// the cull rect. No caching progress should occur during this time, the
// access_count should remain 0 because the DisplayList was never "visible".
@ -496,16 +537,19 @@ TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
for (int i = 0; i < 10; i++) {
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context());
ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kNone);
ASSERT_TRUE(raster_cache_item->GetId().has_value());
EXPECT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kNone);
ASSERT_TRUE(layer->raster_cache_item()->GetId().has_value());
ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
raster_cache_item->GetId().value(), SkMatrix::I()),
layer->raster_cache_item()->GetId().value(), SkMatrix::I()),
0);
ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
size_t(0));
ASSERT_FALSE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
ASSERT_FALSE(raster_cache_item->Draw(paint_context(), nullptr));
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
ASSERT_FALSE(layer->raster_cache_item()->Draw(paint_context(), nullptr));
}
// Next Preroll the DisplayListLayer once where it does intersect
@ -516,16 +560,18 @@ TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
preroll_context()->state_stack.set_preroll_delegate(hit_cull_rect);
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context());
ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kNone);
ASSERT_TRUE(raster_cache_item->GetId().has_value());
EXPECT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
ASSERT_TRUE(layer->raster_cache_item()->GetId().has_value());
ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
raster_cache_item->GetId().value(), SkMatrix::I()),
layer->raster_cache_item()->GetId().value(), SkMatrix::I()),
1);
ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
size_t(0));
ASSERT_FALSE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
ASSERT_FALSE(raster_cache_item->Draw(paint_context(), nullptr));
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
ASSERT_FALSE(layer->raster_cache_item()->Draw(paint_context(), nullptr));
// Now we can Preroll the DisplayListLayer again with a cull rect that
// it does not intersect and it should continue to count these operations
@ -536,16 +582,19 @@ TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
for (int i = 0; i < 10; i++) {
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context());
ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kNone);
ASSERT_TRUE(raster_cache_item->GetId().has_value());
EXPECT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kNone);
ASSERT_TRUE(layer->raster_cache_item()->GetId().has_value());
ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
raster_cache_item->GetId().value(), SkMatrix::I()),
layer->raster_cache_item()->GetId().value(), SkMatrix::I()),
i + 2);
ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
size_t(0));
ASSERT_FALSE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
ASSERT_FALSE(raster_cache_item->Draw(paint_context(), nullptr));
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
ASSERT_FALSE(layer->raster_cache_item()->Draw(paint_context(), nullptr));
}
// Finally Preroll the DisplayListLayer again where it does intersect
@ -556,18 +605,21 @@ TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
preroll_context()->state_stack.set_preroll_delegate(hit_cull_rect);
preroll_context()->raster_cached_entries->clear();
layer->Preroll(preroll_context());
ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kCurrent);
ASSERT_TRUE(raster_cache_item->GetId().has_value());
EXPECT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(layer->raster_cache_item()->GetId().has_value());
ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
raster_cache_item->GetId().value(), SkMatrix::I()),
layer->raster_cache_item()->GetId().value(), SkMatrix::I()),
12);
ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
size_t(0));
ASSERT_TRUE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
ASSERT_GT(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
size_t(0));
ASSERT_TRUE(raster_cache_item->Draw(paint_context(), nullptr));
ASSERT_TRUE(layer->raster_cache_item()->Draw(paint_context(), nullptr));
}
TEST_F(DisplayListLayerTest, OverflowCachedDisplayListOpacityInheritance) {

View File

@ -56,8 +56,7 @@ void ImageFilterLayer::Preroll(PrerollContext* context) {
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context);
AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context,
context->state_stack.transform_3x3());
AutoCache cache(*this, context);
SkRect child_bounds = SkRect::MakeEmpty();
@ -87,13 +86,9 @@ void ImageFilterLayer::Preroll(PrerollContext* context) {
// CacheChildren only when the transformed_filter_ doesn't equal null.
// So in here we reset the LayerRasterCacheItem cache state.
layer_raster_cache_item_->MarkNotCacheChildren();
transformed_filter_ =
filter_->makeWithLocalMatrix(context->state_stack.transform_3x3());
if (transformed_filter_) {
layer_raster_cache_item_->MarkCacheChildren();
}
MarkCanCacheChildren(transformed_filter_ != nullptr);
}
void ImageFilterLayer::Paint(PaintContext& context) const {

View File

@ -367,27 +367,26 @@ TEST_F(ImageFilterLayerTest, CacheChild) {
DlPaint paint;
use_mock_raster_cache();
const auto* cacheable_image_filter_item = layer->raster_cache_item();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
// ImageFilterLayer default cache itself.
EXPECT_EQ(cacheable_image_filter_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_image_filter_item->Draw(paint_context(), &paint));
EXPECT_EQ(cacheable_items().size(), 0u);
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
EXPECT_EQ(cacheable_items().size(), 1u);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
// The layer_cache_item's strategy is Children, mean we will must cache
// his children
EXPECT_EQ(cacheable_image_filter_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kChildren);
EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(
cacheable_image_filter_item->GetId().value(), other_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
}
TEST_F(ImageFilterLayerTest, CacheChildren) {
@ -413,30 +412,27 @@ TEST_F(ImageFilterLayerTest, CacheChildren) {
use_mock_raster_cache();
const auto* cacheable_image_filter_item = layer->raster_cache_item();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
// ImageFilterLayer default cache itself.
EXPECT_EQ(cacheable_image_filter_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_image_filter_item->Draw(paint_context(), &paint));
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
// The layer_cache_item's strategy is Children, mean we will must cache his
// children
EXPECT_EQ(cacheable_image_filter_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kChildren);
EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(
cacheable_image_filter_item->GetId().value(), other_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
SkRect children_bounds = child_path1.getBounds();
children_bounds.join(child_path2.getBounds());
@ -459,7 +455,7 @@ TEST_F(ImageFilterLayerTest, CacheChildren) {
expected_builder.Transform(snapped_matrix);
DlPaint dl_paint;
dl_paint.setImageFilter(transformed_filter.get());
raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
expected_builder, &dl_paint);
}
expected_builder.Restore();
@ -468,6 +464,45 @@ TEST_F(ImageFilterLayerTest, CacheChildren) {
EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
}
TEST_F(ImageFilterLayerTest, NullRasterCacheResetsRasterCacheItem) {
auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
SkMatrix(), DlImageSampling::kMipmapLinear);
const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
auto mock_layer = std::make_shared<MockLayer>(child_path);
auto layer = std::make_shared<ImageFilterLayer>(dl_image_filter);
layer->Add(mock_layer);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
int limit = RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer;
for (int i = 1; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kChildren);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) {
auto dl_image_filter = std::make_shared<DlMatrixImageFilter>(
SkMatrix(), DlImageSampling::kMipmapLinear);
@ -495,9 +530,10 @@ TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) {
use_mock_raster_cache();
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
const auto* cacheable_image_filter_item = layer->raster_cache_item();
EXPECT_EQ(layer->raster_cache_item(), nullptr);
// frame 1.
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
layer->Paint(display_list_paint_context());
{
@ -537,14 +573,14 @@ TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) {
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)2);
// ImageFilterLayer default cache itself.
EXPECT_EQ(cacheable_image_filter_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kCurrent);
EXPECT_EQ(cacheable_image_filter_item->GetId(),
EXPECT_EQ(layer->raster_cache_item()->GetId(),
RasterCacheKeyID(layer->unique_id(), RasterCacheKeyType::kLayer));
EXPECT_TRUE(raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(
cacheable_image_filter_item->GetId().value(), other_canvas, &paint));
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
layer->Preroll(preroll_context());
@ -556,7 +592,7 @@ TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) {
expected_builder.Save();
{
EXPECT_TRUE(
raster_cache()->Draw(cacheable_image_filter_item->GetId().value(),
raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
expected_builder, nullptr));
}
expected_builder.Restore();

View File

@ -45,9 +45,9 @@ class LayerRasterCacheItem : public RasterCacheItem {
bool TryToPrepareRasterCache(const PaintContext& context,
bool parent_cached = false) const override;
void MarkCacheChildren() { can_cache_children_ = true; }
void MarkNotCacheChildren() { can_cache_children_ = false; }
void MarkCanCacheChildren(bool can_cache_children) {
can_cache_children_ = can_cache_children;
}
bool IsCacheChildren() const { return cache_state_ == CacheState::kChildren; }

View File

@ -42,8 +42,7 @@ void OpacityLayer::Preroll(PrerollContext* context) {
mutator.translate(offset_);
mutator.applyOpacity(SkRect(), DlColor::toOpacity(alpha_));
AutoCache auto_cache = AutoCache(layer_raster_cache_item_.get(), context,
context->state_stack.transform_3x3());
AutoCache auto_cache(*this, context);
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context);
@ -78,7 +77,7 @@ void OpacityLayer::Paint(PaintContext& context) const {
mutator.applyOpacity(child_paint_bounds(), opacity());
if (!children_can_accept_opacity()) {
if (context.raster_cache && !children_can_accept_opacity()) {
DlPaint paint;
if (layer_raster_cache_item_->Draw(context,
context.state_stack.fill(paint))) {

View File

@ -103,29 +103,24 @@ TEST_F(OpacityLayerTest, CacheChild) {
use_mock_raster_cache();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
const auto* cacheable_opacity_item = layer->raster_cache_item();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_opacity_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_opacity_item->GetId().has_value());
EXPECT_EQ(layer->raster_cache_item(), nullptr);
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(cacheable_opacity_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kChildren);
EXPECT_EQ(
cacheable_opacity_item->GetId().value(),
layer->raster_cache_item()->GetId().value(),
RasterCacheKeyID(RasterCacheKeyID::LayerChildrenIds(layer.get()).value(),
RasterCacheKeyType::kLayerChildren));
EXPECT_FALSE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
EXPECT_TRUE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
@ -152,32 +147,61 @@ TEST_F(OpacityLayerTest, CacheChildren) {
use_mock_raster_cache();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
const auto* cacheable_opacity_item = layer->raster_cache_item();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_opacity_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_opacity_item->GetId().has_value());
EXPECT_EQ(layer->raster_cache_item(), nullptr);
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(cacheable_opacity_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kChildren);
EXPECT_EQ(
cacheable_opacity_item->GetId().value(),
layer->raster_cache_item()->GetId().value(),
RasterCacheKeyID(RasterCacheKeyID::LayerChildrenIds(layer.get()).value(),
RasterCacheKeyType::kLayerChildren));
EXPECT_FALSE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
EXPECT_FALSE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
other_canvas, &paint));
EXPECT_TRUE(raster_cache()->Draw(cacheable_opacity_item->GetId().value(),
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
TEST_F(OpacityLayerTest, NullRasterCacheResetsRasterCacheItem) {
const SkAlpha alpha_half = 255 / 2;
const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
auto mock_layer = std::make_shared<MockLayer>(child_path);
mock_layer->set_fake_opacity_compatible(false);
auto layer =
std::make_shared<OpacityLayer>(alpha_half, SkPoint::Make(0.0f, 0.0f));
layer->Add(mock_layer);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
// OpacityLayer will never cache itself, only its children
int limit = 10 * RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer;
for (int i = 1; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kChildren);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(OpacityLayerTest, ShouldNotCacheChildren) {
DlPaint paint;
auto opacity_layer =
@ -190,24 +214,20 @@ TEST_F(OpacityLayerTest, ShouldNotCacheChildren) {
use_mock_raster_cache();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
const auto* cacheable_opacity_item = opacity_layer->raster_cache_item();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_opacity_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_opacity_item->GetId().has_value());
EXPECT_EQ(opacity_layer->raster_cache_item(), nullptr);
opacity_layer->Preroll(preroll_context());
EXPECT_NE(opacity_layer->raster_cache_item(), nullptr);
EXPECT_EQ(context->renderable_state_flags,
LayerStateStack::kCallerCanApplyOpacity);
EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_opacity_item->cache_state(),
EXPECT_EQ(opacity_layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_opacity_item->Draw(paint_context(), &paint));
EXPECT_FALSE(
opacity_layer->raster_cache_item()->Draw(paint_context(), &paint));
}
TEST_F(OpacityLayerTest, FullyOpaque) {

View File

@ -37,8 +37,7 @@ void ShaderMaskLayer::Diff(DiffContext* context, const Layer* old_layer) {
void ShaderMaskLayer::Preroll(PrerollContext* context) {
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context);
AutoCache cache = AutoCache(layer_raster_cache_item_.get(), context,
context->state_stack.transform_3x3());
AutoCache cache(*this, context);
ContainerLayer::Preroll(context);
// We always paint with a saveLayer (or a cached rendering),

View File

@ -334,39 +334,78 @@ TEST_F(ShaderMaskLayerTest, LayerCached) {
use_mock_raster_cache();
preroll_context()->state_stack.set_preroll_delegate(initial_transform);
const auto* cacheable_shader_masker_item = layer->raster_cache_item();
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_shader_masker_item->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_shader_masker_item->GetId().has_value());
EXPECT_EQ(layer->raster_cache_item(), nullptr);
// frame 1.
layer->Preroll(preroll_context());
EXPECT_NE(layer->raster_cache_item(), nullptr);
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_shader_masker_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_shader_masker_item->GetId().has_value());
EXPECT_FALSE(layer->raster_cache_item()->GetId().has_value());
// frame 2.
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)0);
EXPECT_EQ(cacheable_shader_masker_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kNone);
EXPECT_FALSE(cacheable_shader_masker_item->GetId().has_value());
EXPECT_FALSE(layer->raster_cache_item()->GetId().has_value());
// frame 3.
layer->Preroll(preroll_context());
LayerTree::TryToRasterCache(cacheable_items(), &paint_context());
EXPECT_EQ(raster_cache()->GetLayerCachedEntriesCount(), (size_t)1);
EXPECT_EQ(cacheable_shader_masker_item->cache_state(),
EXPECT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::CacheState::kCurrent);
EXPECT_TRUE(raster_cache()->Draw(
cacheable_shader_masker_item->GetId().value(), cache_canvas, &paint));
EXPECT_TRUE(raster_cache()->Draw(layer->raster_cache_item()->GetId().value(),
cache_canvas, &paint));
}
TEST_F(ShaderMaskLayerTest, NullRasterCacheResetsRasterCacheItem) {
auto dl_filter = MakeFilter(DlColor::kBlue());
DlPaint paint;
const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 20.5f, 20.5f);
const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
auto mock_layer = std::make_shared<MockLayer>(child_path);
auto layer = std::make_shared<ShaderMaskLayer>(dl_filter, layer_bounds,
DlBlendMode::kSrc);
layer->Add(mock_layer);
ASSERT_EQ(layer->raster_cache_item(), nullptr);
layer->Preroll(preroll_context());
ASSERT_EQ(layer->raster_cache_item(), nullptr);
use_mock_raster_cache();
int limit = RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer;
for (int i = 1; i < limit; i++) {
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kNone);
ASSERT_FALSE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
}
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(),
RasterCacheItem::kCurrent);
ASSERT_TRUE(
layer->raster_cache_item()->TryToPrepareRasterCache(paint_context()));
use_null_raster_cache();
layer->Preroll(preroll_context());
ASSERT_NE(layer->raster_cache_item(), nullptr);
ASSERT_EQ(layer->raster_cache_item()->cache_state(), RasterCacheItem::kNone);
}
TEST_F(ShaderMaskLayerTest, OpacityInheritance) {

View File

@ -57,6 +57,8 @@ class RasterCacheItem {
void set_matrix(const SkMatrix& matrix) { matrix_ = matrix; }
void reset_cache_state() { cache_state_ = kNone; }
CacheState cache_state() const { return cache_state_; }
bool need_caching() const { return cache_state_ != CacheState::kNone; }

View File

@ -66,17 +66,29 @@ void MockLayer::Paint(PaintContext& context) const {
void MockCacheableContainerLayer::Preroll(PrerollContext* context) {
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context);
auto cache = AutoCache(layer_raster_cache_item_.get(), context,
context->state_stack.transform_3x3());
AutoCache cache(*this, context);
ContainerLayer::Preroll(context);
}
RasterCacheItem* MockCacheableLayer::realize_raster_cache_item() {
if (!raster_cache_item_) {
raster_cache_item_ =
std::make_unique<MockLayerCacheableItem>(this, render_limit_);
}
return raster_cache_item_.get();
}
void MockCacheableLayer::disable_raster_cache_item() {
if (raster_cache_item_) {
raster_cache_item_->reset_cache_state();
}
}
void MockCacheableLayer::Preroll(PrerollContext* context) {
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context);
auto cache = AutoCache(raster_cache_item_.get(), context,
context->state_stack.transform_3x3());
AutoCache cache(*this, context);
MockLayer::Preroll(context);
}

View File

@ -150,15 +150,12 @@ class MockLayerCacheableItem : public LayerRasterCacheItem {
public:
using LayerRasterCacheItem::LayerRasterCacheItem;
};
class MockCacheableLayer : public MockLayer {
class MockCacheableLayer : public MockLayer, public CacheableLayer {
public:
explicit MockCacheableLayer(SkPath path,
DlPaint paint = DlPaint(),
int render_limit = 3)
: MockLayer(path, paint) {
raster_cache_item_ =
std::make_unique<MockLayerCacheableItem>(this, render_limit);
}
: MockLayer(path, paint), render_limit_(render_limit) {}
const LayerRasterCacheItem* raster_cache_item() const {
return raster_cache_item_.get();
@ -167,7 +164,11 @@ class MockCacheableLayer : public MockLayer {
void Preroll(PrerollContext* context) override;
private:
RasterCacheItem* realize_raster_cache_item() override;
void disable_raster_cache_item() override;
std::unique_ptr<LayerRasterCacheItem> raster_cache_item_;
int render_limit_;
};
} // namespace testing

View File

@ -62,7 +62,8 @@ void MockRasterCache::AddMockPicture(int width, int height) {
DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
false);
for (size_t i = 0; i < access_threshold(); i++) {
AutoCache(&display_list_item, &preroll_context_, ctm);
display_list_item.PrerollSetup(&preroll_context_, ctm);
display_list_item.PrerollFinalize(&preroll_context_, ctm);
}
RasterCache::Context r_context = {
// clang-format off