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