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_; |