| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/gpu_image_decode_controller.h" | 5 #include "cc/tiles/gpu_image_decode_controller.h" |
| 6 | 6 |
| 7 #include <inttypes.h> | 7 #include <inttypes.h> |
| 8 | 8 |
| 9 #include "base/memory/discardable_memory_allocator.h" | 9 #include "base/memory/discardable_memory_allocator.h" |
| 10 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
| 11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
| 12 #include "base/numerics/safe_math.h" | 12 #include "base/numerics/safe_math.h" |
| 13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/threading/thread_task_runner_handle.h" | 14 #include "base/threading/thread_task_runner_handle.h" |
| 15 #include "cc/debug/devtools_instrumentation.h" | 15 #include "cc/debug/devtools_instrumentation.h" |
| 16 #include "cc/output/context_provider.h" | 16 #include "cc/output/context_provider.h" |
| 17 #include "cc/raster/tile_task.h" | 17 #include "cc/raster/tile_task.h" |
| 18 #include "cc/resources/resource_format_utils.h" | 18 #include "cc/resources/resource_format_utils.h" |
| 19 #include "cc/tiles/mipmap_util.h" |
| 19 #include "gpu/command_buffer/client/context_support.h" | 20 #include "gpu/command_buffer/client/context_support.h" |
| 20 #include "gpu/command_buffer/client/gles2_interface.h" | 21 #include "gpu/command_buffer/client/gles2_interface.h" |
| 21 #include "gpu_image_decode_controller.h" | 22 #include "gpu_image_decode_controller.h" |
| 22 #include "skia/ext/texture_handle.h" | 23 #include "skia/ext/texture_handle.h" |
| 23 #include "third_party/skia/include/core/SkCanvas.h" | 24 #include "third_party/skia/include/core/SkCanvas.h" |
| 24 #include "third_party/skia/include/core/SkRefCnt.h" | 25 #include "third_party/skia/include/core/SkRefCnt.h" |
| 25 #include "third_party/skia/include/core/SkSurface.h" | 26 #include "third_party/skia/include/core/SkSurface.h" |
| 26 #include "third_party/skia/include/gpu/GrContext.h" | 27 #include "third_party/skia/include/gpu/GrContext.h" |
| 27 #include "third_party/skia/include/gpu/GrTexture.h" | 28 #include "third_party/skia/include/gpu/GrTexture.h" |
| 28 #include "ui/gfx/skia_util.h" | 29 #include "ui/gfx/skia_util.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 40 return true; | 41 return true; |
| 41 if (std::abs(draw_image.scale().width()) < | 42 if (std::abs(draw_image.scale().width()) < |
| 42 std::numeric_limits<float>::epsilon() || | 43 std::numeric_limits<float>::epsilon() || |
| 43 std::abs(draw_image.scale().height()) < | 44 std::abs(draw_image.scale().height()) < |
| 44 std::numeric_limits<float>::epsilon()) { | 45 std::numeric_limits<float>::epsilon()) { |
| 45 return true; | 46 return true; |
| 46 } | 47 } |
| 47 return false; | 48 return false; |
| 48 } | 49 } |
| 49 | 50 |
| 51 // Returns the filter quality to use for scaling the image to upload scale. For |
| 52 // GPU raster, medium and high filter quality are identical for downscales. |
| 53 // Upload scaling is always a downscale, so cap our filter quality to medium. |
| 54 SkFilterQuality CalculateUploadScaleFilterQuality(const DrawImage& draw_image) { |
| 55 return std::min(kMedium_SkFilterQuality, draw_image.filter_quality()); |
| 56 } |
| 57 |
| 50 SkImage::DeferredTextureImageUsageParams ParamsFromDrawImage( | 58 SkImage::DeferredTextureImageUsageParams ParamsFromDrawImage( |
| 51 const DrawImage& draw_image) { | 59 const DrawImage& draw_image, |
| 60 int upload_scale_mip_level) { |
| 52 SkImage::DeferredTextureImageUsageParams params; | 61 SkImage::DeferredTextureImageUsageParams params; |
| 53 params.fMatrix = draw_image.matrix(); | 62 params.fMatrix = draw_image.matrix(); |
| 54 params.fQuality = draw_image.filter_quality(); | 63 params.fQuality = draw_image.filter_quality(); |
| 64 params.fPreScaleMipLevel = upload_scale_mip_level; |
| 55 | 65 |
| 56 return params; | 66 return params; |
| 57 } | 67 } |
| 58 | 68 |
| 69 // Calculate the mip level to upload-scale the image to before uploading. We use |
| 70 // mip levels rather than exact scales to increase re-use of scaled images. |
| 71 int CalculateUploadScaleMipLevel(const DrawImage& draw_image) { |
| 72 // Images which are being clipped will have color-bleeding if scaled. |
| 73 // TODO(ericrk): Investigate uploading clipped images to handle this case and |
| 74 // provide further optimization. crbug.com/620899 |
| 75 if (draw_image.src_rect() != draw_image.image()->bounds()) |
| 76 return 0; |
| 77 |
| 78 gfx::Size base_size(draw_image.image()->width(), |
| 79 draw_image.image()->height()); |
| 80 // Ceil our scaled size so that the mip map generated is guaranteed to be |
| 81 // larger. Take the abs of the scale, as mipmap functions don't handle |
| 82 // (and aren't impacted by) negative image dimensions. |
| 83 gfx::Size scaled_size = |
| 84 gfx::ScaleToCeiledSize(base_size, std::abs(draw_image.scale().width()), |
| 85 std::abs(draw_image.scale().height())); |
| 86 |
| 87 return MipMapUtil::GetLevelForSize(base_size, scaled_size); |
| 88 } |
| 89 |
| 90 // Calculates the scale factor which can be used to scale an image to a given |
| 91 // mip level. |
| 92 SkSize CalculateScaleFactorForMipLevel(const DrawImage& draw_image, |
| 93 int mip_level) { |
| 94 gfx::Size base_size(draw_image.image()->width(), |
| 95 draw_image.image()->height()); |
| 96 return MipMapUtil::GetScaleAdjustmentForLevel(base_size, mip_level); |
| 97 } |
| 98 |
| 99 // Calculates the size of a given mip level. |
| 100 gfx::Size CalculateSizeForMipLevel(const DrawImage& draw_image, int mip_level) { |
| 101 gfx::Size base_size(draw_image.image()->width(), |
| 102 draw_image.image()->height()); |
| 103 return MipMapUtil::GetSizeForLevel(base_size, mip_level); |
| 104 } |
| 105 |
| 106 // Generates a uint64_t which uniquely identifies a DrawImage for the purposes |
| 107 // of the |in_use_cache_|. The key is generated as follows: |
| 108 // ╔══════════════════════╤═══════════╤═══════════╗ |
| 109 // ║ image_id │ mip_level │ quality ║ |
| 110 // ╚════════32═bits═══════╧══16═bits══╧══16═bits══╝ |
| 111 uint64_t GenerateInUseCacheKey(const DrawImage& draw_image) { |
| 112 static_assert( |
| 113 kLast_SkFilterQuality <= std::numeric_limits<uint16_t>::max(), |
| 114 "InUseCacheKey depends on SkFilterQuality fitting in a uint16_t."); |
| 115 |
| 116 SkFilterQuality filter_quality = |
| 117 CalculateUploadScaleFilterQuality(draw_image); |
| 118 DCHECK_LE(filter_quality, kLast_SkFilterQuality); |
| 119 |
| 120 // An image has at most log_2(max(width, height)) mip levels, so given our |
| 121 // usage of 32-bit sizes for images, key.mip_level is at most 31. |
| 122 int32_t mip_level = CalculateUploadScaleMipLevel(draw_image); |
| 123 DCHECK_LT(mip_level, 32); |
| 124 |
| 125 return (static_cast<uint64_t>(draw_image.image()->uniqueID()) << 32) | |
| 126 (mip_level << 16) | filter_quality; |
| 127 } |
| 128 |
| 59 } // namespace | 129 } // namespace |
| 60 | 130 |
| 131 GpuImageDecodeController::InUseCacheEntry::InUseCacheEntry( |
| 132 scoped_refptr<ImageData> image_data) |
| 133 : image_data(std::move(image_data)) {} |
| 134 GpuImageDecodeController::InUseCacheEntry::InUseCacheEntry( |
| 135 const InUseCacheEntry&) = default; |
| 136 GpuImageDecodeController::InUseCacheEntry::InUseCacheEntry(InUseCacheEntry&&) = |
| 137 default; |
| 138 GpuImageDecodeController::InUseCacheEntry::~InUseCacheEntry() = default; |
| 139 |
| 61 // Task which decodes an image and stores the result in discardable memory. | 140 // Task which decodes an image and stores the result in discardable memory. |
| 62 // This task does not use GPU resources and can be run on any thread. | 141 // This task does not use GPU resources and can be run on any thread. |
| 63 class ImageDecodeTaskImpl : public TileTask { | 142 class ImageDecodeTaskImpl : public TileTask { |
| 64 public: | 143 public: |
| 65 ImageDecodeTaskImpl(GpuImageDecodeController* controller, | 144 ImageDecodeTaskImpl(GpuImageDecodeController* controller, |
| 66 const DrawImage& draw_image, | 145 const DrawImage& draw_image, |
| 67 const ImageDecodeController::TracingInfo& tracing_info) | 146 const ImageDecodeController::TracingInfo& tracing_info) |
| 68 : TileTask(true), | 147 : TileTask(true), |
| 69 controller_(controller), | 148 controller_(controller), |
| 70 image_(draw_image), | 149 image_(draw_image), |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 | 249 |
| 171 void GpuImageDecodeController::DecodedImageData::ResetData() { | 250 void GpuImageDecodeController::DecodedImageData::ResetData() { |
| 172 DCHECK(!is_locked_); | 251 DCHECK(!is_locked_); |
| 173 if (data_) | 252 if (data_) |
| 174 ReportUsageStats(); | 253 ReportUsageStats(); |
| 175 data_ = nullptr; | 254 data_ = nullptr; |
| 176 usage_stats_ = UsageStats(); | 255 usage_stats_ = UsageStats(); |
| 177 } | 256 } |
| 178 | 257 |
| 179 void GpuImageDecodeController::DecodedImageData::ReportUsageStats() const { | 258 void GpuImageDecodeController::DecodedImageData::ReportUsageStats() const { |
| 180 // lock_count | used | result state | 259 // lock_count │ used │ result state |
| 181 // ===========+=======+================== | 260 // ═══════════╪═══════╪══════════════════ |
| 182 // 1 | false | WASTED_ONCE | 261 // 1 │ false │ WASTED_ONCE |
| 183 // 1 | true | USED_ONCE | 262 // 1 │ true │ USED_ONCE |
| 184 // >1 | false | WASTED_RELOCKED | 263 // >1 │ false │ WASTED_RELOCKED |
| 185 // >1 | true | USED_RELOCKED | 264 // >1 │ true │ USED_RELOCKED |
| 186 // Note that it's important not to reorder the following enums, since the | 265 // Note that it's important not to reorder the following enums, since the |
| 187 // numerical values are used in the histogram code. | 266 // numerical values are used in the histogram code. |
| 188 enum State : int { | 267 enum State : int { |
| 189 DECODED_IMAGE_STATE_WASTED_ONCE, | 268 DECODED_IMAGE_STATE_WASTED_ONCE, |
| 190 DECODED_IMAGE_STATE_USED_ONCE, | 269 DECODED_IMAGE_STATE_USED_ONCE, |
| 191 DECODED_IMAGE_STATE_WASTED_RELOCKED, | 270 DECODED_IMAGE_STATE_WASTED_RELOCKED, |
| 192 DECODED_IMAGE_STATE_USED_RELOCKED, | 271 DECODED_IMAGE_STATE_USED_RELOCKED, |
| 193 DECODED_IMAGE_STATE_COUNT | 272 DECODED_IMAGE_STATE_COUNT |
| 194 } state = DECODED_IMAGE_STATE_WASTED_ONCE; | 273 } state = DECODED_IMAGE_STATE_WASTED_ONCE; |
| 195 | 274 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 226 image_ = std::move(image); | 305 image_ = std::move(image); |
| 227 } | 306 } |
| 228 | 307 |
| 229 void GpuImageDecodeController::UploadedImageData::ReportUsageStats() const { | 308 void GpuImageDecodeController::UploadedImageData::ReportUsageStats() const { |
| 230 UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageUploadState.Used", | 309 UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageUploadState.Used", |
| 231 usage_stats_.used); | 310 usage_stats_.used); |
| 232 UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageUploadState.FirstRefWasted", | 311 UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuImageUploadState.FirstRefWasted", |
| 233 usage_stats_.first_ref_wasted); | 312 usage_stats_.first_ref_wasted); |
| 234 } | 313 } |
| 235 | 314 |
| 236 GpuImageDecodeController::ImageData::ImageData(DecodedDataMode mode, | 315 GpuImageDecodeController::ImageData::ImageData( |
| 237 size_t size) | 316 DecodedDataMode mode, |
| 238 : mode(mode), size(size) {} | 317 size_t size, |
| 318 int upload_scale_mip_level, |
| 319 SkFilterQuality upload_scale_filter_quality) |
| 320 : mode(mode), |
| 321 size(size), |
| 322 upload_scale_mip_level(upload_scale_mip_level), |
| 323 upload_scale_filter_quality(upload_scale_filter_quality) {} |
| 239 | 324 |
| 240 GpuImageDecodeController::ImageData::~ImageData() = default; | 325 GpuImageDecodeController::ImageData::~ImageData() { |
| 326 // We should never delete ImageData while it is in use or before it has been |
| 327 // cleaned up. |
| 328 DCHECK_EQ(0u, upload.ref_count); |
| 329 DCHECK_EQ(0u, decode.ref_count); |
| 330 DCHECK_EQ(false, decode.is_locked()); |
| 331 // This should always be cleaned up before deleting the image, as it needs to |
| 332 // be freed with the GL context lock held. |
| 333 DCHECK(!upload.image()); |
| 334 } |
| 241 | 335 |
| 242 GpuImageDecodeController::GpuImageDecodeController(ContextProvider* context, | 336 GpuImageDecodeController::GpuImageDecodeController(ContextProvider* context, |
| 243 ResourceFormat decode_format, | 337 ResourceFormat decode_format, |
| 244 size_t max_gpu_image_bytes) | 338 size_t max_gpu_image_bytes) |
| 245 : format_(decode_format), | 339 : format_(decode_format), |
| 246 context_(context), | 340 context_(context), |
| 247 image_data_(ImageDataMRUCache::NO_AUTO_EVICT), | 341 persistent_cache_(PersistentCache::NO_AUTO_EVICT), |
| 248 cached_items_limit_(kMaxDiscardableItems), | 342 cached_items_limit_(kMaxDiscardableItems), |
| 249 cached_bytes_limit_(max_gpu_image_bytes), | 343 cached_bytes_limit_(max_gpu_image_bytes), |
| 250 bytes_used_(0), | 344 bytes_used_(0), |
| 251 max_gpu_image_bytes_(max_gpu_image_bytes) { | 345 max_gpu_image_bytes_(max_gpu_image_bytes) { |
| 252 // Acquire the context_lock so that we can safely retrieve the | 346 // Acquire the context_lock so that we can safely retrieve the |
| 253 // GrContextThreadSafeProxy. This proxy can then be used with no lock held. | 347 // GrContextThreadSafeProxy. This proxy can then be used with no lock held. |
| 254 { | 348 { |
| 255 ContextProvider::ScopedContextLock context_lock(context_); | 349 ContextProvider::ScopedContextLock context_lock(context_); |
| 256 context_threadsafe_proxy_ = sk_sp<GrContextThreadSafeProxy>( | 350 context_threadsafe_proxy_ = sk_sp<GrContextThreadSafeProxy>( |
| 257 context->GrContext()->threadSafeProxy()); | 351 context->GrContext()->threadSafeProxy()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 280 const DrawImage& draw_image, | 374 const DrawImage& draw_image, |
| 281 const TracingInfo& tracing_info, | 375 const TracingInfo& tracing_info, |
| 282 scoped_refptr<TileTask>* task) { | 376 scoped_refptr<TileTask>* task) { |
| 283 if (SkipImage(draw_image)) { | 377 if (SkipImage(draw_image)) { |
| 284 *task = nullptr; | 378 *task = nullptr; |
| 285 return false; | 379 return false; |
| 286 } | 380 } |
| 287 | 381 |
| 288 base::AutoLock lock(lock_); | 382 base::AutoLock lock(lock_); |
| 289 const auto image_id = draw_image.image()->uniqueID(); | 383 const auto image_id = draw_image.image()->uniqueID(); |
| 290 | 384 ImageData* image_data = GetImageDataForDrawImage(draw_image); |
| 291 auto found = image_data_.Get(image_id); | 385 scoped_refptr<ImageData> new_data; |
| 292 if (found != image_data_.end()) { | 386 if (!image_data) { |
| 293 ImageData* image_data = found->second.get(); | 387 // We need an ImageData, create one now. |
| 294 if (image_data->is_at_raster) { | 388 new_data = CreateImageData(draw_image); |
| 295 // Image is at-raster, just return, this usage will be at-raster as well. | 389 image_data = new_data.get(); |
| 296 *task = nullptr; | 390 } else if (image_data->is_at_raster) { |
| 297 return false; | 391 // Image is at-raster, just return, this usage will be at-raster as well. |
| 298 } | 392 *task = nullptr; |
| 299 | 393 return false; |
| 300 if (image_data->decode.decode_failure) { | 394 } else if (image_data->decode.decode_failure) { |
| 301 // We have already tried and failed to decode this image, so just return. | 395 // We have already tried and failed to decode this image, so just return. |
| 302 *task = nullptr; | 396 *task = nullptr; |
| 303 return false; | 397 return false; |
| 304 } | 398 } else if (image_data->upload.image()) { |
| 305 | 399 // The image is already uploaded, ref and return. |
| 306 if (image_data->upload.image()) { | 400 RefImage(draw_image); |
| 307 // The image is already uploaded, ref and return. | 401 *task = nullptr; |
| 308 RefImage(draw_image); | 402 return true; |
| 309 *task = nullptr; | 403 } else if (image_data->upload.task) { |
| 310 return true; | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 // We didn't have a pre-uploaded image, so we need an upload task. Try to find | |
| 315 // an existing one. | |
| 316 scoped_refptr<TileTask>& existing_task = | |
| 317 pending_image_upload_tasks_[image_id]; | |
| 318 if (existing_task) { | |
| 319 // We had an existing upload task, ref the image and return the task. | 404 // We had an existing upload task, ref the image and return the task. |
| 320 RefImage(draw_image); | 405 RefImage(draw_image); |
| 321 *task = existing_task; | 406 *task = image_data->upload.task; |
| 322 return true; | 407 return true; |
| 323 } | 408 } |
| 324 | 409 |
| 325 // We will be creating a new upload task. If necessary, create a placeholder | |
| 326 // ImageData to hold the result. | |
| 327 std::unique_ptr<ImageData> new_data; | |
| 328 ImageData* data; | |
| 329 if (found == image_data_.end()) { | |
| 330 new_data = CreateImageData(draw_image); | |
| 331 data = new_data.get(); | |
| 332 } else { | |
| 333 data = found->second.get(); | |
| 334 } | |
| 335 | |
| 336 // Ensure that the image we're about to decode/upload will fit in memory. | 410 // Ensure that the image we're about to decode/upload will fit in memory. |
| 337 if (!EnsureCapacity(data->size)) { | 411 if (!EnsureCapacity(image_data->size)) { |
| 338 // Image will not fit, do an at-raster decode. | 412 // Image will not fit, do an at-raster decode. |
| 339 *task = nullptr; | 413 *task = nullptr; |
| 340 return false; | 414 return false; |
| 341 } | 415 } |
| 342 | 416 |
| 343 // If we had to create new image data, add it to our map now that we know it | 417 // If we had to create new image data, add it to our map now that we know it |
| 344 // will fit. | 418 // will fit. |
| 345 if (new_data) | 419 if (new_data) |
| 346 found = image_data_.Put(image_id, std::move(new_data)); | 420 persistent_cache_.Put(image_id, std::move(new_data)); |
| 347 | 421 |
| 348 // Ref image and create a upload and decode tasks. We will release this ref | 422 // Ref image and create a upload and decode tasks. We will release this ref |
| 349 // in UploadTaskCompleted. | 423 // in UploadTaskCompleted. |
| 350 RefImage(draw_image); | 424 RefImage(draw_image); |
| 351 existing_task = make_scoped_refptr(new ImageUploadTaskImpl( | 425 *task = make_scoped_refptr(new ImageUploadTaskImpl( |
| 352 this, draw_image, GetImageDecodeTaskAndRef(draw_image, tracing_info), | 426 this, draw_image, GetImageDecodeTaskAndRef(draw_image, tracing_info), |
| 353 tracing_info)); | 427 tracing_info)); |
| 428 image_data->upload.task = *task; |
| 354 | 429 |
| 355 // Ref the image again - this ref is owned by the caller, and it is their | 430 // Ref the image again - this ref is owned by the caller, and it is their |
| 356 // responsibility to release it by calling UnrefImage. | 431 // responsibility to release it by calling UnrefImage. |
| 357 RefImage(draw_image); | 432 RefImage(draw_image); |
| 358 *task = existing_task; | |
| 359 return true; | 433 return true; |
| 360 } | 434 } |
| 361 | 435 |
| 362 void GpuImageDecodeController::UnrefImage(const DrawImage& draw_image) { | 436 void GpuImageDecodeController::UnrefImage(const DrawImage& draw_image) { |
| 363 base::AutoLock lock(lock_); | 437 base::AutoLock lock(lock_); |
| 364 UnrefImageInternal(draw_image); | 438 UnrefImageInternal(draw_image); |
| 365 } | 439 } |
| 366 | 440 |
| 367 DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw( | 441 DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw( |
| 368 const DrawImage& draw_image) { | 442 const DrawImage& draw_image) { |
| 443 TRACE_EVENT0("cc", "GpuImageDecodeController::GetDecodedImageForDraw"); |
| 444 |
| 369 // We are being called during raster. The context lock must already be | 445 // We are being called during raster. The context lock must already be |
| 370 // acquired by the caller. | 446 // acquired by the caller. |
| 371 context_->GetLock()->AssertAcquired(); | 447 context_->GetLock()->AssertAcquired(); |
| 372 | 448 |
| 373 if (SkipImage(draw_image)) | 449 if (SkipImage(draw_image)) |
| 374 return DecodedDrawImage(nullptr, draw_image.filter_quality()); | 450 return DecodedDrawImage(nullptr, draw_image.filter_quality()); |
| 375 | 451 |
| 376 TRACE_EVENT0("cc", "GpuImageDecodeController::GetDecodedImageForDraw"); | |
| 377 | |
| 378 base::AutoLock lock(lock_); | 452 base::AutoLock lock(lock_); |
| 379 const uint32_t unique_id = draw_image.image()->uniqueID(); | 453 ImageData* image_data = GetImageDataForDrawImage(draw_image); |
| 380 auto found = image_data_.Peek(unique_id); | 454 if (!image_data) { |
| 381 if (found == image_data_.end()) { | |
| 382 // We didn't find the image, create a new entry. | 455 // We didn't find the image, create a new entry. |
| 383 auto data = CreateImageData(draw_image); | 456 auto data = CreateImageData(draw_image); |
| 384 found = image_data_.Put(unique_id, std::move(data)); | 457 image_data = data.get(); |
| 458 persistent_cache_.Put(draw_image.image()->uniqueID(), std::move(data)); |
| 385 } | 459 } |
| 386 | 460 |
| 387 ImageData* image_data = found->second.get(); | |
| 388 | |
| 389 if (!image_data->upload.budgeted) { | 461 if (!image_data->upload.budgeted) { |
| 390 // If image data is not budgeted by this point, it is at-raster. | 462 // If image data is not budgeted by this point, it is at-raster. |
| 391 image_data->is_at_raster = true; | 463 image_data->is_at_raster = true; |
| 392 } | 464 } |
| 393 | 465 |
| 394 // Ref the image and decode so that they stay alive while we are | 466 // Ref the image and decode so that they stay alive while we are |
| 395 // decoding/uploading. | 467 // decoding/uploading. |
| 396 RefImage(draw_image); | 468 RefImage(draw_image); |
| 397 RefImageDecode(draw_image); | 469 RefImageDecode(draw_image); |
| 398 | 470 |
| 399 // We may or may not need to decode and upload the image we've found, the | 471 // We may or may not need to decode and upload the image we've found, the |
| 400 // following functions early-out to if we already decoded. | 472 // following functions early-out to if we already decoded. |
| 401 DecodeImageIfNecessary(draw_image, image_data); | 473 DecodeImageIfNecessary(draw_image, image_data); |
| 402 UploadImageIfNecessary(draw_image, image_data); | 474 UploadImageIfNecessary(draw_image, image_data); |
| 403 // Unref the image decode, but not the image. The image ref will be released | 475 // Unref the image decode, but not the image. The image ref will be released |
| 404 // in DrawWithImageFinished. | 476 // in DrawWithImageFinished. |
| 405 UnrefImageDecode(draw_image); | 477 UnrefImageDecode(draw_image); |
| 406 | 478 |
| 407 sk_sp<SkImage> image = image_data->upload.image(); | 479 sk_sp<SkImage> image = image_data->upload.image(); |
| 408 image_data->upload.mark_used(); | 480 image_data->upload.mark_used(); |
| 409 DCHECK(image || image_data->decode.decode_failure); | 481 DCHECK(image || image_data->decode.decode_failure); |
| 410 | 482 |
| 411 DecodedDrawImage decoded_draw_image(std::move(image), | 483 SkSize scale_factor = CalculateScaleFactorForMipLevel( |
| 484 draw_image, image_data->upload_scale_mip_level); |
| 485 DecodedDrawImage decoded_draw_image(std::move(image), SkSize(), scale_factor, |
| 412 draw_image.filter_quality()); | 486 draw_image.filter_quality()); |
| 413 decoded_draw_image.set_at_raster_decode(image_data->is_at_raster); | 487 decoded_draw_image.set_at_raster_decode(image_data->is_at_raster); |
| 414 return decoded_draw_image; | 488 return decoded_draw_image; |
| 415 } | 489 } |
| 416 | 490 |
| 417 void GpuImageDecodeController::DrawWithImageFinished( | 491 void GpuImageDecodeController::DrawWithImageFinished( |
| 418 const DrawImage& draw_image, | 492 const DrawImage& draw_image, |
| 419 const DecodedDrawImage& decoded_draw_image) { | 493 const DecodedDrawImage& decoded_draw_image) { |
| 494 TRACE_EVENT0("cc", "GpuImageDecodeController::DrawWithImageFinished"); |
| 495 |
| 420 // We are being called during raster. The context lock must already be | 496 // We are being called during raster. The context lock must already be |
| 421 // acquired by the caller. | 497 // acquired by the caller. |
| 422 context_->GetLock()->AssertAcquired(); | 498 context_->GetLock()->AssertAcquired(); |
| 423 | 499 |
| 424 if (SkipImage(draw_image)) | 500 if (SkipImage(draw_image)) |
| 425 return; | 501 return; |
| 426 | 502 |
| 427 base::AutoLock lock(lock_); | 503 base::AutoLock lock(lock_); |
| 428 UnrefImageInternal(draw_image); | 504 UnrefImageInternal(draw_image); |
| 429 | 505 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 453 DeletePendingImages(); | 529 DeletePendingImages(); |
| 454 } else { | 530 } else { |
| 455 base::AutoLock lock(lock_); | 531 base::AutoLock lock(lock_); |
| 456 cached_bytes_limit_ = max_gpu_image_bytes_; | 532 cached_bytes_limit_ = max_gpu_image_bytes_; |
| 457 } | 533 } |
| 458 } | 534 } |
| 459 | 535 |
| 460 bool GpuImageDecodeController::OnMemoryDump( | 536 bool GpuImageDecodeController::OnMemoryDump( |
| 461 const base::trace_event::MemoryDumpArgs& args, | 537 const base::trace_event::MemoryDumpArgs& args, |
| 462 base::trace_event::ProcessMemoryDump* pmd) { | 538 base::trace_event::ProcessMemoryDump* pmd) { |
| 463 for (const auto& image_pair : image_data_) { | 539 for (const auto& image_pair : persistent_cache_) { |
| 464 const ImageData* image_data = image_pair.second.get(); | 540 const ImageData* image_data = image_pair.second.get(); |
| 465 const uint32_t image_id = image_pair.first; | 541 const uint32_t image_id = image_pair.first; |
| 466 | 542 |
| 467 // If we have discardable decoded data, dump this here. | 543 // If we have discardable decoded data, dump this here. |
| 468 if (image_data->decode.data()) { | 544 if (image_data->decode.data()) { |
| 469 std::string discardable_dump_name = base::StringPrintf( | 545 std::string discardable_dump_name = base::StringPrintf( |
| 470 "cc/image_memory/controller_0x%" PRIXPTR "/discardable/image_%d", | 546 "cc/image_memory/controller_0x%" PRIXPTR "/discardable/image_%d", |
| 471 reinterpret_cast<uintptr_t>(this), image_id); | 547 reinterpret_cast<uintptr_t>(this), image_id); |
| 472 base::trace_event::MemoryAllocatorDump* dump = | 548 base::trace_event::MemoryAllocatorDump* dump = |
| 473 image_data->decode.data()->CreateMemoryAllocatorDump( | 549 image_data->decode.data()->CreateMemoryAllocatorDump( |
| 474 discardable_dump_name.c_str(), pmd); | 550 discardable_dump_name.c_str(), pmd); |
| 475 | |
| 476 // If our image is locked, dump the "locked_size" as an additional column. | 551 // If our image is locked, dump the "locked_size" as an additional column. |
| 477 // This lets us see the amount of discardable which is contributing to | 552 // This lets us see the amount of discardable which is contributing to |
| 478 // memory pressure. | 553 // memory pressure. |
| 479 if (image_data->decode.is_locked()) { | 554 if (image_data->decode.is_locked()) { |
| 480 dump->AddScalar("locked_size", | 555 dump->AddScalar("locked_size", |
| 481 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | 556 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 482 image_data->size); | 557 image_data->size); |
| 483 } | 558 } |
| 484 } | 559 } |
| 485 | 560 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 513 pmd->CreateSharedGlobalAllocatorDump(guid); | 588 pmd->CreateSharedGlobalAllocatorDump(guid); |
| 514 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance); | 589 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance); |
| 515 } | 590 } |
| 516 } | 591 } |
| 517 | 592 |
| 518 return true; | 593 return true; |
| 519 } | 594 } |
| 520 | 595 |
| 521 void GpuImageDecodeController::DecodeImage(const DrawImage& draw_image) { | 596 void GpuImageDecodeController::DecodeImage(const DrawImage& draw_image) { |
| 522 base::AutoLock lock(lock_); | 597 base::AutoLock lock(lock_); |
| 523 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | 598 ImageData* image_data = GetImageDataForDrawImage(draw_image); |
| 524 DCHECK(found != image_data_.end()); | 599 DCHECK(image_data); |
| 525 DCHECK(!found->second->is_at_raster); | 600 DCHECK(!image_data->is_at_raster); |
| 526 DecodeImageIfNecessary(draw_image, found->second.get()); | 601 DecodeImageIfNecessary(draw_image, image_data); |
| 527 } | 602 } |
| 528 | 603 |
| 529 void GpuImageDecodeController::UploadImage(const DrawImage& draw_image) { | 604 void GpuImageDecodeController::UploadImage(const DrawImage& draw_image) { |
| 530 ContextProvider::ScopedContextLock context_lock(context_); | 605 ContextProvider::ScopedContextLock context_lock(context_); |
| 531 base::AutoLock lock(lock_); | 606 base::AutoLock lock(lock_); |
| 532 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | 607 ImageData* image_data = GetImageDataForDrawImage(draw_image); |
| 533 DCHECK(found != image_data_.end()); | 608 DCHECK(image_data); |
| 534 DCHECK(!found->second->is_at_raster); | 609 DCHECK(!image_data->is_at_raster); |
| 535 UploadImageIfNecessary(draw_image, found->second.get()); | 610 UploadImageIfNecessary(draw_image, image_data); |
| 536 } | 611 } |
| 537 | 612 |
| 538 void GpuImageDecodeController::OnImageDecodeTaskCompleted( | 613 void GpuImageDecodeController::OnImageDecodeTaskCompleted( |
| 539 const DrawImage& draw_image) { | 614 const DrawImage& draw_image) { |
| 540 base::AutoLock lock(lock_); | 615 base::AutoLock lock(lock_); |
| 541 // Decode task is complete, remove it from our list of pending tasks. | 616 // Decode task is complete, remove our reference to it. |
| 542 pending_image_decode_tasks_.erase(draw_image.image()->uniqueID()); | 617 ImageData* image_data = GetImageDataForDrawImage(draw_image); |
| 618 DCHECK(image_data); |
| 619 DCHECK(image_data->decode.task); |
| 620 image_data->decode.task = nullptr; |
| 543 | 621 |
| 544 // While the decode task is active, we keep a ref on the decoded data. | 622 // While the decode task is active, we keep a ref on the decoded data. |
| 545 // Release that ref now. | 623 // Release that ref now. |
| 546 UnrefImageDecode(draw_image); | 624 UnrefImageDecode(draw_image); |
| 547 } | 625 } |
| 548 | 626 |
| 549 void GpuImageDecodeController::OnImageUploadTaskCompleted( | 627 void GpuImageDecodeController::OnImageUploadTaskCompleted( |
| 550 const DrawImage& draw_image) { | 628 const DrawImage& draw_image) { |
| 551 base::AutoLock lock(lock_); | 629 base::AutoLock lock(lock_); |
| 552 // Upload task is complete, remove it from our list of pending tasks. | 630 // Upload task is complete, remove our reference to it. |
| 553 pending_image_upload_tasks_.erase(draw_image.image()->uniqueID()); | 631 ImageData* image_data = GetImageDataForDrawImage(draw_image); |
| 632 DCHECK(image_data); |
| 633 DCHECK(image_data->upload.task); |
| 634 image_data->upload.task = nullptr; |
| 554 | 635 |
| 555 // While the upload task is active, we keep a ref on both the image it will be | 636 // While the upload task is active, we keep a ref on both the image it will be |
| 556 // populating, as well as the decode it needs to populate it. Release these | 637 // populating, as well as the decode it needs to populate it. Release these |
| 557 // refs now. | 638 // refs now. |
| 558 UnrefImageDecode(draw_image); | 639 UnrefImageDecode(draw_image); |
| 559 UnrefImageInternal(draw_image); | 640 UnrefImageInternal(draw_image); |
| 560 } | 641 } |
| 561 | 642 |
| 562 // Checks if an existing image decode exists. If not, returns a task to produce | 643 // Checks if an existing image decode exists. If not, returns a task to produce |
| 563 // the requested decode. | 644 // the requested decode. |
| 564 scoped_refptr<TileTask> GpuImageDecodeController::GetImageDecodeTaskAndRef( | 645 scoped_refptr<TileTask> GpuImageDecodeController::GetImageDecodeTaskAndRef( |
| 565 const DrawImage& draw_image, | 646 const DrawImage& draw_image, |
| 566 const TracingInfo& tracing_info) { | 647 const TracingInfo& tracing_info) { |
| 567 lock_.AssertAcquired(); | 648 lock_.AssertAcquired(); |
| 568 | 649 |
| 569 const uint32_t image_id = draw_image.image()->uniqueID(); | |
| 570 | |
| 571 // This ref is kept alive while an upload task may need this decode. We | 650 // This ref is kept alive while an upload task may need this decode. We |
| 572 // release this ref in UploadTaskCompleted. | 651 // release this ref in UploadTaskCompleted. |
| 573 RefImageDecode(draw_image); | 652 RefImageDecode(draw_image); |
| 574 | 653 |
| 575 auto found = image_data_.Peek(image_id); | 654 ImageData* image_data = GetImageDataForDrawImage(draw_image); |
| 576 if (found != image_data_.end() && found->second->decode.is_locked()) { | 655 DCHECK(image_data); |
| 656 if (image_data->decode.is_locked()) { |
| 577 // We should never be creating a decode task for an at raster image. | 657 // We should never be creating a decode task for an at raster image. |
| 578 DCHECK(!found->second->is_at_raster); | 658 DCHECK(!image_data->is_at_raster); |
| 579 // We should never be creating a decode for an already-uploaded image. | 659 // We should never be creating a decode for an already-uploaded image. |
| 580 DCHECK(!found->second->upload.image()); | 660 DCHECK(!image_data->upload.image()); |
| 581 return nullptr; | 661 return nullptr; |
| 582 } | 662 } |
| 583 | 663 |
| 584 // We didn't have an existing locked image, create a task to lock or decode. | 664 // We didn't have an existing locked image, create a task to lock or decode. |
| 585 scoped_refptr<TileTask>& existing_task = | 665 scoped_refptr<TileTask>& existing_task = image_data->decode.task; |
| 586 pending_image_decode_tasks_[image_id]; | |
| 587 if (!existing_task) { | 666 if (!existing_task) { |
| 588 // Ref image decode and create a decode task. This ref will be released in | 667 // Ref image decode and create a decode task. This ref will be released in |
| 589 // DecodeTaskCompleted. | 668 // DecodeTaskCompleted. |
| 590 RefImageDecode(draw_image); | 669 RefImageDecode(draw_image); |
| 591 existing_task = make_scoped_refptr( | 670 existing_task = make_scoped_refptr( |
| 592 new ImageDecodeTaskImpl(this, draw_image, tracing_info)); | 671 new ImageDecodeTaskImpl(this, draw_image, tracing_info)); |
| 593 } | 672 } |
| 594 return existing_task; | 673 return existing_task; |
| 595 } | 674 } |
| 596 | 675 |
| 597 void GpuImageDecodeController::RefImageDecode(const DrawImage& draw_image) { | 676 void GpuImageDecodeController::RefImageDecode(const DrawImage& draw_image) { |
| 598 lock_.AssertAcquired(); | 677 lock_.AssertAcquired(); |
| 599 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | 678 auto found = in_use_cache_.find(GenerateInUseCacheKey(draw_image)); |
| 600 DCHECK(found != image_data_.end()); | 679 DCHECK(found != in_use_cache_.end()); |
| 601 ++found->second->decode.ref_count; | 680 ++found->second.ref_count; |
| 602 RefCountChanged(found->second.get()); | 681 ++found->second.image_data->decode.ref_count; |
| 682 OwnershipChanged(found->second.image_data.get()); |
| 603 } | 683 } |
| 604 | 684 |
| 605 void GpuImageDecodeController::UnrefImageDecode(const DrawImage& draw_image) { | 685 void GpuImageDecodeController::UnrefImageDecode(const DrawImage& draw_image) { |
| 606 lock_.AssertAcquired(); | 686 lock_.AssertAcquired(); |
| 607 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | 687 auto found = in_use_cache_.find(GenerateInUseCacheKey(draw_image)); |
| 608 DCHECK(found != image_data_.end()); | 688 DCHECK(found != in_use_cache_.end()); |
| 609 DCHECK_GT(found->second->decode.ref_count, 0u); | 689 DCHECK_GT(found->second.image_data->decode.ref_count, 0u); |
| 610 --found->second->decode.ref_count; | 690 DCHECK_GT(found->second.ref_count, 0u); |
| 611 RefCountChanged(found->second.get()); | 691 --found->second.ref_count; |
| 692 --found->second.image_data->decode.ref_count; |
| 693 OwnershipChanged(found->second.image_data.get()); |
| 694 if (found->second.ref_count == 0u) { |
| 695 in_use_cache_.erase(found); |
| 696 } |
| 612 } | 697 } |
| 613 | 698 |
| 614 void GpuImageDecodeController::RefImage(const DrawImage& draw_image) { | 699 void GpuImageDecodeController::RefImage(const DrawImage& draw_image) { |
| 615 lock_.AssertAcquired(); | 700 lock_.AssertAcquired(); |
| 616 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | 701 InUseCacheKey key = GenerateInUseCacheKey(draw_image); |
| 617 DCHECK(found != image_data_.end()); | 702 auto found = in_use_cache_.find(key); |
| 618 ++found->second->upload.ref_count; | 703 |
| 619 RefCountChanged(found->second.get()); | 704 // If no secondary cache entry was found for the given |draw_image|, then |
| 705 // the draw_image only exists in the |persistent_cache_|. Create an in-use |
| 706 // cache entry now. |
| 707 if (found == in_use_cache_.end()) { |
| 708 auto found_image = persistent_cache_.Peek(draw_image.image()->uniqueID()); |
| 709 DCHECK(found_image != persistent_cache_.end()); |
| 710 DCHECK(found_image->second->upload_scale_mip_level <= |
| 711 CalculateUploadScaleMipLevel(draw_image)); |
| 712 found = in_use_cache_ |
| 713 .insert(InUseCache::value_type( |
| 714 key, InUseCacheEntry(found_image->second))) |
| 715 .first; |
| 716 } |
| 717 |
| 718 DCHECK(found != in_use_cache_.end()); |
| 719 ++found->second.ref_count; |
| 720 ++found->second.image_data->upload.ref_count; |
| 721 OwnershipChanged(found->second.image_data.get()); |
| 620 } | 722 } |
| 621 | 723 |
| 622 void GpuImageDecodeController::UnrefImageInternal(const DrawImage& draw_image) { | 724 void GpuImageDecodeController::UnrefImageInternal(const DrawImage& draw_image) { |
| 623 lock_.AssertAcquired(); | 725 lock_.AssertAcquired(); |
| 624 auto found = image_data_.Peek(draw_image.image()->uniqueID()); | 726 auto found = in_use_cache_.find(GenerateInUseCacheKey(draw_image)); |
| 625 DCHECK(found != image_data_.end()); | 727 DCHECK(found != in_use_cache_.end()); |
| 626 DCHECK_GT(found->second->upload.ref_count, 0u); | 728 DCHECK_GT(found->second.image_data->upload.ref_count, 0u); |
| 627 --found->second->upload.ref_count; | 729 DCHECK_GT(found->second.ref_count, 0u); |
| 628 if (found->second->upload.ref_count == 0) | 730 --found->second.ref_count; |
| 629 found->second->upload.notify_ref_reached_zero(); | 731 --found->second.image_data->upload.ref_count; |
| 630 RefCountChanged(found->second.get()); | 732 OwnershipChanged(found->second.image_data.get()); |
| 733 if (found->second.ref_count == 0u) { |
| 734 in_use_cache_.erase(found); |
| 735 } |
| 631 } | 736 } |
| 632 | 737 |
| 633 // Called any time an image or decode ref count changes. Takes care of any | 738 // Called any time an image or decode ref count changes. Takes care of any |
| 634 // necessary memory budget book-keeping and cleanup. | 739 // necessary memory budget book-keeping and cleanup. |
| 635 void GpuImageDecodeController::RefCountChanged(ImageData* image_data) { | 740 void GpuImageDecodeController::OwnershipChanged(ImageData* image_data) { |
| 636 lock_.AssertAcquired(); | 741 lock_.AssertAcquired(); |
| 637 | 742 |
| 638 bool has_any_refs = | 743 bool has_any_refs = |
| 639 image_data->upload.ref_count > 0 || image_data->decode.ref_count > 0; | 744 image_data->upload.ref_count > 0 || image_data->decode.ref_count > 0; |
| 640 | 745 |
| 746 // Don't keep around orphaned images. |
| 747 if (image_data->is_orphaned && !has_any_refs) { |
| 748 images_pending_deletion_.push_back(std::move(image_data->upload.image())); |
| 749 image_data->upload.SetImage(nullptr); |
| 750 } |
| 751 |
| 641 // Don't keep CPU images if they are unused, these images can be recreated by | 752 // Don't keep CPU images if they are unused, these images can be recreated by |
| 642 // re-locking discardable (rather than requiring a full upload like GPU | 753 // re-locking discardable (rather than requiring a full upload like GPU |
| 643 // images). | 754 // images). |
| 644 if (image_data->mode == DecodedDataMode::CPU && !has_any_refs) { | 755 if (image_data->mode == DecodedDataMode::CPU && !has_any_refs) { |
| 645 images_pending_deletion_.push_back(image_data->upload.image()); | 756 images_pending_deletion_.push_back(image_data->upload.image()); |
| 646 image_data->upload.SetImage(nullptr); | 757 image_data->upload.SetImage(nullptr); |
| 647 } | 758 } |
| 648 | 759 |
| 649 if (image_data->is_at_raster && !has_any_refs) { | 760 if (image_data->is_at_raster && !has_any_refs) { |
| 650 // We have an at-raster image which has reached zero refs. If it won't fit | 761 // We have an at-raster image which has reached zero refs. If it won't fit |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 lock_.AssertAcquired(); | 827 lock_.AssertAcquired(); |
| 717 | 828 |
| 718 if (CanFitSize(required_size) && !ExceedsPreferredCount()) | 829 if (CanFitSize(required_size) && !ExceedsPreferredCount()) |
| 719 return true; | 830 return true; |
| 720 | 831 |
| 721 // While we are over memory or preferred item capacity, we iterate through | 832 // While we are over memory or preferred item capacity, we iterate through |
| 722 // our set of cached image data in LRU order. For each image, we can do two | 833 // our set of cached image data in LRU order. For each image, we can do two |
| 723 // things: 1) We can free the uploaded image, reducing the memory usage of | 834 // things: 1) We can free the uploaded image, reducing the memory usage of |
| 724 // the cache and 2) we can remove the entry entirely, reducing the count of | 835 // the cache and 2) we can remove the entry entirely, reducing the count of |
| 725 // elements in the cache. | 836 // elements in the cache. |
| 726 for (auto it = image_data_.rbegin(); it != image_data_.rend();) { | 837 for (auto it = persistent_cache_.rbegin(); it != persistent_cache_.rend();) { |
| 727 if (it->second->decode.ref_count != 0 || | 838 if (it->second->decode.ref_count != 0 || |
| 728 it->second->upload.ref_count != 0) { | 839 it->second->upload.ref_count != 0) { |
| 729 ++it; | 840 ++it; |
| 730 continue; | 841 continue; |
| 731 } | 842 } |
| 732 | 843 |
| 733 // Current entry has no refs. Ensure it is not locked. | 844 // Current entry has no refs. Ensure it is not locked. |
| 734 DCHECK(!it->second->decode.is_locked()); | 845 DCHECK(!it->second->decode.is_locked()); |
| 735 | 846 |
| 736 // If an image without refs is budgeted, it must have an associated image | 847 // If an image without refs is budgeted, it must have an associated image |
| 737 // upload. | 848 // upload. |
| 738 DCHECK(!it->second->upload.budgeted || it->second->upload.image()); | 849 DCHECK(!it->second->upload.budgeted || it->second->upload.image()); |
| 739 | 850 |
| 740 // Free the uploaded image if possible. | 851 // Free the uploaded image if possible. |
| 741 if (it->second->upload.image()) { | 852 if (it->second->upload.image()) { |
| 742 DCHECK(it->second->upload.budgeted); | 853 DCHECK(it->second->upload.budgeted); |
| 743 DCHECK_GE(bytes_used_, it->second->size); | 854 DCHECK_GE(bytes_used_, it->second->size); |
| 744 bytes_used_ -= it->second->size; | 855 bytes_used_ -= it->second->size; |
| 745 images_pending_deletion_.push_back(it->second->upload.image()); | 856 images_pending_deletion_.push_back(it->second->upload.image()); |
| 746 it->second->upload.SetImage(nullptr); | 857 it->second->upload.SetImage(nullptr); |
| 747 it->second->upload.budgeted = false; | 858 it->second->upload.budgeted = false; |
| 748 } | 859 } |
| 749 | 860 |
| 750 // Free the entire entry if necessary. | 861 // Free the entire entry if necessary. |
| 751 if (ExceedsPreferredCount()) { | 862 if (ExceedsPreferredCount()) { |
| 752 it = image_data_.Erase(it); | 863 it = persistent_cache_.Erase(it); |
| 753 } else { | 864 } else { |
| 754 ++it; | 865 ++it; |
| 755 } | 866 } |
| 756 | 867 |
| 757 if (CanFitSize(required_size) && !ExceedsPreferredCount()) | 868 if (CanFitSize(required_size) && !ExceedsPreferredCount()) |
| 758 return true; | 869 return true; |
| 759 } | 870 } |
| 760 | 871 |
| 761 // Preferred count is only used as a guideline when triming the cache. Allow | 872 // Preferred count is only used as a guideline when triming the cache. Allow |
| 762 // new elements to be added as long as we are below our size limit. | 873 // new elements to be added as long as we are below our size limit. |
| 763 return CanFitSize(required_size); | 874 return CanFitSize(required_size); |
| 764 } | 875 } |
| 765 | 876 |
| 766 bool GpuImageDecodeController::CanFitSize(size_t size) const { | 877 bool GpuImageDecodeController::CanFitSize(size_t size) const { |
| 767 lock_.AssertAcquired(); | 878 lock_.AssertAcquired(); |
| 768 | 879 |
| 769 base::CheckedNumeric<uint32_t> new_size(bytes_used_); | 880 base::CheckedNumeric<uint32_t> new_size(bytes_used_); |
| 770 new_size += size; | 881 new_size += size; |
| 771 return new_size.IsValid() && new_size.ValueOrDie() <= cached_bytes_limit_; | 882 return new_size.IsValid() && new_size.ValueOrDie() <= cached_bytes_limit_; |
| 772 } | 883 } |
| 773 | 884 |
| 774 bool GpuImageDecodeController::ExceedsPreferredCount() const { | 885 bool GpuImageDecodeController::ExceedsPreferredCount() const { |
| 775 lock_.AssertAcquired(); | 886 lock_.AssertAcquired(); |
| 776 | 887 |
| 777 return image_data_.size() > cached_items_limit_; | 888 return persistent_cache_.size() > cached_items_limit_; |
| 778 } | 889 } |
| 779 | 890 |
| 780 void GpuImageDecodeController::DecodeImageIfNecessary( | 891 void GpuImageDecodeController::DecodeImageIfNecessary( |
| 781 const DrawImage& draw_image, | 892 const DrawImage& draw_image, |
| 782 ImageData* image_data) { | 893 ImageData* image_data) { |
| 783 lock_.AssertAcquired(); | 894 lock_.AssertAcquired(); |
| 784 | 895 |
| 785 DCHECK_GT(image_data->decode.ref_count, 0u); | 896 DCHECK_GT(image_data->decode.ref_count, 0u); |
| 786 | 897 |
| 787 if (image_data->decode.decode_failure) { | 898 if (image_data->decode.decode_failure) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 804 | 915 |
| 805 image_data->decode.ResetData(); | 916 image_data->decode.ResetData(); |
| 806 std::unique_ptr<base::DiscardableMemory> backing_memory; | 917 std::unique_ptr<base::DiscardableMemory> backing_memory; |
| 807 { | 918 { |
| 808 base::AutoUnlock unlock(lock_); | 919 base::AutoUnlock unlock(lock_); |
| 809 switch (image_data->mode) { | 920 switch (image_data->mode) { |
| 810 case DecodedDataMode::CPU: { | 921 case DecodedDataMode::CPU: { |
| 811 backing_memory = | 922 backing_memory = |
| 812 base::DiscardableMemoryAllocator::GetInstance() | 923 base::DiscardableMemoryAllocator::GetInstance() |
| 813 ->AllocateLockedDiscardableMemory(image_data->size); | 924 ->AllocateLockedDiscardableMemory(image_data->size); |
| 814 SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image); | 925 SkImageInfo image_info = CreateImageInfoForDrawImage( |
| 815 if (!draw_image.image()->readPixels(image_info, backing_memory->data(), | 926 draw_image, image_data->upload_scale_mip_level); |
| 816 image_info.minRowBytes(), 0, 0, | 927 // In order to match GPU scaling quality (which uses mip-maps at high |
| 817 SkImage::kDisallow_CachingHint)) { | 928 // quality), we want to use at most medium filter quality for the |
| 929 // scale. |
| 930 SkPixmap image_pixmap(image_info, backing_memory->data(), |
| 931 image_info.minRowBytes()); |
| 932 // Note that scalePixels falls back to readPixels if the sale is 1x, so |
| 933 // no need to special case that as an optimization. |
| 934 if (!draw_image.image()->scalePixels( |
| 935 image_pixmap, CalculateUploadScaleFilterQuality(draw_image), |
| 936 SkImage::kDisallow_CachingHint)) { |
| 818 backing_memory.reset(); | 937 backing_memory.reset(); |
| 819 } | 938 } |
| 820 break; | 939 break; |
| 821 } | 940 } |
| 822 case DecodedDataMode::GPU: { | 941 case DecodedDataMode::GPU: { |
| 823 backing_memory = | 942 backing_memory = |
| 824 base::DiscardableMemoryAllocator::GetInstance() | 943 base::DiscardableMemoryAllocator::GetInstance() |
| 825 ->AllocateLockedDiscardableMemory(image_data->size); | 944 ->AllocateLockedDiscardableMemory(image_data->size); |
| 826 auto params = ParamsFromDrawImage(draw_image); | 945 auto params = |
| 946 ParamsFromDrawImage(draw_image, image_data->upload_scale_mip_level); |
| 827 if (!draw_image.image()->getDeferredTextureImageData( | 947 if (!draw_image.image()->getDeferredTextureImageData( |
| 828 *context_threadsafe_proxy_.get(), ¶ms, 1, | 948 *context_threadsafe_proxy_.get(), ¶ms, 1, |
| 829 backing_memory->data())) { | 949 backing_memory->data())) { |
| 830 backing_memory.reset(); | 950 backing_memory.reset(); |
| 831 } | 951 } |
| 832 break; | 952 break; |
| 833 } | 953 } |
| 834 } | 954 } |
| 835 } | 955 } |
| 836 | 956 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 872 // We are about to upload a new image and are holding the context lock. | 992 // We are about to upload a new image and are holding the context lock. |
| 873 // Ensure that any images which have been marked for deletion are actually | 993 // Ensure that any images which have been marked for deletion are actually |
| 874 // cleaned up so we don't exceed our memory limit during this upload. | 994 // cleaned up so we don't exceed our memory limit during this upload. |
| 875 DeletePendingImages(); | 995 DeletePendingImages(); |
| 876 | 996 |
| 877 sk_sp<SkImage> uploaded_image; | 997 sk_sp<SkImage> uploaded_image; |
| 878 { | 998 { |
| 879 base::AutoUnlock unlock(lock_); | 999 base::AutoUnlock unlock(lock_); |
| 880 switch (image_data->mode) { | 1000 switch (image_data->mode) { |
| 881 case DecodedDataMode::CPU: { | 1001 case DecodedDataMode::CPU: { |
| 882 SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image); | 1002 SkImageInfo image_info = CreateImageInfoForDrawImage( |
| 1003 draw_image, image_data->upload_scale_mip_level); |
| 883 SkPixmap pixmap(image_info, image_data->decode.data()->data(), | 1004 SkPixmap pixmap(image_info, image_data->decode.data()->data(), |
| 884 image_info.minRowBytes()); | 1005 image_info.minRowBytes()); |
| 885 uploaded_image = | 1006 uploaded_image = |
| 886 SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr); | 1007 SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr); |
| 887 break; | 1008 break; |
| 888 } | 1009 } |
| 889 case DecodedDataMode::GPU: { | 1010 case DecodedDataMode::GPU: { |
| 890 uploaded_image = SkImage::MakeFromDeferredTextureImageData( | 1011 uploaded_image = SkImage::MakeFromDeferredTextureImageData( |
| 891 context_->GrContext(), image_data->decode.data()->data(), | 1012 context_->GrContext(), image_data->decode.data()->data(), |
| 892 SkBudgeted::kNo); | 1013 SkBudgeted::kNo); |
| 893 break; | 1014 break; |
| 894 } | 1015 } |
| 895 } | 1016 } |
| 896 } | 1017 } |
| 897 image_data->decode.mark_used(); | 1018 image_data->decode.mark_used(); |
| 898 DCHECK(uploaded_image); | 1019 DCHECK(uploaded_image); |
| 899 | 1020 |
| 900 // At-raster may have decoded this while we were unlocked. If so, ignore our | 1021 // At-raster may have decoded this while we were unlocked. If so, ignore our |
| 901 // result. | 1022 // result. |
| 902 if (!image_data->upload.image()) | 1023 if (!image_data->upload.image()) |
| 903 image_data->upload.SetImage(std::move(uploaded_image)); | 1024 image_data->upload.SetImage(std::move(uploaded_image)); |
| 904 } | 1025 } |
| 905 | 1026 |
| 906 std::unique_ptr<GpuImageDecodeController::ImageData> | 1027 scoped_refptr<GpuImageDecodeController::ImageData> |
| 907 GpuImageDecodeController::CreateImageData(const DrawImage& draw_image) { | 1028 GpuImageDecodeController::CreateImageData(const DrawImage& draw_image) { |
| 908 lock_.AssertAcquired(); | 1029 lock_.AssertAcquired(); |
| 909 | 1030 |
| 910 DecodedDataMode mode; | 1031 DecodedDataMode mode; |
| 911 SkImageInfo info = CreateImageInfoForDrawImage(draw_image); | 1032 int upload_scale_mip_level = CalculateUploadScaleMipLevel(draw_image); |
| 912 SkImage::DeferredTextureImageUsageParams params = | 1033 SkImage::DeferredTextureImageUsageParams params = |
| 913 ParamsFromDrawImage(draw_image); | 1034 ParamsFromDrawImage(draw_image, upload_scale_mip_level); |
| 914 size_t data_size = draw_image.image()->getDeferredTextureImageData( | 1035 size_t data_size = draw_image.image()->getDeferredTextureImageData( |
| 915 *context_threadsafe_proxy_.get(), ¶ms, 1, nullptr); | 1036 *context_threadsafe_proxy_.get(), ¶ms, 1, nullptr); |
| 916 | 1037 |
| 917 if (data_size == 0) { | 1038 if (data_size == 0) { |
| 918 // Can't upload image, too large or other failure. Try to use SW fallback. | 1039 // Can't upload image, too large or other failure. Try to use SW fallback. |
| 919 data_size = info.getSafeSize(info.minRowBytes()); | 1040 SkImageInfo image_info = |
| 1041 CreateImageInfoForDrawImage(draw_image, upload_scale_mip_level); |
| 1042 data_size = image_info.getSafeSize(image_info.minRowBytes()); |
| 920 mode = DecodedDataMode::CPU; | 1043 mode = DecodedDataMode::CPU; |
| 921 } else { | 1044 } else { |
| 922 mode = DecodedDataMode::GPU; | 1045 mode = DecodedDataMode::GPU; |
| 923 } | 1046 } |
| 924 | 1047 |
| 925 return base::WrapUnique(new ImageData(mode, data_size)); | 1048 return make_scoped_refptr( |
| 1049 new ImageData(mode, data_size, upload_scale_mip_level, |
| 1050 CalculateUploadScaleFilterQuality(draw_image))); |
| 926 } | 1051 } |
| 927 | 1052 |
| 928 void GpuImageDecodeController::DeletePendingImages() { | 1053 void GpuImageDecodeController::DeletePendingImages() { |
| 929 context_->GetLock()->AssertAcquired(); | 1054 context_->GetLock()->AssertAcquired(); |
| 930 lock_.AssertAcquired(); | 1055 lock_.AssertAcquired(); |
| 931 images_pending_deletion_.clear(); | 1056 images_pending_deletion_.clear(); |
| 932 } | 1057 } |
| 933 | 1058 |
| 934 SkImageInfo GpuImageDecodeController::CreateImageInfoForDrawImage( | 1059 SkImageInfo GpuImageDecodeController::CreateImageInfoForDrawImage( |
| 935 const DrawImage& draw_image) const { | 1060 const DrawImage& draw_image, |
| 936 return SkImageInfo::Make( | 1061 int upload_scale_mip_level) const { |
| 937 draw_image.image()->width(), draw_image.image()->height(), | 1062 gfx::Size mip_size = |
| 938 ResourceFormatToClosestSkColorType(format_), kPremul_SkAlphaType); | 1063 CalculateSizeForMipLevel(draw_image, upload_scale_mip_level); |
| 1064 return SkImageInfo::Make(mip_size.width(), mip_size.height(), |
| 1065 ResourceFormatToClosestSkColorType(format_), |
| 1066 kPremul_SkAlphaType); |
| 1067 } |
| 1068 |
| 1069 // Tries to find an ImageData that can be used to draw the provided |
| 1070 // |draw_image|. First looks for an exact entry in our |in_use_cache_|. If one |
| 1071 // cannot be found, it looks for a compatible entry in our |persistent_cache_|. |
| 1072 GpuImageDecodeController::ImageData* |
| 1073 GpuImageDecodeController::GetImageDataForDrawImage( |
| 1074 const DrawImage& draw_image) { |
| 1075 lock_.AssertAcquired(); |
| 1076 auto found_in_use = in_use_cache_.find(GenerateInUseCacheKey(draw_image)); |
| 1077 if (found_in_use != in_use_cache_.end()) |
| 1078 return found_in_use->second.image_data.get(); |
| 1079 |
| 1080 auto found_persistent = persistent_cache_.Get(draw_image.image()->uniqueID()); |
| 1081 if (found_persistent != persistent_cache_.end()) { |
| 1082 ImageData* image_data = found_persistent->second.get(); |
| 1083 if (IsCompatible(image_data, draw_image)) { |
| 1084 return image_data; |
| 1085 } else { |
| 1086 found_persistent->second->is_orphaned = true; |
| 1087 // Call OwnershipChanged before erasing the orphaned task from the |
| 1088 // persistent cache. This ensures that if the orphaned task has 0 |
| 1089 // references, it is cleaned up safely before it is deleted. |
| 1090 OwnershipChanged(image_data); |
| 1091 persistent_cache_.Erase(found_persistent); |
| 1092 } |
| 1093 } |
| 1094 |
| 1095 return nullptr; |
| 1096 } |
| 1097 |
| 1098 // Determines if we can draw the provided |draw_image| using the provided |
| 1099 // |image_data|. This is true if the |image_data| is not scaled, or if it |
| 1100 // is scaled at an equal or larger scale and equal or larger quality to |
| 1101 // the provided |draw_image|. |
| 1102 bool GpuImageDecodeController::IsCompatible(const ImageData* image_data, |
| 1103 const DrawImage& draw_image) const { |
| 1104 bool is_scaled = image_data->upload_scale_mip_level != 0; |
| 1105 bool scale_is_compatible = CalculateUploadScaleMipLevel(draw_image) >= |
| 1106 image_data->upload_scale_mip_level; |
| 1107 bool quality_is_compatible = CalculateUploadScaleFilterQuality(draw_image) <= |
| 1108 image_data->upload_scale_filter_quality; |
| 1109 return !is_scaled || (scale_is_compatible && quality_is_compatible); |
| 1110 } |
| 1111 |
| 1112 size_t GpuImageDecodeController::GetDrawImageSizeForTesting( |
| 1113 const DrawImage& image) { |
| 1114 base::AutoLock lock(lock_); |
| 1115 scoped_refptr<ImageData> data = CreateImageData(image); |
| 1116 return data->size; |
| 939 } | 1117 } |
| 940 | 1118 |
| 941 void GpuImageDecodeController::SetImageDecodingFailedForTesting( | 1119 void GpuImageDecodeController::SetImageDecodingFailedForTesting( |
| 942 const DrawImage& image) { | 1120 const DrawImage& image) { |
| 943 base::AutoLock lock(lock_); | 1121 base::AutoLock lock(lock_); |
| 944 auto found = image_data_.Peek(image.image()->uniqueID()); | 1122 auto found = persistent_cache_.Peek(image.image()->uniqueID()); |
| 945 DCHECK(found != image_data_.end()); | 1123 DCHECK(found != persistent_cache_.end()); |
| 946 ImageData* image_data = found->second.get(); | 1124 ImageData* image_data = found->second.get(); |
| 947 image_data->decode.decode_failure = true; | 1125 image_data->decode.decode_failure = true; |
| 948 } | 1126 } |
| 949 | 1127 |
| 950 bool GpuImageDecodeController::DiscardableIsLockedForTesting( | 1128 bool GpuImageDecodeController::DiscardableIsLockedForTesting( |
| 951 const DrawImage& image) { | 1129 const DrawImage& image) { |
| 952 base::AutoLock lock(lock_); | 1130 base::AutoLock lock(lock_); |
| 953 auto found = image_data_.Peek(image.image()->uniqueID()); | 1131 auto found = persistent_cache_.Peek(image.image()->uniqueID()); |
| 954 DCHECK(found != image_data_.end()); | 1132 DCHECK(found != persistent_cache_.end()); |
| 955 ImageData* image_data = found->second.get(); | 1133 ImageData* image_data = found->second.get(); |
| 956 return image_data->decode.is_locked(); | 1134 return image_data->decode.is_locked(); |
| 957 } | 1135 } |
| 958 | 1136 |
| 959 } // namespace cc | 1137 } // namespace cc |
| OLD | NEW |