| 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_);
|
|
|