forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
raster_cache.h
260 lines (218 loc) · 8.42 KB
/
raster_cache.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
// 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/flow/display_list.h"
#include "flutter/flow/raster_cache_key.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSize.h"
namespace flutter {
class RasterCacheResult {
public:
RasterCacheResult(sk_sp<SkImage> image, const SkRect& logical_rect);
virtual ~RasterCacheResult() = default;
virtual void draw(SkCanvas& canvas, const SkPaint* paint) const;
virtual SkISize image_dimensions() const {
return image_ ? image_->dimensions() : SkISize::Make(0, 0);
};
virtual int64_t image_bytes() const {
return image_ ? image_->imageInfo().computeMinByteSize() : 0;
};
private:
sk_sp<SkImage> image_;
SkRect logical_rect_;
};
struct PrerollContext;
class RasterCache {
public:
// The default max number of picture raster caches to be generated per frame.
// Generating too many caches in one frame may cause jank on that frame. This
// limit allows us to throttle the cache and distribute the work across
// multiple frames.
static constexpr int kDefaultPictureCacheLimitPerFrame = 3;
explicit RasterCache(
size_t access_threshold = 3,
size_t picture_cache_limit_per_frame = kDefaultPictureCacheLimitPerFrame);
virtual ~RasterCache() = default;
/**
* @brief Rasterize a picture object and produce a RasterCacheResult
* to be stored in the cache.
*
* @param picture the SkPicture object to be cached.
* @param context the GrDirectContext used for rendering.
* @param ctm the transformation matrix used for rendering.
* @param dst_color_space the destination color space that the cached
* rendering will be drawn into
* @param checkerboard a flag indicating whether or not a checkerboard
* pattern should be rendered into the cached image for debug
* analysis
* @return a RasterCacheResult that can draw the rendered picture into
* the destination using a simple image blit
*/
virtual std::unique_ptr<RasterCacheResult> RasterizePicture(
SkPicture* picture,
GrDirectContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard) const;
virtual std::unique_ptr<RasterCacheResult> RasterizeDisplayList(
DisplayList* display_list,
GrDirectContext* context,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool checkerboard) const;
/**
* @brief Rasterize an engine Layer and produce a RasterCacheResult
* to be stored in the cache.
*
* @param context the PrerollContext containing important information
* needed for rendering a layer.
* @param layer the Layer object to be cached.
* @param ctm the transformation matrix used for rendering.
* @param checkerboard a flag indicating whether or not a checkerboard
* pattern should be rendered into the cached image for debug
* analysis
* @return a RasterCacheResult that can draw the rendered layer into
* the destination using a simple image blit
*/
virtual std::unique_ptr<RasterCacheResult> RasterizeLayer(
PrerollContext* context,
Layer* layer,
const SkMatrix& ctm,
bool checkerboard) const;
static SkIRect GetDeviceBounds(const SkRect& rect, const SkMatrix& ctm) {
SkRect device_rect;
ctm.mapRect(&device_rect, rect);
SkIRect bounds;
device_rect.roundOut(&bounds);
return bounds;
}
/**
* @brief Snap the translation components of the matrix to integers.
*
* The snapping will only happen if the matrix only has scale and translation
* transformations.
*
* @param ctm the current transformation matrix.
* @return SkMatrix the snapped transformation matrix.
*/
static SkMatrix GetIntegralTransCTM(const SkMatrix& ctm) {
// Avoid integral snapping if the matrix has complex transformation to avoid
// the artifact observed in https://github.com/flutter/flutter/issues/41654.
if (!ctm.isScaleTranslate()) {
return ctm;
}
SkMatrix result = ctm;
result[SkMatrix::kMTransX] = SkScalarRoundToScalar(ctm.getTranslateX());
result[SkMatrix::kMTransY] = SkScalarRoundToScalar(ctm.getTranslateY());
return result;
}
// Return true if the cache is generated.
//
// We may return false and not generate the cache if
// 1. The picture is not worth rasterizing
// 2. The matrix is singular
// 3. The picture is accessed too few times
// 4. There are too many pictures to be cached in the current frame.
// (See also kDefaultPictureCacheLimitPerFrame.)
bool Prepare(GrDirectContext* context,
SkPicture* picture,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change);
bool Prepare(GrDirectContext* context,
DisplayList* display_list,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change);
void Prepare(PrerollContext* context, Layer* layer, const SkMatrix& ctm);
// Find the raster cache for the picture and draw it to the canvas.
//
// Return true if it's found and drawn.
bool Draw(const SkPicture& picture, SkCanvas& canvas) const;
// Find the raster cache for the display list and draw it to the canvas.
//
// Return true if it's found and drawn.
bool Draw(const DisplayList& display_list, SkCanvas& canvas) const;
// Find the raster cache for the layer and draw it to the canvas.
//
// Additional paint can be given to change how the raster cache is drawn
// (e.g., draw the raster cache with some opacity).
//
// Return true if the layer raster cache is found and drawn.
bool Draw(const Layer* layer,
SkCanvas& canvas,
SkPaint* paint = nullptr) const;
void SweepAfterFrame();
void Clear();
void SetCheckboardCacheImages(bool checkerboard);
size_t GetCachedEntriesCount() const;
size_t GetLayerCachedEntriesCount() const;
size_t GetPictureCachedEntriesCount() const;
size_t GetDisplayListCachedEntriesCount() 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 display list 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 EstimateDisplayListCacheByteSize() 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;
private:
struct Entry {
bool used_this_frame = false;
size_t access_count = 0;
std::unique_ptr<RasterCacheResult> image;
};
template <class Cache>
static void SweepOneCacheAfterFrame(Cache& cache) {
std::vector<typename Cache::iterator> dead;
for (auto it = cache.begin(); it != cache.end(); ++it) {
Entry& entry = it->second;
if (!entry.used_this_frame) {
dead.push_back(it);
}
entry.used_this_frame = false;
}
for (auto it : dead) {
cache.erase(it);
}
}
const size_t access_threshold_;
const size_t picture_cache_limit_per_frame_;
size_t picture_cached_this_frame_ = 0;
mutable PictureRasterCacheKey::Map<Entry> picture_cache_;
mutable DisplayListRasterCacheKey::Map<Entry> display_list_cache_;
mutable LayerRasterCacheKey::Map<Entry> layer_cache_;
bool checkerboard_images_;
void TraceStatsToTimeline() const;
FML_DISALLOW_COPY_AND_ASSIGN(RasterCache);
};
} // namespace flutter
#endif // FLUTTER_FLOW_RASTER_CACHE_H_