OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium 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 CC_TILES_SOFTWARE_IMAGE_DECODE_CONTROLLER_H_ | |
6 #define CC_TILES_SOFTWARE_IMAGE_DECODE_CONTROLLER_H_ | |
7 | |
8 #include <stdint.h> | |
9 | |
10 #include <memory> | |
11 #include <unordered_map> | |
12 #include <unordered_set> | |
13 | |
14 #include "base/atomic_sequence_num.h" | |
15 #include "base/containers/mru_cache.h" | |
16 #include "base/hash.h" | |
17 #include "base/memory/discardable_memory_allocator.h" | |
18 #include "base/memory/memory_coordinator_client.h" | |
19 #include "base/memory/ref_counted.h" | |
20 #include "base/numerics/safe_math.h" | |
21 #include "base/threading/thread_checker.h" | |
22 #include "base/trace_event/memory_dump_provider.h" | |
23 #include "cc/base/cc_export.h" | |
24 #include "cc/playback/decoded_draw_image.h" | |
25 #include "cc/playback/draw_image.h" | |
26 #include "cc/resources/resource_format.h" | |
27 #include "cc/tiles/image_decode_controller.h" | |
28 #include "third_party/skia/include/core/SkRefCnt.h" | |
29 #include "ui/gfx/geometry/rect.h" | |
30 | |
31 namespace cc { | |
32 | |
33 // ImageDecodeControllerKey is a class that gets a cache key out of a given draw | |
34 // image. That is, this key uniquely identifies an image in the cache. Note that | |
35 // it's insufficient to use SkImage's unique id, since the same image can appear | |
36 // in the cache multiple times at different scales and filter qualities. | |
37 class CC_EXPORT ImageDecodeControllerKey { | |
38 public: | |
39 static ImageDecodeControllerKey FromDrawImage(const DrawImage& image); | |
40 | |
41 ImageDecodeControllerKey(const ImageDecodeControllerKey& other); | |
42 | |
43 bool operator==(const ImageDecodeControllerKey& other) const { | |
44 // The image_id always has to be the same. However, after that all original | |
45 // decodes are the same, so if we can use the original decode, return true. | |
46 // If not, then we have to compare every field. | |
47 return image_id_ == other.image_id_ && | |
48 can_use_original_decode_ == other.can_use_original_decode_ && | |
49 (can_use_original_decode_ || | |
50 (src_rect_ == other.src_rect_ && | |
51 target_size_ == other.target_size_ && | |
52 filter_quality_ == other.filter_quality_)); | |
53 } | |
54 | |
55 bool operator!=(const ImageDecodeControllerKey& other) const { | |
56 return !(*this == other); | |
57 } | |
58 | |
59 uint32_t image_id() const { return image_id_; } | |
60 SkFilterQuality filter_quality() const { return filter_quality_; } | |
61 gfx::Rect src_rect() const { return src_rect_; } | |
62 gfx::Size target_size() const { return target_size_; } | |
63 | |
64 bool can_use_original_decode() const { return can_use_original_decode_; } | |
65 bool should_use_subrect() const { return should_use_subrect_; } | |
66 size_t get_hash() const { return hash_; } | |
67 | |
68 // Helper to figure out how much memory the locked image represented by this | |
69 // key would take. | |
70 size_t locked_bytes() const { | |
71 // TODO(vmpstr): Handle formats other than RGBA. | |
72 base::CheckedNumeric<size_t> result = 4; | |
73 result *= target_size_.width(); | |
74 result *= target_size_.height(); | |
75 return result.ValueOrDefault(std::numeric_limits<size_t>::max()); | |
76 } | |
77 | |
78 std::string ToString() const; | |
79 | |
80 private: | |
81 ImageDecodeControllerKey(uint32_t image_id, | |
82 const gfx::Rect& src_rect, | |
83 const gfx::Size& size, | |
84 SkFilterQuality filter_quality, | |
85 bool can_use_original_decode, | |
86 bool should_use_subrect); | |
87 | |
88 uint32_t image_id_; | |
89 gfx::Rect src_rect_; | |
90 gfx::Size target_size_; | |
91 SkFilterQuality filter_quality_; | |
92 bool can_use_original_decode_; | |
93 bool should_use_subrect_; | |
94 size_t hash_; | |
95 }; | |
96 | |
97 // Hash function for the above ImageDecodeControllerKey. | |
98 struct ImageDecodeControllerKeyHash { | |
99 size_t operator()(const ImageDecodeControllerKey& key) const { | |
100 return key.get_hash(); | |
101 } | |
102 }; | |
103 | |
104 class CC_EXPORT SoftwareImageDecodeController | |
105 : public ImageDecodeController, | |
106 public base::trace_event::MemoryDumpProvider, | |
107 public base::MemoryCoordinatorClient { | |
108 public: | |
109 using ImageKey = ImageDecodeControllerKey; | |
110 using ImageKeyHash = ImageDecodeControllerKeyHash; | |
111 | |
112 SoftwareImageDecodeController(ResourceFormat format, | |
113 size_t locked_memory_limit_bytes); | |
114 ~SoftwareImageDecodeController() override; | |
115 | |
116 // ImageDecodeController overrides. | |
117 bool GetTaskForImageAndRef(const DrawImage& image, | |
118 const TracingInfo& tracing_info, | |
119 scoped_refptr<TileTask>* task) override; | |
120 void UnrefImage(const DrawImage& image) override; | |
121 DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override; | |
122 void DrawWithImageFinished(const DrawImage& image, | |
123 const DecodedDrawImage& decoded_image) override; | |
124 void ReduceCacheUsage() override; | |
125 // Software doesn't keep outstanding images pinned, so this is a no-op. | |
126 void SetShouldAggressivelyFreeResources( | |
127 bool aggressively_free_resources) override {} | |
128 | |
129 // Decode the given image and store it in the cache. This is only called by an | |
130 // image decode task from a worker thread. | |
131 void DecodeImage(const ImageKey& key, const DrawImage& image); | |
132 | |
133 void RemovePendingTask(const ImageKey& key); | |
134 | |
135 // MemoryDumpProvider overrides. | |
136 bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, | |
137 base::trace_event::ProcessMemoryDump* pmd) override; | |
138 | |
139 private: | |
140 // DecodedImage is a convenience storage for discardable memory. It can also | |
141 // construct an image out of SkImageInfo and stored discardable memory. | |
142 class DecodedImage { | |
143 public: | |
144 DecodedImage(const SkImageInfo& info, | |
145 std::unique_ptr<base::DiscardableMemory> memory, | |
146 const SkSize& src_rect_offset, | |
147 uint64_t tracing_id); | |
148 ~DecodedImage(); | |
149 | |
150 const sk_sp<SkImage>& image() const { | |
151 DCHECK(locked_); | |
152 return image_; | |
153 } | |
154 | |
155 const SkSize& src_rect_offset() const { return src_rect_offset_; } | |
156 | |
157 bool is_locked() const { return locked_; } | |
158 bool Lock(); | |
159 void Unlock(); | |
160 | |
161 const base::DiscardableMemory* memory() const { return memory_.get(); } | |
162 | |
163 // An ID which uniquely identifies this DecodedImage within the image decode | |
164 // controller. Used in memory tracing. | |
165 uint64_t tracing_id() const { return tracing_id_; } | |
166 // Mark this image as being used in either a draw or as a source for a | |
167 // scaled image. Either case represents this decode as being valuable and | |
168 // not wasted. | |
169 void mark_used() { usage_stats_.used = true; } | |
170 | |
171 private: | |
172 struct UsageStats { | |
173 // We can only create a decoded image in a locked state, so the initial | |
174 // lock count is 1. | |
175 int lock_count = 1; | |
176 bool used = false; | |
177 bool last_lock_failed = false; | |
178 bool first_lock_wasted = false; | |
179 }; | |
180 | |
181 bool locked_; | |
182 SkImageInfo image_info_; | |
183 std::unique_ptr<base::DiscardableMemory> memory_; | |
184 sk_sp<SkImage> image_; | |
185 SkSize src_rect_offset_; | |
186 uint64_t tracing_id_; | |
187 UsageStats usage_stats_; | |
188 }; | |
189 | |
190 // MemoryBudget is a convenience class for memory bookkeeping and ensuring | |
191 // that we don't go over the limit when pre-decoding. | |
192 class MemoryBudget { | |
193 public: | |
194 explicit MemoryBudget(size_t limit_bytes); | |
195 | |
196 size_t AvailableMemoryBytes() const; | |
197 void AddUsage(size_t usage); | |
198 void SubtractUsage(size_t usage); | |
199 void ResetUsage(); | |
200 size_t total_limit_bytes() const { return limit_bytes_; } | |
201 size_t GetCurrentUsageSafe() const; | |
202 | |
203 private: | |
204 size_t limit_bytes_; | |
205 base::CheckedNumeric<size_t> current_usage_bytes_; | |
206 }; | |
207 | |
208 using ImageMRUCache = base::HashingMRUCache<ImageKey, | |
209 std::unique_ptr<DecodedImage>, | |
210 ImageKeyHash>; | |
211 | |
212 // Looks for the key in the cache and returns true if it was found and was | |
213 // successfully locked (or if it was already locked). Note that if this | |
214 // function returns true, then a ref count is increased for the image. | |
215 bool LockDecodedImageIfPossibleAndRef(const ImageKey& key); | |
216 | |
217 // Actually decode the image. Note that this function can (and should) be | |
218 // called with no lock acquired, since it can do a lot of work. Note that it | |
219 // can also return nullptr to indicate the decode failed. | |
220 std::unique_ptr<DecodedImage> DecodeImageInternal( | |
221 const ImageKey& key, | |
222 const DrawImage& draw_image); | |
223 | |
224 // Get the decoded draw image for the given key and draw_image. Note that this | |
225 // function has to be called with no lock acquired, since it will acquire its | |
226 // own locks and might call DecodeImageInternal above. Also note that this | |
227 // function will use the provided key, even if | |
228 // ImageKey::FromDrawImage(draw_image) would return a different key. | |
229 // Note that when used internally, we still require that | |
230 // DrawWithImageFinished() is called afterwards. | |
231 DecodedDrawImage GetDecodedImageForDrawInternal(const ImageKey& key, | |
232 const DrawImage& draw_image); | |
233 | |
234 // GetOriginalImageDecode is called by DecodeImageInternal when the quality | |
235 // does not scale the image. Like DecodeImageInternal, it should be called | |
236 // with no lock acquired and it returns nullptr if the decoding failed. | |
237 std::unique_ptr<DecodedImage> GetOriginalImageDecode( | |
238 sk_sp<const SkImage> image); | |
239 | |
240 // GetSubrectImageDecode is similar to GetOriginalImageDecode in that no scale | |
241 // is performed on the image. However, we extract a subrect (copy it out) and | |
242 // only return this subrect in order to cache a smaller amount of memory. Note | |
243 // that this uses GetOriginalImageDecode to get the initial data, which | |
244 // ensures that we cache an unlocked version of the original image in case we | |
245 // need to extract multiple subrects (as would be the case in an atlas). | |
246 std::unique_ptr<DecodedImage> GetSubrectImageDecode( | |
247 const ImageKey& key, | |
248 sk_sp<const SkImage> image); | |
249 | |
250 // GetScaledImageDecode is called by DecodeImageInternal when the quality | |
251 // requires the image be scaled. Like DecodeImageInternal, it should be | |
252 // called with no lock acquired and it returns nullptr if the decoding or | |
253 // scaling failed. | |
254 std::unique_ptr<DecodedImage> GetScaledImageDecode( | |
255 const ImageKey& key, | |
256 sk_sp<const SkImage> image); | |
257 | |
258 void SanityCheckState(int line, bool lock_acquired); | |
259 void RefImage(const ImageKey& key); | |
260 void RefAtRasterImage(const ImageKey& key); | |
261 void UnrefAtRasterImage(const ImageKey& key); | |
262 | |
263 // Helper function which dumps all images in a specific ImageMRUCache. | |
264 void DumpImageMemoryForCache(const ImageMRUCache& cache, | |
265 const char* cache_name, | |
266 base::trace_event::ProcessMemoryDump* pmd) const; | |
267 | |
268 // Overriden from base::MemoryCoordinatorClient. | |
269 void OnMemoryStateChange(base::MemoryState state) override; | |
270 | |
271 std::unordered_map<ImageKey, scoped_refptr<TileTask>, ImageKeyHash> | |
272 pending_image_tasks_; | |
273 | |
274 // The members below this comment can only be accessed if the lock is held to | |
275 // ensure that they are safe to access on multiple threads. | |
276 base::Lock lock_; | |
277 | |
278 // Decoded images and ref counts (predecode path). | |
279 ImageMRUCache decoded_images_; | |
280 std::unordered_map<ImageKey, int, ImageKeyHash> decoded_images_ref_counts_; | |
281 | |
282 // Decoded image and ref counts (at-raster decode path). | |
283 ImageMRUCache at_raster_decoded_images_; | |
284 std::unordered_map<ImageKey, int, ImageKeyHash> | |
285 at_raster_decoded_images_ref_counts_; | |
286 | |
287 MemoryBudget locked_images_budget_; | |
288 | |
289 ResourceFormat format_; | |
290 size_t max_items_in_cache_; | |
291 | |
292 // Used to uniquely identify DecodedImages for memory traces. | |
293 base::AtomicSequenceNumber next_tracing_id_; | |
294 }; | |
295 | |
296 } // namespace cc | |
297 | |
298 #endif // CC_TILES_SOFTWARE_IMAGE_DECODE_CONTROLLER_H_ | |
OLD | NEW |