Chromium Code Reviews| 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> |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 42 // upload completes), this memory is not counted against our sized cache | 42 // upload completes), this memory is not counted against our sized cache |
| 43 // limits. Uploaded GPU memory, being non-discardable, always counts against | 43 // limits. Uploaded GPU memory, being non-discardable, always counts against |
| 44 // our limits. | 44 // our limits. |
| 45 // | 45 // |
| 46 // 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 |
| 47 // 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 |
| 48 // tasks, and images are decoded/uploaded as needed, immediately before being | 48 // tasks, and images are decoded/uploaded as needed, immediately before being |
| 49 // 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 |
| 50 // 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 |
| 51 // lifetime longer than is necessary. | 51 // lifetime longer than is necessary. |
| 52 // | |
| 53 // In order to save memory, images which are going to be scaled may be uploaded | |
| 54 // at lower than original resolution. In these cases, we may later need to | |
| 55 // re-upload the image at a higher resolution, to accomodate a new use case. In | |
| 56 // dealing with multiple scales of the same image, we take the following | |
| 57 // approach: | |
| 58 // 1) If an image is already uploaded at a larger resolution than is needed, | |
| 59 // use that upload directly. | |
| 60 // 2) If an image is already uploaded at a lower resolution than is needed, | |
| 61 // orphan the existing upload (removing it from the main cache) and start | |
| 62 // uploading the larger version. | |
| 63 // 2a) Orphaned images will be deleted as soon as all existing references | |
| 64 // to them are removed. | |
| 65 // | |
| 66 // In order to accomodate orphaned tasks, we have a two-part caching system. The | |
| 67 // primary cache, |image_data_|, stores one ImageData per image id. These | |
| 68 // ImageDatas are not necessarily associated with a given DrawImage, and are | |
| 69 // saved even when their ref-count reaches zero to allow for future re-use. | |
|
vmpstr
2016/06/14 21:35:27
It would be good to mention that it's kept there a
ericrk
2016/06/16 23:03:33
Done.
| |
| 70 // | |
| 71 // The second cache, |image_data_for_draw_image_|, stores one image data per | |
| 72 // DrawImage - this may be the same ImageData that is in the primary cache. | |
| 73 // These cache entries are more transient than the primary cache and are deleted | |
| 74 // as soon as all refs to the given DrawImage are released. | |
| 75 // | |
| 76 // We consider an ImageData "orphaned" if it is in the secondary cache, but not | |
| 77 // the primary. This typically happens when we need a higher-quality/larger | |
| 78 // version of an image than what is in the primary cache, so we replace the | |
| 79 // primary cache entry. Orphaned ImageDatas still count against our budgets, | |
| 80 // but are cleaned up as soon as their ref count reaches zero. | |
| 52 class CC_EXPORT GpuImageDecodeController | 81 class CC_EXPORT GpuImageDecodeController |
| 53 : public ImageDecodeController, | 82 : public ImageDecodeController, |
| 54 public base::trace_event::MemoryDumpProvider { | 83 public base::trace_event::MemoryDumpProvider { |
| 55 public: | 84 public: |
| 56 explicit GpuImageDecodeController(ContextProvider* context, | 85 explicit GpuImageDecodeController(ContextProvider* context, |
| 57 ResourceFormat decode_format, | 86 ResourceFormat decode_format, |
| 58 size_t max_gpu_image_bytes); | 87 size_t max_gpu_image_bytes); |
| 59 ~GpuImageDecodeController() override; | 88 ~GpuImageDecodeController() override; |
| 60 | 89 |
| 61 // ImageDecodeController overrides. | 90 // ImageDecodeController overrides. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 86 void OnImageUploadTaskCompleted(const DrawImage& image); | 115 void OnImageUploadTaskCompleted(const DrawImage& image); |
| 87 | 116 |
| 88 // For testing only. | 117 // For testing only. |
| 89 void SetCachedItemLimitForTesting(size_t limit) { | 118 void SetCachedItemLimitForTesting(size_t limit) { |
| 90 cached_items_limit_ = limit; | 119 cached_items_limit_ = limit; |
| 91 } | 120 } |
| 92 void SetCachedBytesLimitForTesting(size_t limit) { | 121 void SetCachedBytesLimitForTesting(size_t limit) { |
| 93 cached_bytes_limit_ = limit; | 122 cached_bytes_limit_ = limit; |
| 94 } | 123 } |
| 95 size_t GetBytesUsedForTesting() const { return bytes_used_; } | 124 size_t GetBytesUsedForTesting() const { return bytes_used_; } |
| 125 size_t GetDrawImageSizeForTesting(const DrawImage& image); | |
| 96 void SetImageDecodingFailedForTesting(const DrawImage& image); | 126 void SetImageDecodingFailedForTesting(const DrawImage& image); |
| 97 bool DiscardableIsLockedForTesting(const DrawImage& image); | 127 bool DiscardableIsLockedForTesting(const DrawImage& image); |
| 98 | 128 |
| 99 private: | 129 private: |
| 100 enum class DecodedDataMode { GPU, CPU }; | 130 enum class DecodedDataMode { GPU, CPU }; |
| 101 | 131 |
| 102 // Stores the CPU-side decoded bits of an image and supporting fields. | 132 // Stores the CPU-side decoded bits of an image and supporting fields. |
| 103 struct DecodedImageData { | 133 struct DecodedImageData { |
| 104 DecodedImageData(); | 134 DecodedImageData(); |
| 105 ~DecodedImageData(); | 135 ~DecodedImageData(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 int ref_reached_zero_count = 0; | 187 int ref_reached_zero_count = 0; |
| 158 }; | 188 }; |
| 159 | 189 |
| 160 void ReportUsageStats() const; | 190 void ReportUsageStats() const; |
| 161 | 191 |
| 162 // May be null if image not yet uploaded / prepared. | 192 // May be null if image not yet uploaded / prepared. |
| 163 sk_sp<SkImage> image_; | 193 sk_sp<SkImage> image_; |
| 164 UsageStats usage_stats_; | 194 UsageStats usage_stats_; |
| 165 }; | 195 }; |
| 166 | 196 |
| 167 struct ImageData { | 197 struct ImageData : public base::RefCounted<ImageData> { |
| 168 ImageData(DecodedDataMode mode, size_t size); | 198 ImageData(DecodedDataMode mode, |
| 169 ~ImageData(); | 199 size_t size, |
| 200 int pre_scale_mip_level, | |
| 201 SkFilterQuality pre_scale_filter_quality); | |
| 170 | 202 |
| 171 const DecodedDataMode mode; | 203 const DecodedDataMode mode; |
| 172 const size_t size; | 204 const size_t size; |
| 173 bool is_at_raster = false; | 205 bool is_at_raster = false; |
| 206 int pre_scale_mip_level; | |
| 207 SkFilterQuality pre_scale_filter_quality; | |
| 208 bool is_orphaned = false; | |
| 174 | 209 |
| 175 DecodedImageData decode; | 210 DecodedImageData decode; |
| 176 UploadedImageData upload; | 211 UploadedImageData upload; |
| 212 | |
| 213 private: | |
| 214 friend class base::RefCounted<ImageData>; | |
| 215 ~ImageData(); | |
| 177 }; | 216 }; |
| 178 | 217 |
| 179 using ImageDataMRUCache = | 218 // A ref-count and ImageData, used to associate the ImageData with a specific |
| 180 base::MRUCache<uint32_t, std::unique_ptr<ImageData>>; | 219 // DrawImage in the secondary |image_data_for_draw_image_| cache. |
| 220 struct ImageDataForDrawImageEntry { | |
| 221 explicit ImageDataForDrawImageEntry( | |
| 222 const scoped_refptr<ImageData>& image_data); | |
|
vmpstr
2016/06/14 21:35:27
Pass by value, move into place?
ericrk
2016/06/16 23:03:33
Done.
| |
| 223 ImageDataForDrawImageEntry(const ImageDataForDrawImageEntry&); | |
|
vmpstr
2016/06/14 21:35:27
nit: can you name the parameters? "other"?
Also,
ericrk
2016/06/16 23:03:33
sadness:
error: [chromium-style] Complex construc
| |
| 224 ImageDataForDrawImageEntry(ImageDataForDrawImageEntry&&); | |
| 225 ~ImageDataForDrawImageEntry(); | |
| 226 | |
| 227 uint32_t ref_count = 0; | |
| 228 scoped_refptr<ImageData> image_data; | |
| 229 }; | |
| 230 | |
| 231 // A key used to identify a DrawImage in the |image_data_for_draw_image_| | |
| 232 // cache, as well as the pending task maps. | |
| 233 struct DrawImageKey { | |
| 234 uint32_t image_id; | |
|
vmpstr
2016/06/14 21:35:27
= 0 here and below
ericrk
2016/06/16 23:03:33
Done.
| |
| 235 int mip_level; | |
| 236 SkFilterQuality quality; | |
| 237 | |
| 238 bool operator==(const DrawImageKey& other) const { | |
| 239 return other.image_id == image_id && other.mip_level == mip_level && | |
| 240 other.quality == quality; | |
| 241 } | |
| 242 }; | |
| 243 | |
| 244 struct DrawImageKeyHash { | |
| 245 std::size_t operator()(const DrawImageKey& key) const { | |
| 246 return base::HashInts(key.image_id, | |
| 247 base::HashInts(key.mip_level, key.quality)); | |
|
vmpstr
2016/06/14 21:35:27
I wonder if you can do something smarter than Hash
ericrk
2016/06/16 23:03:33
Sure, I'll make a better hash :P
| |
| 248 } | |
| 249 }; | |
| 181 | 250 |
| 182 // All private functions should only be called while holding |lock_|. Some | 251 // All private functions should only be called while holding |lock_|. Some |
| 183 // functions also require the |context_| lock. These are indicated by | 252 // functions also require the |context_| lock. These are indicated by |
| 184 // additional comments. | 253 // additional comments. |
| 185 | 254 |
| 186 // Similar to GetTaskForImageAndRef, but gets the dependent decode task | 255 // Similar to GetTaskForImageAndRef, but gets the dependent decode task |
| 187 // rather than the upload task, if necessary. | 256 // rather than the upload task, if necessary. |
| 188 scoped_refptr<TileTask> GetImageDecodeTaskAndRef( | 257 scoped_refptr<TileTask> GetImageDecodeTaskAndRef( |
| 189 const DrawImage& image, | 258 const DrawImage& image, |
| 190 const TracingInfo& tracing_info); | 259 const TracingInfo& tracing_info); |
| 191 | 260 |
| 192 void RefImageDecode(const DrawImage& draw_image); | 261 void RefImageDecode(const DrawImage& draw_image); |
| 193 void UnrefImageDecode(const DrawImage& draw_image); | 262 void UnrefImageDecode(const DrawImage& draw_image); |
| 194 void RefImage(const DrawImage& draw_image); | 263 void RefImage(const DrawImage& draw_image); |
| 195 void UnrefImageInternal(const DrawImage& draw_image); | 264 void UnrefImageInternal(const DrawImage& draw_image); |
| 196 void RefCountChanged(ImageData* image_data); | 265 void RefCountChanged(ImageData* image_data); |
| 197 | 266 |
| 198 // Ensures that the cache can hold an element of |required_size|, freeing | 267 // Ensures that the cache can hold an element of |required_size|, freeing |
| 199 // unreferenced cache entries if necessary to make room. | 268 // unreferenced cache entries if necessary to make room. |
| 200 bool EnsureCapacity(size_t required_size); | 269 bool EnsureCapacity(size_t required_size); |
| 201 bool CanFitSize(size_t size) const; | 270 bool CanFitSize(size_t size) const; |
| 202 bool ExceedsPreferredCount() const; | 271 bool ExceedsPreferredCount() const; |
| 203 | 272 |
| 204 void DecodeImageIfNecessary(const DrawImage& draw_image, | 273 void DecodeImageIfNecessary(const DrawImage& draw_image, |
| 205 ImageData* image_data); | 274 ImageData* image_data); |
| 206 | 275 |
| 207 std::unique_ptr<GpuImageDecodeController::ImageData> CreateImageData( | 276 scoped_refptr<GpuImageDecodeController::ImageData> CreateImageData( |
| 208 const DrawImage& image); | 277 const DrawImage& image); |
| 209 SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image) const; | 278 SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image) const; |
| 279 ImageData* GetImageDataForDrawImage(const DrawImage& image); | |
| 280 | |
| 281 // Returns true if the given ImageData is as large or larger than the | |
|
vmpstr
2016/06/14 21:35:28
This comment reads like like this could be an out
ericrk
2016/06/16 23:03:33
Now that the key is a uint64_t, moved this out-of-
| |
| 282 // DrawImage. | |
| 283 bool IsCompatibleWithDrawImage(const ImageData* image_data, | |
| 284 const DrawImage& draw_image) const; | |
| 285 | |
| 286 // Generates a key which can be used to look up the provided |draw_image| in | |
| 287 // the |image_data_for_draw_image_| map. | |
| 288 DrawImageKey GenerateDrawImageKey(const DrawImage& draw_image) const; | |
|
vmpstr
2016/06/14 21:35:27
This needs a better comment; specifically, can you
ericrk
2016/06/16 23:03:33
Removed the second fn and cleaned this up.
| |
| 289 | |
| 290 // Generates a key which can be used to look up the task for the provided | |
| 291 // |draw_image| in the task maps. | |
| 292 DrawImageKey GenerateTaskKeyForDrawImage(const DrawImage& draw_image); | |
| 210 | 293 |
| 211 // The following two functions also require the |context_| lock to be held. | 294 // The following two functions also require the |context_| lock to be held. |
| 212 void UploadImageIfNecessary(const DrawImage& draw_image, | 295 void UploadImageIfNecessary(const DrawImage& draw_image, |
| 213 ImageData* image_data); | 296 ImageData* image_data); |
| 214 void DeletePendingImages(); | 297 void DeletePendingImages(); |
| 215 | 298 |
| 216 const ResourceFormat format_; | 299 const ResourceFormat format_; |
| 217 ContextProvider* context_; | 300 ContextProvider* context_; |
| 218 sk_sp<GrContextThreadSafeProxy> context_threadsafe_proxy_; | 301 sk_sp<GrContextThreadSafeProxy> context_threadsafe_proxy_; |
| 219 | 302 |
| 220 // All members below this point must only be accessed while holding |lock_|. | 303 // All members below this point must only be accessed while holding |lock_|. |
| 221 base::Lock lock_; | 304 base::Lock lock_; |
| 222 | 305 |
| 223 std::unordered_map<uint32_t, scoped_refptr<TileTask>> | 306 using ImageDataMRUCache = base::MRUCache<uint32_t, scoped_refptr<ImageData>>; |
| 224 pending_image_upload_tasks_; | 307 // |image_data_| represents the primary (long-lived) cache. |
| 225 std::unordered_map<uint32_t, scoped_refptr<TileTask>> | 308 ImageDataMRUCache image_data_; |
| 226 pending_image_decode_tasks_; | |
| 227 | 309 |
| 228 ImageDataMRUCache image_data_; | 310 template <typename T> |
| 311 using DrawImageMap = std::unordered_map<DrawImageKey, T, DrawImageKeyHash>; | |
| 312 // |image_data_for_draw_image_| represents the secondary (short-lived) cache. | |
| 313 DrawImageMap<ImageDataForDrawImageEntry> image_data_for_draw_image_; | |
|
vmpstr
2016/06/14 21:35:27
I'd find better names for these caches, maybe some
ericrk
2016/06/16 23:03:33
Renamed to |persistent_cache_| and |in_use_cache_|
| |
| 314 | |
| 315 // Upload and decode tasks are keyed on the exact DrawImage they are decoding. | |
| 316 DrawImageMap<scoped_refptr<TileTask>> pending_image_upload_tasks_; | |
| 317 DrawImageMap<scoped_refptr<TileTask>> pending_image_decode_tasks_; | |
| 229 | 318 |
| 230 size_t cached_items_limit_; | 319 size_t cached_items_limit_; |
| 231 size_t cached_bytes_limit_; | 320 size_t cached_bytes_limit_; |
| 232 size_t bytes_used_; | 321 size_t bytes_used_; |
| 233 const size_t max_gpu_image_bytes_; | 322 const size_t max_gpu_image_bytes_; |
| 234 | 323 |
| 235 // We can't release GPU backed SkImages without holding the context lock, | 324 // We can't release GPU backed SkImages without holding the context lock, |
| 236 // so we add them to this list and defer deletion until the next time the lock | 325 // so we add them to this list and defer deletion until the next time the lock |
| 237 // is held. | 326 // is held. |
| 238 std::vector<sk_sp<SkImage>> images_pending_deletion_; | 327 std::vector<sk_sp<SkImage>> images_pending_deletion_; |
| 239 }; | 328 }; |
| 240 | 329 |
| 241 } // namespace cc | 330 } // namespace cc |
| 242 | 331 |
| 243 #endif // CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ | 332 #endif // CC_TILES_GPU_IMAGE_DECODE_CONTROLLER_H_ |
| OLD | NEW |