Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: cc/tiles/gpu_image_decode_controller.cc

Issue 1832573004: Gpu Image Decode Controller (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: small fixes Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include "cc/tiles/gpu_image_decode_controller.h" 5 #include "cc/tiles/gpu_image_decode_controller.h"
6 6
7 #include "base/memory/discardable_memory_allocator.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/thread_task_runner_handle.h"
7 #include "cc/debug/devtools_instrumentation.h" 11 #include "cc/debug/devtools_instrumentation.h"
12 #include "cc/output/context_provider.h"
8 #include "cc/raster/tile_task_runner.h" 13 #include "cc/raster/tile_task_runner.h"
14 #include "gpu/command_buffer/client/context_support.h"
15 #include "gpu/command_buffer/client/gles2_interface.h"
16 #include "gpu_image_decode_controller.h"
9 #include "skia/ext/refptr.h" 17 #include "skia/ext/refptr.h"
18 #include "skia/ext/texture_handle.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "third_party/skia/include/core/SkSurface.h"
21 #include "third_party/skia/include/gpu/GrContext.h"
22 #include "third_party/skia/include/gpu/GrTexture.h"
23 #include "ui/gfx/skia_util.h"
24 #include "ui/gl/trace_util.h"
10 25
11 namespace cc { 26 namespace cc {
27 namespace {
12 28
29 static const int kMaxGpuImageBytes = 1024 * 1024 * 96;
30 static const int kMaxDiscardableItems = 1000;
31
32 // Returns true if an image would not be drawn and should therefore be
33 // skipped rather than decoded.
34 bool SkipImage(const DrawImage& draw_image) {
35 if (!SkIRect::Intersects(draw_image.src_rect(), draw_image.image()->bounds()))
36 return true;
37 if (draw_image.matrix_is_decomposable() &&
vmpstr 2016/03/28 23:55:52 If matrix is not decomposable, then the scale is s
ericrk 2016/03/29 23:11:29 ah, good point.
38 (std::abs(draw_image.scale().width()) <
39 std::numeric_limits<float>::epsilon() ||
40 std::abs(draw_image.scale().height()) <
41 std::numeric_limits<float>::epsilon()))
vmpstr 2016/03/28 23:55:53 Can you add braces for this if-statement please?
ericrk 2016/03/29 23:11:30 Done.
42 return true;
43 return false;
44 }
45
46 SkImage::DeferredTextureImageUsageParams ParamsFromDrawImage(
47 const DrawImage& draw_image) {
48 SkImage::DeferredTextureImageUsageParams params;
49 params.fMatrix = draw_image.matrix();
50 params.fQuality = draw_image.filter_quality();
51
52 return params;
53 }
54
55 } // namespace
56
57 // Task which decodes an image and stores the result in discardable memory.
58 // This task does not use GPU resources and can be run on any thread.
13 class ImageDecodeTaskImpl : public ImageDecodeTask { 59 class ImageDecodeTaskImpl : public ImageDecodeTask {
14 public: 60 public:
15 ImageDecodeTaskImpl(GpuImageDecodeController* controller, 61 ImageDecodeTaskImpl(GpuImageDecodeController* controller,
16 const DrawImage& image, 62 const DrawImage& draw_image,
17 uint64_t source_prepare_tiles_id) 63 uint64_t source_prepare_tiles_id)
18 : controller_(controller), 64 : controller_(controller),
19 image_(image), 65 image_(draw_image),
20 image_ref_(skia::SharePtr(image.image())), 66 image_ref_(skia::SharePtr(draw_image.image())),
21 source_prepare_tiles_id_(source_prepare_tiles_id) {} 67 source_prepare_tiles_id_(source_prepare_tiles_id) {
68 DCHECK(!SkipImage(draw_image));
69 }
22 70
23 // Overridden from Task: 71 // Overridden from Task:
24 void RunOnWorkerThread() override { 72 void RunOnWorkerThread() override {
25 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", "gpu", 73 TRACE_EVENT2("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "mode", "gpu",
26 "source_prepare_tiles_id", source_prepare_tiles_id_); 74 "source_prepare_tiles_id", source_prepare_tiles_id_);
27 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
28 image_ref_.get());
29 controller_->DecodeImage(image_); 75 controller_->DecodeImage(image_);
30 } 76 }
31 77
32 // Overridden from TileTask: 78 // Overridden from TileTask:
33 void ScheduleOnOriginThread(TileTaskClient* client) override {} 79 void ScheduleOnOriginThread(TileTaskClient* client) override {}
34 void CompleteOnOriginThread(TileTaskClient* client) override { 80 void CompleteOnOriginThread(TileTaskClient* client) override {
35 controller_->RemovePendingTaskForImage(image_); 81 controller_->DecodeTaskCompleted(image_);
36 } 82 }
37 83
38 protected: 84 protected:
39 ~ImageDecodeTaskImpl() override {} 85 ~ImageDecodeTaskImpl() override {}
40 86
41 private: 87 private:
42 GpuImageDecodeController* controller_; 88 GpuImageDecodeController* controller_;
43 DrawImage image_; 89 DrawImage image_;
44 skia::RefPtr<const SkImage> image_ref_; 90 skia::RefPtr<const SkImage> image_ref_;
91 const uint64_t source_prepare_tiles_id_;
92
93 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
94 };
95
96 // Task which creates an image from decoded data. Typically this involves
97 // uploading data to the GPU, which requires this task be run on the non-
98 // concurrent thread.
99 class ImageUploadTaskImpl : public ImageDecodeTask {
100 public:
101 ImageUploadTaskImpl(GpuImageDecodeController* controller,
102 const DrawImage& draw_image,
103 scoped_refptr<ImageDecodeTask> decode_dependency,
104 uint64_t source_prepare_tiles_id)
105 : ImageDecodeTask(std::move(decode_dependency)),
106 controller_(controller),
107 image_(draw_image),
108 image_ref_(skia::SharePtr(draw_image.image())),
109 source_prepare_tiles_id_(source_prepare_tiles_id) {
110 DCHECK(!SkipImage(draw_image));
111 }
112
113 // Override from Task:
114 void RunOnWorkerThread() override {
115 TRACE_EVENT2("cc", "ImageUploadTaskImpl::RunOnWorkerThread", "mode", "gpu",
116 "source_prepare_tiles_id", source_prepare_tiles_id_);
117 controller_->UploadImage(image_);
118 }
119
120 void ScheduleOnOriginThread(TileTaskClient* client) override {}
121 void CompleteOnOriginThread(TileTaskClient* client) override {
122 controller_->UploadTaskCompleted(image_);
123 }
124
125 // Override from ImageDecodeTask:
126 bool SupportsConcurrentExecution() const override { return false; }
127
128 protected:
129 ~ImageUploadTaskImpl() override {}
130
131 private:
132 GpuImageDecodeController* controller_;
133 DrawImage image_;
134 skia::RefPtr<const SkImage> image_ref_;
45 uint64_t source_prepare_tiles_id_; 135 uint64_t source_prepare_tiles_id_;
46 136
47 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); 137 DISALLOW_COPY_AND_ASSIGN(ImageUploadTaskImpl);
48 }; 138 };
49 139
50 GpuImageDecodeController::GpuImageDecodeController() {} 140 GpuImageDecodeController::DecodedImageData::DecodedImageData()
141 : ref_count(0), is_locked(false) {}
142
143 GpuImageDecodeController::DecodedImageData::~DecodedImageData() = default;
144
145 GpuImageDecodeController::UploadedImageData::UploadedImageData()
146 : pending(false), ref_count(0) {}
147
148 GpuImageDecodeController::UploadedImageData::~UploadedImageData() = default;
149
150 GpuImageDecodeController::ImageData::ImageData(DecodedDataMode mode,
151 size_t size)
152 : mode(mode), size(size), is_at_raster(false) {}
153
154 GpuImageDecodeController::ImageData::~ImageData() = default;
155
156 GpuImageDecodeController::GpuImageDecodeController(ContextProvider* context,
157 ResourceFormat decode_format)
158 : format_(decode_format),
159 context_(context),
160 context_threadsafe_proxy_(context->GrContext()->threadSafeProxy()),
161 image_data_(ImageDataMRUCache::NO_AUTO_EVICT),
162 cached_items_limit_(kMaxDiscardableItems),
163 cached_bytes_limit_(kMaxGpuImageBytes),
164 bytes_used_(0) {}
51 165
52 GpuImageDecodeController::~GpuImageDecodeController() {} 166 GpuImageDecodeController::~GpuImageDecodeController() {}
53 167
54 bool GpuImageDecodeController::GetTaskForImageAndRef( 168 bool GpuImageDecodeController::GetTaskForImageAndRef(
55 const DrawImage& image, 169 const DrawImage& draw_image,
56 uint64_t prepare_tiles_id, 170 uint64_t prepare_tiles_id,
57 scoped_refptr<ImageDecodeTask>* task) { 171 scoped_refptr<ImageDecodeTask>* task) {
58 auto image_id = image.image()->uniqueID(); 172 if (SkipImage(draw_image)) {
59 base::AutoLock lock(lock_);
60 if (prerolled_images_.count(image_id) != 0) {
61 *task = nullptr; 173 *task = nullptr;
62 return false; 174 return false;
63 } 175 }
64 176
177 base::AutoLock lock(lock_);
178 const auto image_id = draw_image.image()->uniqueID();
179
180 auto found = image_data_.Get(image_id);
181 if (found != image_data_.end() && found->second->upload.image) {
182 // The image is already uploaded. If it is not at-raster, or if it will now
183 // fit in the cache (can be converted to not at-raster) ref and return.
184 if (!found->second->is_at_raster ||
185 EnsureCapacityWithClassLock(found->second->size)) {
186 found->second->is_at_raster = false;
187 RefImageWithClassLock(draw_image);
188 *task = nullptr;
189 return true;
190 }
191
192 // Image is at-raster and doesn't fit in the cache. Keep using the image as
193 // at-raster.
194 *task = nullptr;
195 return false;
196 }
197
198 // We didn't have a pre-uploaded image. Try to find an existing upload task.
65 scoped_refptr<ImageDecodeTask>& existing_task = 199 scoped_refptr<ImageDecodeTask>& existing_task =
66 pending_image_tasks_[image_id]; 200 pending_image_upload_tasks_[image_id];
201 if (existing_task) {
202 // We had an existing upload task, ref to the image and return the task.
vmpstr 2016/03/28 23:55:53 either "add ref to the image" or "ref the image"
ericrk 2016/03/29 23:11:30 Done.
203 RefImageWithClassLock(draw_image);
204 *task = existing_task;
205 return true;
206 }
207
208 // We will be creating a new upload task. If necessary, create a placeholder
209 // ImageData to hold the result.
210 scoped_ptr<ImageData> new_data;
211 ImageData* data;
212 if (found == image_data_.end()) {
213 new_data = CreateImageData(draw_image);
214 data = new_data.get();
215 } else {
216 data = found->second.get();
217 }
218
219 // Ensure that the image we're about to decode/upload will fit in memory.
220 // Otherwise do an at-raster decode.
221 if (!EnsureCapacityWithClassLock(data->size)) {
222 *task = nullptr;
223 return false;
224 }
225
226 // If we had to create new image data, add it to our map now that we know it
227 // will fit.
228 if (new_data)
229 found = image_data_.Put(image_id, std::move(new_data));
230
231 // Increment |bytes_used_| to reserve room for the pending image. As there is
232 // no |image| created yet, mark the data as |pending|. This lets us account
233 // for the image's size correctly if we cancel this task before uploading.
234 DCHECK(!data->upload.pending);
235 bytes_used_ += data->size;
vmpstr 2016/03/28 23:55:53 There's some extremely rare but possible overflow
ericrk 2016/03/29 23:11:30 Updated CanFitSize to use checked math. Now that a
236 data->upload.pending = true;
237
238 // Ref image and create an upload task. We will release this ref in
vmpstr 2016/03/28 23:55:52 nit: create both upload and decode tasks.
ericrk 2016/03/29 23:11:30 Done.
239 // UploadTaskCompleted.
240 RefImageWithClassLock(draw_image);
241 existing_task = make_scoped_refptr(new ImageUploadTaskImpl(
242 this, draw_image,
243 GetImageDecodeTaskAndRefWithClassLock(draw_image, prepare_tiles_id),
244 prepare_tiles_id));
245
246 RefImageWithClassLock(draw_image);
vmpstr 2016/03/28 23:55:52 There's two Refs here (lines 240 and 246). Is that
ericrk 2016/03/29 23:11:30 This was intentional - one ref is kept alive by th
247 *task = existing_task;
248 return true;
249 }
250
251 void GpuImageDecodeController::UnrefImage(const DrawImage& draw_image) {
252 base::AutoLock lock(lock_);
253 UnrefImageWithClassLock(draw_image);
254 }
255
256 DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw(
257 const DrawImage& draw_image) {
258 TRACE_EVENT0("cc", "GpuImageDecodeController::GetDecodedImageForDraw");
259 if (SkipImage(draw_image))
260 return DecodedDrawImage(nullptr, draw_image.filter_quality());
261
262 // We are being called during raster. The context lock must already be
263 // acquired by the caller.
264 context_->GetLock()->AssertAcquired();
vmpstr 2016/03/28 23:55:52 Since we have public functions that need context l
ericrk 2016/03/29 23:11:29 I agree.
265 base::AutoLock lock(lock_);
266
267 const uint32_t unique_id = draw_image.image()->uniqueID();
268 auto found = image_data_.Peek(unique_id);
269 if (found == image_data_.end()) {
270 // We didn't find the image, we are doing at-raster decode.
vmpstr 2016/03/28 23:55:53 Is it possible that the raster task started runnin
ericrk 2016/03/29 23:11:29 Going to just always assume at-raster here.
271 auto data = CreateImageData(draw_image);
272 data->is_at_raster = true;
273 DCHECK(!EnsureCapacityWithClassLock(data->size));
vmpstr 2016/03/28 23:55:52 I'm not sure if I asked you to add this, but since
ericrk 2016/03/29 23:11:30 Removed this, it works fine either way. We can inv
274
275 // Increment |bytes_used_| to reserve room for the pending image. As there
276 // is no |image| created yet, mark the data as |pending|.
277 bytes_used_ += data->size;
vmpstr 2016/03/28 23:55:53 This is a little bit questionable for me. If this
ericrk 2016/03/29 23:11:30 Ah, fair point... I think a lot of stuff gets easi
278 data->upload.pending = true;
279
280 found = image_data_.Put(unique_id, std::move(data));
281 }
282
283 // Ref the image and decode so that they stay alive while we are
284 // decoding/uploading.
285 RefImageWithClassLock(draw_image);
286 RefImageDecodeWithClassLock(draw_image);
287
288 // We may or may not need to decode and upload the image we've found, the
289 // following functions early-out to if we already decoded.
290 DecodeImageIfNecessaryWithClassLock(draw_image, found->second.get());
291 UploadImageIfNecessaryWithClassAndContextLock(draw_image,
292 found->second.get());
293 // Unref the image decode, but not the image. The image ref will be released
294 // in DrawWithImageFinished.
295 UnrefImageDecodeWithClassLock(draw_image);
296
297 SkImage* image = found->second->upload.image.get();
298 DCHECK(image);
299
300 DecodedDrawImage decoded_draw_image(image, draw_image.filter_quality());
301 decoded_draw_image.set_at_raster_decode(found->second->is_at_raster);
302 return decoded_draw_image;
303 }
304
305 void GpuImageDecodeController::DrawWithImageFinished(
306 const DrawImage& draw_image,
307 const DecodedDrawImage& decoded_draw_image) {
308 if (SkipImage(draw_image))
309 return;
310
311 base::AutoLock lock(lock_);
312 UnrefImageWithClassLock(draw_image);
313
314 // We are mid-draw and holding the context lock, ensure we clean up any
315 // textures (especially at-raster), which may have just been marked for
316 // deletion by UnrefImage.
317 DeletePendingImagesWithClassAndContextLock();
318 }
319
320 void GpuImageDecodeController::ReduceCacheUsage() {
321 base::AutoLock lock(lock_);
322 EnsureCapacityWithClassLock(0);
323 }
324
325 void GpuImageDecodeController::DecodeImage(const DrawImage& draw_image) {
326 base::AutoLock lock(lock_);
327 auto found = image_data_.Peek(draw_image.image()->uniqueID());
328 DCHECK(found != image_data_.end());
329 DCHECK(!found->second->is_at_raster);
330 DecodeImageIfNecessaryWithClassLock(draw_image, found->second.get());
331 }
332
333 void GpuImageDecodeController::UploadImage(const DrawImage& draw_image) {
334 ContextProvider::ScopedContextLock context_lock(context_);
335 base::AutoLock lock(lock_);
336 auto found = image_data_.Peek(draw_image.image()->uniqueID());
337 DCHECK(found != image_data_.end());
338 DCHECK(!found->second->is_at_raster);
339
340 UploadImageIfNecessaryWithClassAndContextLock(draw_image,
341 found->second.get());
342 }
343
344 void GpuImageDecodeController::DecodeTaskCompleted(
345 const DrawImage& draw_image) {
346 base::AutoLock lock(lock_);
347 // Decode task is complete, remove it from our list of pending tasks.
348 pending_image_decode_tasks_.erase(draw_image.image()->uniqueID());
349
350 // While the decode task is active, we keep a ref on the decoded data.
351 // Release that ref now that the decode is completed.
352 UnrefImageDecodeWithClassLock(draw_image);
353 }
354
355 void GpuImageDecodeController::UploadTaskCompleted(
356 const DrawImage& draw_image) {
357 base::AutoLock lock(lock_);
358 const uint32_t image_id = draw_image.image()->uniqueID();
359 // Upload task is complete, remove it from our list of pending tasks.
360 pending_image_upload_tasks_.erase(image_id);
361
362 // If the image was never uploaded (|pending| is true), we need to subtract
363 // the pending bytes.
vmpstr 2016/03/28 23:55:52 Otherwise, I guess the bytes are still accounted f
ericrk 2016/03/29 23:11:30 Moved all memory tracking to RefCountChanged/Ensur
364 auto found = image_data_.Peek(image_id);
365 DCHECK(found != image_data_.end());
366 if (found->second->upload.pending) {
367 bytes_used_ -= found->second->size;
368 found->second->upload.pending = false;
369 }
370
371 // While the upload task is active, we keep a ref on both the image it will be
372 // populating, as well as the decode it needs to populate it. Release these
373 // refs now.
374 UnrefImageDecodeWithClassLock(draw_image);
375 UnrefImageWithClassLock(draw_image);
376 }
377
378 // Checks if an existing image decode exists. If not, returns a task to produce
vmpstr 2016/03/28 23:55:53 I guess normally it's not possible that we're tryi
ericrk 2016/03/29 23:11:30 We create this when we create the upload task - so
379 // the requested decode.
380 scoped_refptr<ImageDecodeTask>
381 GpuImageDecodeController::GetImageDecodeTaskAndRefWithClassLock(
382 const DrawImage& draw_image,
383 uint64_t prepare_tiles_id) {
384 lock_.AssertAcquired();
385 uint32_t image_id = draw_image.image()->uniqueID();
386 // This ref is kept alive while an upload task may need this decode. We
387 // release this ref in UploadTaskCompleted.
388 RefImageDecodeWithClassLock(draw_image);
389
390 auto found = image_data_.Peek(image_id);
391 if (found != image_data_.end() && found->second->decode.is_locked) {
392 // We should never be creating a decode task for an at raster image.
393 DCHECK(!found->second->is_at_raster);
394 // We should never be creating a decode for an already-uploaded image.
395 DCHECK(!found->second->upload.image);
396 return nullptr;
397 }
398
399 scoped_refptr<ImageDecodeTask>& existing_task =
400 pending_image_decode_tasks_[image_id];
67 if (!existing_task) { 401 if (!existing_task) {
402 // Ref image and create a decode task. This ref will be released in
403 // DecodeTaskCompleted.
404 RefImageDecodeWithClassLock(draw_image);
68 existing_task = make_scoped_refptr( 405 existing_task = make_scoped_refptr(
69 new ImageDecodeTaskImpl(this, image, prepare_tiles_id)); 406 new ImageDecodeTaskImpl(this, draw_image, prepare_tiles_id));
70 } 407 }
71 *task = existing_task; 408 return existing_task;
409 }
410
411 void GpuImageDecodeController::RefImageDecodeWithClassLock(
412 const DrawImage& draw_image) {
413 lock_.AssertAcquired();
414 auto found = image_data_.Peek(draw_image.image()->uniqueID());
415 DCHECK(found != image_data_.end());
416 // Sanity-check our ref-count.
417 DCHECK_GE(found->second->decode.ref_count, 0u);
418 ++found->second->decode.ref_count;
419 }
420
421 void GpuImageDecodeController::UnrefImageDecodeWithClassLock(
422 const DrawImage& draw_image) {
423 lock_.AssertAcquired();
424 auto found = image_data_.Peek(draw_image.image()->uniqueID());
425 DCHECK(found != image_data_.end());
426 DCHECK_GT(found->second->decode.ref_count, 0u);
427 --found->second->decode.ref_count;
428 if (found->second->decode.ref_count == 0) {
429 if (found->second->decode.is_locked) {
430 found->second->decode.is_locked = false;
431 found->second->decode.data->Unlock();
432 }
433 EnsureCapacityWithClassLock(0);
434 }
435 }
436
437 void GpuImageDecodeController::RefImageWithClassLock(
438 const DrawImage& draw_image) {
439 lock_.AssertAcquired();
440 auto image_id = draw_image.image()->uniqueID();
441 auto found = image_data_.Peek(image_id);
442 DCHECK(found != image_data_.end());
443 ++found->second->upload.ref_count;
444 }
445
446 void GpuImageDecodeController::UnrefImageWithClassLock(
447 const DrawImage& draw_image) {
448 lock_.AssertAcquired();
449 auto image_id = draw_image.image()->uniqueID();
450 auto found = image_data_.Peek(image_id);
451 DCHECK(found != image_data_.end());
452 DCHECK_GT(found->second->upload.ref_count, 0u);
453 --found->second->upload.ref_count;
454 if (found->second->upload.ref_count == 0) {
455 // If the ref count has reached 0, the image should no longer be pending.
456 DCHECK(!found->second->upload.pending);
457
458 // If this image was created as at-raster, it may now fit into the cache.
459 // If so, we'd like to convert it to non-at-raster. Otherwise we'd like to
460 // delete the image.
461 //
462 // We can handle both cases by converting the image into non-at-raster and
463 // then calling EnsureCapacityWithClassLock. If the image now fits,
464 // EnsureCapacityWithClassLock will leave it in the cache, otherwise it
465 // will be removed (independent of the at-raster flag).
466 found->second->is_at_raster = false;
467 EnsureCapacityWithClassLock(0);
468 }
469 }
470
471 // Ensures that we can fit a new image of size |required_size| in our cache. In
472 // doing so, this function will free unreferenced image data as necessary to
473 // create rooom.
474 bool GpuImageDecodeController::EnsureCapacityWithClassLock(
475 size_t required_size) {
476 lock_.AssertAcquired();
477 const size_t new_elements = required_size ? 1 : 0;
478 if (CanFitSizeWithClassLock(required_size) &&
479 CanFitCountWithClassLock(new_elements))
480 return true;
481
482 // While we are over memory or item capacity, we iterate through our set of
483 // cached image data in LRU order. For each image, we can do two things:
484 // 1) We can free the uploaded image, reducing the memory usage of the cache
485 // and 2) we can remove the entry entirely, reducing the count of elements in
486 // the cache.
487 for (auto it = image_data_.rbegin(); it != image_data_.rend();) {
488 if (it->second->decode.ref_count != 0 ||
489 it->second->upload.ref_count != 0) {
490 ++it;
491 continue;
492 }
493
494 // Current entry has no refs. Ensure it is not locked or pending.
495 DCHECK(!it->second->decode.is_locked);
496 DCHECK(!it->second->upload.pending);
497
498 // Free the uploaded image if possible.
499 if (it->second->upload.image) {
500 DCHECK_GE(bytes_used_, it->second->size);
501 bytes_used_ -= it->second->size;
502 images_pending_deletion_.push_back(std::move(it->second->upload.image));
503 it->second->upload.image = nullptr;
504 }
505
506 // Free the entire entry if necessary.
507 if (!CanFitCountWithClassLock(new_elements)) {
508 it = image_data_.Erase(it);
509 } else {
510 ++it;
511 }
512
513 if (CanFitSizeWithClassLock(required_size) &&
514 CanFitCountWithClassLock(new_elements))
515 return true;
516 }
517
518 // We couldn't reach a state where we are under our memory / count limits.
72 return false; 519 return false;
73 } 520 }
74 521
75 void GpuImageDecodeController::UnrefImage(const DrawImage& image) { 522 bool GpuImageDecodeController::CanFitSizeWithClassLock(size_t size) const {
76 NOTREACHED(); 523 return bytes_used_ + size <= cached_bytes_limit_;
vmpstr 2016/03/28 23:55:52 There's a possible overflow here which would erron
ericrk 2016/03/29 23:11:30 Added safe math. This function is used to gate all
77 } 524 }
78 525
79 DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw( 526 bool GpuImageDecodeController::CanFitCountWithClassLock(
80 const DrawImage& draw_image) { 527 size_t num_elements) const {
81 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality()); 528 return image_data_.size() + num_elements <= cached_items_limit_;
82 } 529 }
83 530
84 void GpuImageDecodeController::DrawWithImageFinished( 531 void GpuImageDecodeController::DecodeImageIfNecessaryWithClassLock(
85 const DrawImage& image, 532 const DrawImage& draw_image,
86 const DecodedDrawImage& decoded_image) {} 533 ImageData* image_data) {
87 534 lock_.AssertAcquired();
88 void GpuImageDecodeController::ReduceCacheUsage() {} 535
89 536 if (image_data->upload.image) {
90 void GpuImageDecodeController::DecodeImage(const DrawImage& image) { 537 // We already have an uploaded image, no reason to decode.
91 image.image()->preroll(); 538 return;
92 base::AutoLock lock(lock_); 539 }
93 prerolled_images_.insert(image.image()->uniqueID()); 540
94 } 541 if (image_data->decode.data &&
95 542 (image_data->decode.is_locked || image_data->decode.data->Lock())) {
96 void GpuImageDecodeController::RemovePendingTaskForImage( 543 // We already decoded this, or we just needed to lock, early out.
97 const DrawImage& image) { 544 image_data->decode.is_locked = true;
98 base::AutoLock lock(lock_); 545 return;
99 pending_image_tasks_.erase(image.image()->uniqueID()); 546 }
547
548 TRACE_EVENT0("cc", "GpuImageDecodeController::DecodeImage");
549 DCHECK_GT(image_data->decode.ref_count, 0u);
550
551 image_data->decode.data = nullptr;
552 scoped_ptr<base::DiscardableMemory> backing_memory;
553 {
554 base::AutoUnlock unlock(lock_);
555 switch (image_data->mode) {
556 case DecodedDataMode::CPU: {
557 backing_memory =
558 base::DiscardableMemoryAllocator::GetInstance()
559 ->AllocateLockedDiscardableMemory(image_data->size);
560 SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image);
561 if (!draw_image.image()->readPixels(image_info, backing_memory->data(),
562 image_info.minRowBytes(), 0, 0,
563 SkImage::kDisallow_CachingHint)) {
564 backing_memory->Unlock();
565 return;
566 }
567 break;
568 }
569 case DecodedDataMode::GPU: {
570 backing_memory =
571 base::DiscardableMemoryAllocator::GetInstance()
572 ->AllocateLockedDiscardableMemory(image_data->size);
573 auto params = ParamsFromDrawImage(draw_image);
574 if (!draw_image.image()->getDeferredTextureImageData(
575 *context_threadsafe_proxy_, &params, 1,
576 backing_memory->data())) {
577 backing_memory->Unlock();
578 return;
579 }
580 break;
581 }
582 }
583 }
584
585 if (!image_data->decode.data) {
vmiura 2016/03/29 01:33:17 Can this be unconditional, since image_data->decod
ericrk 2016/03/29 23:11:30 Not in this case, as we unlock during the actual d
586 image_data->decode.data = std::move(backing_memory);
587 DCHECK(!image_data->decode.is_locked);
588 image_data->decode.is_locked = true;
589 }
590 }
591
592 void GpuImageDecodeController::UploadImageIfNecessaryWithClassAndContextLock(
593 const DrawImage& draw_image,
594 ImageData* image_data) {
595 context_->GetLock()->AssertAcquired();
596 lock_.AssertAcquired();
597
598 if (image_data->upload.image) {
599 // Someone has uploaded this image before us (at raster).
600 return;
601 }
602
603 TRACE_EVENT0("cc", "GpuImageDecodeController::UploadImage");
604 DCHECK(image_data->decode.is_locked);
605 DCHECK_GT(image_data->decode.ref_count, 0u);
606 DCHECK_GT(image_data->upload.ref_count, 0u);
607
608 // We are about to upload a new image and are holding the context lock.
609 // Ensure that any images which have been marked for deletion are actually
610 // cleaned up so we don't exceed our memory limit during this upload.
611 DeletePendingImagesWithClassAndContextLock();
612
613 skia::RefPtr<SkImage> uploaded_image;
614 {
615 base::AutoUnlock unlock(lock_);
616 switch (image_data->mode) {
617 case DecodedDataMode::CPU: {
618 SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image);
619 uploaded_image = skia::AdoptRef(SkImage::NewFromRaster(
620 image_info, image_data->decode.data->data(),
621 image_info.minRowBytes(), [](const void*, void*) {}, nullptr));
622 break;
623 }
624 case DecodedDataMode::GPU: {
625 uploaded_image =
626 skia::AdoptRef(SkImage::NewFromDeferredTextureImageData(
627 context_->GrContext(), image_data->decode.data->data(),
628 SkBudgeted::kNo));
629 break;
630 }
631 }
632 }
633 DCHECK(uploaded_image);
634
635 // At-raster may have decoded this while we were unlocked. If so, ignore our
636 // result.
637 if (!image_data->upload.image) {
638 image_data->upload.image = std::move(uploaded_image);
639 DCHECK(image_data->upload.pending);
640 image_data->upload.pending = false;
641 }
642 }
643
644 scoped_ptr<GpuImageDecodeController::ImageData>
645 GpuImageDecodeController::CreateImageData(const DrawImage& draw_image) {
646 DecodedDataMode mode;
647 SkImageInfo info = CreateImageInfoForDrawImage(draw_image);
648 SkImage::DeferredTextureImageUsageParams params =
649 ParamsFromDrawImage(draw_image);
650 size_t data_size = draw_image.image()->getDeferredTextureImageData(
651 *context_threadsafe_proxy_, &params, 1, nullptr);
652
653 if (data_size == 0) {
654 // Can't upload image, too large or other failure. Try to use SW fallback.
655 data_size = info.getSafeSize(info.minRowBytes());
656 mode = DecodedDataMode::CPU;
657 } else {
658 mode = DecodedDataMode::GPU;
659 }
660
661 return make_scoped_ptr(new ImageData(mode, data_size));
662 }
663
664 void GpuImageDecodeController::DeletePendingImagesWithClassAndContextLock() {
665 context_->GetLock()->AssertAcquired();
666 lock_.AssertAcquired();
667 images_pending_deletion_.clear();
668 }
669
670 SkImageInfo GpuImageDecodeController::CreateImageInfoForDrawImage(
671 const DrawImage& draw_image) const {
672 return SkImageInfo::Make(
673 draw_image.image()->width(), draw_image.image()->height(),
674 ResourceFormatToClosestSkColorType(format_), kPremul_SkAlphaType);
100 } 675 }
101 676
102 } // namespace cc 677 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698