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

Side by Side Diff: cc/tiles/software_image_decode_controller.cc

Issue 1839833003: Add medium image quality to software predecode. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« base/bits.h ('K') | « cc/tiles/software_image_decode_controller.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/tiles/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
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
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
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
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
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
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
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
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
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
OLDNEW
« base/bits.h ('K') | « cc/tiles/software_image_decode_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698