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

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

Issue 1682803003: cc: ImageDecodes: handle low quality filters. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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
« no previous file with comments | « cc/tiles/image_decode_controller.h ('k') | cc/tiles/image_decode_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/image_decode_controller.h" 5 #include "cc/tiles/image_decode_controller.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <functional>
10
9 #include "base/macros.h" 11 #include "base/macros.h"
10 #include "base/memory/discardable_memory.h" 12 #include "base/memory/discardable_memory.h"
11 #include "cc/debug/devtools_instrumentation.h" 13 #include "cc/debug/devtools_instrumentation.h"
12 #include "third_party/skia/include/core/SkCanvas.h" 14 #include "third_party/skia/include/core/SkCanvas.h"
13 #include "third_party/skia/include/core/SkImage.h" 15 #include "third_party/skia/include/core/SkImage.h"
14 #include "ui/gfx/skia_util.h" 16 #include "ui/gfx/skia_util.h"
15 17
16 namespace cc { 18 namespace cc {
17 namespace { 19 namespace {
18 20
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 73
72 template <typename Type> 74 template <typename Type>
73 typename std::deque<Type>::iterator FindImage( 75 typename std::deque<Type>::iterator FindImage(
74 std::deque<Type>* collection, 76 std::deque<Type>* collection,
75 const ImageDecodeControllerKey& key) { 77 const ImageDecodeControllerKey& key) {
76 return std::find_if(collection->begin(), collection->end(), 78 return std::find_if(collection->begin(), collection->end(),
77 [key](const Type& image) { return image.first == key; }); 79 [key](const Type& image) { return image.first == key; });
78 } 80 }
79 81
80 SkSize GetScaleAdjustment(const ImageDecodeControllerKey& key) { 82 SkSize GetScaleAdjustment(const ImageDecodeControllerKey& key) {
83 // If the requested filter quality did not require scale, then the adjustment
84 // is identity. Note that we still might have extracted a subrect, so
85 // can_use_original_decode is not a sufficient check.
86 if (key.filter_quality() == kLow_SkFilterQuality ||
87 key.filter_quality() == kNone_SkFilterQuality) {
88 return SkSize::Make(1.f, 1.f);
89 }
90
81 float x_scale = 91 float x_scale =
82 key.target_size().width() / static_cast<float>(key.src_rect().width()); 92 key.target_size().width() / static_cast<float>(key.src_rect().width());
83 float y_scale = 93 float y_scale =
84 key.target_size().height() / static_cast<float>(key.src_rect().height()); 94 key.target_size().height() / static_cast<float>(key.src_rect().height());
85 return SkSize::Make(x_scale, y_scale); 95 return SkSize::Make(x_scale, y_scale);
86 } 96 }
87 97
98 SkFilterQuality GetDecodedFilterQuality(const ImageDecodeControllerKey& key) {
99 return std::min(key.filter_quality(), kLow_SkFilterQuality);
100 }
101
88 } // namespace 102 } // namespace
89 103
90 ImageDecodeController::ImageDecodeController() 104 ImageDecodeController::ImageDecodeController()
91 : is_using_gpu_rasterization_(false), 105 : is_using_gpu_rasterization_(false),
92 locked_images_budget_(kLockedMemoryLimitBytes) {} 106 locked_images_budget_(kLockedMemoryLimitBytes) {}
93 107
94 ImageDecodeController::~ImageDecodeController() { 108 ImageDecodeController::~ImageDecodeController() {
95 DCHECK_EQ(0u, decoded_images_ref_counts_.size()); 109 DCHECK_EQ(0u, decoded_images_ref_counts_.size());
96 DCHECK_EQ(0u, at_raster_decoded_images_ref_counts_.size()); 110 DCHECK_EQ(0u, at_raster_decoded_images_ref_counts_.size());
97 } 111 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 *task = nullptr; 150 *task = nullptr;
137 } 151 }
138 return false; 152 return false;
139 } 153 }
140 154
141 base::AutoLock lock(lock_); 155 base::AutoLock lock(lock_);
142 156
143 // If we already have the image in cache, then we can return it. 157 // If we already have the image in cache, then we can return it.
144 auto decoded_it = FindImage(&decoded_images_, key); 158 auto decoded_it = FindImage(&decoded_images_, key);
145 bool new_image_fits_in_memory = 159 bool new_image_fits_in_memory =
146 locked_images_budget_.AvailableMemoryBytes() >= key.target_bytes(); 160 locked_images_budget_.AvailableMemoryBytes() >= key.locked_bytes();
147 if (decoded_it != decoded_images_.end()) { 161 if (decoded_it != decoded_images_.end()) {
148 if (decoded_it->second->is_locked() || 162 if (decoded_it->second->is_locked() ||
149 (new_image_fits_in_memory && decoded_it->second->Lock())) { 163 (new_image_fits_in_memory && decoded_it->second->Lock())) {
150 RefImage(key); 164 RefImage(key);
151 *task = nullptr; 165 *task = nullptr;
152 SanityCheckState(__LINE__, true); 166 SanityCheckState(__LINE__, true);
153 return true; 167 return true;
154 } 168 }
155 // If the image fits in memory, then we at least tried to lock it and 169 // If the image fits in memory, then we at least tried to lock it and
156 // failed. This means that it's not valid anymore. 170 // failed. This means that it's not valid anymore.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 SanityCheckState(__LINE__, true); 202 SanityCheckState(__LINE__, true);
189 return true; 203 return true;
190 } 204 }
191 205
192 void ImageDecodeController::RefImage(const ImageKey& key) { 206 void ImageDecodeController::RefImage(const ImageKey& key) {
193 TRACE_EVENT1("disabled-by-default-cc.debug", 207 TRACE_EVENT1("disabled-by-default-cc.debug",
194 "ImageDecodeController::RefImage", "key", key.ToString()); 208 "ImageDecodeController::RefImage", "key", key.ToString());
195 lock_.AssertAcquired(); 209 lock_.AssertAcquired();
196 int ref = ++decoded_images_ref_counts_[key]; 210 int ref = ++decoded_images_ref_counts_[key];
197 if (ref == 1) { 211 if (ref == 1) {
198 DCHECK_GE(locked_images_budget_.AvailableMemoryBytes(), key.target_bytes()); 212 DCHECK_GE(locked_images_budget_.AvailableMemoryBytes(), key.locked_bytes());
199 locked_images_budget_.AddUsage(key.target_bytes()); 213 locked_images_budget_.AddUsage(key.locked_bytes());
200 } 214 }
201 } 215 }
202 216
203 void ImageDecodeController::UnrefImage(const DrawImage& image) { 217 void ImageDecodeController::UnrefImage(const DrawImage& image) {
204 // When we unref the image, there are several situations we need to consider: 218 // When we unref the image, there are several situations we need to consider:
205 // 1. The ref did not reach 0, which means we have to keep the image locked. 219 // 1. The ref did not reach 0, which means we have to keep the image locked.
206 // 2. The ref reached 0, we should unlock it. 220 // 2. The ref reached 0, we should unlock it.
207 // 2a. The image isn't in the locked cache because we didn't get to decode 221 // 2a. The image isn't in the locked cache because we didn't get to decode
208 // it yet (or failed to decode it). 222 // it yet (or failed to decode it).
209 // 2b. Unlock the image but keep it in list. 223 // 2b. Unlock the image but keep it in list.
210 const ImageKey& key = ImageKey::FromDrawImage(image); 224 const ImageKey& key = ImageKey::FromDrawImage(image);
211 DCHECK(CanHandleImage(key, image)); 225 DCHECK(CanHandleImage(key, image));
212 TRACE_EVENT1("disabled-by-default-cc.debug", 226 TRACE_EVENT1("disabled-by-default-cc.debug",
213 "ImageDecodeController::UnrefImage", "key", key.ToString()); 227 "ImageDecodeController::UnrefImage", "key", key.ToString());
214 228
215 base::AutoLock lock(lock_); 229 base::AutoLock lock(lock_);
216 auto ref_count_it = decoded_images_ref_counts_.find(key); 230 auto ref_count_it = decoded_images_ref_counts_.find(key);
217 DCHECK(ref_count_it != decoded_images_ref_counts_.end()); 231 DCHECK(ref_count_it != decoded_images_ref_counts_.end());
218 232
219 --ref_count_it->second; 233 --ref_count_it->second;
220 if (ref_count_it->second == 0) { 234 if (ref_count_it->second == 0) {
221 decoded_images_ref_counts_.erase(ref_count_it); 235 decoded_images_ref_counts_.erase(ref_count_it);
222 locked_images_budget_.SubtractUsage(key.target_bytes()); 236 locked_images_budget_.SubtractUsage(key.locked_bytes());
223 237
224 auto decoded_image_it = FindImage(&decoded_images_, key); 238 auto decoded_image_it = FindImage(&decoded_images_, key);
225 // If we've never decoded the image before ref reached 0, then we wouldn't 239 // If we've never decoded the image before ref reached 0, then we wouldn't
226 // have it in our cache. This would happen if we canceled tasks. 240 // have it in our cache. This would happen if we canceled tasks.
227 if (decoded_image_it == decoded_images_.end()) { 241 if (decoded_image_it == decoded_images_.end()) {
228 SanityCheckState(__LINE__, true); 242 SanityCheckState(__LINE__, true);
229 return; 243 return;
230 } 244 }
231 DCHECK(decoded_image_it->second->is_locked()); 245 DCHECK(decoded_image_it->second->is_locked());
232 decoded_image_it->second->Unlock(); 246 decoded_image_it->second->Unlock();
(...skipping 26 matching lines...) Expand all
259 if (image_it->second->is_locked() || image_it->second->Lock()) { 273 if (image_it->second->is_locked() || image_it->second->Lock()) {
260 pending_image_tasks_.erase(key); 274 pending_image_tasks_.erase(key);
261 return; 275 return;
262 } 276 }
263 decoded_images_.erase(image_it); 277 decoded_images_.erase(image_it);
264 } 278 }
265 279
266 scoped_refptr<DecodedImage> decoded_image; 280 scoped_refptr<DecodedImage> decoded_image;
267 { 281 {
268 base::AutoUnlock unlock(lock_); 282 base::AutoUnlock unlock(lock_);
269 decoded_image = DecodeImageInternal(key, image.image()); 283 decoded_image = DecodeImageInternal(key, image);
270 } 284 }
271 285
272 // Erase the pending task from the queue, since the task won't be doing 286 // Erase the pending task from the queue, since the task won't be doing
273 // anything useful after this function terminates. That is, if this image 287 // anything useful after this function terminates. That is, if this image
274 // needs to be decoded again, we have to create a new task. 288 // needs to be decoded again, we have to create a new task.
275 pending_image_tasks_.erase(key); 289 pending_image_tasks_.erase(key);
276 290
277 // Abort if we failed to decode the image. 291 // Abort if we failed to decode the image.
278 if (!decoded_image) 292 if (!decoded_image)
279 return; 293 return;
(...skipping 19 matching lines...) Expand all
299 decoded_images_ref_counts_.end()) { 313 decoded_images_ref_counts_.end()) {
300 decoded_image->Unlock(); 314 decoded_image->Unlock();
301 } 315 }
302 316
303 decoded_images_.push_back(AnnotatedDecodedImage(key, decoded_image)); 317 decoded_images_.push_back(AnnotatedDecodedImage(key, decoded_image));
304 SanityCheckState(__LINE__, true); 318 SanityCheckState(__LINE__, true);
305 } 319 }
306 320
307 scoped_refptr<ImageDecodeController::DecodedImage> 321 scoped_refptr<ImageDecodeController::DecodedImage>
308 ImageDecodeController::DecodeImageInternal(const ImageKey& key, 322 ImageDecodeController::DecodeImageInternal(const ImageKey& key,
309 const SkImage* image) { 323 const DrawImage& draw_image) {
310 TRACE_EVENT1("disabled-by-default-cc.debug", 324 TRACE_EVENT1("disabled-by-default-cc.debug",
311 "ImageDecodeController::DecodeImageInternal", "key", 325 "ImageDecodeController::DecodeImageInternal", "key",
312 key.ToString()); 326 key.ToString());
327 const SkImage* image = draw_image.image();
313 328
314 // Get the decoded image first (at the original scale). 329 // If we can use the original decode, then we don't need to do scaling. We can
315 SkImageInfo decoded_info = SkImageInfo::MakeN32Premul( 330 // just read pixels into the final memory.
316 key.src_rect().width(), key.src_rect().height()); 331 if (key.can_use_original_decode()) {
317 scoped_ptr<uint8_t[]> decoded_pixels; 332 SkImageInfo decoded_info =
318 { 333 SkImageInfo::MakeN32Premul(image->width(), image->height());
319 TRACE_EVENT0( 334 scoped_ptr<base::DiscardableMemory> decoded_pixels;
320 "disabled-by-default-cc.debug", 335 {
321 "ImageDecodeController::DecodeImageInternal - allocate decoded pixels"); 336 TRACE_EVENT0("disabled-by-default-cc.debug",
322 decoded_pixels.reset( 337 "ImageDecodeController::DecodeImageInternal - allocate "
323 new uint8_t[decoded_info.minRowBytes() * decoded_info.height()]); 338 "decoded pixels");
324 } 339 decoded_pixels =
325 { 340 base::DiscardableMemoryAllocator::GetInstance()
326 TRACE_EVENT0("disabled-by-default-cc.debug", 341 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() *
327 "ImageDecodeController::DecodeImageInternal - read pixels"); 342 decoded_info.height());
328 bool result = image->readPixels( 343 }
329 decoded_info, decoded_pixels.get(), decoded_info.minRowBytes(), 344 {
330 key.src_rect().x(), key.src_rect().y(), SkImage::kAllow_CachingHint); 345 TRACE_EVENT0("disabled-by-default-cc.debug",
346 "ImageDecodeController::DecodeImageInternal - read pixels");
347 bool result = image->readPixels(decoded_info, decoded_pixels->data(),
348 decoded_info.minRowBytes(), 0, 0,
349 SkImage::kDisallow_CachingHint);
331 350
332 if (!result) 351 if (!result) {
333 return nullptr; 352 decoded_pixels->Unlock();
353 return nullptr;
354 }
355 }
356
357 return make_scoped_refptr(new DecodedImage(
358 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0)));
334 } 359 }
335 360
336 SkPixmap decoded_pixmap(decoded_info, decoded_pixels.get(), 361 // If we get here, that means we couldn't use the original sized decode for
337 decoded_info.minRowBytes()); 362 // whatever reason. However, in all cases we do need an original decode to
363 // either do a scale or to extract a subrect from the image. So, what we can
364 // do is construct a key that would require a full sized decode, then get that
365 // decode via GetDecodedImageForDrawInternal(), use it, and unref it. This
366 // ensures that if the original sized decode is already available in any of
367 // the caches, we reuse that. We also ensure that all the proper locking takes
368 // place. If, on the other hand, the decode was not available,
369 // GetDecodedImageForDrawInternal() would decode the image, and unreffing it
370 // later ensures that we will store the discardable memory unlocked in the
371 // cache to be used by future requests.
372 SkSize identity_scale = SkSize::Make(1.f, 1.f);
373 bool matrix_has_perspective = false;
374 bool matrix_is_decomposable = true;
375 gfx::Rect full_image_rect(image->width(), image->height());
376 DrawImage original_size_draw_image(
377 image, gfx::RectToSkIRect(full_image_rect), identity_scale,
378 kNone_SkFilterQuality, matrix_has_perspective, matrix_is_decomposable);
379 ImageKey original_size_key =
380 ImageKey::FromDrawImage(original_size_draw_image);
381 // Sanity checks.
382 DCHECK(original_size_key.can_use_original_decode());
383 DCHECK(full_image_rect.size() == original_size_key.target_size());
338 384
339 // Now scale the pixels into the destination size. 385 auto decoded_draw_image = GetDecodedImageForDrawInternal(
386 original_size_key, original_size_draw_image);
387 if (!decoded_draw_image.image()) {
388 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
389 return nullptr;
390 }
391
392 scoped_ptr<uint8_t[]> decoded_subrect_pixels;
393 SkPixmap decoded_pixmap;
394 bool result;
395 if (key.src_rect() == full_image_rect) {
396 result = decoded_draw_image.image()->peekPixels(&decoded_pixmap);
397 } else if (key.filter_quality() != kNone_SkFilterQuality &&
398 key.filter_quality() != kLow_SkFilterQuality) {
399 SkImageInfo decoded_info = SkImageInfo::MakeN32Premul(
400 key.src_rect().width(), key.src_rect().height());
401 {
402 TRACE_EVENT0("disabled-by-default-cc.debug",
403 "ImageDecodeController::DecodeImageInternal - allocate "
404 "decoded pixels");
405 decoded_subrect_pixels.reset(
406 new uint8_t[decoded_info.minRowBytes() * decoded_info.height()]);
407 }
408 {
409 TRACE_EVENT0("disabled-by-default-cc.debug",
410 "ImageDecodeController::DecodeImageInternal - read pixels");
411 result =
412 image->readPixels(decoded_info, decoded_subrect_pixels.get(),
413 decoded_info.minRowBytes(), key.src_rect().x(),
414 key.src_rect().y(), SkImage::kDisallow_CachingHint);
415 }
416 decoded_pixmap = SkPixmap(decoded_info, decoded_subrect_pixels.get(),
417 decoded_info.minRowBytes());
418 } else {
419 // In a low and none filter quality cases if we need a subrect, we need to
420 // extract it but then we don't need to scale it.
421 SkImageInfo decoded_info = SkImageInfo::MakeN32Premul(
422 key.src_rect().width(), key.src_rect().height());
423 scoped_ptr<base::DiscardableMemory> discardable_subrect_pixels;
424 {
425 TRACE_EVENT0("disabled-by-default-cc.debug",
426 "ImageDecodeController::DecodeImageInternal - allocate "
427 "discardable subrect pixels");
428 discardable_subrect_pixels =
429 base::DiscardableMemoryAllocator::GetInstance()
430 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() *
431 decoded_info.height());
432 }
433 {
434 TRACE_EVENT0(
435 "disabled-by-default-cc.debug",
436 "ImageDecodeController::DecodeImageInternal - read subrect pixels");
437 result =
438 image->readPixels(decoded_info, discardable_subrect_pixels->data(),
439 decoded_info.minRowBytes(), key.src_rect().x(),
440 key.src_rect().y(), SkImage::kDisallow_CachingHint);
441 }
442 DCHECK(result);
443 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
444 return make_scoped_refptr(new DecodedImage(
445 decoded_info, std::move(discardable_subrect_pixels),
446 SkSize::Make(-key.src_rect().x(), -key.src_rect().y())));
447 }
448
449 // Since the decoded_draw_image has locked memory, it should always succeed on
450 // both peekPixels and readPixels.
451 DCHECK(result);
452
453 // Now we have a decoded_pixmap which represents the src_rect at the
454 // original
455 // scale. All we need to do is scale it.
340 DCHECK(!key.target_size().IsEmpty()); 456 DCHECK(!key.target_size().IsEmpty());
341 SkImageInfo scaled_info = SkImageInfo::MakeN32Premul( 457 SkImageInfo scaled_info = SkImageInfo::MakeN32Premul(
342 key.target_size().width(), key.target_size().height()); 458 key.target_size().width(), key.target_size().height());
343 scoped_ptr<base::DiscardableMemory> scaled_pixels; 459 scoped_ptr<base::DiscardableMemory> scaled_pixels;
344 { 460 {
345 TRACE_EVENT0( 461 TRACE_EVENT0("disabled-by-default-cc.debug",
346 "disabled-by-default-cc.debug", 462 "ImageDecodeController::DecodeImageInternal - allocate "
347 "ImageDecodeController::DecodeImageInternal - allocate scaled pixels"); 463 "scaled pixels");
348 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() 464 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance()
349 ->AllocateLockedDiscardableMemory( 465 ->AllocateLockedDiscardableMemory(
350 scaled_info.minRowBytes() * scaled_info.height()); 466 scaled_info.minRowBytes() * scaled_info.height());
351 } 467 }
352 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), 468 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(),
353 scaled_info.minRowBytes()); 469 scaled_info.minRowBytes());
354 // TODO(vmpstr): Start handling more than just high filter quality. 470 // TODO(vmpstr): Start handling more than just high filter quality.
355 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); 471 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality());
356 { 472 {
357 TRACE_EVENT0("disabled-by-default-cc.debug", 473 TRACE_EVENT0("disabled-by-default-cc.debug",
358 "ImageDecodeController::DecodeImageInternal - scale pixels"); 474 "ImageDecodeController::DecodeImageInternal - scale pixels");
359 bool result = 475 bool result =
360 decoded_pixmap.scalePixels(scaled_pixmap, kHigh_SkFilterQuality); 476 decoded_pixmap.scalePixels(scaled_pixmap, key.filter_quality());
361 DCHECK(result); 477 DCHECK(result);
362 } 478 }
479
480 // Release the original sized decode. Any other intermediate result to release
481 // would be the subrect memory. However, that's in a scoped_ptr and will be
482 // deleted automatically when we return.
483 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
484
363 return make_scoped_refptr( 485 return make_scoped_refptr(
364 new DecodedImage(scaled_info, std::move(scaled_pixels), 486 new DecodedImage(scaled_info, std::move(scaled_pixels),
365 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); 487 SkSize::Make(-key.src_rect().x(), -key.src_rect().y())));
366 } 488 }
367 489
368 DecodedDrawImage ImageDecodeController::GetDecodedImageForDraw( 490 DecodedDrawImage ImageDecodeController::GetDecodedImageForDraw(
369 const DrawImage& draw_image) { 491 const DrawImage& draw_image) {
370 ImageKey key = ImageKey::FromDrawImage(draw_image); 492 ImageKey key = ImageKey::FromDrawImage(draw_image);
371 TRACE_EVENT1("disabled-by-default-cc.debug", 493 TRACE_EVENT1("disabled-by-default-cc.debug",
372 "ImageDecodeController::GetDecodedImageAndRef", "key", 494 "ImageDecodeController::GetDecodedImageForDraw", "key",
373 key.ToString()); 495 key.ToString());
374 // If the target size is empty, we can skip this image draw. 496 // If the target size is empty, we can skip this image draw.
375 if (key.target_size().IsEmpty()) 497 if (key.target_size().IsEmpty())
376 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); 498 return DecodedDrawImage(nullptr, kNone_SkFilterQuality);
377 499
378 if (!CanHandleImage(key, draw_image)) 500 if (!CanHandleImage(key, draw_image))
379 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality()); 501 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality());
380 502
503 return GetDecodedImageForDrawInternal(key, draw_image);
504 }
505
506 DecodedDrawImage ImageDecodeController::GetDecodedImageForDrawInternal(
507 const ImageKey& key,
508 const DrawImage& draw_image) {
509 TRACE_EVENT1("disabled-by-default-cc.debug",
510 "ImageDecodeController::GetDecodedImageForDrawInternal", "key",
511 key.ToString());
381 base::AutoLock lock(lock_); 512 base::AutoLock lock(lock_);
382 auto decoded_images_it = FindImage(&decoded_images_, key); 513 auto decoded_images_it = FindImage(&decoded_images_, key);
383 // If we found the image and it's locked, then return it. If it's not locked, 514 // If we found the image and it's locked, then return it. If it's not locked,
384 // erase it from the cache since it might be put into the at-raster cache. 515 // erase it from the cache since it might be put into the at-raster cache.
385 scoped_refptr<DecodedImage> decoded_image; 516 scoped_refptr<DecodedImage> decoded_image;
386 if (decoded_images_it != decoded_images_.end()) { 517 if (decoded_images_it != decoded_images_.end()) {
387 decoded_image = decoded_images_it->second; 518 decoded_image = decoded_images_it->second;
388 if (decoded_image->is_locked()) { 519 if (decoded_image->is_locked()) {
389 RefImage(key); 520 RefImage(key);
390 SanityCheckState(__LINE__, true); 521 SanityCheckState(__LINE__, true);
391 return DecodedDrawImage(decoded_image->image(), 522 return DecodedDrawImage(
392 decoded_image->src_rect_offset(), 523 decoded_image->image(), decoded_image->src_rect_offset(),
393 GetScaleAdjustment(key), kLow_SkFilterQuality); 524 GetScaleAdjustment(key), GetDecodedFilterQuality(key));
394 } else { 525 } else {
395 decoded_images_.erase(decoded_images_it); 526 decoded_images_.erase(decoded_images_it);
396 } 527 }
397 } 528 }
398 529
399 // See if another thread already decoded this image at raster time. If so, we 530 // See if another thread already decoded this image at raster time. If so, we
400 // can just use that result directly. 531 // can just use that result directly.
401 auto at_raster_images_it = FindImage(&at_raster_decoded_images_, key); 532 auto at_raster_images_it = FindImage(&at_raster_decoded_images_, key);
402 if (at_raster_images_it != at_raster_decoded_images_.end()) { 533 if (at_raster_images_it != at_raster_decoded_images_.end()) {
403 DCHECK(at_raster_images_it->second->is_locked()); 534 DCHECK(at_raster_images_it->second->is_locked());
404 RefAtRasterImage(key); 535 RefAtRasterImage(key);
405 SanityCheckState(__LINE__, true); 536 SanityCheckState(__LINE__, true);
537 const scoped_refptr<DecodedImage>& at_raster_decoded_image =
538 at_raster_images_it->second;
406 auto decoded_draw_image = 539 auto decoded_draw_image =
407 DecodedDrawImage(at_raster_images_it->second->image(), 540 DecodedDrawImage(at_raster_decoded_image->image(),
408 at_raster_images_it->second->src_rect_offset(), 541 at_raster_decoded_image->src_rect_offset(),
409 GetScaleAdjustment(key), kLow_SkFilterQuality); 542 GetScaleAdjustment(key), GetDecodedFilterQuality(key));
410 decoded_draw_image.set_at_raster_decode(true); 543 decoded_draw_image.set_at_raster_decode(true);
411 return decoded_draw_image; 544 return decoded_draw_image;
412 } 545 }
413 546
414 // Now we know that we don't have a locked image, and we seem to be the first 547 // Now we know that we don't have a locked image, and we seem to be the first
415 // thread encountering this image (that might not be true, since other threads 548 // thread encountering this image (that might not be true, since other threads
416 // might be decoding it already). This means that we need to decode the image 549 // might be decoding it already). This means that we need to decode the image
417 // assuming we can't lock the one we found in the cache. 550 // assuming we can't lock the one we found in the cache.
418 bool check_at_raster_cache = false; 551 bool check_at_raster_cache = false;
419 if (!decoded_image || !decoded_image->Lock()) { 552 if (!decoded_image || !decoded_image->Lock()) {
420 // Note that we have to release the lock, since this lock is also accessed 553 // Note that we have to release the lock, since this lock is also accessed
421 // on the compositor thread. This means holding on to the lock might stall 554 // on the compositor thread. This means holding on to the lock might stall
422 // the compositor thread for the duration of the decode! 555 // the compositor thread for the duration of the decode!
423 base::AutoUnlock unlock(lock_); 556 base::AutoUnlock unlock(lock_);
424 decoded_image = DecodeImageInternal(key, draw_image.image()); 557 decoded_image = DecodeImageInternal(key, draw_image);
425 558
426 // Skip the image if we couldn't decode it. 559 // Skip the image if we couldn't decode it.
427 if (!decoded_image) 560 if (!decoded_image)
428 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); 561 return DecodedDrawImage(nullptr, kNone_SkFilterQuality);
429 check_at_raster_cache = true; 562 check_at_raster_cache = true;
430 } 563 }
431 564
432 // While we unlocked the lock, it could be the case that another thread 565 // While we unlocked the lock, it could be the case that another thread
433 // already decoded this already and put it in the at-raster cache. Look it up 566 // already decoded this already and put it in the at-raster cache. Look it up
434 // first. 567 // first.
(...skipping 15 matching lines...) Expand all
450 at_raster_decoded_images_.push_back( 583 at_raster_decoded_images_.push_back(
451 AnnotatedDecodedImage(key, decoded_image)); 584 AnnotatedDecodedImage(key, decoded_image));
452 } 585 }
453 586
454 DCHECK(decoded_image); 587 DCHECK(decoded_image);
455 DCHECK(decoded_image->is_locked()); 588 DCHECK(decoded_image->is_locked());
456 RefAtRasterImage(key); 589 RefAtRasterImage(key);
457 SanityCheckState(__LINE__, true); 590 SanityCheckState(__LINE__, true);
458 auto decoded_draw_image = 591 auto decoded_draw_image =
459 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), 592 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(),
460 GetScaleAdjustment(key), kLow_SkFilterQuality); 593 GetScaleAdjustment(key), GetDecodedFilterQuality(key));
461 decoded_draw_image.set_at_raster_decode(true); 594 decoded_draw_image.set_at_raster_decode(true);
462 return decoded_draw_image; 595 return decoded_draw_image;
463 } 596 }
464 597
465 void ImageDecodeController::DrawWithImageFinished( 598 void ImageDecodeController::DrawWithImageFinished(
466 const DrawImage& image, 599 const DrawImage& image,
467 const DecodedDrawImage& decoded_image) { 600 const DecodedDrawImage& decoded_image) {
468 TRACE_EVENT1("disabled-by-default-cc.debug", 601 TRACE_EVENT1("disabled-by-default-cc.debug",
469 "ImageDecodeController::DrawWithImageFinished", "key", 602 "ImageDecodeController::DrawWithImageFinished", "key",
470 ImageKey::FromDrawImage(image).ToString()); 603 ImageKey::FromDrawImage(image).ToString());
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 // TODO(vmpstr): Handle GPU rasterization. 674 // TODO(vmpstr): Handle GPU rasterization.
542 if (is_using_gpu_rasterization_) 675 if (is_using_gpu_rasterization_)
543 return false; 676 return false;
544 if (!CanHandleFilterQuality(key.filter_quality())) 677 if (!CanHandleFilterQuality(key.filter_quality()))
545 return false; 678 return false;
546 return true; 679 return true;
547 } 680 }
548 681
549 bool ImageDecodeController::CanHandleFilterQuality( 682 bool ImageDecodeController::CanHandleFilterQuality(
550 SkFilterQuality filter_quality) { 683 SkFilterQuality filter_quality) {
551 // We don't need to handle low quality filters.
552 if (filter_quality == kLow_SkFilterQuality ||
553 filter_quality == kNone_SkFilterQuality) {
554 return false;
555 }
556
557 // TODO(vmpstr): We need to start caching mipmaps for medium quality and 684 // TODO(vmpstr): We need to start caching mipmaps for medium quality and
558 // caching the interpolated values from those. For now, we don't have this. 685 // caching the interpolated values from those. For now, we don't have this.
559 if (filter_quality == kMedium_SkFilterQuality) 686 return filter_quality != kMedium_SkFilterQuality;
560 return false;
561 DCHECK(filter_quality == kHigh_SkFilterQuality);
562 return true;
563 } 687 }
564 688
565 void ImageDecodeController::ReduceCacheUsage() { 689 void ImageDecodeController::ReduceCacheUsage() {
566 TRACE_EVENT0("cc", "ImageDecodeController::ReduceCacheUsage"); 690 TRACE_EVENT0("cc", "ImageDecodeController::ReduceCacheUsage");
567 base::AutoLock lock(lock_); 691 base::AutoLock lock(lock_);
568 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache) 692 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache)
569 ? (decoded_images_.size() - kMaxItemsInCache) 693 ? (decoded_images_.size() - kMaxItemsInCache)
570 : 0; 694 : 0;
571 for (auto it = decoded_images_.begin(); 695 for (auto it = decoded_images_.begin();
572 num_to_remove != 0 && it != decoded_images_.end();) { 696 num_to_remove != 0 && it != decoded_images_.end();) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 void ImageDecodeController::SanityCheckState(int line, bool lock_acquired) { 735 void ImageDecodeController::SanityCheckState(int line, bool lock_acquired) {
612 #if DCHECK_IS_ON() 736 #if DCHECK_IS_ON()
613 if (!lock_acquired) { 737 if (!lock_acquired) {
614 base::AutoLock lock(lock_); 738 base::AutoLock lock(lock_);
615 SanityCheckState(line, true); 739 SanityCheckState(line, true);
616 return; 740 return;
617 } 741 }
618 742
619 MemoryBudget budget(kLockedMemoryLimitBytes); 743 MemoryBudget budget(kLockedMemoryLimitBytes);
620 for (const auto& annotated_image : decoded_images_) { 744 for (const auto& annotated_image : decoded_images_) {
621 auto ref_it = decoded_images_ref_counts_.find(annotated_image.first); 745 DCHECK_EQ(1, std::count_if(
746 decoded_images_.begin(), decoded_images_.end(),
747 [&annotated_image](const AnnotatedDecodedImage& image) {
748 return image.first == annotated_image.first;
749 }))
750 << line;
751 auto key = annotated_image.first;
752 auto ref_it = decoded_images_ref_counts_.find(key);
622 if (annotated_image.second->is_locked()) { 753 if (annotated_image.second->is_locked()) {
623 budget.AddUsage(annotated_image.first.target_bytes()); 754 budget.AddUsage(annotated_image.first.locked_bytes());
624 DCHECK(ref_it != decoded_images_ref_counts_.end()) << line; 755 DCHECK(ref_it != decoded_images_ref_counts_.end()) << line;
625 } else { 756 } else {
626 DCHECK(ref_it == decoded_images_ref_counts_.end() || 757 DCHECK(ref_it == decoded_images_ref_counts_.end() ||
627 pending_image_tasks_.find(annotated_image.first) != 758 pending_image_tasks_.find(annotated_image.first) !=
628 pending_image_tasks_.end()) 759 pending_image_tasks_.end())
629 << line; 760 << line;
630 } 761 }
631 } 762 }
632 DCHECK_GE(budget.AvailableMemoryBytes(), 763 DCHECK_GE(budget.AvailableMemoryBytes(),
633 locked_images_budget_.AvailableMemoryBytes()) 764 locked_images_budget_.AvailableMemoryBytes())
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
680 811
681 // Drop from medium to low if the matrix we applied wasn't decomposable or if 812 // Drop from medium to low if the matrix we applied wasn't decomposable or if
682 // we're enlarging the image in both dimensions. 813 // we're enlarging the image in both dimensions.
683 if (quality == kMedium_SkFilterQuality) { 814 if (quality == kMedium_SkFilterQuality) {
684 if (!image.matrix_is_decomposable() || 815 if (!image.matrix_is_decomposable() ||
685 (scale.width() >= 1.f && scale.height() >= 1.f)) { 816 (scale.width() >= 1.f && scale.height() >= 1.f)) {
686 quality = kLow_SkFilterQuality; 817 quality = kLow_SkFilterQuality;
687 } 818 }
688 } 819 }
689 820
821 gfx::Size full_image_size(image.image()->width(), image.image()->height());
822 gfx::Rect full_image_rect(full_image_size);
823 bool scale_needs_caching =
824 quality != kLow_SkFilterQuality && quality != kNone_SkFilterQuality;
825 bool is_full_image_rect = full_image_rect == src_rect;
826 bool scale_is_required = src_rect.width() != target_size.width() ||
827 src_rect.height() != target_size.height();
828 bool can_use_original_decode =
829 !scale_needs_caching && (is_full_image_rect || !scale_is_required);
830 // If we're going to use the original decode, then the target size should be
831 // the full image size, since that will allow for proper memory accounting.
832 // Note we skip the decode if the target size is empty altogether, so don't
833 // update the target size in that case.
834 if (can_use_original_decode && !target_size.IsEmpty())
835 target_size = full_image_size;
836
690 return ImageDecodeControllerKey(image.image()->uniqueID(), src_rect, 837 return ImageDecodeControllerKey(image.image()->uniqueID(), src_rect,
691 target_size, quality); 838 target_size, quality,
839 can_use_original_decode);
692 } 840 }
693 841
694 ImageDecodeControllerKey::ImageDecodeControllerKey( 842 ImageDecodeControllerKey::ImageDecodeControllerKey(
695 uint32_t image_id, 843 uint32_t image_id,
696 const gfx::Rect& src_rect, 844 const gfx::Rect& src_rect,
697 const gfx::Size& target_size, 845 const gfx::Size& target_size,
698 SkFilterQuality filter_quality) 846 SkFilterQuality filter_quality,
847 bool can_use_original_decode)
699 : image_id_(image_id), 848 : image_id_(image_id),
700 src_rect_(src_rect), 849 src_rect_(src_rect),
701 target_size_(target_size), 850 target_size_(target_size),
702 filter_quality_(filter_quality) {} 851 filter_quality_(filter_quality),
852 can_use_original_decode_(can_use_original_decode) {
853 if (can_use_original_decode_) {
854 hash_ = std::hash<uint32_t>()(image_id_);
855 } else {
856 // TODO(vmpstr): This is a mess. Maybe it's faster to just search the vector
857 // always (forwards or backwards to account for LRU).
858 uint64_t src_rect_hash = base::HashInts(
859 static_cast<uint64_t>(base::HashInts(src_rect_.x(), src_rect_.y())),
860 static_cast<uint64_t>(
861 base::HashInts(src_rect_.width(), src_rect_.height())));
862
863 uint64_t target_size_hash =
864 base::HashInts(target_size_.width(), target_size_.height());
865
866 hash_ = base::HashInts(base::HashInts(src_rect_hash, target_size_hash),
867 base::HashInts(image_id_, filter_quality_));
868 }
869 }
703 870
704 std::string ImageDecodeControllerKey::ToString() const { 871 std::string ImageDecodeControllerKey::ToString() const {
705 std::ostringstream str; 872 std::ostringstream str;
706 str << "id[" << image_id_ << "] src_rect[" << src_rect_.x() << "," 873 str << "id[" << image_id_ << "] src_rect[" << src_rect_.x() << ","
707 << src_rect_.y() << " " << src_rect_.width() << "x" << src_rect_.height() 874 << src_rect_.y() << " " << src_rect_.width() << "x" << src_rect_.height()
708 << "] target_size[" << target_size_.width() << "x" 875 << "] target_size[" << target_size_.width() << "x"
709 << target_size_.height() << "] filter_quality[" << filter_quality_ << "]"; 876 << target_size_.height() << "] filter_quality[" << filter_quality_
877 << "] can_use_original_decode [" << can_use_original_decode_ << "] hash ["
878 << hash_ << "]";
710 return str.str(); 879 return str.str();
711 } 880 }
712 881
713 // DecodedImage 882 // DecodedImage
714 ImageDecodeController::DecodedImage::DecodedImage( 883 ImageDecodeController::DecodedImage::DecodedImage(
715 const SkImageInfo& info, 884 const SkImageInfo& info,
716 scoped_ptr<base::DiscardableMemory> memory, 885 scoped_ptr<base::DiscardableMemory> memory,
717 const SkSize& src_rect_offset) 886 const SkSize& src_rect_offset)
718 : locked_(true), 887 : locked_(true),
719 image_info_(info), 888 image_info_(info),
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 932
764 void ImageDecodeController::MemoryBudget::ResetUsage() { 933 void ImageDecodeController::MemoryBudget::ResetUsage() {
765 current_usage_bytes_ = 0; 934 current_usage_bytes_ = 0;
766 } 935 }
767 936
768 size_t ImageDecodeController::MemoryBudget::GetCurrentUsageSafe() const { 937 size_t ImageDecodeController::MemoryBudget::GetCurrentUsageSafe() const {
769 return current_usage_bytes_.ValueOrDie(); 938 return current_usage_bytes_.ValueOrDie();
770 } 939 }
771 940
772 } // namespace cc 941 } // namespace cc
OLDNEW
« no previous file with comments | « cc/tiles/image_decode_controller.h ('k') | cc/tiles/image_decode_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698