1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #ifndef FLUTTER_FLOW_RASTER_CACHE_H_ |
6 | #define FLUTTER_FLOW_RASTER_CACHE_H_ |
7 | |
8 | #include <memory> |
9 | #include <unordered_map> |
10 | |
11 | #include "flutter/display_list/dl_canvas.h" |
12 | #include "flutter/flow/raster_cache_key.h" |
13 | #include "flutter/flow/raster_cache_util.h" |
14 | #include "flutter/fml/macros.h" |
15 | #include "flutter/fml/memory/weak_ptr.h" |
16 | #include "flutter/fml/trace_event.h" |
17 | #include "third_party/skia/include/core/SkMatrix.h" |
18 | #include "third_party/skia/include/core/SkRect.h" |
19 | |
20 | class GrDirectContext; |
21 | class SkColorSpace; |
22 | |
23 | namespace flutter { |
24 | |
25 | enum class RasterCacheLayerStrategy { kLayer, kLayerChildren }; |
26 | |
27 | class RasterCacheResult { |
28 | public: |
29 | RasterCacheResult(sk_sp<DlImage> image, |
30 | const SkRect& logical_rect, |
31 | const char* type, |
32 | sk_sp<const DlRTree> rtree = nullptr); |
33 | |
34 | virtual ~RasterCacheResult() = default; |
35 | |
36 | virtual void draw(DlCanvas& canvas, |
37 | const DlPaint* paint, |
38 | bool preserve_rtree) const; |
39 | |
40 | virtual SkISize image_dimensions() const { |
41 | return image_ ? image_->dimensions() : SkISize::Make(w: 0, h: 0); |
42 | }; |
43 | |
44 | virtual int64_t image_bytes() const { |
45 | return image_ ? image_->GetApproximateByteSize() : 0; |
46 | }; |
47 | |
48 | private: |
49 | sk_sp<DlImage> image_; |
50 | SkRect logical_rect_; |
51 | fml::tracing::TraceFlow flow_; |
52 | sk_sp<const DlRTree> rtree_; |
53 | }; |
54 | |
55 | class Layer; |
56 | class RasterCacheItem; |
57 | struct PrerollContext; |
58 | struct PaintContext; |
59 | |
60 | struct RasterCacheMetrics { |
61 | /** |
62 | * The number of cache entries with images evicted in this frame. |
63 | */ |
64 | size_t eviction_count = 0; |
65 | |
66 | /** |
67 | * The size of all of the images evicted in this frame. |
68 | */ |
69 | size_t eviction_bytes = 0; |
70 | |
71 | /** |
72 | * The number of cache entries with images used in this frame. |
73 | */ |
74 | size_t in_use_count = 0; |
75 | |
76 | /** |
77 | * The size of all of the images used in this frame. |
78 | */ |
79 | size_t in_use_bytes = 0; |
80 | |
81 | /** |
82 | * The total cache entries that had images during this frame. |
83 | */ |
84 | size_t total_count() const { return in_use_count; } |
85 | |
86 | /** |
87 | * The size of all of the cached images during this frame. |
88 | */ |
89 | size_t total_bytes() const { return in_use_bytes; } |
90 | }; |
91 | |
92 | /** |
93 | * RasterCache is used to cache rasterized layers or display lists to improve |
94 | * performance. |
95 | * |
96 | * Life cycle of RasterCache methods: |
97 | * - Preroll stage |
98 | * - LayerTree::Preroll - for each Layer in the tree: |
99 | * - RasterCacheItem::PrerollSetup |
100 | * At the start of each layer's preroll, add cache items to |
101 | * `PrerollContext::raster_cached_entries`. |
102 | * - RasterCacheItem::PrerollFinalize |
103 | * At the end of each layer's preroll, may mark cache entries as |
104 | * encountered by the current frame. |
105 | * - Paint stage |
106 | * - RasterCache::EvictUnusedCacheEntries |
107 | * Evict cached images that are no longer used. |
108 | * - LayerTree::TryToPrepareRasterCache |
109 | * Create cache image for each cache entry if it does not exist. |
110 | * - LayerTree::Paint - for each layer in the tree: |
111 | * If layers or display lists are cached as cached images, the method |
112 | * `RasterCache::Draw` will be used to draw those cache images. |
113 | * - RasterCache::EndFrame: |
114 | * Computes used counts and memory then reports cache metrics. |
115 | */ |
116 | class RasterCache { |
117 | public: |
118 | struct Context { |
119 | GrDirectContext* gr_context; |
120 | const SkColorSpace* dst_color_space; |
121 | const SkMatrix& matrix; |
122 | const SkRect& logical_rect; |
123 | const char* flow_type; |
124 | }; |
125 | struct CacheInfo { |
126 | const size_t accesses_since_visible; |
127 | const bool has_image; |
128 | }; |
129 | |
130 | std::unique_ptr<RasterCacheResult> Rasterize( |
131 | const RasterCache::Context& context, |
132 | sk_sp<const DlRTree> rtree, |
133 | const std::function<void(DlCanvas*)>& draw_function, |
134 | const std::function<void(DlCanvas*, const SkRect& rect)>& |
135 | draw_checkerboard) const; |
136 | |
137 | explicit RasterCache( |
138 | size_t access_threshold = 3, |
139 | size_t picture_and_display_list_cache_limit_per_frame = |
140 | RasterCacheUtil::kDefaultPictureAndDisplayListCacheLimitPerFrame); |
141 | |
142 | virtual ~RasterCache() = default; |
143 | |
144 | // Draws this item if it should be rendered from the cache and returns |
145 | // true iff it was successfully drawn. Typically this should only fail |
146 | // if the item was disabled due to conditions discovered during |Preroll| |
147 | // or if the attempt to populate the entry failed due to bounds overflow |
148 | // conditions. |
149 | // If |preserve_rtree| is true, the raster cache will preserve the original |
150 | // RTree of cached content by blitting individual rectangles from the cached |
151 | // image to the canvas according to the original layer R-Tree (if present). |
152 | // This is to ensure that the target surface R-Tree will not be clobbered with |
153 | // one large blit as it can affect platform view overlays and hit testing. |
154 | bool Draw(const RasterCacheKeyID& id, |
155 | DlCanvas& canvas, |
156 | const DlPaint* paint, |
157 | bool preserve_rtree = false) const; |
158 | |
159 | bool HasEntry(const RasterCacheKeyID& id, const SkMatrix&) const; |
160 | |
161 | void BeginFrame(); |
162 | |
163 | void EvictUnusedCacheEntries(); |
164 | |
165 | void EndFrame(); |
166 | |
167 | void Clear(); |
168 | |
169 | void SetCheckboardCacheImages(bool checkerboard); |
170 | |
171 | const RasterCacheMetrics& picture_metrics() const { return picture_metrics_; } |
172 | const RasterCacheMetrics& layer_metrics() const { return layer_metrics_; } |
173 | |
174 | size_t GetCachedEntriesCount() const; |
175 | |
176 | /** |
177 | * Return the number of map entries in the layer cache regardless of whether |
178 | * the entries have been populated with an image. |
179 | */ |
180 | size_t GetLayerCachedEntriesCount() const; |
181 | |
182 | /** |
183 | * Return the number of map entries in the picture (DisplayList) cache |
184 | * regardless of whether the entries have been populated with an image. |
185 | */ |
186 | size_t GetPictureCachedEntriesCount() const; |
187 | |
188 | /** |
189 | * @brief Estimate how much memory is used by picture raster cache entries in |
190 | * bytes. |
191 | * |
192 | * Only SkImage's memory usage is counted as other objects are often much |
193 | * smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to |
194 | * estimate the SkImage memory usage. |
195 | */ |
196 | size_t EstimatePictureCacheByteSize() const; |
197 | |
198 | /** |
199 | * @brief Estimate how much memory is used by layer raster cache entries in |
200 | * bytes. |
201 | * |
202 | * Only SkImage's memory usage is counted as other objects are often much |
203 | * smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to |
204 | * estimate the SkImage memory usage. |
205 | */ |
206 | size_t EstimateLayerCacheByteSize() const; |
207 | |
208 | /** |
209 | * @brief Return the number of frames that a picture must be prepared |
210 | * before it will be cached. If the number is 0, then no picture will |
211 | * ever be cached. |
212 | * |
213 | * If the number is one, then it must be prepared and drawn on 1 frame |
214 | * and it will then be cached on the next frame if it is prepared. |
215 | */ |
216 | size_t access_threshold() const { return access_threshold_; } |
217 | |
218 | bool GenerateNewCacheInThisFrame() const { |
219 | // Disabling caching when access_threshold is zero is historic behavior. |
220 | return access_threshold_ != 0 && display_list_cached_this_frame_ < |
221 | display_list_cache_limit_per_frame_; |
222 | } |
223 | |
224 | /** |
225 | * @brief The entry whose RasterCacheKey is generated by RasterCacheKeyID |
226 | * and matrix is marked as encountered by the current frame. The entry |
227 | * will be created if it does not exist. Optionally the entry will be marked |
228 | * as visible in the current frame if the caller determines that it |
229 | * intersects the cull rect. The access_count of the entry will be |
230 | * increased if it is visible, or if it was ever visible. |
231 | * @return the number of times the entry has been hit since it was created. |
232 | * For a new entry that will be 1 if it is visible, or zero if non-visible. |
233 | */ |
234 | CacheInfo MarkSeen(const RasterCacheKeyID& id, |
235 | const SkMatrix& matrix, |
236 | bool visible) const; |
237 | |
238 | /** |
239 | * Returns the access count (i.e. accesses_since_visible) for the given |
240 | * entry in the cache, or -1 if no such entry exists. |
241 | */ |
242 | int GetAccessCount(const RasterCacheKeyID& id, const SkMatrix& matrix) const; |
243 | |
244 | bool UpdateCacheEntry(const RasterCacheKeyID& id, |
245 | const Context& raster_cache_context, |
246 | const std::function<void(DlCanvas*)>& render_function, |
247 | sk_sp<const DlRTree> rtree = nullptr) const; |
248 | |
249 | private: |
250 | struct Entry { |
251 | bool encountered_this_frame = false; |
252 | bool visible_this_frame = false; |
253 | size_t accesses_since_visible = 0; |
254 | std::unique_ptr<RasterCacheResult> image; |
255 | }; |
256 | |
257 | void UpdateMetrics(); |
258 | |
259 | RasterCacheMetrics& GetMetricsForKind(RasterCacheKeyKind kind); |
260 | |
261 | const size_t access_threshold_; |
262 | const size_t display_list_cache_limit_per_frame_; |
263 | mutable size_t display_list_cached_this_frame_ = 0; |
264 | RasterCacheMetrics layer_metrics_; |
265 | RasterCacheMetrics picture_metrics_; |
266 | mutable RasterCacheKey::Map<Entry> cache_; |
267 | bool checkerboard_images_; |
268 | |
269 | void TraceStatsToTimeline() const; |
270 | |
271 | friend class RasterCacheItem; |
272 | friend class LayerRasterCacheItem; |
273 | |
274 | FML_DISALLOW_COPY_AND_ASSIGN(RasterCache); |
275 | }; |
276 | |
277 | } // namespace flutter |
278 | |
279 | #endif // FLUTTER_FLOW_RASTER_CACHE_H_ |
280 | |