Index: cc/tiles/gpu_image_decode_controller.cc |
diff --git a/cc/tiles/gpu_image_decode_controller.cc b/cc/tiles/gpu_image_decode_controller.cc |
index 8a76daf9cd20278e89c9aed82e6aeb61f9fe6846..ada6a91e081e540ccdeea8d27bfdb13b027aab55 100644 |
--- a/cc/tiles/gpu_image_decode_controller.cc |
+++ b/cc/tiles/gpu_image_decode_controller.cc |
@@ -4,6 +4,7 @@ |
#include "cc/tiles/gpu_image_decode_controller.h" |
+#include "base/debug/stack_trace.h" |
#include "base/memory/discardable_memory_allocator.h" |
#include "base/memory/ptr_util.h" |
#include "base/metrics/histogram_macros.h" |
@@ -14,6 +15,7 @@ |
#include "cc/output/context_provider.h" |
#include "cc/raster/tile_task.h" |
#include "cc/resources/resource_format_utils.h" |
+#include "cc/tiles/mipmap_util.h" |
#include "gpu/command_buffer/client/context_support.h" |
#include "gpu/command_buffer/client/gles2_interface.h" |
#include "gpu_image_decode_controller.h" |
@@ -46,16 +48,47 @@ bool SkipImage(const DrawImage& draw_image) { |
} |
SkImage::DeferredTextureImageUsageParams ParamsFromDrawImage( |
- const DrawImage& draw_image) { |
+ const DrawImage& draw_image, |
+ int pre_scale_mip_level) { |
SkImage::DeferredTextureImageUsageParams params; |
params.fMatrix = draw_image.matrix(); |
params.fQuality = draw_image.filter_quality(); |
+ params.fPreScaleMipLevel = pre_scale_mip_level; |
return params; |
} |
+// Calculate the mp level to pre-scale the image to before uploading. We use mip |
+// levels rather than exact scales to increase re-use of scaled images. |
+int CalculatePreScaleMipLevel(const DrawImage& draw_image) { |
+ gfx::Size base_size(draw_image.image()->width(), |
+ draw_image.image()->height()); |
+ // Ceil our scaled size so that the mip map generated is guaranteed to be |
+ // larger. |
+ gfx::Size scaled_size = gfx::ScaleToCeiledSize( |
+ base_size, draw_image.scale().width(), draw_image.scale().height()); |
+ |
+ return MipMapUtil::GetLevelForSize(base_size, scaled_size); |
+} |
+ |
+SkSize CalculatePreScaleFactor(const DrawImage& draw_image, int mip_level) { |
+ gfx::Size base_size(draw_image.image()->width(), |
+ draw_image.image()->height()); |
+ return MipMapUtil::GetScaleAdjustmentForLevel(base_size, mip_level); |
+} |
+ |
} // namespace |
+GpuImageDecodeController::ImageDataForDrawImageEntry:: |
+ ImageDataForDrawImageEntry(const scoped_refptr<ImageData>& image_data) |
+ : image_data(image_data) {} |
+GpuImageDecodeController::ImageDataForDrawImageEntry:: |
+ ImageDataForDrawImageEntry(const ImageDataForDrawImageEntry&) = default; |
+GpuImageDecodeController::ImageDataForDrawImageEntry:: |
+ ImageDataForDrawImageEntry(ImageDataForDrawImageEntry&&) = default; |
+GpuImageDecodeController::ImageDataForDrawImageEntry:: |
+ ~ImageDataForDrawImageEntry() = default; |
+ |
// Task which decodes an image and stores the result in discardable memory. |
// This task does not use GPU resources and can be run on any thread. |
class ImageDecodeTaskImpl : public TileTask { |
@@ -231,11 +264,26 @@ void GpuImageDecodeController::UploadedImageData::ReportUsageStats() const { |
usage_stats_.first_ref_wasted); |
} |
-GpuImageDecodeController::ImageData::ImageData(DecodedDataMode mode, |
- size_t size) |
- : mode(mode), size(size) {} |
- |
-GpuImageDecodeController::ImageData::~ImageData() = default; |
+GpuImageDecodeController::ImageData::ImageData( |
+ DecodedDataMode mode, |
+ size_t size, |
+ int pre_scale_mip_level, |
+ SkFilterQuality pre_scale_filter_quality) |
+ : mode(mode), |
+ size(size), |
+ pre_scale_mip_level(pre_scale_mip_level), |
+ pre_scale_filter_quality(pre_scale_filter_quality) {} |
+ |
+GpuImageDecodeController::ImageData::~ImageData() { |
+ // We should never delete ImageData while it is in use or before it has been |
+ // cleaned up. |
+ DCHECK_EQ(0u, upload.ref_count); |
+ DCHECK_EQ(0u, decode.ref_count); |
+ DCHECK_EQ(false, decode.is_locked()); |
+ // This should always be cleaned up before deleting the image, as it needs to |
+ // be freed with the GL context lock held. |
+ DCHECK(!upload.image()); |
+} |
GpuImageDecodeController::GpuImageDecodeController(ContextProvider* context, |
ResourceFormat decode_format, |
@@ -285,10 +333,8 @@ bool GpuImageDecodeController::GetTaskForImageAndRef( |
base::AutoLock lock(lock_); |
const auto image_id = draw_image.image()->uniqueID(); |
- |
- auto found = image_data_.Get(image_id); |
- if (found != image_data_.end()) { |
- ImageData* image_data = found->second.get(); |
+ ImageData* image_data = GetImageDataForDrawImage(draw_image); |
+ if (image_data) { |
if (image_data->is_at_raster) { |
// Image is at-raster, just return, this usage will be at-raster as well. |
*task = nullptr; |
@@ -307,32 +353,30 @@ bool GpuImageDecodeController::GetTaskForImageAndRef( |
*task = nullptr; |
return true; |
} |
- } |
- // We didn't have a pre-uploaded image, so we need an upload task. Try to find |
- // an existing one. |
- scoped_refptr<TileTask>& existing_task = |
- pending_image_upload_tasks_[image_id]; |
- if (existing_task) { |
- // We had an existing upload task, ref the image and return the task. |
- RefImage(draw_image); |
- *task = existing_task; |
- return true; |
+ // We didn't have a pre-uploaded image, so we need an upload task. Try to |
+ // find an existing one. |
+ auto existing_task = pending_image_upload_tasks_.find( |
+ GenerateTaskKeyForDrawImage(draw_image)); |
+ if (existing_task != pending_image_upload_tasks_.end()) { |
+ // We had an existing upload task, ref the image and return the task. |
+ RefImage(draw_image); |
+ *task = existing_task->second; |
+ return true; |
+ } else { |
+ } |
} |
// We will be creating a new upload task. If necessary, create a placeholder |
// ImageData to hold the result. |
- std::unique_ptr<ImageData> new_data; |
- ImageData* data; |
- if (found == image_data_.end()) { |
+ scoped_refptr<ImageData> new_data; |
+ if (!image_data) { |
new_data = CreateImageData(draw_image); |
- data = new_data.get(); |
- } else { |
- data = found->second.get(); |
+ image_data = new_data.get(); |
} |
// Ensure that the image we're about to decode/upload will fit in memory. |
- if (!EnsureCapacity(data->size)) { |
+ if (!EnsureCapacity(image_data->size)) { |
// Image will not fit, do an at-raster decode. |
*task = nullptr; |
return false; |
@@ -341,19 +385,20 @@ bool GpuImageDecodeController::GetTaskForImageAndRef( |
// If we had to create new image data, add it to our map now that we know it |
// will fit. |
if (new_data) |
- found = image_data_.Put(image_id, std::move(new_data)); |
+ image_data_.Put(image_id, std::move(new_data)); |
// Ref image and create a upload and decode tasks. We will release this ref |
// in UploadTaskCompleted. |
RefImage(draw_image); |
- existing_task = make_scoped_refptr(new ImageUploadTaskImpl( |
+ *task = make_scoped_refptr(new ImageUploadTaskImpl( |
this, draw_image, GetImageDecodeTaskAndRef(draw_image, tracing_info), |
tracing_info)); |
+ pending_image_upload_tasks_.insert( |
+ std::make_pair(GenerateTaskKeyForDrawImage(draw_image), *task)); |
// Ref the image again - this ref is owned by the caller, and it is their |
// responsibility to release it by calling UnrefImage. |
RefImage(draw_image); |
- *task = existing_task; |
return true; |
} |
@@ -374,16 +419,14 @@ DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw( |
TRACE_EVENT0("cc", "GpuImageDecodeController::GetDecodedImageForDraw"); |
base::AutoLock lock(lock_); |
- const uint32_t unique_id = draw_image.image()->uniqueID(); |
- auto found = image_data_.Peek(unique_id); |
- if (found == image_data_.end()) { |
+ ImageData* image_data = GetImageDataForDrawImage(draw_image); |
+ if (!image_data) { |
// We didn't find the image, create a new entry. |
auto data = CreateImageData(draw_image); |
- found = image_data_.Put(unique_id, std::move(data)); |
+ image_data = data.get(); |
+ image_data_.Put(draw_image.image()->uniqueID(), std::move(data)); |
} |
- ImageData* image_data = found->second.get(); |
- |
if (!image_data->upload.budgeted) { |
// If image data is not budgeted by this point, it is at-raster. |
image_data->is_at_raster = true; |
@@ -406,7 +449,9 @@ DecodedDrawImage GpuImageDecodeController::GetDecodedImageForDraw( |
image_data->upload.mark_used(); |
DCHECK(image || image_data->decode.decode_failure); |
- DecodedDrawImage decoded_draw_image(std::move(image), |
+ SkSize scale_factor = |
+ CalculatePreScaleFactor(draw_image, image_data->pre_scale_mip_level); |
+ DecodedDrawImage decoded_draw_image(std::move(image), SkSize(), scale_factor, |
draw_image.filter_quality()); |
decoded_draw_image.set_at_raster_decode(image_data->is_at_raster); |
return decoded_draw_image; |
@@ -423,6 +468,7 @@ void GpuImageDecodeController::DrawWithImageFinished( |
return; |
base::AutoLock lock(lock_); |
+ TRACE_EVENT0("cc", "GpuImageDecodeController::DrawWithImageFinished"); |
UnrefImageInternal(draw_image); |
// We are mid-draw and holding the context lock, ensure we clean up any |
@@ -516,26 +562,26 @@ bool GpuImageDecodeController::OnMemoryDump( |
void GpuImageDecodeController::DecodeImage(const DrawImage& draw_image) { |
base::AutoLock lock(lock_); |
- auto found = image_data_.Peek(draw_image.image()->uniqueID()); |
- DCHECK(found != image_data_.end()); |
- DCHECK(!found->second->is_at_raster); |
- DecodeImageIfNecessary(draw_image, found->second.get()); |
+ ImageData* image_data = GetImageDataForDrawImage(draw_image); |
+ DCHECK(image_data); |
+ DCHECK(!image_data->is_at_raster); |
+ DecodeImageIfNecessary(draw_image, image_data); |
} |
void GpuImageDecodeController::UploadImage(const DrawImage& draw_image) { |
ContextProvider::ScopedContextLock context_lock(context_); |
base::AutoLock lock(lock_); |
- auto found = image_data_.Peek(draw_image.image()->uniqueID()); |
- DCHECK(found != image_data_.end()); |
- DCHECK(!found->second->is_at_raster); |
- UploadImageIfNecessary(draw_image, found->second.get()); |
+ ImageData* image_data = GetImageDataForDrawImage(draw_image); |
+ DCHECK(image_data); |
+ DCHECK(!image_data->is_at_raster); |
+ UploadImageIfNecessary(draw_image, image_data); |
} |
void GpuImageDecodeController::OnImageDecodeTaskCompleted( |
const DrawImage& draw_image) { |
base::AutoLock lock(lock_); |
// Decode task is complete, remove it from our list of pending tasks. |
- pending_image_decode_tasks_.erase(draw_image.image()->uniqueID()); |
+ pending_image_decode_tasks_.erase(GenerateTaskKeyForDrawImage(draw_image)); |
// While the decode task is active, we keep a ref on the decoded data. |
// Release that ref now. |
@@ -546,7 +592,7 @@ void GpuImageDecodeController::OnImageUploadTaskCompleted( |
const DrawImage& draw_image) { |
base::AutoLock lock(lock_); |
// Upload task is complete, remove it from our list of pending tasks. |
- pending_image_upload_tasks_.erase(draw_image.image()->uniqueID()); |
+ pending_image_upload_tasks_.erase(GenerateTaskKeyForDrawImage(draw_image)); |
// While the upload task is active, we keep a ref on both the image it will be |
// populating, as well as the decode it needs to populate it. Release these |
@@ -562,24 +608,22 @@ scoped_refptr<TileTask> GpuImageDecodeController::GetImageDecodeTaskAndRef( |
const TracingInfo& tracing_info) { |
lock_.AssertAcquired(); |
- const uint32_t image_id = draw_image.image()->uniqueID(); |
- |
// This ref is kept alive while an upload task may need this decode. We |
// release this ref in UploadTaskCompleted. |
RefImageDecode(draw_image); |
- auto found = image_data_.Peek(image_id); |
- if (found != image_data_.end() && found->second->decode.is_locked()) { |
+ ImageData* image_data = GetImageDataForDrawImage(draw_image); |
+ if (image_data && image_data->decode.is_locked()) { |
// We should never be creating a decode task for an at raster image. |
- DCHECK(!found->second->is_at_raster); |
+ DCHECK(!image_data->is_at_raster); |
// We should never be creating a decode for an already-uploaded image. |
- DCHECK(!found->second->upload.image()); |
+ DCHECK(!image_data->upload.image()); |
return nullptr; |
} |
// We didn't have an existing locked image, create a task to lock or decode. |
scoped_refptr<TileTask>& existing_task = |
- pending_image_decode_tasks_[image_id]; |
+ pending_image_decode_tasks_[GenerateTaskKeyForDrawImage(draw_image)]; |
if (!existing_task) { |
// Ref image decode and create a decode task. This ref will be released in |
// DecodeTaskCompleted. |
@@ -592,38 +636,68 @@ scoped_refptr<TileTask> GpuImageDecodeController::GetImageDecodeTaskAndRef( |
void GpuImageDecodeController::RefImageDecode(const DrawImage& draw_image) { |
lock_.AssertAcquired(); |
- auto found = image_data_.Peek(draw_image.image()->uniqueID()); |
- DCHECK(found != image_data_.end()); |
- ++found->second->decode.ref_count; |
- RefCountChanged(found->second.get()); |
+ auto found = |
+ image_data_for_draw_image_.find(GenerateDrawImageKey(draw_image)); |
+ DCHECK(found != image_data_for_draw_image_.end()); |
+ ++found->second.ref_count; |
+ ++found->second.image_data->decode.ref_count; |
+ RefCountChanged(found->second.image_data.get()); |
} |
void GpuImageDecodeController::UnrefImageDecode(const DrawImage& draw_image) { |
lock_.AssertAcquired(); |
- auto found = image_data_.Peek(draw_image.image()->uniqueID()); |
- DCHECK(found != image_data_.end()); |
- DCHECK_GT(found->second->decode.ref_count, 0u); |
- --found->second->decode.ref_count; |
- RefCountChanged(found->second.get()); |
+ auto found = |
+ image_data_for_draw_image_.find(GenerateDrawImageKey(draw_image)); |
+ DCHECK(found != image_data_for_draw_image_.end()); |
+ DCHECK_GT(found->second.image_data->decode.ref_count, 0u); |
+ DCHECK_GT(found->second.ref_count, 0u); |
+ --found->second.ref_count; |
+ --found->second.image_data->decode.ref_count; |
+ RefCountChanged(found->second.image_data.get()); |
+ if (found->second.ref_count == 0u) { |
+ image_data_for_draw_image_.erase(found); |
+ } |
} |
void GpuImageDecodeController::RefImage(const DrawImage& draw_image) { |
lock_.AssertAcquired(); |
- auto found = image_data_.Peek(draw_image.image()->uniqueID()); |
- DCHECK(found != image_data_.end()); |
- ++found->second->upload.ref_count; |
- RefCountChanged(found->second.get()); |
+ auto found = |
+ image_data_for_draw_image_.find(GenerateDrawImageKey(draw_image)); |
+ |
+ // If no secondary cache entry was found for the given |draw_image|, then |
+ // the draw_image only exists in the primary cache. Create a secondary |
+ // cache entry now. |
+ if (found == image_data_for_draw_image_.end()) { |
+ auto found_image = image_data_.Peek(draw_image.image()->uniqueID()); |
+ DCHECK(found_image != image_data_.end()); |
+ DCHECK(found_image->second->pre_scale_mip_level <= |
+ CalculatePreScaleMipLevel(draw_image)); |
+ found = image_data_for_draw_image_ |
+ .insert(std::make_pair( |
+ GenerateDrawImageKey(draw_image), |
+ ImageDataForDrawImageEntry(found_image->second))) |
+ .first; |
+ } |
+ |
+ DCHECK(found != image_data_for_draw_image_.end()); |
+ ++found->second.ref_count; |
+ ++found->second.image_data->upload.ref_count; |
+ RefCountChanged(found->second.image_data.get()); |
} |
void GpuImageDecodeController::UnrefImageInternal(const DrawImage& draw_image) { |
lock_.AssertAcquired(); |
- auto found = image_data_.Peek(draw_image.image()->uniqueID()); |
- DCHECK(found != image_data_.end()); |
- DCHECK_GT(found->second->upload.ref_count, 0u); |
- --found->second->upload.ref_count; |
- if (found->second->upload.ref_count == 0) |
- found->second->upload.notify_ref_reached_zero(); |
- RefCountChanged(found->second.get()); |
+ auto found = |
+ image_data_for_draw_image_.find(GenerateDrawImageKey(draw_image)); |
+ DCHECK(found != image_data_for_draw_image_.end()); |
+ DCHECK_GT(found->second.image_data->upload.ref_count, 0u); |
+ DCHECK_GT(found->second.ref_count, 0u); |
+ --found->second.ref_count; |
+ --found->second.image_data->upload.ref_count; |
+ RefCountChanged(found->second.image_data.get()); |
+ if (found->second.ref_count == 0u) { |
+ image_data_for_draw_image_.erase(found); |
+ } |
} |
// Called any time an image or decode ref count changes. Takes care of any |
@@ -634,6 +708,12 @@ void GpuImageDecodeController::RefCountChanged(ImageData* image_data) { |
bool has_any_refs = |
image_data->upload.ref_count > 0 || image_data->decode.ref_count > 0; |
+ // Don't keep around orphaned images. |
+ if (image_data->is_orphaned && !has_any_refs) { |
+ images_pending_deletion_.push_back(std::move(image_data->upload.image())); |
+ image_data->upload.SetImage(nullptr); |
+ } |
+ |
// Don't keep CPU images if they are unused, these images can be recreated by |
// re-locking discardable (rather than requiring a full upload like GPU |
// images). |
@@ -807,10 +887,21 @@ void GpuImageDecodeController::DecodeImageIfNecessary( |
backing_memory = |
base::DiscardableMemoryAllocator::GetInstance() |
->AllocateLockedDiscardableMemory(image_data->size); |
- SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image); |
- if (!draw_image.image()->readPixels(image_info, backing_memory->data(), |
- image_info.minRowBytes(), 0, 0, |
- SkImage::kDisallow_CachingHint)) { |
+ DrawImage scaled_draw_image = |
+ draw_image.ApplyScale(CalculatePreScaleFactor( |
+ draw_image, image_data->pre_scale_mip_level)); |
+ SkImageInfo scaled_image_info = |
+ CreateImageInfoForDrawImage(scaled_draw_image); |
+ // We are doing a software scale of the image before handing off to the |
+ // GPU. In order to match GPU scaling quality (which uses mip-maps at |
+ // high quality), we want to use at most medium filter quality for the |
+ // scale. |
+ SkFilterQuality scale_quality = |
+ std::max(kMedium_SkFilterQuality, draw_image.filter_quality()); |
+ SkPixmap full_image_pixmap(scaled_image_info, backing_memory->data(), |
+ scaled_image_info.minRowBytes()); |
+ if (!draw_image.image()->scalePixels(full_image_pixmap, scale_quality, |
+ SkImage::kDisallow_CachingHint)) { |
backing_memory.reset(); |
} |
break; |
@@ -819,7 +910,8 @@ void GpuImageDecodeController::DecodeImageIfNecessary( |
backing_memory = |
base::DiscardableMemoryAllocator::GetInstance() |
->AllocateLockedDiscardableMemory(image_data->size); |
- auto params = ParamsFromDrawImage(draw_image); |
+ auto params = |
+ ParamsFromDrawImage(draw_image, image_data->pre_scale_mip_level); |
if (!draw_image.image()->getDeferredTextureImageData( |
*context_threadsafe_proxy_.get(), ¶ms, 1, |
backing_memory->data())) { |
@@ -875,9 +967,13 @@ void GpuImageDecodeController::UploadImageIfNecessary( |
base::AutoUnlock unlock(lock_); |
switch (image_data->mode) { |
case DecodedDataMode::CPU: { |
- SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image); |
- SkPixmap pixmap(image_info, image_data->decode.data()->data(), |
- image_info.minRowBytes()); |
+ DrawImage scaled_draw_image = |
+ draw_image.ApplyScale(CalculatePreScaleFactor( |
+ draw_image, image_data->pre_scale_mip_level)); |
+ SkImageInfo scaled_image_info = |
+ CreateImageInfoForDrawImage(scaled_draw_image); |
+ SkPixmap pixmap(scaled_image_info, image_data->decode.data()->data(), |
+ scaled_image_info.minRowBytes()); |
uploaded_image = |
SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr); |
break; |
@@ -899,26 +995,31 @@ void GpuImageDecodeController::UploadImageIfNecessary( |
image_data->upload.SetImage(std::move(uploaded_image)); |
} |
-std::unique_ptr<GpuImageDecodeController::ImageData> |
+scoped_refptr<GpuImageDecodeController::ImageData> |
GpuImageDecodeController::CreateImageData(const DrawImage& draw_image) { |
lock_.AssertAcquired(); |
DecodedDataMode mode; |
- SkImageInfo info = CreateImageInfoForDrawImage(draw_image); |
+ int pre_scale_mip_level = CalculatePreScaleMipLevel(draw_image); |
SkImage::DeferredTextureImageUsageParams params = |
- ParamsFromDrawImage(draw_image); |
+ ParamsFromDrawImage(draw_image, pre_scale_mip_level); |
size_t data_size = draw_image.image()->getDeferredTextureImageData( |
*context_threadsafe_proxy_.get(), ¶ms, 1, nullptr); |
if (data_size == 0) { |
// Can't upload image, too large or other failure. Try to use SW fallback. |
- data_size = info.getSafeSize(info.minRowBytes()); |
+ DrawImage scaled_draw_image = draw_image.ApplyScale( |
+ CalculatePreScaleFactor(draw_image, pre_scale_mip_level)); |
+ SkImageInfo scaled_image_info = |
+ CreateImageInfoForDrawImage(scaled_draw_image); |
+ data_size = scaled_image_info.getSafeSize(scaled_image_info.minRowBytes()); |
mode = DecodedDataMode::CPU; |
} else { |
mode = DecodedDataMode::GPU; |
} |
- return base::WrapUnique(new ImageData(mode, data_size)); |
+ return make_scoped_refptr(new ImageData(mode, data_size, pre_scale_mip_level, |
+ draw_image.filter_quality())); |
} |
void GpuImageDecodeController::DeletePendingImages() { |
@@ -930,10 +1031,81 @@ void GpuImageDecodeController::DeletePendingImages() { |
SkImageInfo GpuImageDecodeController::CreateImageInfoForDrawImage( |
const DrawImage& draw_image) const { |
return SkImageInfo::Make( |
- draw_image.image()->width(), draw_image.image()->height(), |
+ draw_image.image()->width() * draw_image.scale().width(), |
+ draw_image.image()->height() * draw_image.scale().height(), |
ResourceFormatToClosestSkColorType(format_), kPremul_SkAlphaType); |
} |
+GpuImageDecodeController::ImageData* |
+GpuImageDecodeController::GetImageDataForDrawImage( |
+ const DrawImage& draw_image) { |
+ lock_.AssertAcquired(); |
+ { |
+ auto found = |
+ image_data_for_draw_image_.find(GenerateDrawImageKey(draw_image)); |
+ if (found != image_data_for_draw_image_.end()) { |
+ return found->second.image_data.get(); |
+ } |
+ } |
+ { |
+ auto found = image_data_.Get(draw_image.image()->uniqueID()); |
+ if (found != image_data_.end()) { |
+ if (IsCompatibleWithDrawImage(found->second.get(), draw_image)) { |
+ return found->second.get(); |
+ } else { |
+ found->second->is_orphaned = true; |
+ // Call RefCountChanged before erasing the orphaned task to ensure |
+ // that we clean up any SkImage safely. |
+ RefCountChanged(found->second.get()); |
+ image_data_.Erase(found); |
+ } |
+ } |
+ } |
+ |
+ return nullptr; |
+} |
+ |
+bool GpuImageDecodeController::IsCompatibleWithDrawImage( |
+ const ImageData* image_data, |
+ const DrawImage& draw_image) const { |
+ bool not_scaled = image_data->pre_scale_mip_level == 0; |
+ bool scale_is_compatible = |
+ CalculatePreScaleMipLevel(draw_image) >= |
+ image_data->pre_scale_mip_level && |
+ draw_image.filter_quality() <= image_data->pre_scale_filter_quality; |
+ return not_scaled || scale_is_compatible; |
+} |
+ |
+GpuImageDecodeController::DrawImageKey |
+GpuImageDecodeController::GenerateDrawImageKey( |
+ const DrawImage& draw_image) const { |
+ DrawImageKey key; |
+ key.image_id = draw_image.image()->uniqueID(); |
+ key.mip_level = CalculatePreScaleMipLevel(draw_image); |
+ key.quality = draw_image.filter_quality(); |
+ return key; |
+} |
+ |
+GpuImageDecodeController::DrawImageKey |
+GpuImageDecodeController::GenerateTaskKeyForDrawImage( |
+ const DrawImage& draw_image) { |
+ lock_.AssertAcquired(); |
+ ImageData* image_data = GetImageDataForDrawImage(draw_image); |
+ DDCHECK(image_data); |
+ DrawImageKey key; |
+ key.image_id = draw_image.image()->uniqueID(); |
+ key.mip_level = image_data->pre_scale_mip_level; |
+ key.quality = image_data->pre_scale_filter_quality; |
+ return key; |
+} |
+ |
+size_t GpuImageDecodeController::GetDrawImageSizeForTesting( |
+ const DrawImage& image) { |
+ base::AutoLock lock(lock_); |
+ scoped_refptr<ImageData> data = CreateImageData(image); |
+ return data->size; |
+} |
+ |
void GpuImageDecodeController::SetImageDecodingFailedForTesting( |
const DrawImage& image) { |
base::AutoLock lock(lock_); |