diff --git a/flow/layers/cacheable_layer.cc b/flow/layers/cacheable_layer.cc index 7cdfacfb7d4c7..7ce398037dc0f 100644 --- a/flow/layers/cacheable_layer.cc +++ b/flow/layers/cacheable_layer.cc @@ -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 diff --git a/flow/layers/cacheable_layer.h b/flow/layers/cacheable_layer.h index 856ce47546ec3..46c502d8a1985 100644 --- a/flow/layers/cacheable_layer.h +++ b/flow/layers/cacheable_layer.h @@ -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 layer_raster_cache_item_; + + int layer_cache_threshold_; + bool can_cache_children_; }; } // namespace flutter diff --git a/flow/layers/clip_path_layer_unittests.cc b/flow/layers/clip_path_layer_unittests.cc index 582ae97fcf059..922c71263e2c8 100644 --- a/flow/layers/clip_path_layer_unittests.cc +++ b/flow/layers/clip_path_layer_unittests.cc @@ -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(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); diff --git a/flow/layers/clip_rect_layer_unittests.cc b/flow/layers/clip_rect_layer_unittests.cc index 55359b378a707..2614ddedaea30 100644 --- a/flow/layers/clip_rect_layer_unittests.cc +++ b/flow/layers/clip_rect_layer_unittests.cc @@ -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(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); diff --git a/flow/layers/clip_rrect_layer_unittests.cc b/flow/layers/clip_rrect_layer_unittests.cc index 98d6493ba7bb5..f0f43954be4e8 100644 --- a/flow/layers/clip_rrect_layer_unittests.cc +++ b/flow/layers/clip_rrect_layer_unittests.cc @@ -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(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) { diff --git a/flow/layers/clip_shape_layer.h b/flow/layers/clip_shape_layer.h index d33267853e30d..3af0b3f61b75b 100644 --- a/flow/layers/clip_shape_layer.h +++ b/flow/layers/clip_shape_layer.h @@ -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( diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 056efa7472dc7..aa25727f70635 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -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); diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index 1ec1f35bd0bcc..5ecc790d5a445 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -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(child_path); + auto layer = std::make_shared(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) { diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 5987dbecae7ea..e74daca596c94 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -18,11 +18,26 @@ DisplayListLayer::DisplayListLayer(const SkPoint& offset, sk_sp 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(); } } @@ -94,8 +109,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; } diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h index d7efe4e8ee0b9..88243cc8f9f4e 100644 --- a/flow/layers/display_list_layer.h +++ b/flow/layers/display_list_layer.h @@ -8,13 +8,14 @@ #include #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 display_list_raster_cache_item_; + friend class AutoCache; + SkPoint offset_; SkRect bounds_; sk_sp display_list_; + bool is_complex_; + bool will_change_; static bool Compare(DiffContext::Statistics& statistics, const DisplayListLayer* l1, diff --git a/flow/layers/display_list_layer_unittests.cc b/flow/layers/display_list_layer_unittests.cc index e884fb6b10d0a..2b215b23d059c 100644 --- a/flow/layers/display_list_layer_unittests.cc +++ b/flow/layers/display_list_layer_unittests.cc @@ -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(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(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) { diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 834df45ce857d..27d8abe2314a5 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -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 { diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 8d9e2e9ab5091..823bad96f2fa7 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -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( + SkMatrix(), DlImageSampling::kMipmapLinear); + const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); + auto mock_layer = std::make_shared(child_path); + auto layer = std::make_shared(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( 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()); { @@ -539,14 +575,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()); @@ -558,7 +594,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(); diff --git a/flow/layers/layer_raster_cache_item.h b/flow/layers/layer_raster_cache_item.h index 53e9a65237aef..b383ac3899bee 100644 --- a/flow/layers/layer_raster_cache_item.h +++ b/flow/layers/layer_raster_cache_item.h @@ -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; } diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 8b55dff69aa92..20843bef5cbee 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -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))) { diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index 71ccdc15c8476..3a64fc31ca4ba 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -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(child_path); + mock_layer->set_fake_opacity_compatible(false); + auto layer = + std::make_shared(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) { diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index bf7b81f400521..ccf6ee390d91d 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -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), diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index 4354f8715a1db..f72126380ec7f 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -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(child_path); + auto layer = std::make_shared(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) { diff --git a/flow/raster_cache_item.h b/flow/raster_cache_item.h index 6df3066fed7ab..78c7c9f4ad838 100644 --- a/flow/raster_cache_item.h +++ b/flow/raster_cache_item.h @@ -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; } diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 4f0453c383578..31e5f5d41ad68 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -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(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); } diff --git a/flow/testing/mock_layer.h b/flow/testing/mock_layer.h index 4d2efdf367842..0ceb4f45e0244 100644 --- a/flow/testing/mock_layer.h +++ b/flow/testing/mock_layer.h @@ -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(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 raster_cache_item_; + + int render_limit_; }; } // namespace testing diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index 9effd6af12ae4..3aba6b150b081 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -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