Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |