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

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

Powered by Google App Engine
This is Rietveld 408576698