Chromium Code Reviews| Index: cc/tiles/gpu_image_decode_controller.h |
| diff --git a/cc/tiles/gpu_image_decode_controller.h b/cc/tiles/gpu_image_decode_controller.h |
| index 5ced06527577704a4c5a71566ef4329b17890ecb..239d6e0a08255455572ca8369808e0afe2c67ccf 100644 |
| --- a/cc/tiles/gpu_image_decode_controller.h |
| +++ b/cc/tiles/gpu_image_decode_controller.h |
| @@ -49,6 +49,35 @@ class ContextProvider; |
| // used in raster. Cache entries for at-raster tasks are marked as such, which |
| // prevents future tasks from taking a dependency on them and extending their |
| // lifetime longer than is necessary. |
| +// |
| +// In order to save memory, images which are going to be scaled may be uploaded |
| +// at lower than original resolution. In these cases, we may later need to |
| +// re-upload the image at a higher resolution, to accomodate a new use case. In |
| +// dealing with multiple scales of the same image, we take the following |
| +// approach: |
| +// 1) If an image is already uploaded at a larger resolution than is needed, |
| +// use that upload directly. |
| +// 2) If an image is already uploaded at a lower resolution than is needed, |
| +// orphan the existing upload (removing it from the main cache) and start |
| +// uploading the larger version. |
| +// 2a) Orphaned images will be deleted as soon as all existing references |
| +// to them are removed. |
| +// |
| +// In order to accomodate orphaned tasks, we have a two-part caching system. The |
| +// primary cache, |image_data_|, stores one ImageData per image id. These |
| +// ImageDatas are not necessarily associated with a given DrawImage, and are |
| +// 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.
|
| +// |
| +// The second cache, |image_data_for_draw_image_|, stores one image data per |
| +// DrawImage - this may be the same ImageData that is in the primary cache. |
| +// These cache entries are more transient than the primary cache and are deleted |
| +// as soon as all refs to the given DrawImage are released. |
| +// |
| +// We consider an ImageData "orphaned" if it is in the secondary cache, but not |
| +// the primary. This typically happens when we need a higher-quality/larger |
| +// version of an image than what is in the primary cache, so we replace the |
| +// primary cache entry. Orphaned ImageDatas still count against our budgets, |
| +// but are cleaned up as soon as their ref count reaches zero. |
| class CC_EXPORT GpuImageDecodeController |
| : public ImageDecodeController, |
| public base::trace_event::MemoryDumpProvider { |
| @@ -93,6 +122,7 @@ class CC_EXPORT GpuImageDecodeController |
| cached_bytes_limit_ = limit; |
| } |
| size_t GetBytesUsedForTesting() const { return bytes_used_; } |
| + size_t GetDrawImageSizeForTesting(const DrawImage& image); |
| void SetImageDecodingFailedForTesting(const DrawImage& image); |
| bool DiscardableIsLockedForTesting(const DrawImage& image); |
| @@ -164,20 +194,59 @@ class CC_EXPORT GpuImageDecodeController |
| UsageStats usage_stats_; |
| }; |
| - struct ImageData { |
| - ImageData(DecodedDataMode mode, size_t size); |
| - ~ImageData(); |
| + struct ImageData : public base::RefCounted<ImageData> { |
| + ImageData(DecodedDataMode mode, |
| + size_t size, |
| + int pre_scale_mip_level, |
| + SkFilterQuality pre_scale_filter_quality); |
| const DecodedDataMode mode; |
| const size_t size; |
| bool is_at_raster = false; |
| + int pre_scale_mip_level; |
| + SkFilterQuality pre_scale_filter_quality; |
| + bool is_orphaned = false; |
| DecodedImageData decode; |
| UploadedImageData upload; |
| + |
| + private: |
| + friend class base::RefCounted<ImageData>; |
| + ~ImageData(); |
| + }; |
| + |
| + // A ref-count and ImageData, used to associate the ImageData with a specific |
| + // DrawImage in the secondary |image_data_for_draw_image_| cache. |
| + struct ImageDataForDrawImageEntry { |
| + explicit ImageDataForDrawImageEntry( |
| + 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.
|
| + 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
|
| + ImageDataForDrawImageEntry(ImageDataForDrawImageEntry&&); |
| + ~ImageDataForDrawImageEntry(); |
| + |
| + uint32_t ref_count = 0; |
| + scoped_refptr<ImageData> image_data; |
| }; |
| - using ImageDataMRUCache = |
| - base::MRUCache<uint32_t, std::unique_ptr<ImageData>>; |
| + // A key used to identify a DrawImage in the |image_data_for_draw_image_| |
| + // cache, as well as the pending task maps. |
| + struct DrawImageKey { |
| + uint32_t image_id; |
|
vmpstr
2016/06/14 21:35:27
= 0 here and below
ericrk
2016/06/16 23:03:33
Done.
|
| + int mip_level; |
| + SkFilterQuality quality; |
| + |
| + bool operator==(const DrawImageKey& other) const { |
| + return other.image_id == image_id && other.mip_level == mip_level && |
| + other.quality == quality; |
| + } |
| + }; |
| + |
| + struct DrawImageKeyHash { |
| + std::size_t operator()(const DrawImageKey& key) const { |
| + return base::HashInts(key.image_id, |
| + 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
|
| + } |
| + }; |
| // All private functions should only be called while holding |lock_|. Some |
| // functions also require the |context_| lock. These are indicated by |
| @@ -204,9 +273,23 @@ class CC_EXPORT GpuImageDecodeController |
| void DecodeImageIfNecessary(const DrawImage& draw_image, |
| ImageData* image_data); |
| - std::unique_ptr<GpuImageDecodeController::ImageData> CreateImageData( |
| + scoped_refptr<GpuImageDecodeController::ImageData> CreateImageData( |
| const DrawImage& image); |
| SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image) const; |
| + ImageData* GetImageDataForDrawImage(const DrawImage& image); |
| + |
| + // 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-
|
| + // DrawImage. |
| + bool IsCompatibleWithDrawImage(const ImageData* image_data, |
| + const DrawImage& draw_image) const; |
| + |
| + // Generates a key which can be used to look up the provided |draw_image| in |
| + // the |image_data_for_draw_image_| map. |
| + 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.
|
| + |
| + // Generates a key which can be used to look up the task for the provided |
| + // |draw_image| in the task maps. |
| + DrawImageKey GenerateTaskKeyForDrawImage(const DrawImage& draw_image); |
| // The following two functions also require the |context_| lock to be held. |
| void UploadImageIfNecessary(const DrawImage& draw_image, |
| @@ -220,13 +303,19 @@ class CC_EXPORT GpuImageDecodeController |
| // All members below this point must only be accessed while holding |lock_|. |
| base::Lock lock_; |
| - std::unordered_map<uint32_t, scoped_refptr<TileTask>> |
| - pending_image_upload_tasks_; |
| - std::unordered_map<uint32_t, scoped_refptr<TileTask>> |
| - pending_image_decode_tasks_; |
| - |
| + using ImageDataMRUCache = base::MRUCache<uint32_t, scoped_refptr<ImageData>>; |
| + // |image_data_| represents the primary (long-lived) cache. |
| ImageDataMRUCache image_data_; |
| + template <typename T> |
| + using DrawImageMap = std::unordered_map<DrawImageKey, T, DrawImageKeyHash>; |
| + // |image_data_for_draw_image_| represents the secondary (short-lived) cache. |
| + 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_|
|
| + |
| + // Upload and decode tasks are keyed on the exact DrawImage they are decoding. |
| + DrawImageMap<scoped_refptr<TileTask>> pending_image_upload_tasks_; |
| + DrawImageMap<scoped_refptr<TileTask>> pending_image_decode_tasks_; |
| + |
| size_t cached_items_limit_; |
| size_t cached_bytes_limit_; |
| size_t bytes_used_; |