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 "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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |