• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/flow/instrumentation.h"
12 #include "flutter/flow/raster_cache_key.h"
13 #include "flutter/fml/macros.h"
14 #include "flutter/fml/memory/weak_ptr.h"
15 #include "third_party/skia/include/core/SkImage.h"
16 #include "third_party/skia/include/core/SkSize.h"
17 
18 namespace flutter {
19 
20 class RasterCacheResult {
21  public:
22   RasterCacheResult();
23 
24   RasterCacheResult(const RasterCacheResult& other);
25 
26   ~RasterCacheResult();
27 
28   RasterCacheResult(sk_sp<SkImage> image, const SkRect& logical_rect);
29 
30   operator bool() const { return static_cast<bool>(image_); }
31 
is_valid()32   bool is_valid() const { return static_cast<bool>(image_); };
33 
34   void draw(SkCanvas& canvas, const SkPaint* paint = nullptr) const;
35 
image_dimensions()36   SkISize image_dimensions() const {
37     return image_ ? image_->dimensions() : SkISize::Make(0, 0);
38   };
39 
40  private:
41   sk_sp<SkImage> image_;
42   SkRect logical_rect_;
43 };
44 
45 struct PrerollContext;
46 
47 class RasterCache {
48  public:
49   // The default max number of picture raster caches to be generated per frame.
50   // Generating too many caches in one frame may cause jank on that frame. This
51   // limit allows us to throttle the cache and distribute the work across
52   // multiple frames.
53   static constexpr int kDefaultPictureCacheLimitPerFrame = 3;
54 
55   explicit RasterCache(
56       size_t access_threshold = 3,
57       size_t picture_cache_limit_per_frame = kDefaultPictureCacheLimitPerFrame);
58 
59   ~RasterCache();
60 
GetDeviceBounds(const SkRect & rect,const SkMatrix & ctm)61   static SkIRect GetDeviceBounds(const SkRect& rect, const SkMatrix& ctm) {
62     SkRect device_rect;
63     ctm.mapRect(&device_rect, rect);
64     SkIRect bounds;
65     device_rect.roundOut(&bounds);
66     return bounds;
67   }
68 
GetIntegralTransCTM(const SkMatrix & ctm)69   static SkMatrix GetIntegralTransCTM(const SkMatrix& ctm) {
70     SkMatrix result = ctm;
71     result[SkMatrix::kMTransX] = SkScalarRoundToScalar(ctm.getTranslateX());
72     result[SkMatrix::kMTransY] = SkScalarRoundToScalar(ctm.getTranslateY());
73     return result;
74   }
75 
76   // Return true if the cache is generated.
77   //
78   // We may return false and not generate the cache if
79   // 1. The picture is not worth rasterizing
80   // 2. The matrix is singular
81   // 3. The picture is accessed too few times
82   // 4. There are too many pictures to be cached in the current frame.
83   //    (See also kDefaultPictureCacheLimitPerFrame.)
84   bool Prepare(GrContext* context,
85                SkPicture* picture,
86                const SkMatrix& transformation_matrix,
87                SkColorSpace* dst_color_space,
88                bool is_complex,
89                bool will_change);
90 
91   void Prepare(PrerollContext* context, Layer* layer, const SkMatrix& ctm);
92 
93   RasterCacheResult Get(const SkPicture& picture, const SkMatrix& ctm) const;
94 
95   RasterCacheResult Get(Layer* layer, const SkMatrix& ctm) const;
96 
97   void SweepAfterFrame();
98 
99   void Clear();
100 
101   void SetCheckboardCacheImages(bool checkerboard);
102 
103  private:
104   struct Entry {
105     bool used_this_frame = false;
106     size_t access_count = 0;
107     RasterCacheResult image;
108   };
109 
110   template <class Cache, class Iterator>
SweepOneCacheAfterFrame(Cache & cache)111   static void SweepOneCacheAfterFrame(Cache& cache) {
112     std::vector<Iterator> dead;
113 
114     for (auto it = cache.begin(); it != cache.end(); ++it) {
115       Entry& entry = it->second;
116       if (!entry.used_this_frame) {
117         dead.push_back(it);
118       }
119       entry.used_this_frame = false;
120     }
121 
122     for (auto it : dead) {
123       cache.erase(it);
124     }
125   }
126 
127   const size_t access_threshold_;
128   const size_t picture_cache_limit_per_frame_;
129   size_t picture_cached_this_frame_ = 0;
130   PictureRasterCacheKey::Map<Entry> picture_cache_;
131   LayerRasterCacheKey::Map<Entry> layer_cache_;
132   bool checkerboard_images_;
133   fml::WeakPtrFactory<RasterCache> weak_factory_;
134 
135   void TraceStatsToTimeline() const;
136 
137   FML_DISALLOW_COPY_AND_ASSIGN(RasterCache);
138 };
139 
140 }  // namespace flutter
141 
142 #endif  // FLUTTER_FLOW_RASTER_CACHE_H_
143