Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
raster_cache.cc
Go to the documentation of this file.
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#include "flutter/flow/raster_cache.h"
6
7#include <cstddef>
8#include <vector>
9
10#include "flutter/common/constants.h"
11#include "flutter/display_list/skia/dl_sk_dispatcher.h"
12#include "flutter/flow/layers/container_layer.h"
13#include "flutter/flow/layers/layer.h"
14#include "flutter/flow/paint_utils.h"
15#include "flutter/flow/raster_cache_util.h"
16#include "flutter/fml/logging.h"
17#include "flutter/fml/trace_event.h"
24
25namespace flutter {
26
28 const SkRect& logical_rect,
29 const char* type,
31 : image_(std::move(image)),
32 logical_rect_(logical_rect),
33 flow_(type),
34 rtree_(std::move(rtree)) {}
35
37 const DlPaint* paint,
38 bool preserve_rtree) const {
39 DlAutoCanvasRestore auto_restore(&canvas, true);
40
42 SkRect bounds =
43 RasterCacheUtil::GetRoundedOutDeviceBounds(logical_rect_, matrix);
44 FML_DCHECK(std::abs(bounds.width() - image_->dimensions().width()) <= 1 &&
45 std::abs(bounds.height() - image_->dimensions().height()) <= 1);
46 canvas.TransformReset();
47 flow_.Step();
48 if (!preserve_rtree || !rtree_) {
49 canvas.DrawImage(image_, {bounds.fLeft, bounds.fTop},
51 } else {
52 // On some platforms RTree from overlay layers is used for unobstructed
53 // platform views and hit testing. To preserve the RTree raster cache must
54 // paint individual rects instead of the whole image.
55 auto rects = rtree_->region().getRects(true);
56
57 canvas.Translate(bounds.fLeft, bounds.fTop);
58
59 SkRect rtree_bounds =
60 RasterCacheUtil::GetRoundedOutDeviceBounds(rtree_->bounds(), matrix);
61 for (auto rect : rects) {
63 SkRect::Make(rect), matrix);
64 device_rect.offset(-rtree_bounds.fLeft, -rtree_bounds.fTop);
65 canvas.DrawImageRect(image_, device_rect, device_rect,
67 }
68 }
69}
70
71RasterCache::RasterCache(size_t access_threshold,
72 size_t display_list_cache_limit_per_frame)
73 : access_threshold_(access_threshold),
74 display_list_cache_limit_per_frame_(display_list_cache_limit_per_frame) {}
75
76/// @note Procedure doesn't copy all closures.
77std::unique_ptr<RasterCacheResult> RasterCache::Rasterize(
78 const RasterCache::Context& context,
80 const std::function<void(DlCanvas*)>& draw_function,
81 const std::function<void(DlCanvas*, const SkRect& rect)>& draw_checkerboard)
82 const {
83 auto matrix = RasterCacheUtil::GetIntegralTransCTM(context.matrix);
84 SkRect dest_rect =
86
87 const SkImageInfo image_info = SkImageInfo::MakeN32Premul(
88 dest_rect.width(), dest_rect.height(), context.dst_color_space);
89
91 context.gr_context
93 image_info)
94 : SkSurfaces::Raster(image_info);
95
96 if (!surface) {
97 return nullptr;
98 }
99
100 DlSkCanvasAdapter canvas(surface->getCanvas());
102
103 canvas.Translate(-dest_rect.left(), -dest_rect.top());
104 canvas.Transform(matrix);
105 draw_function(&canvas);
106
107 if (checkerboard_images_) {
108 draw_checkerboard(&canvas, context.logical_rect);
109 }
110
111 auto image = DlImage::Make(surface->makeImageSnapshot());
112 return std::make_unique<RasterCacheResult>(
113 image, context.logical_rect, context.flow_type, std::move(rtree));
114}
115
117 const RasterCacheKeyID& id,
118 const Context& raster_cache_context,
119 const std::function<void(DlCanvas*)>& render_function,
120 sk_sp<const DlRTree> rtree) const {
121 RasterCacheKey key = RasterCacheKey(id, raster_cache_context.matrix);
122 Entry& entry = cache_[key];
123 if (!entry.image) {
124 void (*func)(DlCanvas*, const SkRect& rect) = DrawCheckerboard;
125 entry.image = Rasterize(raster_cache_context, std::move(rtree),
126 render_function, func);
127 if (entry.image != nullptr) {
128 switch (id.type()) {
130 display_list_cached_this_frame_++;
131 break;
132 }
133 default:
134 break;
135 }
136 return true;
137 }
138 }
139 return entry.image != nullptr;
140}
141
143 const SkMatrix& matrix,
144 bool visible) const {
145 RasterCacheKey key = RasterCacheKey(id, matrix);
146 Entry& entry = cache_[key];
147 entry.encountered_this_frame = true;
148 entry.visible_this_frame = visible;
149 if (visible || entry.accesses_since_visible > 0) {
150 entry.accesses_since_visible++;
151 }
152 return {entry.accesses_since_visible, entry.image != nullptr};
153}
154
156 const SkMatrix& matrix) const {
157 RasterCacheKey key = RasterCacheKey(id, matrix);
158 auto entry = cache_.find(key);
159 if (entry != cache_.cend()) {
160 return entry->second.accesses_since_visible;
161 }
162 return -1;
163}
164
166 const SkMatrix& matrix) const {
167 RasterCacheKey key = RasterCacheKey(id, matrix);
168 if (cache_.find(key) != cache_.cend()) {
169 return true;
170 }
171 return false;
172}
173
175 DlCanvas& canvas,
176 const DlPaint* paint,
177 bool preserve_rtree) const {
178 auto it = cache_.find(RasterCacheKey(id, canvas.GetTransform()));
179 if (it == cache_.end()) {
180 return false;
181 }
182
183 Entry& entry = it->second;
184
185 if (entry.image) {
186 entry.image->draw(canvas, paint, preserve_rtree);
187 return true;
188 }
189
190 return false;
191}
192
194 display_list_cached_this_frame_ = 0;
195 picture_metrics_ = {};
196 layer_metrics_ = {};
197}
198
199void RasterCache::UpdateMetrics() {
200 for (auto it = cache_.begin(); it != cache_.end(); ++it) {
201 Entry& entry = it->second;
202 FML_DCHECK(entry.encountered_this_frame);
203 if (entry.image) {
204 RasterCacheMetrics& metrics = GetMetricsForKind(it->first.kind());
205 metrics.in_use_count++;
206 metrics.in_use_bytes += entry.image->image_bytes();
207 }
208 entry.encountered_this_frame = false;
209 }
210}
211
213 std::vector<RasterCacheKey::Map<Entry>::iterator> dead;
214
215 for (auto it = cache_.begin(); it != cache_.end(); ++it) {
216 Entry& entry = it->second;
217 if (!entry.encountered_this_frame) {
218 dead.push_back(it);
219 }
220 }
221
222 for (auto it : dead) {
223 if (it->second.image) {
224 RasterCacheMetrics& metrics = GetMetricsForKind(it->first.kind());
225 metrics.eviction_count++;
226 metrics.eviction_bytes += it->second.image->image_bytes();
227 }
228 cache_.erase(it);
229 }
230}
231
233 UpdateMetrics();
234 TraceStatsToTimeline();
235}
236
238 cache_.clear();
239 picture_metrics_ = {};
240 layer_metrics_ = {};
241}
242
244 return cache_.size();
245}
246
248 size_t layer_cached_entries_count = 0;
249 for (const auto& item : cache_) {
250 if (item.first.kind() == RasterCacheKeyKind::kLayerMetrics) {
251 layer_cached_entries_count++;
252 }
253 }
254 return layer_cached_entries_count;
255}
256
258 size_t display_list_cached_entries_count = 0;
259 for (const auto& item : cache_) {
260 if (item.first.kind() == RasterCacheKeyKind::kDisplayListMetrics) {
261 display_list_cached_entries_count++;
262 }
263 }
264 return display_list_cached_entries_count;
265}
266
268 if (checkerboard_images_ == checkerboard) {
269 return;
270 }
271
272 checkerboard_images_ = checkerboard;
273
274 // Clear all existing entries so previously rasterized items (with or without
275 // a checkerboard) will be refreshed in subsequent passes.
276 Clear();
277}
278
279void RasterCache::TraceStatsToTimeline() const {
280#if !FLUTTER_RELEASE
282 "flutter", //
283 "RasterCache", reinterpret_cast<int64_t>(this), //
284 "LayerCount", layer_metrics_.total_count(), //
285 "LayerMBytes", layer_metrics_.total_bytes() / kMegaByteSizeInBytes, //
286 "PictureCount", picture_metrics_.total_count(), //
287 "PictureMBytes", picture_metrics_.total_bytes() / kMegaByteSizeInBytes);
288
289#endif // !FLUTTER_RELEASE
290}
291
293 size_t layer_cache_bytes = 0;
294 for (const auto& item : cache_) {
295 if (item.first.kind() == RasterCacheKeyKind::kLayerMetrics &&
296 item.second.image) {
297 layer_cache_bytes += item.second.image->image_bytes();
298 }
299 }
300 return layer_cache_bytes;
301}
302
304 size_t picture_cache_bytes = 0;
305 for (const auto& item : cache_) {
306 if (item.first.kind() == RasterCacheKeyKind::kDisplayListMetrics &&
307 item.second.image) {
308 picture_cache_bytes += item.second.image->image_bytes();
309 }
310 }
311 return picture_cache_bytes;
312}
313
314RasterCacheMetrics& RasterCache::GetMetricsForKind(RasterCacheKeyKind kind) {
315 switch (kind) {
317 return picture_metrics_;
319 return layer_metrics_;
320 }
321}
322
323} // namespace flutter
Developer-facing API for rendering anything within the engine.
Definition dl_canvas.h:37
virtual void TransformReset()=0
virtual void Translate(SkScalar tx, SkScalar ty)=0
void Clear(DlColor color)
Definition dl_canvas.h:131
virtual void DrawImageRect(const sk_sp< DlImage > &image, const SkRect &src, const SkRect &dst, DlImageSampling sampling, const DlPaint *paint=nullptr, SrcRectConstraint constraint=SrcRectConstraint::kFast)=0
virtual SkMatrix GetTransform() const =0
virtual void DrawImage(const sk_sp< DlImage > &image, const SkPoint point, DlImageSampling sampling, const DlPaint *paint=nullptr)=0
static sk_sp< DlImage > Make(const SkImage *image)
Definition dl_image.cc:11
Backend implementation of |DlCanvas| for |SkCanvas|.
void Transform(const SkMatrix *matrix) override
void Translate(SkScalar tx, SkScalar ty) override
RasterCacheResult(sk_sp< DlImage > image, const SkRect &logical_rect, const char *type, sk_sp< const DlRTree > rtree=nullptr)
virtual void draw(DlCanvas &canvas, const DlPaint *paint, bool preserve_rtree) const
bool Draw(const RasterCacheKeyID &id, DlCanvas &canvas, const DlPaint *paint, bool preserve_rtree=false) const
void SetCheckboardCacheImages(bool checkerboard)
CacheInfo MarkSeen(const RasterCacheKeyID &id, const SkMatrix &matrix, bool visible) const
The entry whose RasterCacheKey is generated by RasterCacheKeyID and matrix is marked as encountered b...
size_t EstimatePictureCacheByteSize() const
Estimate how much memory is used by picture raster cache entries in bytes.
bool HasEntry(const RasterCacheKeyID &id, const SkMatrix &) 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
RasterCache(size_t access_threshold=3, size_t picture_and_display_list_cache_limit_per_frame=RasterCacheUtil::kDefaultPictureAndDisplayListCacheLimitPerFrame)
int GetAccessCount(const RasterCacheKeyID &id, const SkMatrix &matrix) const
size_t GetCachedEntriesCount() const
size_t GetPictureCachedEntriesCount() const
size_t EstimateLayerCacheByteSize() const
Estimate how much memory is used by layer raster cache entries in bytes.
size_t GetLayerCachedEntriesCount() const
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
void Step(const char *label=nullptr) const
const Paint & paint
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
#define FML_DCHECK(condition)
Definition logging.h:103
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
constexpr double kMegaByteSizeInBytes
Definition constants.h:9
void DrawCheckerboard(DlCanvas *canvas, const SkRect &rect)
Definition ref_ptr.h:256
static SkImageInfo MakeN32Premul(int width, int height)
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
constexpr float left() const
Definition SkRect.h:734
constexpr float top() const
Definition SkRect.h:741
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
void offset(float dx, float dy)
Definition SkRect.h:1016
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15
static constexpr DlColor kTransparent()
Definition dl_color.h:21
static SkMatrix GetIntegralTransCTM(const SkMatrix &ctm)
Snap the translation components of the matrix to integers.
static SkRect GetRoundedOutDeviceBounds(const SkRect &rect, const SkMatrix &ctm)
const sk_sp< SkColorSpace > dst_color_space
#define FML_TRACE_COUNTER(category_group, name, counter_id, arg1,...)
Definition trace_event.h:85
static void checkerboard(SkCanvas *canvas, SkColor c1, SkColor c2, int size)