| // 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_ |