OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ | 5 #ifndef CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ |
6 #define CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ | 6 #define CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ |
7 | 7 |
8 #include <memory> | 8 #include <memory> |
9 #include <unordered_map> | 9 #include <unordered_map> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/containers/mru_cache.h" | 12 #include "base/containers/mru_cache.h" |
13 #include "base/memory/discardable_memory.h" | 13 #include "base/memory/discardable_memory.h" |
14 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
15 #include "base/trace_event/memory_dump_provider.h" | 15 #include "base/trace_event/memory_dump_provider.h" |
16 #include "cc/base/cc_export.h" | 16 #include "cc/base/cc_export.h" |
17 #include "cc/resources/resource_format.h" | 17 #include "cc/resources/resource_format.h" |
18 #include "cc/tiles/image_decode_controller.h" | 18 #include "cc/tiles/image_decode_controller.h" |
19 #include "third_party/skia/include/core/SkRefCnt.h" | 19 #include "third_party/skia/include/core/SkRefCnt.h" |
20 | 20 |
21 class SkImageTextureData; | 21 class SkImageTextureData; |
22 | 22 |
23 namespace cc { | 23 namespace cc { |
24 | 24 |
25 class ContextProvider; | 25 class ContextProvider; |
26 | 26 |
27 // OVERVIEW: | |
28 // | |
29 // GpuImageDecodeController handles the decode and upload of images that will | 27 // GpuImageDecodeController handles the decode and upload of images that will |
30 // be used by Skia's GPU raster path. It also maintains a cache of these | 28 // be used by Skia's GPU raster path. It also maintains a cache of these |
31 // decoded/uploaded images for later re-use. | 29 // decoded/uploaded images for later re-use. |
32 // | 30 // |
33 // Generally, when an image is required for raster, GpuImageDecodeController | 31 // Generally, when an image is required for raster, GpuImageDecodeController |
34 // creates two tasks, one to decode the image, and one to upload the image to | 32 // creates two tasks, one to decode the image, and one to upload the image to |
35 // the GPU. These tasks are completed before the raster task which depends on | 33 // the GPU. These tasks are completed before the raster task which depends on |
36 // the image. We need to seperate decode and upload tasks, as decode can occur | 34 // the image. We need to seperate decode and upload tasks, as decode can occur |
37 // simultaneously on multiple threads, while upload requires the GL context | 35 // simultaneously on multiple threads, while upload requires the GL context |
38 // lock must happen on our non-concurrent raster thread. | 36 // lock must happen on our non-concurrent raster thread. |
39 // | 37 // |
40 // Decoded and Uploaded image data share a single cache entry. Depending on how | 38 // Decoded and Uploaded image data share a single cache entry. Depending on how |
41 // far we've progressed, this cache entry may contain CPU-side decoded data, | 39 // far we've progressed, this cache entry may contain CPU-side decoded data, |
42 // GPU-side uploaded data, or both. Because CPU-side decoded data is stored in | 40 // GPU-side uploaded data, or both. Because CPU-side decoded data is stored in |
43 // discardable memory, and is only locked for short periods of time (until the | 41 // discardable memory, and is only locked for short periods of time (until the |
44 // upload completes), this memory is not counted against our sized cache | 42 // upload completes), this memory is not counted against our sized cache |
45 // limits. Uploaded GPU memory, being non-discardable, always counts against | 43 // limits. Uploaded GPU memory, being non-discardable, always counts against |
46 // our limits. | 44 // our limits. |
47 // | 45 // |
48 // In cases where the number of images needed exceeds our cache limits, we | 46 // In cases where the number of images needed exceeds our cache limits, we |
49 // operate in an "at-raster" mode. In this mode, there are no decode/upload | 47 // operate in an "at-raster" mode. In this mode, there are no decode/upload |
50 // tasks, and images are decoded/uploaded as needed, immediately before being | 48 // tasks, and images are decoded/uploaded as needed, immediately before being |
51 // used in raster. Cache entries for at-raster tasks are marked as such, which | 49 // used in raster. Cache entries for at-raster tasks are marked as such, which |
52 // prevents future tasks from taking a dependency on them and extending their | 50 // prevents future tasks from taking a dependency on them and extending their |
53 // lifetime longer than is necessary. | 51 // lifetime longer than is necessary. |
54 // | |
55 // RASTER-SCALE CACHING: | |
56 // | |
57 // In order to save memory, images which are going to be scaled may be uploaded | |
58 // at lower than original resolution. In these cases, we may later need to | |
59 // re-upload the image at a higher resolution. To handle multiple images of | |
60 // different scales being in use at the same time, we have a two-part caching | |
61 // system. | |
62 // | |
63 // The first cache, |persistent_cache_|, stores one ImageData per image id. | |
64 // These ImageDatas are not necessarily associated with a given DrawImage, and | |
65 // are saved (persisted) even when their ref-count reaches zero (assuming they | |
66 // fit in the current memory budget). This allows for future re-use of image | |
67 // resources. | |
68 // | |
69 // The second cache, |in_use_cache_|, stores one image data per DrawImage - | |
70 // this may be the same ImageData that is in the persistent_cache_. These | |
71 // cache entries are more transient and are deleted as soon as all refs to the | |
72 // given DrawImage are released (the image is no longer in-use). | |
73 // | |
74 // For examples of raster-scale caching, see https://goo.gl/0zCd9Z | |
75 // | |
76 // REF COUNTING: | |
77 // | |
78 // In dealing with the two caches in GpuImageDecodeController, there are three | |
79 // ref-counting concepts in use: | |
80 // 1) ImageData upload/decode ref-counts. | |
81 // These ref-counts represent the overall number of references to the | |
82 // upload or decode portion of an ImageData. These ref-counts control | |
83 // both whether the upload/decode data can be freed, as well as whether an | |
84 // ImageData can be removed from the |persistent_cache_|. ImageDatas are | |
85 // only removed from the |persistent_cache_| if their upload/decode | |
86 // ref-counts are zero or if they are orphaned and replaced by a new entry. | |
87 // 2) InUseCacheEntry ref-counts. | |
88 // These ref-counts represent the number of references to an | |
89 // InUseCacheEntry from a specific DrawImage. When the InUseCacheEntry's | |
90 // ref-count reaches 0 it will be deleted. | |
91 // 3) scoped_refptr ref-counts. | |
92 // Because both the persistent_cache_ and the in_use_cache_ point at the | |
93 // same ImageDatas (and may need to keep these ImageDatas alive independent | |
94 // of each other), they hold ImageDatas by scoped_refptr. The scoped_refptr | |
95 // keeps an ImageData alive while it is present in either the | |
96 // |persistent_cache_| or |in_use_cache_|. | |
97 // | |
98 class CC_EXPORT GpuImageDecodeController | 52 class CC_EXPORT GpuImageDecodeController |
99 : public ImageDecodeController, | 53 : public ImageDecodeController, |
100 public base::trace_event::MemoryDumpProvider { | 54 public base::trace_event::MemoryDumpProvider { |
101 public: | 55 public: |
102 explicit GpuImageDecodeController(ContextProvider* context, | 56 explicit GpuImageDecodeController(ContextProvider* context, |
103 ResourceFormat decode_format, | 57 ResourceFormat decode_format, |
104 size_t max_gpu_image_bytes); | 58 size_t max_gpu_image_bytes); |
105 ~GpuImageDecodeController() override; | 59 ~GpuImageDecodeController() override; |
106 | 60 |
107 // ImageDecodeController overrides. | 61 // ImageDecodeController overrides. |
(...skipping 24 matching lines...) Expand all Loading... |
132 void OnImageUploadTaskCompleted(const DrawImage& image); | 86 void OnImageUploadTaskCompleted(const DrawImage& image); |
133 | 87 |
134 // For testing only. | 88 // For testing only. |
135 void SetCachedItemLimitForTesting(size_t limit) { | 89 void SetCachedItemLimitForTesting(size_t limit) { |
136 cached_items_limit_ = limit; | 90 cached_items_limit_ = limit; |
137 } | 91 } |
138 void SetCachedBytesLimitForTesting(size_t limit) { | 92 void SetCachedBytesLimitForTesting(size_t limit) { |
139 cached_bytes_limit_ = limit; | 93 cached_bytes_limit_ = limit; |
140 } | 94 } |
141 size_t GetBytesUsedForTesting() const { return bytes_used_; } | 95 size_t GetBytesUsedForTesting() const { return bytes_used_; } |
142 size_t GetDrawImageSizeForTesting(const DrawImage& image); | |
143 void SetImageDecodingFailedForTesting(const DrawImage& image); | 96 void SetImageDecodingFailedForTesting(const DrawImage& image); |
144 bool DiscardableIsLockedForTesting(const DrawImage& image); | 97 bool DiscardableIsLockedForTesting(const DrawImage& image); |
145 | 98 |
146 private: | 99 private: |
147 enum class DecodedDataMode { GPU, CPU }; | 100 enum class DecodedDataMode { GPU, CPU }; |
148 | 101 |
149 // Stores the CPU-side decoded bits of an image and supporting fields. | 102 // Stores the CPU-side decoded bits of an image and supporting fields. |
150 struct DecodedImageData { | 103 struct DecodedImageData { |
151 DecodedImageData(); | 104 DecodedImageData(); |
152 ~DecodedImageData(); | 105 ~DecodedImageData(); |
153 | 106 |
154 bool is_locked() const { return is_locked_; } | 107 bool is_locked() const { return is_locked_; } |
155 bool Lock(); | 108 bool Lock(); |
156 void Unlock(); | 109 void Unlock(); |
157 void SetLockedData(std::unique_ptr<base::DiscardableMemory> data); | 110 void SetLockedData(std::unique_ptr<base::DiscardableMemory> data); |
158 void ResetData(); | 111 void ResetData(); |
159 base::DiscardableMemory* data() const { return data_.get(); } | 112 base::DiscardableMemory* data() const { return data_.get(); } |
| 113 |
160 void mark_used() { usage_stats_.used = true; } | 114 void mark_used() { usage_stats_.used = true; } |
161 | 115 |
| 116 // May be null if image not yet decoded. |
162 uint32_t ref_count = 0; | 117 uint32_t ref_count = 0; |
163 // Set to true if the image was corrupt and could not be decoded. | 118 // Set to true if the image was corrupt and could not be decoded. |
164 bool decode_failure = false; | 119 bool decode_failure = false; |
165 // If non-null, this is the pending decode task for this image. | |
166 scoped_refptr<TileTask> task; | |
167 | 120 |
168 private: | 121 private: |
169 struct UsageStats { | 122 struct UsageStats { |
170 int lock_count = 1; | 123 int lock_count = 1; |
171 bool used = false; | 124 bool used = false; |
172 bool first_lock_wasted = false; | 125 bool first_lock_wasted = false; |
173 }; | 126 }; |
174 | 127 |
175 void ReportUsageStats() const; | 128 void ReportUsageStats() const; |
176 | 129 |
(...skipping 12 matching lines...) Expand all Loading... |
189 | 142 |
190 void mark_used() { usage_stats_.used = true; } | 143 void mark_used() { usage_stats_.used = true; } |
191 void notify_ref_reached_zero() { | 144 void notify_ref_reached_zero() { |
192 if (++usage_stats_.ref_reached_zero_count == 1) | 145 if (++usage_stats_.ref_reached_zero_count == 1) |
193 usage_stats_.first_ref_wasted = !usage_stats_.used; | 146 usage_stats_.first_ref_wasted = !usage_stats_.used; |
194 } | 147 } |
195 | 148 |
196 // True if the image is counting against our memory limits. | 149 // True if the image is counting against our memory limits. |
197 bool budgeted = false; | 150 bool budgeted = false; |
198 uint32_t ref_count = 0; | 151 uint32_t ref_count = 0; |
199 // If non-null, this is the pending upload task for this image. | |
200 scoped_refptr<TileTask> task; | |
201 | 152 |
202 private: | 153 private: |
203 struct UsageStats { | 154 struct UsageStats { |
204 bool used = false; | 155 bool used = false; |
205 bool first_ref_wasted = false; | 156 bool first_ref_wasted = false; |
206 int ref_reached_zero_count = 0; | 157 int ref_reached_zero_count = 0; |
207 }; | 158 }; |
208 | 159 |
209 void ReportUsageStats() const; | 160 void ReportUsageStats() const; |
210 | 161 |
211 // May be null if image not yet uploaded / prepared. | 162 // May be null if image not yet uploaded / prepared. |
212 sk_sp<SkImage> image_; | 163 sk_sp<SkImage> image_; |
213 UsageStats usage_stats_; | 164 UsageStats usage_stats_; |
214 }; | 165 }; |
215 | 166 |
216 struct ImageData : public base::RefCounted<ImageData> { | 167 struct ImageData { |
217 ImageData(DecodedDataMode mode, | 168 ImageData(DecodedDataMode mode, size_t size); |
218 size_t size, | 169 ~ImageData(); |
219 int upload_scale_mip_level, | |
220 SkFilterQuality upload_scale_filter_quality); | |
221 | 170 |
222 const DecodedDataMode mode; | 171 const DecodedDataMode mode; |
223 const size_t size; | 172 const size_t size; |
224 bool is_at_raster = false; | 173 bool is_at_raster = false; |
225 | 174 |
226 // Variables used to identify/track multiple scale levels of a single image. | |
227 int upload_scale_mip_level = 0; | |
228 SkFilterQuality upload_scale_filter_quality = kNone_SkFilterQuality; | |
229 // If true, this image is no longer in our |persistent_cache_| and will be | |
230 // deleted as soon as its ref count reaches zero. | |
231 bool is_orphaned = false; | |
232 | |
233 DecodedImageData decode; | 175 DecodedImageData decode; |
234 UploadedImageData upload; | 176 UploadedImageData upload; |
235 | |
236 private: | |
237 friend class base::RefCounted<ImageData>; | |
238 ~ImageData(); | |
239 }; | 177 }; |
240 | 178 |
241 // A ref-count and ImageData, used to associate the ImageData with a specific | 179 using ImageDataMRUCache = |
242 // DrawImage in the |in_use_cache_|. | 180 base::MRUCache<uint32_t, std::unique_ptr<ImageData>>; |
243 struct InUseCacheEntry { | |
244 explicit InUseCacheEntry(scoped_refptr<ImageData> image_data); | |
245 InUseCacheEntry(const InUseCacheEntry& other); | |
246 InUseCacheEntry(InUseCacheEntry&& other); | |
247 ~InUseCacheEntry(); | |
248 | |
249 uint32_t ref_count = 0; | |
250 scoped_refptr<ImageData> image_data; | |
251 }; | |
252 | |
253 // Uniquely identifies (without collisions) a specific DrawImage for use in | |
254 // the |in_use_cache_|. | |
255 using InUseCacheKey = uint64_t; | |
256 | 181 |
257 // All private functions should only be called while holding |lock_|. Some | 182 // All private functions should only be called while holding |lock_|. Some |
258 // functions also require the |context_| lock. These are indicated by | 183 // functions also require the |context_| lock. These are indicated by |
259 // additional comments. | 184 // additional comments. |
260 | 185 |
261 // Similar to GetTaskForImageAndRef, but gets the dependent decode task | 186 // Similar to GetTaskForImageAndRef, but gets the dependent decode task |
262 // rather than the upload task, if necessary. | 187 // rather than the upload task, if necessary. |
263 scoped_refptr<TileTask> GetImageDecodeTaskAndRef( | 188 scoped_refptr<TileTask> GetImageDecodeTaskAndRef( |
264 const DrawImage& image, | 189 const DrawImage& image, |
265 const TracingInfo& tracing_info); | 190 const TracingInfo& tracing_info); |
266 | 191 |
267 void RefImageDecode(const DrawImage& draw_image); | 192 void RefImageDecode(const DrawImage& draw_image); |
268 void UnrefImageDecode(const DrawImage& draw_image); | 193 void UnrefImageDecode(const DrawImage& draw_image); |
269 void RefImage(const DrawImage& draw_image); | 194 void RefImage(const DrawImage& draw_image); |
270 void UnrefImageInternal(const DrawImage& draw_image); | 195 void UnrefImageInternal(const DrawImage& draw_image); |
271 | 196 void RefCountChanged(ImageData* image_data); |
272 // Called any time the ownership of an object changed. This includes changes | |
273 // to ref-count or to orphaned status. | |
274 void OwnershipChanged(ImageData* image_data); | |
275 | 197 |
276 // Ensures that the cache can hold an element of |required_size|, freeing | 198 // Ensures that the cache can hold an element of |required_size|, freeing |
277 // unreferenced cache entries if necessary to make room. | 199 // unreferenced cache entries if necessary to make room. |
278 bool EnsureCapacity(size_t required_size); | 200 bool EnsureCapacity(size_t required_size); |
279 bool CanFitSize(size_t size) const; | 201 bool CanFitSize(size_t size) const; |
280 bool ExceedsPreferredCount() const; | 202 bool ExceedsPreferredCount() const; |
281 | 203 |
282 void DecodeImageIfNecessary(const DrawImage& draw_image, | 204 void DecodeImageIfNecessary(const DrawImage& draw_image, |
283 ImageData* image_data); | 205 ImageData* image_data); |
284 | 206 |
285 scoped_refptr<GpuImageDecodeController::ImageData> CreateImageData( | 207 std::unique_ptr<GpuImageDecodeController::ImageData> CreateImageData( |
286 const DrawImage& image); | 208 const DrawImage& image); |
287 SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image, | 209 SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image) const; |
288 int upload_scale_mip_level) const; | |
289 | |
290 // Finds the ImageData that should be used for the given DrawImage. Looks | |
291 // first in the |in_use_cache_|, and then in the |persistent_cache_|. | |
292 ImageData* GetImageDataForDrawImage(const DrawImage& image); | |
293 | |
294 // Returns true if the given ImageData can be used to draw the specified | |
295 // DrawImage. | |
296 bool IsCompatible(const ImageData* image_data, | |
297 const DrawImage& draw_image) const; | |
298 | 210 |
299 // The following two functions also require the |context_| lock to be held. | 211 // The following two functions also require the |context_| lock to be held. |
300 void UploadImageIfNecessary(const DrawImage& draw_image, | 212 void UploadImageIfNecessary(const DrawImage& draw_image, |
301 ImageData* image_data); | 213 ImageData* image_data); |
302 void DeletePendingImages(); | 214 void DeletePendingImages(); |
303 | 215 |
304 const ResourceFormat format_; | 216 const ResourceFormat format_; |
305 ContextProvider* context_; | 217 ContextProvider* context_; |
306 sk_sp<GrContextThreadSafeProxy> context_threadsafe_proxy_; | 218 sk_sp<GrContextThreadSafeProxy> context_threadsafe_proxy_; |
307 | 219 |
308 // All members below this point must only be accessed while holding |lock_|. | 220 // All members below this point must only be accessed while holding |lock_|. |
309 base::Lock lock_; | 221 base::Lock lock_; |
310 | 222 |
311 // |persistent_cache_| represents the long-lived cache, keeping a certain | 223 std::unordered_map<uint32_t, scoped_refptr<TileTask>> |
312 // budget of ImageDatas alive even when their ref count reaches zero. | 224 pending_image_upload_tasks_; |
313 using PersistentCache = base::MRUCache<uint32_t, scoped_refptr<ImageData>>; | 225 std::unordered_map<uint32_t, scoped_refptr<TileTask>> |
314 PersistentCache persistent_cache_; | 226 pending_image_decode_tasks_; |
315 | 227 |
316 // |in_use_cache_| represents the in-use (short-lived) cache. Entries are | 228 ImageDataMRUCache image_data_; |
317 // cleaned up as soon as their ref count reaches zero. | |
318 using InUseCache = std::unordered_map<InUseCacheKey, InUseCacheEntry>; | |
319 InUseCache in_use_cache_; | |
320 | 229 |
321 size_t cached_items_limit_; | 230 size_t cached_items_limit_; |
322 size_t cached_bytes_limit_; | 231 size_t cached_bytes_limit_; |
323 size_t bytes_used_; | 232 size_t bytes_used_; |
324 const size_t max_gpu_image_bytes_; | 233 const size_t max_gpu_image_bytes_; |
325 | 234 |
326 // We can't release GPU backed SkImages without holding the context lock, | 235 // We can't release GPU backed SkImages without holding the context lock, |
327 // so we add them to this list and defer deletion until the next time the lock | 236 // so we add them to this list and defer deletion until the next time the lock |
328 // is held. | 237 // is held. |
329 std::vector<sk_sp<SkImage>> images_pending_deletion_; | 238 std::vector<sk_sp<SkImage>> images_pending_deletion_; |
330 }; | 239 }; |
331 | 240 |
332 } // namespace cc | 241 } // namespace cc |
333 | 242 |
334 #endif // CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ | 243 #endif // CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ |
OLD | NEW |