diff --git a/flow/layers/display_list_raster_cache_item.cc b/flow/layers/display_list_raster_cache_item.cc index 75a79bcf33c14..a37320083ede6 100644 --- a/flow/layers/display_list_raster_cache_item.cc +++ b/flow/layers/display_list_raster_cache_item.cc @@ -14,6 +14,7 @@ #include "flutter/flow/raster_cache_key.h" #include "flutter/flow/raster_cache_util.h" #include "flutter/flow/skia_gpu_object.h" +#include "flutter/fml/logging.h" namespace flutter { @@ -52,7 +53,7 @@ DisplayListRasterCacheItem::DisplayListRasterCacheItem( bool will_change) : RasterCacheItem(RasterCacheKeyID(display_list->unique_id(), RasterCacheKeyType::kDisplayList), - CacheState::kCurrent), + CacheState::kNone), display_list_(display_list), offset_(offset), is_complex_(is_complex), @@ -70,6 +71,9 @@ std::unique_ptr DisplayListRasterCacheItem::Make( void DisplayListRasterCacheItem::PrerollSetup(PrerollContext* context, const SkMatrix& matrix) { cache_state_ = CacheState::kNone; + if (!context->raster_cache->GenerateNewCacheInThisFrame()) { + return; + } DisplayListComplexityCalculator* complexity_calculator = context->gr_context ? DisplayListComplexityCalculator::GetForBackend( context->gr_context->backend()) @@ -81,6 +85,7 @@ void DisplayListRasterCacheItem::PrerollSetup(PrerollContext* context, return; } + matrix_ = matrix; transformation_matrix_ = matrix; transformation_matrix_.preTranslate(offset_.x(), offset_.y()); @@ -88,11 +93,7 @@ void DisplayListRasterCacheItem::PrerollSetup(PrerollContext* context, // The matrix was singular. No point in going further. return; } - - if (context->raster_cached_entries && context->raster_cache) { - context->raster_cached_entries->push_back(this); - cache_state_ = CacheState::kCurrent; - } + cache_state_ = CacheState::kCurrent; return; } @@ -108,17 +109,34 @@ void DisplayListRasterCacheItem::PrerollFinalize(PrerollContext* context, // if the rect is intersect we will get the entry access_count to confirm if // it great than the threshold. Otherwise we only increase the entry // access_count. + cache_state_ = CacheState::kNone; if (context->cull_rect.intersect(bounds)) { - if (raster_cache->MarkSeen(key_id_, transformation_matrix_) < + // Thought MarkDisplayListSeen we only get the access cout or create entry. + // Don't increase the access_count or use_this_frame = true. + if (raster_cache->MarkDisplayListSeen(key_id_, transformation_matrix_) < raster_cache->access_threshold()) { - cache_state_ = CacheState::kNone; return; } + // We need to make sure that we create a maximum of three images per frame. + // This display_list can be cached and current entry doesn't create image, + // so we should increate the cache count. + if (!raster_cache->HasCached(key_id_, transformation_matrix_)) { + context->raster_cache->IncreaseDisplayListCacheCount(); + cache_state_ = CacheState::kCurrent; + } else { + // Current DL has generator a image and in here it may be used in this + // frame, so we need to touch it. + raster_cache->Touch(key_id_, matrix); + } context->subtree_can_inherit_opacity = true; - cache_state_ = CacheState::kCurrent; } else { + // if the bounds with the cull rect is not intersect, we only touch the + // cache entry. And should not cache the display list raster_cache->Touch(key_id_, matrix); + return; } + // If the display_list can be cached we will add it to cache_entries. + context->raster_cached_entries->push_back(this); return; } @@ -133,13 +151,8 @@ bool DisplayListRasterCacheItem::Draw(const PaintContext& context, if (!context.raster_cache || !canvas) { return false; } - if (cache_state_ == CacheState::kCurrent) { - return context.raster_cache->Draw(key_id_, *canvas, paint); - } - // This display_list doesn't cache itself, this only increase the entry - // access_count; - context.raster_cache->Touch(key_id_, canvas->getTotalMatrix()); - return false; + + return context.raster_cache->Draw(key_id_, *canvas, paint); } static const auto* flow_type = "RasterCacheFlow::DisplayList"; @@ -153,11 +166,12 @@ bool DisplayListRasterCacheItem::TryToPrepareRasterCache( // display_list or picture_list to calculate the memory they used, we // shouldn't cache the current node if the memory is more significant than the // limit. - if (cache_state_ == kNone || !context.raster_cache || parent_cached || - !context.raster_cache->GenerateNewCacheInThisFrame()) { + if (cache_state_ == CacheState::kNone || !context.raster_cache || + parent_cached) { return false; } - SkRect bounds = display_list_->bounds().makeOffset(offset_.x(), offset_.y()); + + SkRect bounds = display_list_->bounds(); RasterCache::Context r_context = { // clang-format off .gr_context = context.gr_context, @@ -169,9 +183,9 @@ bool DisplayListRasterCacheItem::TryToPrepareRasterCache( // clang-format on }; return context.raster_cache->UpdateCacheEntry( - GetId().value(), r_context, - [display_list = display_list_](SkCanvas* canvas) { + key_id_, r_context, [display_list = display_list_](SkCanvas* canvas) { display_list->RenderTo(canvas); + return true; }); } } // namespace flutter diff --git a/flow/layers/display_list_raster_cache_item.h b/flow/layers/display_list_raster_cache_item.h index 65d838939e92d..d6ee6c5f7c473 100644 --- a/flow/layers/display_list_raster_cache_item.h +++ b/flow/layers/display_list_raster_cache_item.h @@ -45,7 +45,7 @@ class DisplayListRasterCacheItem : public RasterCacheItem { const SkPaint* paint) const override; bool TryToPrepareRasterCache(const PaintContext& context, - bool parent_cached = false) const override; + bool parent_cached) const override; void ModifyMatrix(SkPoint offset) const { matrix_ = matrix_.preTranslate(offset.x(), offset.y()); diff --git a/flow/layers/layer_raster_cache_item.cc b/flow/layers/layer_raster_cache_item.cc index d0d987fcaa793..032d2b0ecfdb3 100644 --- a/flow/layers/layer_raster_cache_item.cc +++ b/flow/layers/layer_raster_cache_item.cc @@ -42,18 +42,11 @@ void LayerRasterCacheItem::PrerollFinalize(PrerollContext* context, if (!context->raster_cache || !context->raster_cached_entries) { return; } - // We've marked the cache entry that we would like to cache so it stays - // alive, but if the following conditions apply then we need to set our - // state back to kDoNotCache so that we don't populate the entry later. - if (context->has_platform_view || context->has_texture_layer || - !SkRect::Intersects(context->cull_rect, layer_->paint_bounds())) { - return; - } child_items_ = context->raster_cached_entries->size() - child_items_; + // Determine cache current layer or cache children. if (num_cache_attempts_ >= layer_cached_threshold_) { // the layer can be cached cache_state_ = CacheState::kCurrent; - context->raster_cache->MarkSeen(key_id_, matrix_); } else { num_cache_attempts_++; // access current layer @@ -67,9 +60,25 @@ void LayerRasterCacheItem::PrerollFinalize(PrerollContext* context, RasterCacheKeyType::kLayerChildren); } cache_state_ = CacheState::kChildren; - context->raster_cache->MarkSeen(layer_children_id_.value(), matrix_); } } + // We've marked the cache entry that we would like to cache so it stays + // alive, but if the following conditions apply then we need to set our + // state back to kDoNotCache so that we don't populate the entry later. + if (context->has_platform_view || context->has_texture_layer || + !SkRect::Intersects(context->cull_rect, layer_->paint_bounds())) { + if (cache_state_ != CacheState::kNone) { + // Only touch the entry, do not to cache the layer or children. + context->raster_cache->Touch(GetId().value(), matrix_); + cache_state_ = CacheState::kNone; + } + return; + } + // The layer can be cache, so we should create a entry. + if (cache_state_ != CacheState::kNone) { + // Create Cache entry + context->raster_cache->MarkSeen(GetId().value(), matrix_); + } } std::optional LayerRasterCacheItem::GetId() const { @@ -111,19 +120,20 @@ bool Rasterize(RasterCacheItem::CacheState cache_state, .leaf_nodes_canvas = canvas, .gr_context = paint_context.gr_context, .dst_color_space = paint_context.dst_color_space, - .view_embedder = paint_context.view_embedder, + .view_embedder = nullptr, .raster_time = paint_context.raster_time, .ui_time = paint_context.ui_time, .texture_registry = paint_context.texture_registry, - .raster_cache = paint_context.raster_cache, + .raster_cache = layer->subtree_has_platform_view() ? nullptr: paint_context.raster_cache, .checkerboard_offscreen_layers = paint_context.checkerboard_offscreen_layers, .frame_device_pixel_ratio = paint_context.frame_device_pixel_ratio, // clang-format on }; - switch (cache_state) { case RasterCacheItem::CacheState::kCurrent: - FML_DCHECK(layer->needs_painting(context)); + if (!layer->needs_painting(context)) { + return false; + } layer->Paint(context); break; case RasterCacheItem::CacheState::kChildren: @@ -140,7 +150,11 @@ static const auto* flow_type = "RasterCacheFlow::Layer"; bool LayerRasterCacheItem::TryToPrepareRasterCache(const PaintContext& context, bool parent_cached) const { - if (!context.raster_cache || parent_cached) { + if (!context.raster_cache) { + return false; + } + if (parent_cached) { + context.raster_cache->Touch(GetId().value(), matrix_); return false; } if (cache_state_ != kNone) { @@ -159,7 +173,7 @@ bool LayerRasterCacheItem::TryToPrepareRasterCache(const PaintContext& context, GetId().value(), r_context, [ctx = context, cache_state = cache_state_, layer = layer_](SkCanvas* canvas) { - Rasterize(cache_state, layer, ctx, canvas); + return Rasterize(cache_state, layer, ctx, canvas); }); } } @@ -174,20 +188,10 @@ bool LayerRasterCacheItem::Draw(const PaintContext& context, bool LayerRasterCacheItem::Draw(const PaintContext& context, SkCanvas* canvas, const SkPaint* paint) const { - if (!context.raster_cache || !canvas) { + if (!context.raster_cache || !canvas || cache_state_ == CacheState::kNone) { return false; } - switch (cache_state_) { - case RasterCacheItem::kNone: - return false; - case RasterCacheItem::kCurrent: { - return context.raster_cache->Draw(key_id_, *canvas, paint); - } - case RasterCacheItem::kChildren: { - return context.raster_cache->Draw(layer_children_id_.value(), *canvas, - paint); - } - } + return context.raster_cache->Draw(GetId().value(), *canvas, paint); } } // namespace flutter diff --git a/flow/layers/layer_raster_cache_item.h b/flow/layers/layer_raster_cache_item.h index 3588abdf3b627..aaa311cd5513f 100644 --- a/flow/layers/layer_raster_cache_item.h +++ b/flow/layers/layer_raster_cache_item.h @@ -43,7 +43,7 @@ class LayerRasterCacheItem : public RasterCacheItem { const SkPaint* paint) const override; bool TryToPrepareRasterCache(const PaintContext& context, - bool parent_cached = false) const override; + bool parent_cached) const override; void MarkCacheChildren() { can_cache_children_ = true; } diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index e9702629052ca..ef9e45ef6efe5 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -38,6 +38,9 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { SkMatrix child_matrix = matrix; child_matrix.preTranslate(offset_.fX, offset_.fY); + AutoCache auto_cache = + AutoCache(layer_raster_cache_item_.get(), context, child_matrix); + // Similar to what's done in TransformLayer::Preroll, we have to apply the // reverse transformation to the cull rect to properly cull child layers. context->cull_rect = context->cull_rect.makeOffset(-offset_.fX, -offset_.fY); @@ -46,8 +49,6 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { SkMatrix::Translate(offset_.fX, offset_.fY)); context->mutators_stack.PushOpacity(alpha_); - AutoCache auto_cache = - AutoCache(layer_raster_cache_item_.get(), context, matrix); Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index 720efea1866ff..a9428190441e3 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -11,6 +11,7 @@ #include "flutter/flow/layers/container_layer.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/paint_utils.h" +#include "flutter/flow/raster_cache_key.h" #include "flutter/flow/raster_cache_util.h" #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" @@ -51,7 +52,7 @@ RasterCache::RasterCache(size_t access_threshold, /// @note Procedure doesn't copy all closures. std::unique_ptr RasterCache::Rasterize( const RasterCache::Context& context, - const std::function& draw_function) { + const std::function& draw_function) { TRACE_EVENT0("flutter", "RasterCachePopulate"); SkRect dest_rect = @@ -76,7 +77,10 @@ std::unique_ptr RasterCache::Rasterize( canvas->clear(SK_ColorTRANSPARENT); canvas->translate(-dest_rect.left(), -dest_rect.top()); canvas->concat(context.matrix); - draw_function(canvas); + + if (!draw_function(canvas)) { + return nullptr; + } if (context.checkerboard) { DrawCheckerboard(canvas, context.logical_rect); @@ -89,23 +93,12 @@ std::unique_ptr RasterCache::Rasterize( bool RasterCache::UpdateCacheEntry( const RasterCacheKeyID& id, const Context& raster_cache_context, - const std::function& render_function) const { + const std::function& render_function) const { RasterCacheKey key = RasterCacheKey(id, raster_cache_context.matrix); Entry& entry = cache_[key]; entry.used_this_frame = true; if (!entry.image) { entry.image = Rasterize(raster_cache_context, render_function); - if (entry.image != nullptr) { - switch (id.type()) { - case RasterCacheKeyType::kDisplayList: { - display_list_cached_this_frame_++; - break; - } - default: - break; - } - return true; - } } return entry.image != nullptr; } @@ -115,7 +108,6 @@ bool RasterCache::Touch(const RasterCacheKeyID& id, RasterCacheKey cache_key = RasterCacheKey(id, matrix); auto it = cache_.find(cache_key); if (it != cache_.end()) { - it->second.access_count++; it->second.used_this_frame = true; return true; } @@ -126,7 +118,13 @@ int RasterCache::MarkSeen(const RasterCacheKeyID& id, const SkMatrix& matrix) const { RasterCacheKey key = RasterCacheKey(id, matrix); Entry& entry = cache_[key]; - entry.used_this_frame = true; + return entry.access_count; +} + +int RasterCache::MarkDisplayListSeen(const RasterCacheKeyID& id, + const SkMatrix& matrix) const { + RasterCacheKey key = RasterCacheKey(id, matrix); + Entry& entry = cache_[key]; return entry.access_count; } @@ -139,6 +137,16 @@ bool RasterCache::HasEntry(const RasterCacheKeyID& id, return false; } +bool RasterCache::HasCached(const RasterCacheKeyID& id, + const SkMatrix& matrix) const { + RasterCacheKey key = RasterCacheKey(id, matrix); + auto it = cache_.find(key); + if (it != cache_.end()) { + return it->second.image != nullptr; + } + return false; +} + bool RasterCache::Draw(const RasterCacheKeyID& id, SkCanvas& canvas, const SkPaint* paint) const { diff --git a/flow/raster_cache.h b/flow/raster_cache.h index 95feec68dbf0c..82a5e560ba88d 100644 --- a/flow/raster_cache.h +++ b/flow/raster_cache.h @@ -105,7 +105,7 @@ class RasterCache { static std::unique_ptr Rasterize( const RasterCache::Context& context, - const std::function& draw_function); + const std::function& draw_function); explicit RasterCache( size_t access_threshold = 3, @@ -123,6 +123,8 @@ class RasterCache { SkCanvas& canvas, const SkPaint* paint) const; + void IncreaseDisplayListCacheCount() { display_list_cached_this_frame_++; } + bool Touch(const RasterCacheKeyID& id, const SkMatrix& matrix) const; bool HasEntry(const RasterCacheKeyID& id, const SkMatrix&) const; @@ -198,11 +200,15 @@ class RasterCache { * a new entry that will be 1. */ int MarkSeen(const RasterCacheKeyID& id, const SkMatrix& matrix) const; + int MarkDisplayListSeen(const RasterCacheKeyID& id, + const SkMatrix& matrix) const; + + bool HasCached(const RasterCacheKeyID& id, const SkMatrix& matrix) const; bool UpdateCacheEntry( const RasterCacheKeyID& id, const Context& raster_cache_context, - const std::function& render_function) const; + const std::function& render_function) const; private: struct Entry { diff --git a/flow/raster_cache_item.h b/flow/raster_cache_item.h index 8509775589077..9684860d8279f 100644 --- a/flow/raster_cache_item.h +++ b/flow/raster_cache_item.h @@ -55,7 +55,7 @@ class RasterCacheItem { virtual std::optional GetId() const { return key_id_; } virtual bool TryToPrepareRasterCache(const PaintContext& context, - bool parent_cached = false) const = 0; + bool parent_cached) const = 0; unsigned child_items() const { return child_items_; } diff --git a/flow/raster_cache_key.h b/flow/raster_cache_key.h index 2f61f8f6d8ba1..c2804ff84ed54 100644 --- a/flow/raster_cache_key.h +++ b/flow/raster_cache_key.h @@ -25,7 +25,7 @@ class RasterCacheKeyID { RasterCacheKeyID(uint16_t id, RasterCacheKeyType type) : ids_({id}), type_(type) {} - RasterCacheKeyID(const std::vector ids, RasterCacheKeyType type) + RasterCacheKeyID(const std::vector& ids, RasterCacheKeyType type) : ids_(ids), type_(type) {} const std::vector& ids() const { return ids_; } diff --git a/flow/raster_cache_unittests.cc b/flow/raster_cache_unittests.cc index 067e045fa91b6..b9ef14c23e117 100644 --- a/flow/raster_cache_unittests.cc +++ b/flow/raster_cache_unittests.cc @@ -127,7 +127,6 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForSkPicture) { SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); - ; SkCanvas dummy_canvas; SkPaint paint; diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index 9b69eb39103c2..796d2e6ede27a 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -26,7 +26,7 @@ void MockRasterCache::AddMockLayer(int width, int height) { path.addRect(100, 100, 100 + width, 100 + height); MockCacheableLayer layer = MockCacheableLayer(path); layer.Preroll(&preroll_context_, ctm); - layer.raster_cache_item()->TryToPrepareRasterCache(paint_context_); + layer.raster_cache_item()->TryToPrepareRasterCache(paint_context_, false); RasterCache::Context r_context = { // clang-format off .gr_context = preroll_context_.gr_context, @@ -38,10 +38,10 @@ void MockRasterCache::AddMockLayer(int width, int height) { }; UpdateCacheEntry( RasterCacheKeyID(layer.unique_id(), RasterCacheKeyType::kLayer), - r_context, [&](SkCanvas* canvas) { + r_context, [&](SkCanvas* canvas) -> bool { SkRect cache_rect = RasterCacheUtil::GetDeviceBounds( r_context.logical_rect, r_context.matrix); - return std::make_unique(cache_rect); + return std::make_unique(cache_rect) != nullptr; }); } @@ -74,13 +74,14 @@ void MockRasterCache::AddMockPicture(int width, int height) { .checkerboard = preroll_context_.checkerboard_offscreen_layers, // clang-format on }; - UpdateCacheEntry(RasterCacheKeyID(display_list->unique_id(), - RasterCacheKeyType::kDisplayList), - r_context, [&](SkCanvas* canvas) { - SkRect cache_rect = RasterCacheUtil::GetDeviceBounds( - r_context.logical_rect, r_context.matrix); - return std::make_unique(cache_rect); - }); + UpdateCacheEntry( + RasterCacheKeyID(display_list->unique_id(), + RasterCacheKeyType::kDisplayList), + r_context, [&](SkCanvas* canvas) -> bool { + SkRect cache_rect = RasterCacheUtil::GetDeviceBounds( + r_context.logical_rect, r_context.matrix); + return std::make_unique(cache_rect) != nullptr; + }); } static std::vector raster_cache_items_; @@ -152,7 +153,7 @@ bool DisplayListRasterCacheItemTryToRasterCache( display_list_item.PrerollFinalize(&context, matrix); if (display_list_item.cache_state() == RasterCacheItem::CacheState::kCurrent) { - return display_list_item.TryToPrepareRasterCache(paint_context); + return display_list_item.TryToPrepareRasterCache(paint_context, false); } return false; } diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 9c7de893b4a98..56cab59e1a946 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -2434,7 +2434,8 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { matrix); picture_cache_generated = display_list_raster_cache_item.need_caching(); - display_list_raster_cache_item.TryToPrepareRasterCache(paint_context); + display_list_raster_cache_item.TryToPrepareRasterCache(paint_context, + false); display_list_raster_cache_item.Draw(paint_context, &dummy_canvas, &paint); } @@ -2445,7 +2446,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { layer_raster_cache_item.PrerollSetup(&preroll_context, SkMatrix::I()); layer_raster_cache_item.PrerollFinalize(&preroll_context, SkMatrix::I()); - layer_raster_cache_item.TryToPrepareRasterCache(paint_context); + layer_raster_cache_item.TryToPrepareRasterCache(paint_context, false); layer_raster_cache_item.Draw(paint_context, &dummy_canvas, &paint); rasterized.set_value(true); });