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