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/software_image_decode_controller.h" | 5 #include "cc/tiles/software_image_decode_controller.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | |
| 9 #include <functional> | 10 #include <functional> |
| 11 #include <limits> | |
| 10 | 12 |
| 11 #include "base/macros.h" | 13 #include "base/macros.h" |
| 12 #include "base/memory/discardable_memory.h" | 14 #include "base/memory/discardable_memory.h" |
| 13 #include "cc/debug/devtools_instrumentation.h" | 15 #include "cc/debug/devtools_instrumentation.h" |
| 14 #include "cc/raster/tile_task_runner.h" | 16 #include "cc/raster/tile_task_runner.h" |
| 15 #include "third_party/skia/include/core/SkCanvas.h" | 17 #include "third_party/skia/include/core/SkCanvas.h" |
| 16 #include "third_party/skia/include/core/SkImage.h" | 18 #include "third_party/skia/include/core/SkImage.h" |
| 17 #include "ui/gfx/skia_util.h" | 19 #include "ui/gfx/skia_util.h" |
| 18 | 20 |
| 19 namespace cc { | 21 namespace cc { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 100 key.target_size().width() / static_cast<float>(key.src_rect().width()); | 102 key.target_size().width() / static_cast<float>(key.src_rect().width()); |
| 101 float y_scale = | 103 float y_scale = |
| 102 key.target_size().height() / static_cast<float>(key.src_rect().height()); | 104 key.target_size().height() / static_cast<float>(key.src_rect().height()); |
| 103 return SkSize::Make(x_scale, y_scale); | 105 return SkSize::Make(x_scale, y_scale); |
| 104 } | 106 } |
| 105 | 107 |
| 106 SkFilterQuality GetDecodedFilterQuality(const ImageDecodeControllerKey& key) { | 108 SkFilterQuality GetDecodedFilterQuality(const ImageDecodeControllerKey& key) { |
| 107 return std::min(key.filter_quality(), kLow_SkFilterQuality); | 109 return std::min(key.filter_quality(), kLow_SkFilterQuality); |
| 108 } | 110 } |
| 109 | 111 |
| 110 SkColorType SkColorTypeForDecoding(ResourceFormat format) { | |
|
vmpstr
2016/03/29 18:38:13
Why this change?
cblume
2016/03/29 18:53:44
Oh sorry. I branched off my other branch after I h
| |
| 111 // Use kN32_SkColorType if there is no corresponding SkColorType. | |
| 112 switch (format) { | |
| 113 case RGBA_4444: | |
| 114 return kARGB_4444_SkColorType; | |
| 115 case RGBA_8888: | |
| 116 case BGRA_8888: | |
| 117 return kN32_SkColorType; | |
| 118 case ALPHA_8: | |
| 119 return kAlpha_8_SkColorType; | |
| 120 case RGB_565: | |
| 121 return kRGB_565_SkColorType; | |
| 122 case LUMINANCE_8: | |
| 123 return kGray_8_SkColorType; | |
| 124 case ETC1: | |
| 125 case RED_8: | |
| 126 case LUMINANCE_F16: | |
| 127 return kN32_SkColorType; | |
| 128 } | |
| 129 NOTREACHED(); | |
| 130 return kN32_SkColorType; | |
| 131 } | |
| 132 | |
| 133 SkImageInfo CreateImageInfo(size_t width, | |
| 134 size_t height, | |
| 135 ResourceFormat format) { | |
| 136 return SkImageInfo::Make(width, height, SkColorTypeForDecoding(format), | |
| 137 kPremul_SkAlphaType); | |
| 138 } | |
| 139 | |
| 140 } // namespace | 112 } // namespace |
| 141 | 113 |
| 142 SoftwareImageDecodeController::SoftwareImageDecodeController( | 114 SoftwareImageDecodeController::SoftwareImageDecodeController( |
| 143 ResourceFormat format) | 115 ResourceFormat format) |
| 144 : decoded_images_(ImageMRUCache::NO_AUTO_EVICT), | 116 : decoded_images_(ImageMRUCache::NO_AUTO_EVICT), |
| 145 at_raster_decoded_images_(ImageMRUCache::NO_AUTO_EVICT), | 117 at_raster_decoded_images_(ImageMRUCache::NO_AUTO_EVICT), |
| 146 locked_images_budget_(kLockedMemoryLimitBytes), | 118 locked_images_budget_(kLockedMemoryLimitBytes), |
| 147 format_(format) {} | 119 format_(format) {} |
| 148 | 120 |
| 149 SoftwareImageDecodeController::~SoftwareImageDecodeController() { | 121 SoftwareImageDecodeController::~SoftwareImageDecodeController() { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 167 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", | 139 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", |
| 168 key.ToString()); | 140 key.ToString()); |
| 169 | 141 |
| 170 // If the target size is empty, we can skip this image during draw (and thus | 142 // If the target size is empty, we can skip this image during draw (and thus |
| 171 // we don't need to decode it or ref it). | 143 // we don't need to decode it or ref it). |
| 172 if (key.target_size().IsEmpty()) { | 144 if (key.target_size().IsEmpty()) { |
| 173 *task = nullptr; | 145 *task = nullptr; |
| 174 return false; | 146 return false; |
| 175 } | 147 } |
| 176 | 148 |
| 177 // If we're not going to do a scale, we will just create a task to preroll the | |
|
vmpstr
2016/03/29 18:38:13
\o/
| |
| 178 // image the first time we see it. This doesn't need to account for memory. | |
| 179 // TODO(vmpstr): We can also lock the original sized image, in which case it | |
| 180 // does require memory bookkeeping. | |
| 181 if (!CanHandleImage(key)) { | |
| 182 base::AutoLock lock(lock_); | |
| 183 if (prerolled_images_.count(key.image_id()) == 0) { | |
| 184 scoped_refptr<ImageDecodeTask>& existing_task = pending_image_tasks_[key]; | |
| 185 if (!existing_task) { | |
| 186 existing_task = make_scoped_refptr( | |
| 187 new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id)); | |
| 188 } | |
| 189 *task = existing_task; | |
| 190 } else { | |
| 191 *task = nullptr; | |
| 192 } | |
| 193 return false; | |
| 194 } | |
| 195 | |
| 196 base::AutoLock lock(lock_); | 149 base::AutoLock lock(lock_); |
| 197 | 150 |
| 198 // If we already have the image in cache, then we can return it. | 151 // If we already have the image in cache, then we can return it. |
| 199 auto decoded_it = decoded_images_.Get(key); | 152 auto decoded_it = decoded_images_.Get(key); |
| 200 bool new_image_fits_in_memory = | 153 bool new_image_fits_in_memory = |
| 201 locked_images_budget_.AvailableMemoryBytes() >= key.locked_bytes(); | 154 locked_images_budget_.AvailableMemoryBytes() >= key.locked_bytes(); |
| 202 if (decoded_it != decoded_images_.end()) { | 155 if (decoded_it != decoded_images_.end()) { |
| 203 if (decoded_it->second->is_locked() || | 156 if (decoded_it->second->is_locked() || |
| 204 (new_image_fits_in_memory && decoded_it->second->Lock())) { | 157 (new_image_fits_in_memory && decoded_it->second->Lock())) { |
| 205 RefImage(key); | 158 RefImage(key); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 } | 210 } |
| 258 | 211 |
| 259 void SoftwareImageDecodeController::UnrefImage(const DrawImage& image) { | 212 void SoftwareImageDecodeController::UnrefImage(const DrawImage& image) { |
| 260 // When we unref the image, there are several situations we need to consider: | 213 // When we unref the image, there are several situations we need to consider: |
| 261 // 1. The ref did not reach 0, which means we have to keep the image locked. | 214 // 1. The ref did not reach 0, which means we have to keep the image locked. |
| 262 // 2. The ref reached 0, we should unlock it. | 215 // 2. The ref reached 0, we should unlock it. |
| 263 // 2a. The image isn't in the locked cache because we didn't get to decode | 216 // 2a. The image isn't in the locked cache because we didn't get to decode |
| 264 // it yet (or failed to decode it). | 217 // it yet (or failed to decode it). |
| 265 // 2b. Unlock the image but keep it in list. | 218 // 2b. Unlock the image but keep it in list. |
| 266 const ImageKey& key = ImageKey::FromDrawImage(image); | 219 const ImageKey& key = ImageKey::FromDrawImage(image); |
| 267 DCHECK(CanHandleImage(key)); | |
| 268 TRACE_EVENT1("disabled-by-default-cc.debug", | 220 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 269 "SoftwareImageDecodeController::UnrefImage", "key", | 221 "SoftwareImageDecodeController::UnrefImage", "key", |
| 270 key.ToString()); | 222 key.ToString()); |
| 271 | 223 |
| 272 base::AutoLock lock(lock_); | 224 base::AutoLock lock(lock_); |
| 273 auto ref_count_it = decoded_images_ref_counts_.find(key); | 225 auto ref_count_it = decoded_images_ref_counts_.find(key); |
| 274 DCHECK(ref_count_it != decoded_images_ref_counts_.end()); | 226 DCHECK(ref_count_it != decoded_images_ref_counts_.end()); |
| 275 | 227 |
| 276 --ref_count_it->second; | 228 --ref_count_it->second; |
| 277 if (ref_count_it->second == 0) { | 229 if (ref_count_it->second == 0) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 288 DCHECK(decoded_image_it->second->is_locked()); | 240 DCHECK(decoded_image_it->second->is_locked()); |
| 289 decoded_image_it->second->Unlock(); | 241 decoded_image_it->second->Unlock(); |
| 290 } | 242 } |
| 291 SanityCheckState(__LINE__, true); | 243 SanityCheckState(__LINE__, true); |
| 292 } | 244 } |
| 293 | 245 |
| 294 void SoftwareImageDecodeController::DecodeImage(const ImageKey& key, | 246 void SoftwareImageDecodeController::DecodeImage(const ImageKey& key, |
| 295 const DrawImage& image) { | 247 const DrawImage& image) { |
| 296 TRACE_EVENT1("cc", "SoftwareImageDecodeController::DecodeImage", "key", | 248 TRACE_EVENT1("cc", "SoftwareImageDecodeController::DecodeImage", "key", |
| 297 key.ToString()); | 249 key.ToString()); |
| 298 if (!CanHandleImage(key)) { | |
| 299 image.image()->preroll(); | |
| 300 | |
| 301 base::AutoLock lock(lock_); | |
| 302 prerolled_images_.insert(key.image_id()); | |
| 303 // Erase the pending task from the queue, since the task won't be doing | |
| 304 // anything useful after this function terminates. Since we don't preroll | |
| 305 // images twice, this is actually not necessary but it behaves similar to | |
| 306 // the other code path: when this function finishes, the task isn't in the | |
| 307 // pending_image_tasks_ list. | |
| 308 pending_image_tasks_.erase(key); | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 base::AutoLock lock(lock_); | 250 base::AutoLock lock(lock_); |
| 313 AutoRemoveKeyFromTaskMap remove_key_from_task_map(&pending_image_tasks_, key); | 251 AutoRemoveKeyFromTaskMap remove_key_from_task_map(&pending_image_tasks_, key); |
| 314 | 252 |
| 315 // We could have finished all of the raster tasks (cancelled) while the task | 253 // We could have finished all of the raster tasks (cancelled) while the task |
| 316 // was just starting to run. Since this task already started running, it | 254 // was just starting to run. Since this task already started running, it |
| 317 // wasn't cancelled. So, if the ref count for the image is 0 then we can just | 255 // wasn't cancelled. So, if the ref count for the image is 0 then we can just |
| 318 // abort. | 256 // abort. |
| 319 if (decoded_images_ref_counts_.find(key) == | 257 if (decoded_images_ref_counts_.find(key) == |
| 320 decoded_images_ref_counts_.end()) { | 258 decoded_images_ref_counts_.end()) { |
| 321 return; | 259 return; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 if (decoded_images_ref_counts_.find(key) == | 296 if (decoded_images_ref_counts_.find(key) == |
| 359 decoded_images_ref_counts_.end()) { | 297 decoded_images_ref_counts_.end()) { |
| 360 decoded_image->Unlock(); | 298 decoded_image->Unlock(); |
| 361 } | 299 } |
| 362 | 300 |
| 363 decoded_images_.Put(key, std::move(decoded_image)); | 301 decoded_images_.Put(key, std::move(decoded_image)); |
| 364 SanityCheckState(__LINE__, true); | 302 SanityCheckState(__LINE__, true); |
| 365 } | 303 } |
| 366 | 304 |
| 367 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | 305 scoped_ptr<SoftwareImageDecodeController::DecodedImage> |
| 306 SoftwareImageDecodeController::DecodeImageNoneLowQuality(const ImageKey& key, | |
| 307 const SkImage& image) { | |
| 308 DCHECK(key.can_use_original_decode()); | |
| 309 | |
| 310 return AttemptToUseOriginalImage(key, image); | |
| 311 } | |
| 312 | |
| 313 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 314 SoftwareImageDecodeController::DecodeImageMediumQuality(const ImageKey& key, | |
| 315 const SkImage& image) { | |
| 316 // We need an original decode to either do a scale or extract a subrect | |
| 317 // from the image. | |
| 318 auto decoded_image_result = DecodeImageOrUseCache(key, image); | |
| 319 if (!decoded_image_result.decoded_pixmap_.addr()) { | |
| 320 return nullptr; | |
| 321 } | |
| 322 | |
| 323 // Generate a key and scaled image for each mipmap level. | |
| 324 gfx::Rect src_rect = key.src_rect(); | |
| 325 int src_height = src_rect.height(); | |
| 326 int src_width = src_rect.width(); | |
| 327 int largest_axis = std::max(src_height, src_width); | |
| 328 | |
| 329 // Make sure our signed int fits inside a uint32_t | |
| 330 if (largest_axis > numeric_limits<uint32_t>::max()) { | |
|
vmpstr
2016/03/29 18:38:13
Do you know which systems we have that have a 64 b
cblume
2016/03/29 18:53:44
I agree with your comments. Actually, when I origi
| |
| 331 return nullptr; | |
| 332 } | |
| 333 int leading_zeros = SkCLZ(static_cast<uint32_t>(largest_axis)); | |
|
cblume
2016/03/29 18:53:44
Oops. I meant to make this the new CLZ function.
A
| |
| 334 // If the value 00011010 has 3 leading 0s then it had 5 significant bits | |
| 335 // (the bits which are not leading zeros) | |
| 336 int significant_bits = (sizeof(uint32_t) * 8) - leading_zeros; | |
|
vmpstr
2016/03/29 18:38:13
sizeof(uint32_t) == 4 on all platforms that we sup
cblume
2016/03/29 18:53:44
As far as I know, yes.
Maybe make it a DCHECK and
| |
| 337 // This is making the assumption taht the size of a byte is 8 bits | |
|
vmpstr
2016/03/29 18:38:13
s/taht/that/
I think that sizeof(char) is defined
cblume
2016/03/29 18:53:44
Oh holy cow, I didn't know about CHAR_BIT.
We cou
| |
| 338 // and that sizeof(uint32_t)'s implementation-defined behavior is 4. | |
| 339 int mip_level_count = significant_bits; | |
| 340 | |
| 341 scoped_ptr<DecodedImage> last_mip_scaled_image = nullptr; | |
|
vmpstr
2016/03/29 18:38:13
you don't need to initialize scoped_ptrs, they are
cblume
2016/03/29 18:53:44
Done.
| |
| 342 scoped_ptr<DecodedImage> target_mip_image = nullptr; | |
| 343 for (int current_mip_level = 0; current_mip_level < mip_level_count; | |
| 344 current_mip_level++) { | |
| 345 int mip_height = std::max(1, src_height / (1 << current_mip_level)); | |
| 346 int mip_width = std::max(1, src_width / (1 << current_mip_level)); | |
| 347 SkScalar y_scale = static_cast<float>(mip_height) / src_height; | |
| 348 SkScalar x_scale = static_cast<float>(mip_width) / src_width; | |
| 349 | |
| 350 // Generate an image and key to cache it | |
| 351 DrawImage mip_image(*image, src_rect, kMedium_SkFilterQuality, | |
| 352 SkMatrix::MakeScale(x_scale, y_scale)); | |
| 353 ImageKey mip_key = ImageKey::FromDrawImage(mip_image); | |
| 354 scoped_ptr<DecodedImage> mip_scaled_image = | |
| 355 ScaleImage(mip_key, decoded_image_result); | |
| 356 | |
| 357 // Check if this is the first mipmap smaller than target. | |
| 358 // If so, use the mip level below on the stack. | |
| 359 // This effectively always uses the larger image and always scales down. | |
| 360 if (mip_height < key.target_size().height() || | |
| 361 mip_width < key.target_size().width()) { | |
| 362 if (target_mip_image == nullptr) { | |
| 363 target_mip_image = last_mip_scaled_image; | |
|
vmpstr
2016/03/29 18:38:13
scoped_ptrs assign like this? last_mip_scaled_imag
cblume
2016/03/29 18:53:44
The outcome is a build error. Whoops. Fixing.
| |
| 364 } | |
| 365 } | |
| 366 last_mip_scaled_image = mip_scaled_image; | |
| 367 } | |
| 368 | |
| 369 return target_mip_image; | |
| 370 } | |
| 371 | |
| 372 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 373 SoftwareImageDecodeController::DecodeImageHighQuality(const ImageKey& key, | |
| 374 const SkImage& image) { | |
| 375 // We need an original decode to either do a scale or to extract a subrect | |
| 376 // from the image. | |
| 377 auto decoded_image_result = DecodeImageOrUseCache(key, image); | |
| 378 if (!decoded_image_result.decoded_pixmap_.addr()) { | |
| 379 return nullptr; | |
| 380 } | |
| 381 | |
| 382 | |
| 383 // Now we have a decoded_pixmap which represents the src_rect at the | |
| 384 // original scale. All we need to do is scale it. | |
| 385 return ScaleImage(key, decoded_image_result); | |
| 386 } | |
| 387 | |
| 388 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 368 SoftwareImageDecodeController::DecodeImageInternal( | 389 SoftwareImageDecodeController::DecodeImageInternal( |
| 369 const ImageKey& key, | 390 const ImageKey& key, |
| 370 const DrawImage& draw_image) { | 391 const DrawImage& draw_image) { |
| 371 TRACE_EVENT1("disabled-by-default-cc.debug", | 392 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 372 "SoftwareImageDecodeController::DecodeImageInternal", "key", | 393 "SoftwareImageDecodeController::DecodeImageInternal", "key", |
| 373 key.ToString()); | 394 key.ToString()); |
| 374 const SkImage* image = draw_image.image(); | 395 const SkImage* image = draw_image.image(); |
| 375 | 396 if (!image) { |
| 376 // If we can use the original decode, then we don't need to do scaling. We can | |
| 377 // just read pixels into the final memory. | |
| 378 if (key.can_use_original_decode()) { | |
| 379 SkImageInfo decoded_info = | |
| 380 CreateImageInfo(image->width(), image->height(), format_); | |
| 381 scoped_ptr<base::DiscardableMemory> decoded_pixels; | |
| 382 { | |
| 383 TRACE_EVENT0( | |
| 384 "disabled-by-default-cc.debug", | |
| 385 "SoftwareImageDecodeController::DecodeImageInternal - allocate " | |
| 386 "decoded pixels"); | |
| 387 decoded_pixels = | |
| 388 base::DiscardableMemoryAllocator::GetInstance() | |
| 389 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() * | |
| 390 decoded_info.height()); | |
| 391 } | |
| 392 { | |
| 393 TRACE_EVENT0( | |
| 394 "disabled-by-default-cc.debug", | |
| 395 "SoftwareImageDecodeController::DecodeImageInternal - read pixels"); | |
| 396 bool result = image->readPixels(decoded_info, decoded_pixels->data(), | |
| 397 decoded_info.minRowBytes(), 0, 0, | |
| 398 SkImage::kDisallow_CachingHint); | |
| 399 | |
| 400 if (!result) { | |
| 401 decoded_pixels->Unlock(); | |
| 402 return nullptr; | |
| 403 } | |
| 404 } | |
| 405 | |
| 406 return make_scoped_ptr(new DecodedImage( | |
| 407 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0))); | |
| 408 } | |
| 409 | |
| 410 // If we get here, that means we couldn't use the original sized decode for | |
| 411 // whatever reason. However, in all cases we do need an original decode to | |
| 412 // either do a scale or to extract a subrect from the image. So, what we can | |
| 413 // do is construct a key that would require a full sized decode, then get that | |
| 414 // decode via GetDecodedImageForDrawInternal(), use it, and unref it. This | |
| 415 // ensures that if the original sized decode is already available in any of | |
| 416 // the caches, we reuse that. We also ensure that all the proper locking takes | |
| 417 // place. If, on the other hand, the decode was not available, | |
| 418 // GetDecodedImageForDrawInternal() would decode the image, and unreffing it | |
| 419 // later ensures that we will store the discardable memory unlocked in the | |
| 420 // cache to be used by future requests. | |
| 421 gfx::Rect full_image_rect(image->width(), image->height()); | |
| 422 DrawImage original_size_draw_image(image, gfx::RectToSkIRect(full_image_rect), | |
| 423 kNone_SkFilterQuality, SkMatrix::I()); | |
| 424 ImageKey original_size_key = | |
| 425 ImageKey::FromDrawImage(original_size_draw_image); | |
| 426 // Sanity checks. | |
| 427 DCHECK(original_size_key.can_use_original_decode()); | |
| 428 DCHECK(full_image_rect.size() == original_size_key.target_size()); | |
| 429 | |
| 430 auto decoded_draw_image = GetDecodedImageForDrawInternal( | |
| 431 original_size_key, original_size_draw_image); | |
| 432 if (!decoded_draw_image.image()) { | |
| 433 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | |
| 434 return nullptr; | 397 return nullptr; |
| 435 } | 398 } |
| 436 | 399 |
| 437 SkPixmap decoded_pixmap; | 400 switch (key.filter_quality()) { |
| 438 bool result = decoded_draw_image.image()->peekPixels(&decoded_pixmap); | 401 case kNone_SkFilterQuality: |
| 439 DCHECK(result); | 402 // fall through |
| 440 if (key.src_rect() != full_image_rect) { | 403 case kLow_SkFilterQuality: |
| 441 result = decoded_pixmap.extractSubset(&decoded_pixmap, | 404 return DecodeImageNoneLowQuality(key, *image); |
| 442 gfx::RectToSkIRect(key.src_rect())); | 405 case kMedium_SkFilterQuality: |
| 443 DCHECK(result); | 406 return DecodeImageMediumQuality(key, *image); |
| 407 case kHigh_SkFilterQuality: | |
| 408 return DecodeImageHighQuality(key, *image); | |
| 409 default: | |
| 410 NOTREACHED(); | |
| 411 return nullptr; | |
| 444 } | 412 } |
| 445 | |
| 446 // Now we have a decoded_pixmap which represents the src_rect at the | |
| 447 // original scale. All we need to do is scale it. | |
| 448 DCHECK(!key.target_size().IsEmpty()); | |
| 449 SkImageInfo scaled_info = CreateImageInfo( | |
| 450 key.target_size().width(), key.target_size().height(), format_); | |
| 451 scoped_ptr<base::DiscardableMemory> scaled_pixels; | |
| 452 { | |
| 453 TRACE_EVENT0( | |
| 454 "disabled-by-default-cc.debug", | |
| 455 "SoftwareImageDecodeController::DecodeImageInternal - allocate " | |
| 456 "scaled pixels"); | |
| 457 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() | |
| 458 ->AllocateLockedDiscardableMemory( | |
| 459 scaled_info.minRowBytes() * scaled_info.height()); | |
| 460 } | |
| 461 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), | |
| 462 scaled_info.minRowBytes()); | |
| 463 // TODO(vmpstr): Start handling more than just high filter quality. | |
| 464 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); | |
| 465 { | |
| 466 TRACE_EVENT0( | |
| 467 "disabled-by-default-cc.debug", | |
| 468 "SoftwareImageDecodeController::DecodeImageInternal - scale pixels"); | |
| 469 bool result = | |
| 470 decoded_pixmap.scalePixels(scaled_pixmap, key.filter_quality()); | |
| 471 DCHECK(result); | |
| 472 } | |
| 473 | |
| 474 // Release the original sized decode. Any other intermediate result to release | |
| 475 // would be the subrect memory. However, that's in a scoped_ptr and will be | |
| 476 // deleted automatically when we return. | |
| 477 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | |
| 478 | |
| 479 return make_scoped_ptr( | |
| 480 new DecodedImage(scaled_info, std::move(scaled_pixels), | |
| 481 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); | |
| 482 } | 413 } |
| 483 | 414 |
| 484 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( | 415 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( |
| 485 const DrawImage& draw_image) { | 416 const DrawImage& draw_image) { |
| 486 ImageKey key = ImageKey::FromDrawImage(draw_image); | 417 ImageKey key = ImageKey::FromDrawImage(draw_image); |
| 487 TRACE_EVENT1("disabled-by-default-cc.debug", | 418 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 488 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key", | 419 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key", |
| 489 key.ToString()); | 420 key.ToString()); |
| 490 // If the target size is empty, we can skip this image draw. | 421 // If the target size is empty, we can skip this image draw. |
| 491 if (key.target_size().IsEmpty()) | 422 if (key.target_size().IsEmpty()) |
| 492 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); | 423 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); |
| 493 | 424 |
| 494 if (!CanHandleImage(key)) | |
| 495 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality()); | |
| 496 | |
| 497 return GetDecodedImageForDrawInternal(key, draw_image); | 425 return GetDecodedImageForDrawInternal(key, draw_image); |
| 498 } | 426 } |
| 499 | 427 |
| 500 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDrawInternal( | 428 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDrawInternal( |
| 501 const ImageKey& key, | 429 const ImageKey& key, |
| 502 const DrawImage& draw_image) { | 430 const DrawImage& draw_image) { |
| 503 TRACE_EVENT1("disabled-by-default-cc.debug", | 431 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 504 "SoftwareImageDecodeController::GetDecodedImageForDrawInternal", | 432 "SoftwareImageDecodeController::GetDecodedImageForDrawInternal", |
| 505 "key", key.ToString()); | 433 "key", key.ToString()); |
| 506 base::AutoLock lock(lock_); | 434 base::AutoLock lock(lock_); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 542 // Now we know that we don't have a locked image, and we seem to be the first | 470 // Now we know that we don't have a locked image, and we seem to be the first |
| 543 // thread encountering this image (that might not be true, since other threads | 471 // thread encountering this image (that might not be true, since other threads |
| 544 // might be decoding it already). This means that we need to decode the image | 472 // might be decoding it already). This means that we need to decode the image |
| 545 // assuming we can't lock the one we found in the cache. | 473 // assuming we can't lock the one we found in the cache. |
| 546 bool check_at_raster_cache = false; | 474 bool check_at_raster_cache = false; |
| 547 if (!decoded_image || !decoded_image->Lock()) { | 475 if (!decoded_image || !decoded_image->Lock()) { |
| 548 // Note that we have to release the lock, since this lock is also accessed | 476 // Note that we have to release the lock, since this lock is also accessed |
| 549 // on the compositor thread. This means holding on to the lock might stall | 477 // on the compositor thread. This means holding on to the lock might stall |
| 550 // the compositor thread for the duration of the decode! | 478 // the compositor thread for the duration of the decode! |
| 551 base::AutoUnlock unlock(lock_); | 479 base::AutoUnlock unlock(lock_); |
| 552 scoped_decoded_image = DecodeImageInternal(key, draw_image); | 480 const SkImage* image = draw_image.image(); |
| 481 if (!image) { | |
| 482 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); | |
| 483 } | |
| 484 scoped_decoded_image = AttemptToUseOriginalImage(key, *image); | |
| 553 decoded_image = scoped_decoded_image.get(); | 485 decoded_image = scoped_decoded_image.get(); |
| 554 | 486 |
| 555 // Skip the image if we couldn't decode it. | 487 // Skip the image if we couldn't decode it. |
| 556 if (!decoded_image) | 488 if (!decoded_image) |
| 557 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); | 489 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); |
| 558 check_at_raster_cache = true; | 490 check_at_raster_cache = true; |
| 559 } | 491 } |
| 560 | 492 |
| 561 DCHECK(decoded_image == scoped_decoded_image.get()); | 493 DCHECK(decoded_image == scoped_decoded_image.get()); |
| 562 | 494 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 583 DCHECK(decoded_image->is_locked()); | 515 DCHECK(decoded_image->is_locked()); |
| 584 RefAtRasterImage(key); | 516 RefAtRasterImage(key); |
| 585 SanityCheckState(__LINE__, true); | 517 SanityCheckState(__LINE__, true); |
| 586 auto decoded_draw_image = | 518 auto decoded_draw_image = |
| 587 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), | 519 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), |
| 588 GetScaleAdjustment(key), GetDecodedFilterQuality(key)); | 520 GetScaleAdjustment(key), GetDecodedFilterQuality(key)); |
| 589 decoded_draw_image.set_at_raster_decode(true); | 521 decoded_draw_image.set_at_raster_decode(true); |
| 590 return decoded_draw_image; | 522 return decoded_draw_image; |
| 591 } | 523 } |
| 592 | 524 |
| 525 SoftwareImageDecodeController::DecodedImageResult::DecodedImageResult( | |
| 526 SkPixmap decoded_pixmap, | |
| 527 DrawImage original_size_draw_image, | |
| 528 DecodedDrawImage decoded_draw_image) | |
| 529 : decoded_pixmap_(decoded_pixmap), | |
| 530 original_size_draw_image_(original_size_draw_image), | |
| 531 decoded_draw_image_(decoded_draw_image) {} | |
| 532 | |
| 533 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 534 SoftwareImageDecodeController::AttemptToUseOriginalImage(const ImageKey& key, | |
| 535 const SkImage& image) { | |
| 536 TRACE_EVENT1("disabled-by-default-cc.debug", | |
| 537 "SoftwareImageDecodeController::AttemptToUseOriginalImage", | |
| 538 "key", key.ToString()); | |
| 539 if (!key.can_use_original_decode()) { | |
| 540 return nullptr; | |
| 541 } else { | |
| 542 SkImageInfo decoded_info = | |
| 543 SkImageInfo::MakeN32Premul(image.width(), image.height()); | |
| 544 scoped_ptr<base::DiscardableMemory> decoded_pixels; | |
| 545 { | |
| 546 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 547 "SoftwareImageDecodeController::AttemptToUseOriginalImage - " | |
| 548 "allocate decoded pixels"); | |
| 549 decoded_pixels = | |
| 550 base::DiscardableMemoryAllocator::GetInstance() | |
| 551 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() * | |
| 552 decoded_info.height()); | |
| 553 } | |
| 554 { | |
| 555 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 556 "SoftwareImageDecodeController::AttemptToUseOriginalImage - " | |
| 557 "read pixels"); | |
| 558 bool result = image.readPixels(decoded_info, decoded_pixels->data(), | |
| 559 decoded_info.minRowBytes(), 0, 0, | |
| 560 SkImage::kDisallow_CachingHint); | |
| 561 | |
| 562 if (!result) { | |
| 563 decoded_pixels->Unlock(); | |
| 564 return nullptr; | |
| 565 } | |
| 566 } | |
| 567 | |
| 568 return make_scoped_ptr(new DecodedImage( | |
| 569 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0))); | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 SoftwareImageDecodeController::DecodedImageResult | |
| 574 SoftwareImageDecodeController::DecodeImageOrUseCache(const ImageKey& key, | |
| 575 const SkImage& image) { | |
| 576 // Construct a key to use in GetDecodedImageForDrawInternal(). | |
| 577 // This allows us to reuse an image in any cache if available. | |
| 578 gfx::Rect full_image_rect(image.width(), image.height()); | |
| 579 DrawImage original_size_draw_image(&image, | |
| 580 gfx::RectToSkIRect(full_image_rect), | |
| 581 kNone_SkFilterQuality, SkMatrix::I()); | |
| 582 ImageKey original_size_key = | |
| 583 ImageKey::FromDrawImage(original_size_draw_image); | |
| 584 // Sanity checks. | |
| 585 DCHECK(original_size_key.can_use_original_decode()); | |
| 586 DCHECK(full_image_rect.size() == original_size_key.target_size()); | |
| 587 | |
| 588 auto decoded_draw_image = GetDecodedImageForDrawInternal( | |
| 589 original_size_key, original_size_draw_image); | |
| 590 | |
| 591 if (!decoded_draw_image.image()) { | |
| 592 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | |
| 593 return DecodedImageResult(SkPixmap(), DrawImage(), | |
| 594 DecodedDrawImage(nullptr, kNone_SkFilterQuality)); | |
| 595 } | |
| 596 | |
| 597 SkPixmap decoded_pixmap; | |
| 598 bool result = decoded_draw_image.image()->peekPixels(&decoded_pixmap); | |
| 599 DCHECK(result); | |
| 600 if (key.src_rect() != full_image_rect) { | |
| 601 result = decoded_pixmap.extractSubset(&decoded_pixmap, | |
| 602 gfx::RectToSkIRect(key.src_rect())); | |
| 603 DCHECK(result); | |
| 604 } | |
| 605 | |
| 606 return DecodedImageResult(decoded_pixmap, original_size_draw_image, | |
| 607 decoded_draw_image); | |
| 608 } | |
| 609 | |
| 610 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 611 SoftwareImageDecodeController::ScaleImage( | |
| 612 const ImageKey& key, | |
| 613 const DecodedImageResult& decoded_image_result) { | |
| 614 DCHECK(!key.target_size().IsEmpty()); | |
| 615 SkImageInfo scaled_info = SkImageInfo::MakeN32Premul( | |
| 616 key.target_size().width(), key.target_size().height()); | |
| 617 scoped_ptr<base::DiscardableMemory> scaled_pixels; | |
| 618 { | |
| 619 TRACE_EVENT0( | |
| 620 "disabled-by-default-cc.debug", | |
| 621 "SoftwareImageDecodeController::ScaleImage - allocate scaled pixels"); | |
| 622 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() | |
| 623 ->AllocateLockedDiscardableMemory( | |
| 624 scaled_info.minRowBytes() * scaled_info.height()); | |
| 625 } | |
| 626 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), | |
| 627 scaled_info.minRowBytes()); | |
| 628 { | |
| 629 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 630 "SoftwareImageDecodeController::ScaleImage - scale pixels"); | |
| 631 bool result = decoded_image_result.decoded_pixmap_.scalePixels( | |
| 632 scaled_pixmap, key.filter_quality()); | |
| 633 DCHECK(result); | |
| 634 } | |
| 635 | |
| 636 // Release the original sized decode. Any other intermediate result to release | |
| 637 // would be the subrect memory. However, that's in a scoped_ptr and will be | |
| 638 // deleted automatically when we return. | |
| 639 DrawWithImageFinished(decoded_image_result.original_size_draw_image_, | |
| 640 decoded_image_result.decoded_draw_image_); | |
| 641 | |
| 642 return make_scoped_ptr(new SoftwareImageDecodeController::DecodedImage( | |
| 643 scaled_info, std::move(scaled_pixels), | |
| 644 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); | |
| 645 } | |
| 646 | |
| 593 void SoftwareImageDecodeController::DrawWithImageFinished( | 647 void SoftwareImageDecodeController::DrawWithImageFinished( |
| 594 const DrawImage& image, | 648 const DrawImage& image, |
| 595 const DecodedDrawImage& decoded_image) { | 649 const DecodedDrawImage& decoded_image) { |
| 596 TRACE_EVENT1("disabled-by-default-cc.debug", | 650 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 597 "SoftwareImageDecodeController::DrawWithImageFinished", "key", | 651 "SoftwareImageDecodeController::DrawWithImageFinished", "key", |
| 598 ImageKey::FromDrawImage(image).ToString()); | 652 ImageKey::FromDrawImage(image).ToString()); |
| 599 ImageKey key = ImageKey::FromDrawImage(image); | 653 ImageKey key = ImageKey::FromDrawImage(image); |
| 600 if (!decoded_image.image() || !CanHandleImage(key)) | 654 if (!decoded_image.image()) |
| 601 return; | 655 return; |
| 602 | 656 |
| 603 if (decoded_image.is_at_raster_decode()) | 657 if (decoded_image.is_at_raster_decode()) |
| 604 UnrefAtRasterImage(key); | 658 UnrefAtRasterImage(key); |
| 605 else | 659 else |
| 606 UnrefImage(image); | 660 UnrefImage(image); |
| 607 SanityCheckState(__LINE__, false); | 661 SanityCheckState(__LINE__, false); |
| 608 } | 662 } |
| 609 | 663 |
| 610 void SoftwareImageDecodeController::RefAtRasterImage(const ImageKey& key) { | 664 void SoftwareImageDecodeController::RefAtRasterImage(const ImageKey& key) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 657 DCHECK(decoded_images_ref_counts_.find(key) == | 711 DCHECK(decoded_images_ref_counts_.find(key) == |
| 658 decoded_images_ref_counts_.end()); | 712 decoded_images_ref_counts_.end()); |
| 659 at_raster_image_it->second->Unlock(); | 713 at_raster_image_it->second->Unlock(); |
| 660 decoded_images_.Erase(image_it); | 714 decoded_images_.Erase(image_it); |
| 661 decoded_images_.Put(key, std::move(at_raster_image_it->second)); | 715 decoded_images_.Put(key, std::move(at_raster_image_it->second)); |
| 662 } | 716 } |
| 663 at_raster_decoded_images_.Erase(at_raster_image_it); | 717 at_raster_decoded_images_.Erase(at_raster_image_it); |
| 664 } | 718 } |
| 665 } | 719 } |
| 666 | 720 |
| 667 bool SoftwareImageDecodeController::CanHandleImage(const ImageKey& key) { | |
| 668 // TODO(vmpstr): Start handling medium filter quality as well. | |
| 669 return key.filter_quality() != kMedium_SkFilterQuality; | |
| 670 } | |
| 671 | |
| 672 void SoftwareImageDecodeController::ReduceCacheUsage() { | 721 void SoftwareImageDecodeController::ReduceCacheUsage() { |
| 673 TRACE_EVENT0("cc", "SoftwareImageDecodeController::ReduceCacheUsage"); | 722 TRACE_EVENT0("cc", "SoftwareImageDecodeController::ReduceCacheUsage"); |
| 674 base::AutoLock lock(lock_); | 723 base::AutoLock lock(lock_); |
| 675 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache) | 724 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache) |
| 676 ? (decoded_images_.size() - kMaxItemsInCache) | 725 ? (decoded_images_.size() - kMaxItemsInCache) |
| 677 : 0; | 726 : 0; |
| 678 for (auto it = decoded_images_.rbegin(); | 727 for (auto it = decoded_images_.rbegin(); |
| 679 num_to_remove != 0 && it != decoded_images_.rend();) { | 728 num_to_remove != 0 && it != decoded_images_.rend();) { |
| 680 if (it->second->is_locked()) { | 729 if (it->second->is_locked()) { |
| 681 ++it; | 730 ++it; |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 884 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { | 933 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { |
| 885 current_usage_bytes_ = 0; | 934 current_usage_bytes_ = 0; |
| 886 } | 935 } |
| 887 | 936 |
| 888 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() | 937 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() |
| 889 const { | 938 const { |
| 890 return current_usage_bytes_.ValueOrDie(); | 939 return current_usage_bytes_.ValueOrDie(); |
| 891 } | 940 } |
| 892 | 941 |
| 893 } // namespace cc | 942 } // namespace cc |
| OLD | NEW |