| // 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. |
| |
| #ifndef FLUTTER_FLOW_RASTER_CACHE_H_ |
| #define FLUTTER_FLOW_RASTER_CACHE_H_ |
| |
| #include <memory> |
| #include <unordered_map> |
| |
| #include "flutter/display_list/dl_canvas.h" |
| #include "flutter/flow/raster_cache_key.h" |
| #include "flutter/flow/raster_cache_util.h" |
| #include "flutter/fml/macros.h" |
| #include "flutter/fml/memory/weak_ptr.h" |
| #include "flutter/fml/trace_event.h" |
| #include "third_party/skia/include/core/SkMatrix.h" |
| #include "third_party/skia/include/core/SkRect.h" |
| |
| class GrDirectContext; |
| class SkColorSpace; |
| |
| namespace flutter { |
| |
| enum class RasterCacheLayerStrategy { kLayer, kLayerChildren }; |
| |
| class RasterCacheResult { |
| public: |
| RasterCacheResult(sk_sp<DlImage> image, |
| const SkRect& logical_rect, |
| const char* type, |
| sk_sp<const DlRTree> rtree = nullptr); |
| |
| virtual ~RasterCacheResult() = default; |
| |
| virtual void draw(DlCanvas& canvas, |
| const DlPaint* paint, |
| bool preserve_rtree) const; |
| |
| virtual SkISize image_dimensions() const { |
| return image_ ? image_->dimensions() : SkISize::Make(0, 0); |
| }; |
| |
| virtual int64_t image_bytes() const { |
| return image_ ? image_->GetApproximateByteSize() : 0; |
| }; |
| |
| private: |
| sk_sp<DlImage> image_; |
| SkRect logical_rect_; |
| fml::tracing::TraceFlow flow_; |
| sk_sp<const DlRTree> rtree_; |
| }; |
| |
| class Layer; |
| class RasterCacheItem; |
| struct PrerollContext; |
| struct PaintContext; |
| |
| struct RasterCacheMetrics { |
| /** |
| * The number of cache entries with images evicted in this frame. |
| */ |
| size_t eviction_count = 0; |
| |
| /** |
| * The size of all of the images evicted in this frame. |
| */ |
| size_t eviction_bytes = 0; |
| |
| /** |
| * The number of cache entries with images used in this frame. |
| */ |
| size_t in_use_count = 0; |
| |
| /** |
| * The size of all of the images used in this frame. |
| */ |
| size_t in_use_bytes = 0; |
| |
| /** |
| * The total cache entries that had images during this frame. |
| */ |
| size_t total_count() const { return in_use_count; } |
| |
| /** |
| * The size of all of the cached images during this frame. |
| */ |
| size_t total_bytes() const { return in_use_bytes; } |
| }; |
| |
| /** |
| * RasterCache is used to cache rasterized layers or display lists to improve |
| * performance. |
| * |
| * Life cycle of RasterCache methods: |
| * - Preroll stage |
| * - LayerTree::Preroll - for each Layer in the tree: |
| * - RasterCacheItem::PrerollSetup |
| * At the start of each layer's preroll, add cache items to |
| * `PrerollContext::raster_cached_entries`. |
| * - RasterCacheItem::PrerollFinalize |
| * At the end of each layer's preroll, may mark cache entries as |
| * encountered by the current frame. |
| * - Paint stage |
| * - RasterCache::EvictUnusedCacheEntries |
| * Evict cached images that are no longer used. |
| * - LayerTree::TryToPrepareRasterCache |
| * Create cache image for each cache entry if it does not exist. |
| * - LayerTree::Paint - for each layer in the tree: |
| * If layers or display lists are cached as cached images, the method |
| * `RasterCache::Draw` will be used to draw those cache images. |
| * - RasterCache::EndFrame: |
| * Computes used counts and memory then reports cache metrics. |
| */ |
| class RasterCache { |
| public: |
| struct Context { |
| GrDirectContext* gr_context; |
| const SkColorSpace* dst_color_space; |
| const SkMatrix& matrix; |
| const SkRect& logical_rect; |
| const char* flow_type; |
| }; |
| struct CacheInfo { |
| const size_t accesses_since_visible; |
| const bool has_image; |
| }; |
| |
| std::unique_ptr<RasterCacheResult> Rasterize( |
| const RasterCache::Context& context, |
| sk_sp<const DlRTree> rtree, |
| const std::function<void(DlCanvas*)>& draw_function, |
| const std::function<void(DlCanvas*, const SkRect& rect)>& |
| draw_checkerboard) const; |
| |
| explicit RasterCache( |
| size_t access_threshold = 3, |
| size_t picture_and_display_list_cache_limit_per_frame = |
| RasterCacheUtil::kDefaultPictureAndDisplayListCacheLimitPerFrame); |
| |
| virtual ~RasterCache() = default; |
| |
| // Draws this item if it should be rendered from the cache and returns |
| // true iff it was successfully drawn. Typically this should only fail |
| // if the item was disabled due to conditions discovered during |Preroll| |
| // or if the attempt to populate the entry failed due to bounds overflow |
| // conditions. |
| // If |preserve_rtree| is true, the raster cache will preserve the original |
| // RTree of cached content by blitting individual rectangles from the cached |
| // image to the canvas according to the original layer R-Tree (if present). |
| // This is to ensure that the target surface R-Tree will not be clobbered with |
| // one large blit as it can affect platform view overlays and hit testing. |
| bool Draw(const RasterCacheKeyID& id, |
| DlCanvas& canvas, |
| const DlPaint* paint, |
| bool preserve_rtree = false) const; |
| |
| bool HasEntry(const RasterCacheKeyID& id, const SkMatrix&) const; |
| |
| void BeginFrame(); |
| |
| void EvictUnusedCacheEntries(); |
| |
| void EndFrame(); |
| |
| void Clear(); |
| |
| void SetCheckboardCacheImages(bool checkerboard); |
| |
| const RasterCacheMetrics& picture_metrics() const { return picture_metrics_; } |
| const RasterCacheMetrics& layer_metrics() const { return layer_metrics_; } |
| |
| size_t GetCachedEntriesCount() const; |
| |
| /** |
| * Return the number of map entries in the layer cache regardless of whether |
| * the entries have been populated with an image. |
| */ |
| size_t GetLayerCachedEntriesCount() const; |
| |
| /** |
| * Return the number of map entries in the picture (DisplayList) cache |
| * regardless of whether the entries have been populated with an image. |
| */ |
| size_t GetPictureCachedEntriesCount() const; |
| |
| /** |
| * @brief Estimate how much memory is used by picture raster cache entries in |
| * bytes. |
| * |
| * Only SkImage's memory usage is counted as other objects are often much |
| * smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to |
| * estimate the SkImage memory usage. |
| */ |
| size_t EstimatePictureCacheByteSize() const; |
| |
| /** |
| * @brief Estimate how much memory is used by layer raster cache entries in |
| * bytes. |
| * |
| * Only SkImage's memory usage is counted as other objects are often much |
| * smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to |
| * estimate the SkImage memory usage. |
| */ |
| size_t EstimateLayerCacheByteSize() const; |
| |
| /** |
| * @brief Return the number of frames that a picture must be prepared |
| * before it will be cached. If the number is 0, then no picture will |
| * ever be cached. |
| * |
| * If the number is one, then it must be prepared and drawn on 1 frame |
| * and it will then be cached on the next frame if it is prepared. |
| */ |
| size_t access_threshold() const { return access_threshold_; } |
| |
| bool GenerateNewCacheInThisFrame() const { |
| // Disabling caching when access_threshold is zero is historic behavior. |
| return access_threshold_ != 0 && display_list_cached_this_frame_ < |
| display_list_cache_limit_per_frame_; |
| } |
| |
| /** |
| * @brief The entry whose RasterCacheKey is generated by RasterCacheKeyID |
| * and matrix is marked as encountered by the current frame. The entry |
| * will be created if it does not exist. Optionally the entry will be marked |
| * as visible in the current frame if the caller determines that it |
| * intersects the cull rect. The access_count of the entry will be |
| * increased if it is visible, or if it was ever visible. |
| * @return the number of times the entry has been hit since it was created. |
| * For a new entry that will be 1 if it is visible, or zero if non-visible. |
| */ |
| CacheInfo MarkSeen(const RasterCacheKeyID& id, |
| const SkMatrix& matrix, |
| bool visible) const; |
| |
| /** |
| * Returns the access count (i.e. accesses_since_visible) for the given |
| * entry in the cache, or -1 if no such entry exists. |
| */ |
| int GetAccessCount(const RasterCacheKeyID& id, const SkMatrix& matrix) const; |
| |
| bool UpdateCacheEntry(const RasterCacheKeyID& id, |
| const Context& raster_cache_context, |
| const std::function<void(DlCanvas*)>& render_function, |
| sk_sp<const DlRTree> rtree = nullptr) const; |
| |
| private: |
| struct Entry { |
| bool encountered_this_frame = false; |
| bool visible_this_frame = false; |
| size_t accesses_since_visible = 0; |
| std::unique_ptr<RasterCacheResult> image; |
| }; |
| |
| void UpdateMetrics(); |
| |
| RasterCacheMetrics& GetMetricsForKind(RasterCacheKeyKind kind); |
| |
| const size_t access_threshold_; |
| const size_t display_list_cache_limit_per_frame_; |
| mutable size_t display_list_cached_this_frame_ = 0; |
| RasterCacheMetrics layer_metrics_; |
| RasterCacheMetrics picture_metrics_; |
| mutable RasterCacheKey::Map<Entry> cache_; |
| bool checkerboard_images_; |
| |
| void TraceStatsToTimeline() const; |
| |
| friend class RasterCacheItem; |
| friend class LayerRasterCacheItem; |
| |
| FML_DISALLOW_COPY_AND_ASSIGN(RasterCache); |
| }; |
| |
| } // namespace flutter |
| |
| #endif // FLUTTER_FLOW_RASTER_CACHE_H_ |