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

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, 10 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 (key.can_use_original_decode())
84 return SkSize::Make(1.f, 1.f);
85
81 float x_scale = 86 float x_scale =
82 key.target_size().width() / static_cast<float>(key.src_rect().width()); 87 key.target_size().width() / static_cast<float>(key.src_rect().width());
83 float y_scale = 88 float y_scale =
84 key.target_size().height() / static_cast<float>(key.src_rect().height()); 89 key.target_size().height() / static_cast<float>(key.src_rect().height());
85 return SkSize::Make(x_scale, y_scale); 90 return SkSize::Make(x_scale, y_scale);
86 } 91 }
87 92
88 } // namespace 93 } // namespace
89 94
90 ImageDecodeController::ImageDecodeController() 95 ImageDecodeController::ImageDecodeController()
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 *task = nullptr; 141 *task = nullptr;
137 } 142 }
138 return false; 143 return false;
139 } 144 }
140 145
141 base::AutoLock lock(lock_); 146 base::AutoLock lock(lock_);
142 147
143 // If we already have the image in cache, then we can return it. 148 // If we already have the image in cache, then we can return it.
144 auto decoded_it = FindImage(&decoded_images_, key); 149 auto decoded_it = FindImage(&decoded_images_, key);
145 bool new_image_fits_in_memory = 150 bool new_image_fits_in_memory =
146 locked_images_budget_.AvailableMemoryBytes() >= key.target_bytes(); 151 locked_images_budget_.AvailableMemoryBytes() >= key.locked_bytes();
147 if (decoded_it != decoded_images_.end()) { 152 if (decoded_it != decoded_images_.end()) {
148 if (decoded_it->second->is_locked() || 153 if (decoded_it->second->is_locked() ||
149 (new_image_fits_in_memory && decoded_it->second->Lock())) { 154 (new_image_fits_in_memory && decoded_it->second->Lock())) {
150 RefImage(key); 155 RefImage(key);
151 *task = nullptr; 156 *task = nullptr;
152 SanityCheckState(__LINE__, true); 157 SanityCheckState(__LINE__, true);
153 return true; 158 return true;
154 } 159 }
155 // If the image fits in memory, then we at least tried to lock it and 160 // 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. 161 // 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); 193 SanityCheckState(__LINE__, true);
189 return true; 194 return true;
190 } 195 }
191 196
192 void ImageDecodeController::RefImage(const ImageKey& key) { 197 void ImageDecodeController::RefImage(const ImageKey& key) {
193 TRACE_EVENT1("disabled-by-default-cc.debug", 198 TRACE_EVENT1("disabled-by-default-cc.debug",
194 "ImageDecodeController::RefImage", "key", key.ToString()); 199 "ImageDecodeController::RefImage", "key", key.ToString());
195 lock_.AssertAcquired(); 200 lock_.AssertAcquired();
196 int ref = ++decoded_images_ref_counts_[key]; 201 int ref = ++decoded_images_ref_counts_[key];
197 if (ref == 1) { 202 if (ref == 1) {
198 DCHECK_GE(locked_images_budget_.AvailableMemoryBytes(), key.target_bytes()); 203 DCHECK_GE(locked_images_budget_.AvailableMemoryBytes(), key.locked_bytes());
199 locked_images_budget_.AddUsage(key.target_bytes()); 204 locked_images_budget_.AddUsage(key.locked_bytes());
200 } 205 }
201 } 206 }
202 207
203 void ImageDecodeController::UnrefImage(const DrawImage& image) { 208 void ImageDecodeController::UnrefImage(const DrawImage& image) {
204 // When we unref the image, there are several situations we need to consider: 209 // 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. 210 // 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. 211 // 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 212 // 2a. The image isn't in the locked cache because we didn't get to decode
208 // it yet (or failed to decode it). 213 // it yet (or failed to decode it).
209 // 2b. Unlock the image but keep it in list. 214 // 2b. Unlock the image but keep it in list.
210 const ImageKey& key = ImageKey::FromDrawImage(image); 215 const ImageKey& key = ImageKey::FromDrawImage(image);
211 DCHECK(CanHandleImage(key, image)); 216 DCHECK(CanHandleImage(key, image));
212 TRACE_EVENT1("disabled-by-default-cc.debug", 217 TRACE_EVENT1("disabled-by-default-cc.debug",
213 "ImageDecodeController::UnrefImage", "key", key.ToString()); 218 "ImageDecodeController::UnrefImage", "key", key.ToString());
214 219
215 base::AutoLock lock(lock_); 220 base::AutoLock lock(lock_);
216 auto ref_count_it = decoded_images_ref_counts_.find(key); 221 auto ref_count_it = decoded_images_ref_counts_.find(key);
217 DCHECK(ref_count_it != decoded_images_ref_counts_.end()); 222 DCHECK(ref_count_it != decoded_images_ref_counts_.end());
218 223
219 --ref_count_it->second; 224 --ref_count_it->second;
220 if (ref_count_it->second == 0) { 225 if (ref_count_it->second == 0) {
221 decoded_images_ref_counts_.erase(ref_count_it); 226 decoded_images_ref_counts_.erase(ref_count_it);
222 locked_images_budget_.SubtractUsage(key.target_bytes()); 227 locked_images_budget_.SubtractUsage(key.locked_bytes());
223 228
224 auto decoded_image_it = FindImage(&decoded_images_, key); 229 auto decoded_image_it = FindImage(&decoded_images_, key);
225 // If we've never decoded the image before ref reached 0, then we wouldn't 230 // 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. 231 // have it in our cache. This would happen if we canceled tasks.
227 if (decoded_image_it == decoded_images_.end()) { 232 if (decoded_image_it == decoded_images_.end()) {
228 SanityCheckState(__LINE__, true); 233 SanityCheckState(__LINE__, true);
229 return; 234 return;
230 } 235 }
231 DCHECK(decoded_image_it->second->is_locked()); 236 DCHECK(decoded_image_it->second->is_locked());
232 decoded_image_it->second->Unlock(); 237 decoded_image_it->second->Unlock();
(...skipping 26 matching lines...) Expand all
259 if (image_it->second->is_locked() || image_it->second->Lock()) { 264 if (image_it->second->is_locked() || image_it->second->Lock()) {
260 pending_image_tasks_.erase(key); 265 pending_image_tasks_.erase(key);
261 return; 266 return;
262 } 267 }
263 decoded_images_.erase(image_it); 268 decoded_images_.erase(image_it);
264 } 269 }
265 270
266 scoped_refptr<DecodedImage> decoded_image; 271 scoped_refptr<DecodedImage> decoded_image;
267 { 272 {
268 base::AutoUnlock unlock(lock_); 273 base::AutoUnlock unlock(lock_);
269 decoded_image = DecodeImageInternal(key, image.image()); 274 decoded_image = DecodeImageInternal(key, image);
270 } 275 }
271 276
272 // Erase the pending task from the queue, since the task won't be doing 277 // 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 278 // anything useful after this function terminates. That is, if this image
274 // needs to be decoded again, we have to create a new task. 279 // needs to be decoded again, we have to create a new task.
275 pending_image_tasks_.erase(key); 280 pending_image_tasks_.erase(key);
276 281
277 // Abort if we failed to decode the image. 282 // Abort if we failed to decode the image.
278 if (!decoded_image) 283 if (!decoded_image)
279 return; 284 return;
(...skipping 19 matching lines...) Expand all
299 decoded_images_ref_counts_.end()) { 304 decoded_images_ref_counts_.end()) {
300 decoded_image->Unlock(); 305 decoded_image->Unlock();
301 } 306 }
302 307
303 decoded_images_.push_back(AnnotatedDecodedImage(key, decoded_image)); 308 decoded_images_.push_back(AnnotatedDecodedImage(key, decoded_image));
304 SanityCheckState(__LINE__, true); 309 SanityCheckState(__LINE__, true);
305 } 310 }
306 311
307 scoped_refptr<ImageDecodeController::DecodedImage> 312 scoped_refptr<ImageDecodeController::DecodedImage>
308 ImageDecodeController::DecodeImageInternal(const ImageKey& key, 313 ImageDecodeController::DecodeImageInternal(const ImageKey& key,
309 const SkImage* image) { 314 const DrawImage& draw_image) {
310 TRACE_EVENT1("disabled-by-default-cc.debug", 315 TRACE_EVENT1("disabled-by-default-cc.debug",
311 "ImageDecodeController::DecodeImageInternal", "key", 316 "ImageDecodeController::DecodeImageInternal", "key",
312 key.ToString()); 317 key.ToString());
313 318
314 // Get the decoded image first (at the original scale). 319 const SkImage* image = draw_image.image();
315 SkImageInfo decoded_info = SkImageInfo::MakeN32Premul(
316 key.src_rect().width(), key.src_rect().height());
317 scoped_ptr<uint8_t[]> decoded_pixels;
318 {
319 TRACE_EVENT0(
320 "disabled-by-default-cc.debug",
321 "ImageDecodeController::DecodeImageInternal - allocate decoded pixels");
322 decoded_pixels.reset(
323 new uint8_t[decoded_info.minRowBytes() * decoded_info.height()]);
324 }
325 {
326 TRACE_EVENT0("disabled-by-default-cc.debug",
327 "ImageDecodeController::DecodeImageInternal - read pixels");
328 bool result = image->readPixels(
329 decoded_info, decoded_pixels.get(), decoded_info.minRowBytes(),
330 key.src_rect().x(), key.src_rect().y(), SkImage::kAllow_CachingHint);
331 320
332 if (!result) 321 // If we can use the original decode, then we don't need to do scaling. We can
333 return nullptr; 322 // just read pixels into the final memory.
323 if (key.can_use_original_decode()) {
324 SkImageInfo decoded_info =
325 SkImageInfo::MakeN32Premul(image->width(), image->height());
326 scoped_ptr<base::DiscardableMemory> decoded_pixels;
327 {
328 TRACE_EVENT0("disabled-by-default-cc.debug",
329 "ImageDecodeController::DecodeImageInternal - allocate "
330 "decoded pixels");
331 decoded_pixels =
332 base::DiscardableMemoryAllocator::GetInstance()
333 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() *
334 decoded_info.height());
335 }
336 {
337 TRACE_EVENT0("disabled-by-default-cc.debug",
338 "ImageDecodeController::DecodeImageInternal - read pixels");
339 bool result = image->readPixels(decoded_info, decoded_pixels->data(),
340 decoded_info.minRowBytes(), 0, 0,
341 SkImage::kDisallow_CachingHint);
342
343 if (!result) {
344 decoded_pixels->Unlock();
345 return nullptr;
346 }
347 }
348
349 return make_scoped_refptr(new DecodedImage(
350 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0)));
334 } 351 }
335 352
336 SkPixmap decoded_pixmap(decoded_info, decoded_pixels.get(), 353 // If we get here, that means we couldn't use the original sized decode for
337 decoded_info.minRowBytes()); 354 // whatever reason. However, in all cases we do need an original decode to
355 // either do a scale or to extract a subrect from the image. So, what we can
356 // do is construct a key that would require a full sized decode, then get that
357 // decode via GetDecodedImageForDrawInternal(), use it, and unref it. This
358 // ensures that if the original sized decode is already available in any of
359 // the caches, we reuse that. We also ensure that all the proper locking takes
360 // place. If, on the other hand, the decode was not available,
361 // GetDecodedImageForDrawInternal() would decode the image, and unreffing it
362 // later ensures that we will store the discardable memory unlocked in the
363 // cache to be used by future requests.
364 SkSize identity_scale = SkSize::Make(1.f, 1.f);
365 bool matrix_has_perspective = false;
366 bool matrix_is_decomposable = true;
367 gfx::Rect full_image_rect(image->width(), image->height());
368 DrawImage original_size_draw_image(
369 image, gfx::RectToSkIRect(full_image_rect), identity_scale,
370 kLow_SkFilterQuality, matrix_has_perspective, matrix_is_decomposable);
371 ImageKey original_size_key =
372 ImageKey::FromDrawImage(original_size_draw_image);
373 // Sanity checks.
374 DCHECK(original_size_key.can_use_original_decode());
375 DCHECK(full_image_rect.size() == original_size_key.target_size());
338 376
339 // Now scale the pixels into the destination size. 377 auto decoded_draw_image = GetDecodedImageForDrawInternal(
378 original_size_key, original_size_draw_image);
379 if (!decoded_draw_image.image()) {
380 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
ericrk 2016/02/11 01:21:50 not really specific to this change - but would it
vmpstr 2016/02/17 21:21:03 Yeah I have that in the ImageHijackCanvas. I figur
ericrk 2016/02/19 23:22:31 sounds good.
381 return nullptr;
382 }
383
384 scoped_ptr<uint8_t[]> decoded_subrect_pixels;
385 SkPixmap decoded_pixmap;
386 bool result;
387 if (key.src_rect() == full_image_rect) {
388 result = decoded_draw_image.image()->peekPixels(&decoded_pixmap);
389 } else {
390 SkImageInfo decoded_info = SkImageInfo::MakeN32Premul(
391 key.src_rect().width(), key.src_rect().height());
392 {
393 TRACE_EVENT0("disabled-by-default-cc.debug",
394 "ImageDecodeController::DecodeImageInternal - allocate "
395 "decoded pixels");
396 decoded_subrect_pixels.reset(
397 new uint8_t[decoded_info.minRowBytes() * decoded_info.height()]);
398 }
399 {
400 TRACE_EVENT0("disabled-by-default-cc.debug",
401 "ImageDecodeController::DecodeImageInternal - read pixels");
402 result =
403 image->readPixels(decoded_info, decoded_subrect_pixels.get(),
404 decoded_info.minRowBytes(), key.src_rect().x(),
405 key.src_rect().y(), SkImage::kDisallow_CachingHint);
406 }
407 decoded_pixmap = SkPixmap(decoded_info, decoded_subrect_pixels.get(),
408 decoded_info.minRowBytes());
409 }
410
411 // Since the decoded_draw_image has locked memory, it should always succeed on
412 // both peekPixels and readPixels.
413 DCHECK(result);
414
415 // Now we have a decoded_pixmap which represents the src_rect at the original
416 // scale. All we need to do is scale it.
340 DCHECK(!key.target_size().IsEmpty()); 417 DCHECK(!key.target_size().IsEmpty());
341 SkImageInfo scaled_info = SkImageInfo::MakeN32Premul( 418 SkImageInfo scaled_info = SkImageInfo::MakeN32Premul(
342 key.target_size().width(), key.target_size().height()); 419 key.target_size().width(), key.target_size().height());
343 scoped_ptr<base::DiscardableMemory> scaled_pixels; 420 scoped_ptr<base::DiscardableMemory> scaled_pixels;
344 { 421 {
345 TRACE_EVENT0( 422 TRACE_EVENT0(
346 "disabled-by-default-cc.debug", 423 "disabled-by-default-cc.debug",
347 "ImageDecodeController::DecodeImageInternal - allocate scaled pixels"); 424 "ImageDecodeController::DecodeImageInternal - allocate scaled pixels");
348 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() 425 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance()
349 ->AllocateLockedDiscardableMemory( 426 ->AllocateLockedDiscardableMemory(
350 scaled_info.minRowBytes() * scaled_info.height()); 427 scaled_info.minRowBytes() * scaled_info.height());
351 } 428 }
352 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), 429 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(),
353 scaled_info.minRowBytes()); 430 scaled_info.minRowBytes());
354 // TODO(vmpstr): Start handling more than just high filter quality. 431 // TODO(vmpstr): Start handling more than just high filter quality.
355 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); 432 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality());
356 { 433 {
357 TRACE_EVENT0("disabled-by-default-cc.debug", 434 TRACE_EVENT0("disabled-by-default-cc.debug",
358 "ImageDecodeController::DecodeImageInternal - scale pixels"); 435 "ImageDecodeController::DecodeImageInternal - scale pixels");
359 bool result = 436 bool result =
360 decoded_pixmap.scalePixels(scaled_pixmap, kHigh_SkFilterQuality); 437 decoded_pixmap.scalePixels(scaled_pixmap, key.filter_quality());
361 DCHECK(result); 438 DCHECK(result);
362 } 439 }
440
441 // Release the original sized decode. Any other intermediate result to release
442 // would be the subrect memory. However, that's in a scoped_ptr and will be
443 // deleted automatically when we return.
444 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
445
363 return make_scoped_refptr( 446 return make_scoped_refptr(
364 new DecodedImage(scaled_info, std::move(scaled_pixels), 447 new DecodedImage(scaled_info, std::move(scaled_pixels),
365 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); 448 SkSize::Make(-key.src_rect().x(), -key.src_rect().y())));
366 } 449 }
367 450
368 DecodedDrawImage ImageDecodeController::GetDecodedImageForDraw( 451 DecodedDrawImage ImageDecodeController::GetDecodedImageForDraw(
369 const DrawImage& draw_image) { 452 const DrawImage& draw_image) {
370 ImageKey key = ImageKey::FromDrawImage(draw_image); 453 ImageKey key = ImageKey::FromDrawImage(draw_image);
371 TRACE_EVENT1("disabled-by-default-cc.debug", 454 TRACE_EVENT1("disabled-by-default-cc.debug",
372 "ImageDecodeController::GetDecodedImageAndRef", "key", 455 "ImageDecodeController::GetDecodedImageForDraw", "key",
373 key.ToString()); 456 key.ToString());
374 if (!CanHandleImage(key, draw_image)) 457 if (!CanHandleImage(key, draw_image))
375 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality()); 458 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality());
376 459
377 // If the target size is empty, we can skip this image draw. 460 // If the target size is empty, we can skip this image draw.
378 if (key.target_size().IsEmpty()) 461 if (key.target_size().IsEmpty())
379 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); 462 return DecodedDrawImage(nullptr, kNone_SkFilterQuality);
380 463
464 return GetDecodedImageForDrawInternal(key, draw_image);
465 }
466
467 DecodedDrawImage ImageDecodeController::GetDecodedImageForDrawInternal(
468 const ImageKey& key,
469 const DrawImage& draw_image) {
470 TRACE_EVENT1("disabled-by-default-cc.debug",
471 "ImageDecodeController::GetDecodedImageForDrawInternal", "key",
472 key.ToString());
381 base::AutoLock lock(lock_); 473 base::AutoLock lock(lock_);
382 auto decoded_images_it = FindImage(&decoded_images_, key); 474 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, 475 // 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. 476 // erase it from the cache since it might be put into the at-raster cache.
385 scoped_refptr<DecodedImage> decoded_image; 477 scoped_refptr<DecodedImage> decoded_image;
386 if (decoded_images_it != decoded_images_.end()) { 478 if (decoded_images_it != decoded_images_.end()) {
387 decoded_image = decoded_images_it->second; 479 decoded_image = decoded_images_it->second;
388 if (decoded_image->is_locked()) { 480 if (decoded_image->is_locked()) {
389 RefImage(key); 481 RefImage(key);
390 SanityCheckState(__LINE__, true); 482 SanityCheckState(__LINE__, true);
391 return DecodedDrawImage(decoded_image->image(), 483 return DecodedDrawImage(decoded_image->image(),
392 decoded_image->src_rect_offset(), 484 decoded_image->src_rect_offset(),
393 GetScaleAdjustment(key), kLow_SkFilterQuality); 485 GetScaleAdjustment(key), kLow_SkFilterQuality);
394 } else { 486 } else {
395 decoded_images_.erase(decoded_images_it); 487 decoded_images_.erase(decoded_images_it);
396 } 488 }
397 } 489 }
398 490
399 // See if another thread already decoded this image at raster time. If so, we 491 // See if another thread already decoded this image at raster time. If so, we
400 // can just use that result directly. 492 // can just use that result directly.
401 auto at_raster_images_it = FindImage(&at_raster_decoded_images_, key); 493 auto at_raster_images_it = FindImage(&at_raster_decoded_images_, key);
402 if (at_raster_images_it != at_raster_decoded_images_.end()) { 494 if (at_raster_images_it != at_raster_decoded_images_.end()) {
403 DCHECK(at_raster_images_it->second->is_locked()); 495 DCHECK(at_raster_images_it->second->is_locked());
404 RefAtRasterImage(key); 496 RefAtRasterImage(key);
405 SanityCheckState(__LINE__, true); 497 SanityCheckState(__LINE__, true);
498 const scoped_refptr<DecodedImage>& at_raster_decoded_image =
499 at_raster_images_it->second;
406 auto decoded_draw_image = 500 auto decoded_draw_image =
407 DecodedDrawImage(at_raster_images_it->second->image(), 501 DecodedDrawImage(at_raster_decoded_image->image(),
408 at_raster_images_it->second->src_rect_offset(), 502 at_raster_decoded_image->src_rect_offset(),
409 GetScaleAdjustment(key), kLow_SkFilterQuality); 503 GetScaleAdjustment(key), kLow_SkFilterQuality);
410 decoded_draw_image.set_at_raster_decode(true); 504 decoded_draw_image.set_at_raster_decode(true);
411 return decoded_draw_image; 505 return decoded_draw_image;
412 } 506 }
413 507
414 // Now we know that we don't have a locked image, and we seem to be the first 508 // 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 509 // 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 510 // 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. 511 // assuming we can't lock the one we found in the cache.
418 bool check_at_raster_cache = false; 512 bool check_at_raster_cache = false;
419 if (!decoded_image || !decoded_image->Lock()) { 513 if (!decoded_image || !decoded_image->Lock()) {
420 // Note that we have to release the lock, since this lock is also accessed 514 // 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 515 // on the compositor thread. This means holding on to the lock might stall
422 // the compositor thread for the duration of the decode! 516 // the compositor thread for the duration of the decode!
423 base::AutoUnlock unlock(lock_); 517 base::AutoUnlock unlock(lock_);
424 decoded_image = DecodeImageInternal(key, draw_image.image()); 518 decoded_image = DecodeImageInternal(key, draw_image);
425 519
426 // Skip the image if we couldn't decode it. 520 // Skip the image if we couldn't decode it.
427 if (!decoded_image) 521 if (!decoded_image)
428 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); 522 return DecodedDrawImage(nullptr, kNone_SkFilterQuality);
429 check_at_raster_cache = true; 523 check_at_raster_cache = true;
430 } 524 }
431 525
432 // While we unlocked the lock, it could be the case that another thread 526 // 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 527 // already decoded this already and put it in the at-raster cache. Look it up
434 // first. 528 // first.
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 // TODO(vmpstr): Handle GPU rasterization. 635 // TODO(vmpstr): Handle GPU rasterization.
542 if (is_using_gpu_rasterization_) 636 if (is_using_gpu_rasterization_)
543 return false; 637 return false;
544 if (!CanHandleFilterQuality(key.filter_quality())) 638 if (!CanHandleFilterQuality(key.filter_quality()))
545 return false; 639 return false;
546 return true; 640 return true;
547 } 641 }
548 642
549 bool ImageDecodeController::CanHandleFilterQuality( 643 bool ImageDecodeController::CanHandleFilterQuality(
550 SkFilterQuality filter_quality) { 644 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 645 // 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. 646 // caching the interpolated values from those. For now, we don't have this.
559 if (filter_quality == kMedium_SkFilterQuality) 647 return filter_quality != kMedium_SkFilterQuality;
560 return false;
561 DCHECK(filter_quality == kHigh_SkFilterQuality);
562 return true;
563 } 648 }
564 649
565 void ImageDecodeController::ReduceCacheUsage() { 650 void ImageDecodeController::ReduceCacheUsage() {
566 TRACE_EVENT0("cc", "ImageDecodeController::ReduceCacheUsage"); 651 TRACE_EVENT0("cc", "ImageDecodeController::ReduceCacheUsage");
567 base::AutoLock lock(lock_); 652 base::AutoLock lock(lock_);
568 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache) 653 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache)
569 ? (decoded_images_.size() - kMaxItemsInCache) 654 ? (decoded_images_.size() - kMaxItemsInCache)
570 : 0; 655 : 0;
571 for (auto it = decoded_images_.begin(); 656 for (auto it = decoded_images_.begin();
572 num_to_remove != 0 && it != decoded_images_.end();) { 657 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) { 696 void ImageDecodeController::SanityCheckState(int line, bool lock_acquired) {
612 #if DCHECK_IS_ON() 697 #if DCHECK_IS_ON()
613 if (!lock_acquired) { 698 if (!lock_acquired) {
614 base::AutoLock lock(lock_); 699 base::AutoLock lock(lock_);
615 SanityCheckState(line, true); 700 SanityCheckState(line, true);
616 return; 701 return;
617 } 702 }
618 703
619 MemoryBudget budget(kLockedMemoryLimitBytes); 704 MemoryBudget budget(kLockedMemoryLimitBytes);
620 for (const auto& annotated_image : decoded_images_) { 705 for (const auto& annotated_image : decoded_images_) {
621 auto ref_it = decoded_images_ref_counts_.find(annotated_image.first); 706 DCHECK_EQ(1, std::count_if(
707 decoded_images_.begin(), decoded_images_.end(),
708 [&annotated_image](const AnnotatedDecodedImage& image) {
709 return image.first == annotated_image.first;
710 }))
711 << line;
712 auto key = annotated_image.first;
713 auto ref_it = decoded_images_ref_counts_.find(key);
622 if (annotated_image.second->is_locked()) { 714 if (annotated_image.second->is_locked()) {
623 budget.AddUsage(annotated_image.first.target_bytes()); 715 budget.AddUsage(annotated_image.first.locked_bytes());
624 DCHECK(ref_it != decoded_images_ref_counts_.end()) << line; 716 DCHECK(ref_it != decoded_images_ref_counts_.end()) << line;
625 } else { 717 } else {
626 DCHECK(ref_it == decoded_images_ref_counts_.end() || 718 DCHECK(ref_it == decoded_images_ref_counts_.end() ||
627 pending_image_tasks_.find(annotated_image.first) != 719 pending_image_tasks_.find(annotated_image.first) !=
628 pending_image_tasks_.end()) 720 pending_image_tasks_.end())
629 << line; 721 << line;
630 } 722 }
631 } 723 }
632 DCHECK_GE(budget.AvailableMemoryBytes(), 724 DCHECK_GE(budget.AvailableMemoryBytes(),
633 locked_images_budget_.AvailableMemoryBytes()) 725 locked_images_budget_.AvailableMemoryBytes())
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 764
673 // Drop from medium to low if the matrix we applied wasn't decomposable or if 765 // Drop from medium to low if the matrix we applied wasn't decomposable or if
674 // we're enlarging the image in both dimensions. 766 // we're enlarging the image in both dimensions.
675 if (quality == kMedium_SkFilterQuality) { 767 if (quality == kMedium_SkFilterQuality) {
676 if (!image.matrix_is_decomposable() || 768 if (!image.matrix_is_decomposable() ||
677 (scale.width() >= 1.f && scale.height() >= 1.f)) { 769 (scale.width() >= 1.f && scale.height() >= 1.f)) {
678 quality = kLow_SkFilterQuality; 770 quality = kLow_SkFilterQuality;
679 } 771 }
680 } 772 }
681 773
682 return ImageDecodeControllerKey(image.image()->uniqueID(), 774 gfx::Rect src_rect = gfx::SkIRectToRect(image.src_rect());
683 gfx::SkIRectToRect(image.src_rect()), 775 gfx::Size full_image_size(image.image()->width(), image.image()->height());
684 target_size, quality); 776 gfx::Rect full_image_rect(full_image_size);
777 bool scale_needs_caching =
778 quality != kLow_SkFilterQuality && quality != kNone_SkFilterQuality;
779 bool is_full_image_rect = full_image_rect == src_rect;
780 bool scale_is_required = src_rect.width() != target_size.width() ||
781 src_rect.height() != target_size.height();
782 bool can_use_original_decode =
ericrk 2016/02/11 01:21:50 nit: does it make more sense to call it "needs_cac
vmpstr 2016/02/17 21:21:03 Hmm well if scale is not required, then scale_need
ericrk 2016/02/19 23:22:31 Wouldn't a high quality image without scaling set
783 !scale_needs_caching && (is_full_image_rect || !scale_is_required);
784 // If we're going to use the original decode, then the target size should be
785 // the full image size, since that will allow for proper memory accounting.
786 if (can_use_original_decode)
787 target_size = full_image_size;
788
789 return ImageDecodeControllerKey(image.image()->uniqueID(), src_rect,
790 target_size, quality,
791 can_use_original_decode);
685 } 792 }
686 793
687 ImageDecodeControllerKey::ImageDecodeControllerKey( 794 ImageDecodeControllerKey::ImageDecodeControllerKey(
688 uint32_t image_id, 795 uint32_t image_id,
689 const gfx::Rect& src_rect, 796 const gfx::Rect& src_rect,
690 const gfx::Size& target_size, 797 const gfx::Size& target_size,
691 SkFilterQuality filter_quality) 798 SkFilterQuality filter_quality,
799 bool can_use_original_decode)
692 : image_id_(image_id), 800 : image_id_(image_id),
693 src_rect_(src_rect), 801 src_rect_(src_rect),
694 target_size_(target_size), 802 target_size_(target_size),
695 filter_quality_(filter_quality) {} 803 filter_quality_(filter_quality),
804 can_use_original_decode_(can_use_original_decode) {
805 if (can_use_original_decode_) {
806 hash_ = std::hash<uint32_t>()(image_id_);
807 } else {
808 // TODO(vmpstr): This is a mess. Maybe it's faster to just search the vector
809 // always (forwards or backwards to account for LRU).
810 uint64_t src_rect_hash = base::HashInts(
811 static_cast<uint64_t>(base::HashInts(src_rect_.x(), src_rect_.y())),
812 static_cast<uint64_t>(
813 base::HashInts(src_rect_.width(), src_rect_.height())));
814
815 uint64_t target_size_hash =
816 base::HashInts(target_size_.width(), target_size_.height());
817
818 hash_ = base::HashInts(base::HashInts(src_rect_hash, target_size_hash),
819 base::HashInts(image_id_, filter_quality_));
820 }
821 }
696 822
697 std::string ImageDecodeControllerKey::ToString() const { 823 std::string ImageDecodeControllerKey::ToString() const {
698 std::ostringstream str; 824 std::ostringstream str;
699 str << "id[" << image_id_ << "] src_rect[" << src_rect_.x() << "," 825 str << "id[" << image_id_ << "] src_rect[" << src_rect_.x() << ","
700 << src_rect_.y() << " " << src_rect_.width() << "x" << src_rect_.height() 826 << src_rect_.y() << " " << src_rect_.width() << "x" << src_rect_.height()
701 << "] target_size[" << target_size_.width() << "x" 827 << "] target_size[" << target_size_.width() << "x"
702 << target_size_.height() << "] filter_quality[" << filter_quality_ << "]"; 828 << target_size_.height() << "] filter_quality[" << filter_quality_
829 << "] can_use_original_decode [" << can_use_original_decode_ << "] hash ["
830 << hash_ << "]";
703 return str.str(); 831 return str.str();
704 } 832 }
705 833
706 // DecodedImage 834 // DecodedImage
707 ImageDecodeController::DecodedImage::DecodedImage( 835 ImageDecodeController::DecodedImage::DecodedImage(
708 const SkImageInfo& info, 836 const SkImageInfo& info,
709 scoped_ptr<base::DiscardableMemory> memory, 837 scoped_ptr<base::DiscardableMemory> memory,
710 const SkSize& src_rect_offset) 838 const SkSize& src_rect_offset)
711 : locked_(true), 839 : locked_(true),
712 image_info_(info), 840 image_info_(info),
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 884
757 void ImageDecodeController::MemoryBudget::ResetUsage() { 885 void ImageDecodeController::MemoryBudget::ResetUsage() {
758 current_usage_bytes_ = 0; 886 current_usage_bytes_ = 0;
759 } 887 }
760 888
761 size_t ImageDecodeController::MemoryBudget::GetCurrentUsageSafe() const { 889 size_t ImageDecodeController::MemoryBudget::GetCurrentUsageSafe() const {
762 return current_usage_bytes_.ValueOrDie(); 890 return current_usage_bytes_.ValueOrDie();
763 } 891 }
764 892
765 } // namespace cc 893 } // 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