| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/flow/layers/layer_raster_cache_item.h" |
| #include "flutter/flow/layers/container_layer.h" |
| #include "flutter/flow/raster_cache_item.h" |
| |
| namespace flutter { |
| |
| LayerRasterCacheItem::LayerRasterCacheItem(Layer* layer, |
| int layer_cached_threshold, |
| bool can_cache_children) |
| : RasterCacheItem( |
| RasterCacheKeyID(layer->unique_id(), RasterCacheKeyType::kLayer), |
| // The layer raster_cache_item's cache state default value is none. |
| CacheState::kNone), |
| layer_(layer), |
| layer_cached_threshold_(layer_cached_threshold), |
| can_cache_children_(can_cache_children) {} |
| |
| void LayerRasterCacheItem::PrerollSetup(PrerollContext* context, |
| const SkMatrix& matrix) { |
| cache_state_ = CacheState::kNone; |
| if (context->raster_cache && context->raster_cached_entries) { |
| context->raster_cached_entries->push_back(this); |
| child_items_ = context->raster_cached_entries->size(); |
| matrix_ = matrix; |
| } |
| } |
| |
| std::unique_ptr<LayerRasterCacheItem> LayerRasterCacheItem::Make( |
| Layer* layer, |
| int layer_cache_threshold, |
| bool can_cache_children) { |
| return std::make_unique<LayerRasterCacheItem>(layer, layer_cache_threshold, |
| can_cache_children); |
| } |
| |
| void LayerRasterCacheItem::PrerollFinalize(PrerollContext* context, |
| const SkMatrix& matrix) { |
| 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_; |
| if (num_cache_attempts_ >= layer_cached_threshold_) { |
| // the layer can be cached |
| cache_state_ = CacheState::kCurrent; |
| context->raster_cache->MarkSeen(key_id_, matrix_, true); |
| } else { |
| num_cache_attempts_++; |
| // access current layer |
| if (can_cache_children_) { |
| if (!layer_children_id_.has_value()) { |
| auto ids = RasterCacheKeyID::LayerChildrenIds(layer_); |
| if (!ids.has_value()) { |
| return; |
| } |
| layer_children_id_.emplace(std::move(ids.value()), |
| RasterCacheKeyType::kLayerChildren); |
| } |
| cache_state_ = CacheState::kChildren; |
| context->raster_cache->MarkSeen(layer_children_id_.value(), matrix_, |
| true); |
| } |
| } |
| } |
| |
| std::optional<RasterCacheKeyID> LayerRasterCacheItem::GetId() const { |
| switch (cache_state_) { |
| case kCurrent: |
| return key_id_; |
| case kChildren: |
| return layer_children_id_; |
| default: |
| return {}; |
| } |
| } |
| |
| const SkRect* LayerRasterCacheItem::GetPaintBoundsFromLayer() const { |
| switch (cache_state_) { |
| case CacheState::kCurrent: |
| return &(layer_->paint_bounds()); |
| case CacheState::kChildren: |
| FML_DCHECK(layer_->as_container_layer()); |
| return &(layer_->as_container_layer()->child_paint_bounds()); |
| default: |
| FML_DCHECK(cache_state_ != CacheState::kNone); |
| return nullptr; |
| } |
| } |
| |
| bool Rasterize(RasterCacheItem::CacheState cache_state, |
| Layer* layer, |
| const PaintContext& paint_context, |
| SkCanvas* canvas) { |
| FML_DCHECK(cache_state != RasterCacheItem::CacheState::kNone); |
| SkISize canvas_size = canvas->getBaseLayerSize(); |
| SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); |
| internal_nodes_canvas.setMatrix(canvas->getTotalMatrix()); |
| internal_nodes_canvas.addCanvas(canvas); |
| PaintContext context = { |
| // clang-format off |
| .internal_nodes_canvas = static_cast<SkCanvas*>(&internal_nodes_canvas), |
| .leaf_nodes_canvas = canvas, |
| .gr_context = paint_context.gr_context, |
| .dst_color_space = paint_context.dst_color_space, |
| .view_embedder = paint_context.view_embedder, |
| .raster_time = paint_context.raster_time, |
| .ui_time = paint_context.ui_time, |
| .texture_registry = paint_context.texture_registry, |
| .raster_cache = 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)); |
| layer->Paint(context); |
| break; |
| case RasterCacheItem::CacheState::kChildren: |
| layer->PaintChildren(context); |
| break; |
| case RasterCacheItem::CacheState::kNone: |
| FML_DCHECK(cache_state != RasterCacheItem::CacheState::kNone); |
| return false; |
| } |
| return true; |
| } |
| |
| static const auto* flow_type = "RasterCacheFlow::Layer"; |
| |
| bool LayerRasterCacheItem::TryToPrepareRasterCache(const PaintContext& context, |
| bool parent_cached) const { |
| if (!context.raster_cache || parent_cached) { |
| return false; |
| } |
| if (cache_state_ != kNone) { |
| if (const SkRect* paint_bounds = GetPaintBoundsFromLayer()) { |
| RasterCache::Context r_context = { |
| // clang-format off |
| .gr_context = context.gr_context, |
| .dst_color_space = context.dst_color_space, |
| .matrix = matrix_, |
| .logical_rect = *paint_bounds, |
| .flow_type = flow_type, |
| // clang-format on |
| }; |
| return context.raster_cache->UpdateCacheEntry( |
| GetId().value(), r_context, |
| [ctx = context, cache_state = cache_state_, |
| layer = layer_](SkCanvas* canvas) { |
| Rasterize(cache_state, layer, ctx, canvas); |
| }); |
| } |
| } |
| return false; |
| } |
| |
| bool LayerRasterCacheItem::Draw(const PaintContext& context, |
| const SkPaint* paint) const { |
| return Draw(context, context.leaf_nodes_canvas, paint); |
| } |
| |
| bool LayerRasterCacheItem::Draw(const PaintContext& context, |
| SkCanvas* canvas, |
| const SkPaint* paint) const { |
| if (!context.raster_cache || !canvas) { |
| 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); |
| } |
| } |
| } |
| |
| } // namespace flutter |