diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-08-30 10:22:43 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-08-30 12:36:28 +0000 |
commit | 271a6c3487a14599023a9106329505597638d793 (patch) | |
tree | e040d58ffc86c1480b79ca8528020ca9ec919bf8 /chromium/cc/tiles | |
parent | 7b2ffa587235a47d4094787d72f38102089f402a (diff) | |
download | qtwebengine-chromium-271a6c3487a14599023a9106329505597638d793.tar.gz |
BASELINE: Update Chromium to 77.0.3865.59
Change-Id: I1e89a5f3b009a9519a6705102ad65c92fe736f21
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/cc/tiles')
26 files changed, 1271 insertions, 1276 deletions
diff --git a/chromium/cc/tiles/checker_image_tracker.cc b/chromium/cc/tiles/checker_image_tracker.cc index 6eda401d7a5..c31c7b5e3e9 100644 --- a/chromium/cc/tiles/checker_image_tracker.cc +++ b/chromium/cc/tiles/checker_image_tracker.cc @@ -135,8 +135,7 @@ CheckerImageTracker::CheckerImageTracker(ImageController* image_controller, : image_controller_(image_controller), client_(client), enable_checker_imaging_(enable_checker_imaging), - min_image_bytes_to_checker_(min_image_bytes_to_checker), - weak_factory_(this) {} + min_image_bytes_to_checker_(min_image_bytes_to_checker) {} CheckerImageTracker::~CheckerImageTracker() = default; diff --git a/chromium/cc/tiles/checker_image_tracker.h b/chromium/cc/tiles/checker_image_tracker.h index ee5578f8fef..7628689915b 100644 --- a/chromium/cc/tiles/checker_image_tracker.h +++ b/chromium/cc/tiles/checker_image_tracker.h @@ -208,7 +208,7 @@ class CC_EXPORT CheckerImageTracker { base::flat_map<PaintImage::Id, PaintImage::DecodingMode> decoding_mode_map_; - base::WeakPtrFactory<CheckerImageTracker> weak_factory_; + base::WeakPtrFactory<CheckerImageTracker> weak_factory_{this}; }; } // namespace cc diff --git a/chromium/cc/tiles/decoded_image_tracker.cc b/chromium/cc/tiles/decoded_image_tracker.cc index 5db3f198b6d..a7aa6b497ad 100644 --- a/chromium/cc/tiles/decoded_image_tracker.cc +++ b/chromium/cc/tiles/decoded_image_tracker.cc @@ -28,8 +28,7 @@ DecodedImageTracker::DecodedImageTracker( scoped_refptr<base::SequencedTaskRunner> task_runner) : image_controller_(controller), task_runner_(std::move(task_runner)), - tick_clock_(base::DefaultTickClock::GetInstance()), - weak_ptr_factory_(this) { + tick_clock_(base::DefaultTickClock::GetInstance()) { DCHECK(image_controller_); } diff --git a/chromium/cc/tiles/decoded_image_tracker.h b/chromium/cc/tiles/decoded_image_tracker.h index 4803dfa3a2e..c3bf49793bc 100644 --- a/chromium/cc/tiles/decoded_image_tracker.h +++ b/chromium/cc/tiles/decoded_image_tracker.h @@ -93,7 +93,7 @@ class CC_EXPORT DecodedImageTracker { // Defaults to base::TimeTicks::Now(), but overrideable for testing. const base::TickClock* tick_clock_; - base::WeakPtrFactory<DecodedImageTracker> weak_ptr_factory_; + base::WeakPtrFactory<DecodedImageTracker> weak_ptr_factory_{this}; }; } // namespace cc diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc index 30ce3e45e4d..78dd9c6b720 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache.cc @@ -8,7 +8,9 @@ #include "base/auto_reset.h" #include "base/bind.h" +#include "base/containers/span.h" #include "base/debug/alias.h" +#include "base/feature_list.h" #include "base/hash/hash.h" #include "base/memory/discardable_memory_allocator.h" #include "base/metrics/histogram_macros.h" @@ -18,7 +20,6 @@ #include "base/trace_event/memory_dump_manager.h" #include "cc/base/devtools_instrumentation.h" #include "cc/base/histograms.h" -#include "cc/paint/image_transfer_cache_entry.h" #include "cc/raster/scoped_grcontext_access.h" #include "cc/raster/tile_task.h" #include "cc/tiles/mipmap_util.h" @@ -26,6 +27,8 @@ #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/raster_interface.h" +#include "gpu/command_buffer/common/sync_token.h" +#include "gpu/config/gpu_finch_features.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkSurface.h" @@ -33,6 +36,8 @@ #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/GrTexture.h" +#include "ui/gfx/color_space.h" +#include "ui/gfx/geometry/size.h" #include "ui/gfx/skia_util.h" #include "ui/gl/trace_util.h" @@ -160,6 +165,16 @@ bool ShouldGenerateMips(const DrawImage& draw_image, return false; } +// This helper method takes in +// - |yuva_size_info| corresponding to the plane dimensions of a YUV image +// - |info| indicating SkAlphaType and SkColorSpace per plane (though the final +// image color space is currently indicated through other means at creation +// of the YUV SkImage) +// - |memory_ptr| pointing to sufficient contiguous memory for the planes +// +// It then sets each SkPixmap to have the dimensions specified by its respective +// SkYUVAIndex within |yuva_size_info| and to point to bytes in memory at +// |planes[index]|. void SetYuvPixmapsFromSizeInfo(SkPixmap* pixmap_y, SkPixmap* pixmap_u, SkPixmap* pixmap_v, @@ -189,6 +204,41 @@ void SetYuvPixmapsFromSizeInfo(SkPixmap* pixmap_y, v_decode_info.minRowBytes()); } +// Helper method to fill in |scaled_u_size| and |scaled_v_size| by computing +// the mip level for each plane given the final raster dimensions and the +// unscaled U and V plane sizes. Also takes in |draw_image| to compute the Y +// plane mip level and DCHECK that the computed mip levels for U and V are +// reasonable. +// +// TODO(crbug.com/915972): Assumes 420 subsampling and DCHECKs the size ratios. +void ComputeMippedUVPlaneSizes(const gfx::Size& target_raster_size, + const gfx::Size& unscaled_u_size, + const gfx::Size& unscaled_v_size, + const DrawImage& draw_image, + gfx::Size* scaled_u_size, + gfx::Size* scaled_v_size) { + DCHECK(scaled_u_size); + DCHECK(scaled_v_size); + DCHECK_EQ(unscaled_u_size, unscaled_v_size); + DCHECK_EQ((draw_image.paint_image().width() + 1) / 2, + unscaled_u_size.width()); + const int uv_mip_level = + MipMapUtil::GetLevelForSize(unscaled_u_size, target_raster_size); + // Check that the chroma planes do not shrink *more* than the luma. + // At least for YUV420, they will shrink at most one mip level below luma, + // which avoids blurriness. + DCHECK_GE(uv_mip_level, 0); + if (CalculateUploadScaleMipLevel(draw_image) == 0) { + // If Y is not scaled, then U and V shouldn't be either. + DCHECK_EQ(uv_mip_level, 0); + } else { + DCHECK_EQ(CalculateUploadScaleMipLevel(draw_image) - 1, uv_mip_level); + } + + *scaled_u_size = MipMapUtil::GetSizeForLevel(unscaled_u_size, uv_mip_level); + *scaled_v_size = *scaled_u_size; +} + // Draws and scales the provided |draw_image| into the |target_pixmap|. If the // draw/scale can be done directly, calls directly into PaintImage::Decode. // if not, decodes to a compatible temporary pixmap and then converts that into @@ -316,23 +366,34 @@ bool DrawAndScaleImage(const DrawImage& draw_image, &unscaled_pixmap_v, yuva_size_info, planes, decode_info, decode_pixmap.writable_addr()); - // Assumes YUV420 and splits decode_pixmap into pixmaps for each plane. - // TODO(crbug.com/915972): Fix this assumption. const SkImageInfo y_info_scaled = info.makeColorType(kGray_8_SkColorType); - const size_t uv_width_scaled = (y_info_scaled.width() + 1) / 2; - const size_t uv_height_scaled = (y_info_scaled.height() + 1) / 2; - const SkImageInfo uv_info_scaled = - y_info_scaled.makeWH(uv_width_scaled, uv_height_scaled); + // The target raster dimensions get passed through: + // |target_pixmap|.info() -> |pixmap|->info() -> |info| -> |y_info_scaled| + const gfx::Size target_raster_size(y_info_scaled.width(), + y_info_scaled.height()); + gfx::Size unscaled_u_size(unscaled_pixmap_u.width(), + unscaled_pixmap_u.height()); + gfx::Size unscaled_v_size(unscaled_pixmap_v.width(), + unscaled_pixmap_v.height()); + gfx::Size scaled_u_size; + gfx::Size scaled_v_size; + ComputeMippedUVPlaneSizes(target_raster_size, unscaled_u_size, + unscaled_v_size, draw_image, &scaled_u_size, + &scaled_v_size); + const SkImageInfo u_info_scaled = + y_info_scaled.makeWH(scaled_u_size.width(), scaled_u_size.height()); + const SkImageInfo v_info_scaled = + y_info_scaled.makeWH(scaled_v_size.width(), scaled_v_size.height()); const size_t y_plane_bytes = y_info_scaled.computeMinByteSize(); - const size_t u_plane_bytes = uv_info_scaled.computeMinByteSize(); + const size_t u_plane_bytes = u_info_scaled.computeMinByteSize(); DCHECK(!SkImageInfo::ByteSizeOverflowed(y_plane_bytes)); DCHECK(!SkImageInfo::ByteSizeOverflowed(u_plane_bytes)); pixmap_y->reset(y_info_scaled, data_ptr, y_info_scaled.minRowBytes()); - pixmap_u->reset(uv_info_scaled, data_ptr + y_plane_bytes, - uv_info_scaled.minRowBytes()); - pixmap_v->reset(uv_info_scaled, data_ptr + y_plane_bytes + u_plane_bytes, - uv_info_scaled.minRowBytes()); + pixmap_u->reset(u_info_scaled, data_ptr + y_plane_bytes, + u_info_scaled.minRowBytes()); + pixmap_v->reset(v_info_scaled, data_ptr + y_plane_bytes + u_plane_bytes, + v_info_scaled.minRowBytes()); const bool all_planes_scaled_successfully = unscaled_pixmap_y.scalePixels(*pixmap_y, filter_quality) && @@ -520,10 +581,12 @@ class ImageUploadTaskImpl : public TileTask { ImageUploadTaskImpl(GpuImageDecodeCache* cache, const DrawImage& draw_image, scoped_refptr<TileTask> decode_dependency, + sk_sp<SkData> encoded_data, const ImageDecodeCache::TracingInfo& tracing_info) : TileTask(false), cache_(cache), image_(draw_image), + encoded_data_(std::move(encoded_data)), tracing_info_(tracing_info) { DCHECK(!SkipImage(draw_image)); // If an image is already decoded and locked, we will not generate a @@ -539,7 +602,7 @@ class ImageUploadTaskImpl : public TileTask { void RunOnWorkerThread() override { TRACE_EVENT2("cc", "ImageUploadTaskImpl::RunOnWorkerThread", "mode", "gpu", "source_prepare_tiles_id", tracing_info_.prepare_tiles_id); - cache_->UploadImageInTask(image_); + cache_->UploadImageInTask(image_, std::move(encoded_data_)); } // Overridden from TileTask: @@ -553,6 +616,7 @@ class ImageUploadTaskImpl : public TileTask { private: GpuImageDecodeCache* cache_; DrawImage image_; + sk_sp<SkData> encoded_data_; const ImageDecodeCache::TracingInfo tracing_info_; }; @@ -601,8 +665,11 @@ int GpuImageDecodeCache::ImageDataBase::UsageState() const { return state; } -GpuImageDecodeCache::DecodedImageData::DecodedImageData(bool is_bitmap_backed) - : is_bitmap_backed_(is_bitmap_backed) {} +GpuImageDecodeCache::DecodedImageData::DecodedImageData( + bool is_bitmap_backed, + bool do_hardware_accelerated_decode) + : is_bitmap_backed_(is_bitmap_backed), + do_hardware_accelerated_decode_(do_hardware_accelerated_decode) {} GpuImageDecodeCache::DecodedImageData::~DecodedImageData() { ResetData(); } @@ -684,6 +751,14 @@ void GpuImageDecodeCache::DecodedImageData::ResetData() { } void GpuImageDecodeCache::DecodedImageData::ReportUsageStats() const { + if (do_hardware_accelerated_decode_) { + // When doing hardware decode acceleration, we don't want to record usage + // stats for the decode data. The reason is that the decode is done in the + // GPU process and the decoded result stays there. On the renderer side, we + // don't use or lock the decoded data, so reporting this status would + // incorrectly distort the software decoding statistics. + return; + } UMA_HISTOGRAM_ENUMERATION("Renderer4.GpuImageDecodeState", static_cast<ImageUsageState>(UsageState()), IMAGE_USAGE_STATE_COUNT); @@ -786,6 +861,7 @@ GpuImageDecodeCache::ImageData::ImageData( int upload_scale_mip_level, bool needs_mips, bool is_bitmap_backed, + bool do_hardware_accelerated_decode, bool is_yuv_format) : paint_image_id(paint_image_id), mode(mode), @@ -796,7 +872,7 @@ GpuImageDecodeCache::ImageData::ImageData( needs_mips(needs_mips), is_bitmap_backed(is_bitmap_backed), is_yuv(is_yuv_format), - decode(is_bitmap_backed) {} + decode(is_bitmap_backed, do_hardware_accelerated_decode) {} GpuImageDecodeCache::ImageData::~ImageData() { // We should never delete ImageData while it is in use or before it has been @@ -923,9 +999,17 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal( const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image); ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); scoped_refptr<ImageData> new_data; + sk_sp<SkData> encoded_data; if (!image_data) { - // We need an ImageData, create one now. - new_data = CreateImageData(draw_image); + // We need an ImageData, create one now. Note that hardware decode + // acceleration is allowed only in the DecodeTaskType::kPartOfUploadTask + // case. This prevents the img.decode() and checkerboard images paths from + // going through hardware decode acceleration. + new_data = CreateImageData( + draw_image, + task_type == + DecodeTaskType::kPartOfUploadTask /* allow_hardware_decode */, + &encoded_data); image_data = new_data.get(); } else if (image_data->decode.decode_failure) { // We have already tried and failed to decode this image, so just return. @@ -976,7 +1060,7 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal( task = base::MakeRefCounted<ImageUploadTaskImpl>( this, draw_image, GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type), - tracing_info); + std::move(encoded_data), tracing_info); image_data->upload.task = task; } else { task = GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type); @@ -1015,9 +1099,11 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw( base::AutoLock lock(lock_); const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image); ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); + sk_sp<SkData> encoded_data; if (!image_data) { // We didn't find the image, create a new entry. - auto data = CreateImageData(draw_image); + auto data = CreateImageData(draw_image, true /* allow_hardware_decode */, + &encoded_data); image_data = data.get(); AddToPersistentCache(draw_image, std::move(data)); } @@ -1032,7 +1118,7 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw( // We may or may not need to decode and upload the image we've found, the // following functions early-out to if we already decoded. DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster); - UploadImageIfNecessary(draw_image, image_data); + UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data)); // Unref the image decode, but not the image. The image ref will be released // in DrawWithImageFinished. UnrefImageDecode(draw_image, cache_key); @@ -1299,7 +1385,8 @@ void GpuImageDecodeCache::DecodeImageInTask(const DrawImage& draw_image, DecodeImageIfNecessary(draw_image, image_data, task_type); } -void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) { +void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image, + sk_sp<SkData> encoded_data) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "GpuImageDecodeCache::UploadImage"); base::Optional<viz::RasterContextProvider::ScopedRasterContextLock> @@ -1319,7 +1406,7 @@ void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) { if (image_data->is_bitmap_backed) DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster); - UploadImageIfNecessary(draw_image, image_data); + UploadImageIfNecessary(draw_image, image_data, std::move(encoded_data)); } void GpuImageDecodeCache::OnImageDecodeTaskCompleted( @@ -1365,8 +1452,7 @@ void GpuImageDecodeCache::OnImageUploadTaskCompleted( UnrefImageInternal(draw_image, cache_key); } -// Checks if an existing image decode exists. If not, returns a task to produce -// the requested decode. +// Checks if an image decode needs a decode task and returns it. scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef( const DrawImage& draw_image, const TracingInfo& tracing_info, @@ -1384,6 +1470,9 @@ scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef( ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key); DCHECK(image_data); + if (image_data->decode.do_hardware_accelerated_decode()) + return nullptr; + // No decode is necessary for bitmap backed images. if (image_data->decode.is_locked() || image_data->is_bitmap_backed) { // We should never be creating a decode task for a not budgeted image. @@ -1625,6 +1714,28 @@ bool GpuImageDecodeCache::ExceedsPreferredCount() const { return persistent_cache_.size() > items_limit; } +void GpuImageDecodeCache::InsertTransferCacheEntry( + const ClientImageTransferCacheEntry& image_entry, + ImageData* image_data) { + DCHECK(image_data); + uint32_t size = image_entry.SerializedSize(); + void* data = context_->ContextSupport()->MapTransferCacheEntry(size); + if (data) { + bool succeeded = image_entry.Serialize( + base::make_span(reinterpret_cast<uint8_t*>(data), size)); + DCHECK(succeeded); + context_->ContextSupport()->UnmapAndCreateTransferCacheEntry( + image_entry.UnsafeType(), image_entry.Id()); + image_data->upload.SetTransferCacheId(image_entry.Id()); + } else { + // Transfer cache entry can fail due to a lost gpu context or failure + // to allocate shared memory. Handle this gracefully. Mark this + // image as "decode failed" so that we do not try to handle it again. + // If this was a lost context, we'll recreate this image decode cache. + image_data->decode.decode_failure = true; + } +} + void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image, ImageData* image_data, TaskType task_type) { @@ -1632,6 +1743,11 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image, DCHECK_GT(image_data->decode.ref_count, 0u); + if (image_data->decode.do_hardware_accelerated_decode()) { + // We get here in the case of an at-raster decode. + return; + } + if (image_data->decode.decode_failure) { // We have already tried and failed to decode this image. Don't try again. return; @@ -1661,7 +1777,6 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image, } TRACE_EVENT0("cc,benchmark", "GpuImageDecodeCache::DecodeImage"); - RecordImageMipLevelUMA(image_data->upload_scale_mip_level); image_data->decode.ResetData(); std::unique_ptr<base::DiscardableMemory> backing_memory; @@ -1747,7 +1862,8 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image, } void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, - ImageData* image_data) { + ImageData* image_data, + sk_sp<SkData> encoded_data) { CheckContextLockAcquiredIfNecessary(); lock_.AssertAcquired(); @@ -1776,11 +1892,15 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, return; TRACE_EVENT0("cc", "GpuImageDecodeCache::UploadImage"); - DCHECK(image_data->decode.is_locked()); + if (!image_data->decode.do_hardware_accelerated_decode()) { + // These are not needed for accelerated decodes because there was no decode + // task. + DCHECK(image_data->decode.is_locked()); + image_data->decode.mark_used(); + } DCHECK_GT(image_data->decode.ref_count, 0u); DCHECK_GT(image_data->upload.ref_count, 0u); - image_data->decode.mark_used(); sk_sp<SkColorSpace> color_space = SupportsColorSpaceConversion() && draw_image.target_color_space().IsValid() @@ -1799,27 +1919,76 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, if (image_data->mode == DecodedDataMode::kTransferCache) { DCHECK(use_transfer_cache_); - SkPixmap pixmap; - if (!image_data->decode.image()->peekPixels(&pixmap)) + if (image_data->decode.do_hardware_accelerated_decode()) { + // The assumption is that scaling is not currently supported for + // hardware-accelerated decodes. + DCHECK_EQ(0, image_data->upload_scale_mip_level); + const gfx::Size output_size(draw_image.paint_image().width(), + draw_image.paint_image().height()); + // Try to get the encoded data if we don't have it already: this can + // happen, e.g., if we create an upload task using a pre-existing + // ImageData. In that case, we previously decided to do hardware decode + // acceleration but we didn't cache the encoded data. + if (!encoded_data) { + encoded_data = draw_image.paint_image().GetSkImage()->refEncodedData(); + DCHECK(encoded_data); + } + const uint32_t transfer_cache_id = + ClientImageTransferCacheEntry::GetNextId(); + const gpu::SyncToken decode_sync_token = + context_->RasterInterface()->ScheduleImageDecode( + base::make_span<const uint8_t>(encoded_data->bytes(), + encoded_data->size()), + output_size, transfer_cache_id, + color_space ? gfx::ColorSpace(*color_space) : gfx::ColorSpace(), + image_data->needs_mips); + + if (!decode_sync_token.HasData()) { + image_data->decode.decode_failure = true; + return; + } + + image_data->upload.SetTransferCacheId(transfer_cache_id); + + // Note that we wait for the decode sync token here for two reasons: + // + // 1) To make sure that raster work that depends on the image decode + // happens after the decode completes. + // + // 2) To protect the transfer cache entry from being unlocked on the + // service side before the decode is completed. + context_->RasterInterface()->WaitSyncTokenCHROMIUM( + decode_sync_token.GetConstData()); + return; + } - ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get(), - image_data->needs_mips); - uint32_t size = image_entry.SerializedSize(); - void* data = context_->ContextSupport()->MapTransferCacheEntry(size); - if (data) { - bool succeeded = image_entry.Serialize( - base::make_span(reinterpret_cast<uint8_t*>(data), size)); - DCHECK(succeeded); - context_->ContextSupport()->UnmapAndCreateTransferCacheEntry( - image_entry.UnsafeType(), image_entry.Id()); - image_data->upload.SetTransferCacheId(image_entry.Id()); + // Non-hardware-accelerated path. + if (image_data->is_yuv) { + SkPixmap y_pixmap; + SkPixmap u_pixmap; + SkPixmap v_pixmap; + if (!image_data->decode.y_image()->peekPixels(&y_pixmap) || + !image_data->decode.u_image()->peekPixels(&u_pixmap) || + !image_data->decode.v_image()->peekPixels(&v_pixmap)) { + return; + } + // WebP documentation says to use Rec 601 for converting to RGB. + // TODO(crbug.com/915707): Change QueryYUVA8 to set the colorspace based + // on image type. + SkYUVColorSpace yuva_color_space = + SkYUVColorSpace::kRec601_SkYUVColorSpace; + ClientImageTransferCacheEntry image_entry( + &y_pixmap, &u_pixmap, &v_pixmap, decoded_target_colorspace.get(), + yuva_color_space, image_data->needs_mips); + InsertTransferCacheEntry(image_entry, image_data); } else { - // Transfer cache entry can fail due to a lost gpu context or failure - // to allocate shared memory. Handle this gracefully. Mark this - // image as "decode failed" so that we do not try to handle it again. - // If this was a lost context, we'll recreate this image decode cache. - image_data->decode.decode_failure = true; + SkPixmap pixmap; + if (!image_data->decode.image()->peekPixels(&pixmap)) + return; + ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get(), + image_data->needs_mips); + InsertTransferCacheEntry(image_entry, image_data); } return; @@ -1968,7 +2137,9 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, } scoped_refptr<GpuImageDecodeCache::ImageData> -GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { +GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image, + bool allow_hardware_decode, + sk_sp<SkData>* encoded_data) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "GpuImageDecodeCache::CreateImageData"); lock_.AssertAcquired(); @@ -1977,12 +2148,13 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { bool needs_mips = ShouldGenerateMips(draw_image, upload_scale_mip_level); SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image, upload_scale_mip_level); - + const bool image_larger_than_max_texture = + image_info.width() > max_texture_size_ || + image_info.height() > max_texture_size_; DecodedDataMode mode; if (use_transfer_cache_) { mode = DecodedDataMode::kTransferCache; - } else if (image_info.width() > max_texture_size_ || - image_info.height() > max_texture_size_) { + } else if (image_larger_than_max_texture) { // Image too large to upload. Try to use SW fallback. mode = DecodedDataMode::kCpu; } else { @@ -2009,18 +2181,84 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { const bool is_bitmap_backed = !draw_image.paint_image().IsLazyGenerated() && upload_scale_mip_level == 0 && !cache_color_conversion_on_cpu; - const bool is_yuv = - draw_image.paint_image().IsYuv() && mode == DecodedDataMode::kGpu; + + // Figure out if we will do hardware accelerated decoding. The criteria is as + // follows: + // + // - The kVaapiJpegImageDecodeAcceleration feature is enabled. + // - The caller allows hardware decodes. + // - We are using the transfer cache (OOP-R). + // - The image does not require downscaling for uploading (see TODO below). + // - All the encoded data was received prior to any decoding work. Otherwise, + // it means that the software decoder has already started decoding the + // image, so we just let it finish. + // - The image's color space is sRGB. This is because we don't currently + // support detecting embedded color profiles. + // - The image is supported according to the profiles advertised by the GPU + // service. Checking this involves obtaining the contiguous encoded data + // which may require a copy if the data is not already contiguous. Because + // of this, we return a pointer to the contiguous data (as |encoded_data|) + // so that we can re-use it later (when requesting the image decode). + // + // TODO(crbug.com/953363): ideally, we can make the hardware decoder support + // decision without requiring contiguous data. + // + // TODO(crbug.com/953367): currently, we don't support scaling with hardware + // decode acceleration. Note that it's still okay for the image to be + // downscaled by Skia using the GPU. + // + // TODO(crbug.com/981208): |data_size| needs to be set to the size of the + // decoded data, but for accelerated decodes we won't know until the driver + // gives us the result in the GPU process. Figure out what to do. + bool do_hardware_accelerated_decode = false; + if (base::FeatureList::IsEnabled( + features::kVaapiJpegImageDecodeAcceleration) && + allow_hardware_decode && mode == DecodedDataMode::kTransferCache && + upload_scale_mip_level == 0 && + draw_image.paint_image().IsEligibleForAcceleratedDecoding() && + draw_image.paint_image().color_space() && + draw_image.paint_image().color_space()->isSRGB()) { + sk_sp<SkData> tmp_encoded_data = + draw_image.paint_image().GetSkImage() + ? draw_image.paint_image().GetSkImage()->refEncodedData() + : nullptr; + if (tmp_encoded_data && + context_->ContextSupport()->CanDecodeWithHardwareAcceleration( + base::make_span<const uint8_t>(tmp_encoded_data->bytes(), + tmp_encoded_data->size()))) { + do_hardware_accelerated_decode = true; + DCHECK(encoded_data); + *encoded_data = std::move(tmp_encoded_data); + } + } + + // If draw_image.paint_image().IsEligibleForAcceleratedDecoding() returns + // true, the image should not be backed by a bitmap. + DCHECK(!do_hardware_accelerated_decode || !is_bitmap_backed); + + SkYUVASizeInfo target_yuva_size_info; + const bool is_yuv = !do_hardware_accelerated_decode && + draw_image.paint_image().IsYuv(&target_yuva_size_info) && + mode != DecodedDataMode::kCpu && + !image_larger_than_max_texture; // TODO(crbug.com/910276): Change after alpha support. - // TODO(crbug.com/915972): Remove YUV420 assumption. if (is_yuv) { - // We can't use |temp_yuva_size_info| because it doesn't know about - // any scaling based on mip levels that |image_info| does incorporate. size_t y_size_bytes = image_info.width() * image_info.height(); - size_t u_size_bytes = - ((image_info.width() + 1) / 2) * ((image_info.height() + 1) / 2); - size_t v_size_bytes = u_size_bytes; + const gfx::Size target_raster_size(image_info.width(), image_info.height()); + gfx::Size unscaled_u_size( + target_yuva_size_info.fSizes[SkYUVAIndex::kU_Index].width(), + target_yuva_size_info.fSizes[SkYUVAIndex::kU_Index].height()); + gfx::Size unscaled_v_size( + target_yuva_size_info.fSizes[SkYUVAIndex::kV_Index].width(), + target_yuva_size_info.fSizes[SkYUVAIndex::kV_Index].height()); + gfx::Size scaled_u_size; + gfx::Size scaled_v_size; + ComputeMippedUVPlaneSizes(target_raster_size, unscaled_u_size, + unscaled_v_size, draw_image, &scaled_u_size, + &scaled_v_size); + size_t u_size_bytes = base::checked_cast<size_t>(scaled_u_size.GetArea()); + size_t v_size_bytes = base::checked_cast<size_t>(scaled_v_size.GetArea()); data_size = y_size_bytes + u_size_bytes + v_size_bytes; } @@ -2028,7 +2266,7 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { draw_image.paint_image().stable_id(), mode, data_size, draw_image.target_color_space(), CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level, - needs_mips, is_bitmap_backed, is_yuv)); + needs_mips, is_bitmap_backed, do_hardware_accelerated_decode, is_yuv)); } void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) { @@ -2350,7 +2588,8 @@ bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data, size_t GpuImageDecodeCache::GetDrawImageSizeForTesting(const DrawImage& image) { base::AutoLock lock(lock_); - scoped_refptr<ImageData> data = CreateImageData(image); + scoped_refptr<ImageData> data = CreateImageData( + image, false /* allow_hardware_decode */, nullptr /* encoded_data */); return data->size; } @@ -2394,6 +2633,9 @@ sk_sp<SkImage> GpuImageDecodeCache::GetSWImageDecodeForTesting( return image_data->decode.ImageForTesting(); } +// Used for in-process-raster YUV decoding tests, where we often need the +// SkImages for each underlying plane because asserting or requesting fields for +// the YUV SkImage may flatten it to RGB or not be possible to request. sk_sp<SkImage> GpuImageDecodeCache::GetUploadedPlaneForTesting( const DrawImage& draw_image, size_t index) { diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h index 81ca6286703..638a77f2388 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.h +++ b/chromium/cc/tiles/gpu_image_decode_cache.h @@ -16,7 +16,9 @@ #include "base/synchronization/lock.h" #include "base/trace_event/memory_dump_provider.h" #include "cc/cc_export.h" +#include "cc/paint/image_transfer_cache_entry.h" #include "cc/tiles/image_decode_cache.h" +#include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkYUVAIndex.h" #include "third_party/skia/include/gpu/gl/GrGLTypes.h" @@ -36,9 +38,9 @@ namespace cc { // Generally, when an image is required for raster, GpuImageDecodeCache // creates two tasks, one to decode the image, and one to upload the image to // the GPU. These tasks are completed before the raster task which depends on -// the image. We need to seperate decode and upload tasks, as decode can occur +// the image. We need to separate decode and upload tasks, as decode can occur // simultaneously on multiple threads, while upload requires the GL context -// lock must happen on our non-concurrent raster thread. +// lock so it must happen on our non-concurrent raster thread. // // Decoded and Uploaded image data share a single cache entry. Depending on how // far we've progressed, this cache entry may contain CPU-side decoded data, @@ -97,6 +99,35 @@ namespace cc { // keeps an ImageData alive while it is present in either the // |persistent_cache_| or |in_use_cache_|. // +// HARDWARE ACCELERATED DECODES: +// +// In Chrome OS, we have the ability to use specialized hardware to decode +// certain images. Because this requires interacting with drivers, it must be +// done in the GPU process. Therefore, we follow a different path than the usual +// decode -> upload tasks: +// 1) We decide whether to do hardware decode acceleration for an image before +// we create the decode/upload tasks. Under the hood, this involves parsing +// the image and checking if it's supported by the hardware decoder +// according to information advertised by the GPU process. Also, we only +// allow hardware decoding in OOP-R mode. +// 2) If we do decide to do hardware decoding, we don't create a decode task. +// Instead, we create only an upload task and store enough state to +// indicate that the image will go through this hardware accelerated path. +// The reason that we use the upload task is that we need to hold the +// context lock in order to schedule the image decode. +// 3) When the upload task runs, we send a request to the GPU process to start +// the image decode. This is an IPC message that does not require us to +// wait for the response. Instead, we get a sync token that is signalled +// when the decode completes. We insert a wait for this sync token right +// after sending the decode request. +// +// We also handle the more unusual case where images are decoded at raster time. +// The process is similar: we skip the software decode and then request the +// hardware decode in the same way as step (3) above. +// +// Note that the decoded data never makes it back to the renderer. It stays in +// the GPU process. The sync token ensures that any raster work that needs the +// image happens after the decode completes. class CC_EXPORT GpuImageDecodeCache : public ImageDecodeCache, public base::trace_event::MemoryDumpProvider { @@ -144,7 +175,7 @@ class CC_EXPORT GpuImageDecodeCache // Called by Decode / Upload tasks. void DecodeImageInTask(const DrawImage& image, TaskType task_type); - void UploadImageInTask(const DrawImage& image); + void UploadImageInTask(const DrawImage& image, sk_sp<SkData> encoded_data); // Called by Decode / Upload tasks when tasks are finished. void OnImageDecodeTaskCompleted(const DrawImage& image, @@ -216,7 +247,8 @@ class CC_EXPORT GpuImageDecodeCache // Stores the CPU-side decoded bits of an image and supporting fields. struct DecodedImageData : public ImageDataBase { - explicit DecodedImageData(bool is_bitmap_backed); + explicit DecodedImageData(bool is_bitmap_backed, + bool do_hardware_accelerated_decode); ~DecodedImageData(); bool Lock(); @@ -255,6 +287,10 @@ class CC_EXPORT GpuImageDecodeCache bool is_yuv() const { return image_yuv_planes_.has_value(); } + bool do_hardware_accelerated_decode() const { + return do_hardware_accelerated_decode_; + } + // Test-only functions. sk_sp<SkImage> ImageForTesting() const { return image_; } @@ -278,6 +314,12 @@ class CC_EXPORT GpuImageDecodeCache std::unique_ptr<base::DiscardableMemory> data_; sk_sp<SkImage> image_; // RGBX (or null in YUV decode path) base::Optional<YUVSkImages> image_yuv_planes_; + + // |do_hardware_accelerated_decode_| keeps track of images that should go + // through hardware decode acceleration. Currently, this path is intended + // only for Chrome OS and only for some JPEG images (see + // https://crbug.com/868400). + bool do_hardware_accelerated_decode_; }; // Stores the GPU-side image and supporting fields. @@ -447,6 +489,7 @@ class CC_EXPORT GpuImageDecodeCache int upload_scale_mip_level, bool needs_mips, bool is_bitmap_backed, + bool do_hardware_accelerated_decode, bool is_yuv_format); bool IsGpuOrTransferCache() const; @@ -543,6 +586,9 @@ class CC_EXPORT GpuImageDecodeCache bool CanFitInWorkingSet(size_t size) const; bool ExceedsPreferredCount() const; + void InsertTransferCacheEntry( + const ClientImageTransferCacheEntry& image_entry, + ImageData* image_data); void DecodeImageIfNecessary(const DrawImage& draw_image, ImageData* image_data, TaskType task_type); @@ -557,7 +603,9 @@ class CC_EXPORT GpuImageDecodeCache sk_sp<SkColorSpace> decoded_color_space) const; scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData( - const DrawImage& image); + const DrawImage& image, + bool allow_hardware_decode, + sk_sp<SkData>* encoded_data); void WillAddCacheEntry(const DrawImage& draw_image); SkImageInfo CreateImageInfoForDrawImage(const DrawImage& draw_image, int upload_scale_mip_level) const; @@ -591,7 +639,8 @@ class CC_EXPORT GpuImageDecodeCache // Requires that the |context_| lock be held when calling. void UploadImageIfNecessary(const DrawImage& draw_image, - ImageData* image_data); + ImageData* image_data, + sk_sp<SkData> encoded_data); // Flush pending operations on context_->GrContext() for each element of // |yuv_images| and then clear the vector. diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc index a3b7e86666e..70807864351 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc @@ -8,8 +8,8 @@ #include "cc/paint/draw_image.h" #include "cc/paint/paint_image_builder.h" #include "cc/raster/tile_task.h" -#include "cc/test/test_in_process_context_provider.h" #include "cc/tiles/gpu_image_decode_cache.h" +#include "components/viz/test/test_in_process_context_provider.h" #include "gpu/command_buffer/client/raster_interface.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_test.h" @@ -45,9 +45,10 @@ class GpuImageDecodeCachePerfTest : timer_(kWarmupRuns, base::TimeDelta::FromMilliseconds(kTimeLimitMillis), kTimeCheckInterval), - context_provider_(base::MakeRefCounted<TestInProcessContextProvider>( - UseTransferCache(), - false /* support_locking */)), + context_provider_( + base::MakeRefCounted<viz::TestInProcessContextProvider>( + UseTransferCache(), + false /* support_locking */)), cache_(context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType, @@ -87,7 +88,7 @@ class GpuImageDecodeCachePerfTest } base::LapTimer timer_; - scoped_refptr<TestInProcessContextProvider> context_provider_; + scoped_refptr<viz::TestInProcessContextProvider> context_provider_; GpuImageDecodeCache cache_; }; diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc index 77f3210c518..c30c1b1c101 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc @@ -6,6 +6,7 @@ #include <memory> +#include "base/test/scoped_feature_list.h" #include "cc/paint/draw_image.h" #include "cc/paint/image_transfer_cache_entry.h" #include "cc/paint/paint_image_builder.h" @@ -15,12 +16,20 @@ #include "cc/test/transfer_cache_test_helper.h" #include "components/viz/test/test_context_provider.h" #include "components/viz/test/test_gles2_interface.h" +#include "gpu/command_buffer/client/raster_implementation_gles.h" +#include "gpu/command_buffer/common/command_buffer_id.h" +#include "gpu/command_buffer/common/constants.h" +#include "gpu/config/gpu_finch_features.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkImageGenerator.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" +using testing::_; +using testing::StrictMock; + namespace cc { namespace { @@ -101,13 +110,15 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface, public: explicit FakeGPUImageDecodeTestGLES2Interface( FakeDiscardableManager* discardable_manager, - TransferCacheTestHelper* transfer_cache_helper) + TransferCacheTestHelper* transfer_cache_helper, + bool advertise_accelerated_decoding) : extension_string_( "GL_EXT_texture_format_BGRA8888 GL_OES_rgb8_rgba8 " "GL_OES_texture_npot GL_EXT_texture_rg " "GL_OES_texture_half_float GL_OES_texture_half_float_linear"), discardable_manager_(discardable_manager), - transfer_cache_helper_(transfer_cache_helper) {} + transfer_cache_helper_(transfer_cache_helper), + advertise_accelerated_decoding_(advertise_accelerated_decoding) {} ~FakeGPUImageDecodeTestGLES2Interface() override { // All textures / framebuffers / renderbuffers should be cleaned up. @@ -161,6 +172,11 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface, transfer_cache_helper_->DeleteEntryDirect(MakeEntryKey(type, id)); } + bool CanDecodeWithHardwareAcceleration( + base::span<const uint8_t> encoded_data) const override { + return advertise_accelerated_decoding_; + } + std::pair<TransferCacheEntryType, uint32_t> MakeEntryKey(uint32_t type, uint32_t id) { DCHECK_LE(type, static_cast<uint32_t>(TransferCacheEntryType::kLast)); @@ -213,39 +229,78 @@ class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface, const std::string extension_string_; FakeDiscardableManager* discardable_manager_; TransferCacheTestHelper* transfer_cache_helper_; + bool advertise_accelerated_decoding_ = false; size_t mapped_entry_size_ = 0; std::unique_ptr<uint8_t[]> mapped_entry_; }; +class MockRasterImplementation : public gpu::raster::RasterImplementationGLES { + public: + explicit MockRasterImplementation(gpu::gles2::GLES2Interface* gl) + : RasterImplementationGLES(gl) {} + ~MockRasterImplementation() override = default; + + gpu::SyncToken ScheduleImageDecode(base::span<const uint8_t> encoded_data, + const gfx::Size& output_size, + uint32_t transfer_cache_entry_id, + const gfx::ColorSpace& target_color_space, + bool needs_mips) override { + DoScheduleImageDecode(output_size, transfer_cache_entry_id, + target_color_space, needs_mips); + if (!next_accelerated_decode_fails_) { + return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(1u), + next_release_count_++); + } + return gpu::SyncToken(); + } + + void SetAcceleratedDecodingFailed() { next_accelerated_decode_fails_ = true; } + + MOCK_METHOD4(DoScheduleImageDecode, + void(const gfx::Size& /* output_size */, + uint32_t /* transfer_cache_entry_id */, + const gfx::ColorSpace& /* target_color_space */, + bool /* needs_mips */)); + + private: + bool next_accelerated_decode_fails_ = false; + uint64_t next_release_count_ = 1u; +}; + class GPUImageDecodeTestMockContextProvider : public viz::TestContextProvider { public: static scoped_refptr<GPUImageDecodeTestMockContextProvider> Create( FakeDiscardableManager* discardable_manager, - TransferCacheTestHelper* transfer_cache_helper) { + TransferCacheTestHelper* transfer_cache_helper, + bool advertise_accelerated_decoding) { + auto support = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( + discardable_manager, transfer_cache_helper, + advertise_accelerated_decoding); + auto gl = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( + discardable_manager, transfer_cache_helper, + false /* advertise_accelerated_decoding */); + auto raster = + std::make_unique<StrictMock<MockRasterImplementation>>(gl.get()); return new GPUImageDecodeTestMockContextProvider( - std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( - discardable_manager, transfer_cache_helper), - std::make_unique<FakeGPUImageDecodeTestGLES2Interface>( - discardable_manager, transfer_cache_helper)); + std::move(support), std::move(gl), std::move(raster)); } private: ~GPUImageDecodeTestMockContextProvider() override = default; GPUImageDecodeTestMockContextProvider( std::unique_ptr<viz::TestContextSupport> support, - std::unique_ptr<viz::TestGLES2Interface> gl) - : TestContextProvider(std::move(support), std::move(gl), true) {} + std::unique_ptr<viz::TestGLES2Interface> gl, + std::unique_ptr<gpu::raster::RasterInterface> raster) + : TestContextProvider(std::move(support), + std::move(gl), + std::move(raster), + true) {} }; -SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) { +SkMatrix CreateMatrix(const SkSize& scale) { SkMatrix matrix; matrix.setScale(scale.width(), scale.height()); - - if (!is_decomposable) { - // Perspective is not decomposable, add it. - matrix[SkMatrix::kMPersp0] = 0.1f; - } - return matrix; } @@ -260,13 +315,21 @@ SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) { size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024; class GpuImageDecodeCacheTest - : public ::testing::TestWithParam<std::tuple<SkColorType, - bool /* use_transfer_cache */, - bool /* do_yuv_decode */>> { + : public ::testing::TestWithParam< + std::tuple<SkColorType, + bool /* use_transfer_cache */, + bool /* do_yuv_decode */, + bool /* advertise_accelerated_decoding */>> { public: void SetUp() override { + advertise_accelerated_decoding_ = std::get<3>(GetParam()); + if (advertise_accelerated_decoding_) { + feature_list_.InitAndEnableFeature( + features::kVaapiJpegImageDecodeAcceleration); + } context_provider_ = GPUImageDecodeTestMockContextProvider::Create( - &discardable_manager_, &transfer_cache_helper_); + &discardable_manager_, &transfer_cache_helper_, + advertise_accelerated_decoding_); discardable_manager_.SetGLES2Interface( context_provider_->UnboundTestContextGL()); context_provider_->BindToCurrentThread(); @@ -351,6 +414,28 @@ class GpuImageDecodeCacheTest gfx::ColorSpace::TransferID::LINEAR); } + DrawImage CreateDrawImageInternal( + const PaintImage& paint_image, + const SkMatrix& matrix = SkMatrix::I(), + gfx::ColorSpace* color_space = nullptr, + SkFilterQuality filter_quality = kMedium_SkFilterQuality, + SkIRect* src_rect = nullptr, + size_t frame_index = PaintImage::kDefaultFrameIndex) { + SkIRect src_rectangle; + gfx::ColorSpace cs; + if (!src_rect) { + src_rectangle = + SkIRect::MakeWH(paint_image.width(), paint_image.height()); + src_rect = &src_rectangle; + } + if (!color_space) { + cs = DefaultColorSpace(); + color_space = &cs; + } + return DrawImage(paint_image, *src_rect, filter_quality, matrix, + frame_index, *color_space); + } + GPUImageDecodeTestMockContextProvider* context_provider() { return context_provider_.get(); } @@ -404,14 +489,27 @@ class GpuImageDecodeCacheTest return static_cast<ServiceImageTransferCacheEntry*>(entry)->image(); } - void CompareAllPlanesToMippedVersions(GpuImageDecodeCache* cache, - const DrawImage& draw_image, - bool should_have_mips) { + void CompareAllPlanesToMippedVersions( + GpuImageDecodeCache* cache, + const DrawImage& draw_image, + const base::Optional<uint32_t> transfer_cache_id, + bool should_have_mips) { for (size_t i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) { // TODO(crbug.com/910276): Skip alpha plane until supported in cache. if (i != SkYUVAIndex::kA_Index) { - auto original_uploaded_plane = - cache->GetUploadedPlaneForTesting(draw_image, i); + sk_sp<SkImage> original_uploaded_plane; + if (use_transfer_cache_) { + DCHECK(transfer_cache_id.has_value()); + const uint32_t id = transfer_cache_id.value(); + auto* image_entry = + transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>( + id); + original_uploaded_plane = image_entry->GetPlaneImage(i); + } else { + original_uploaded_plane = + cache->GetUploadedPlaneForTesting(draw_image, i); + } + ASSERT_TRUE(original_uploaded_plane); auto plane_with_mips = original_uploaded_plane->makeTextureImage( context_provider()->GrContext(), nullptr /* color space */, @@ -422,35 +520,60 @@ class GpuImageDecodeCacheTest } } + void VerifyUploadedPlaneSizes( + GpuImageDecodeCache* cache, + const DrawImage& draw_image, + const base::Optional<uint32_t> transfer_cache_id, + const SkISize plane_sizes[SkYUVASizeInfo::kMaxCount]) { + for (size_t i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) { + // TODO(crbug.com/910276): Skip alpha plane until supported in cache. + if (i != SkYUVAIndex::kA_Index) { + sk_sp<SkImage> uploaded_plane; + if (use_transfer_cache_) { + DCHECK(transfer_cache_id.has_value()); + const uint32_t id = transfer_cache_id.value(); + auto* image_entry = + transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>( + id); + uploaded_plane = image_entry->GetPlaneImage(i); + } else { + uploaded_plane = cache->GetUploadedPlaneForTesting(draw_image, i); + } + ASSERT_TRUE(uploaded_plane); + EXPECT_EQ(plane_sizes[i], uploaded_plane->dimensions()); + } + } + } + protected: + base::test::ScopedFeatureList feature_list_; + + // The order of these members is important because |context_provider_| depends + // on |discardable_manager_| and |transfer_cache_helper_|. FakeDiscardableManager discardable_manager_; - scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_; TransferCacheTestHelper transfer_cache_helper_; + scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_; + bool use_transfer_cache_; SkColorType color_type_; bool do_yuv_decode_; + bool advertise_accelerated_decoding_; int max_texture_size_ = 0; }; TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); EXPECT_TRUE(result.task); - DrawImage another_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage another_draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -466,13 +589,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -482,10 +600,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { EXPECT_EQ(result.task->dependencies().size(), 1u); EXPECT_TRUE(result.task->dependencies()[0]); - DrawImage another_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage another_draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); @@ -508,21 +624,15 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); - - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f)); + DrawImage draw_image = CreateDrawImageInternal(image, matrix); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); EXPECT_TRUE(result.task); - DrawImage another_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage another_draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -537,25 +647,18 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); EXPECT_TRUE(first_result.task); PaintImage second_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage second_draw_image( - second_image, - SkIRect::MakeWH(second_image.width(), second_image.height()), quality, - CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal( + second_image, CreateMatrix(SkSize::Make(0.25f, 0.25f))); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -573,14 +676,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -591,20 +690,15 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { cache->UnrefImage(first_draw_image); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - DrawImage third_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage third_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -619,33 +713,23 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); EXPECT_TRUE(first_result.task); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - DrawImage third_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage third_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -663,14 +747,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { auto cache = CreateCache(); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); - + SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f)); PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -681,10 +761,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { cache->UnrefImage(first_draw_image); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal( + first_image, matrix, nullptr /* color_space */, kMedium_SkFilterQuality); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -698,14 +776,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -740,14 +813,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -782,14 +850,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -813,14 +876,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -856,14 +914,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -903,14 +956,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -932,14 +980,9 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) { TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -962,14 +1005,9 @@ TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) { TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -996,14 +1034,9 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) { TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1030,16 +1063,11 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) { TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1066,14 +1094,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) { TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), + nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1082,10 +1106,8 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); TestTileTaskRunner::ProcessTask(result.task.get()); - DrawImage larger_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage larger_draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f))); ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef( larger_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(larger_result.need_unref); @@ -1121,13 +1143,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { auto cache = CreateCache(); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable); - + SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f)); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1136,10 +1155,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); TestTileTaskRunner::ProcessTask(result.task.get()); - DrawImage higher_quality_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage higher_quality_draw_image = CreateDrawImageInternal(image, matrix); ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef( higher_quality_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(hq_result.need_unref); @@ -1174,14 +1190,9 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(-0.5f, 0.5f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1212,15 +1223,11 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) { TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreateLargePaintImageForSoftwareFallback( gfx::Size(GetLargeImageSize().width(), GetLargeImageSize().height() * 2)); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), + nullptr /* color_space */, kHigh_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1253,17 +1260,11 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) { TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1297,16 +1298,11 @@ TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) { TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecodeMultipleTimes) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1335,16 +1331,10 @@ TEST_P(GpuImageDecodeCacheTest, TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */); PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1374,14 +1364,9 @@ TEST_P(GpuImageDecodeCacheTest, TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.f, 0.f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1400,15 +1385,12 @@ TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) { TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); DrawImage draw_image(image, SkIRect::MakeXYWH(image.width() + 1, image.height() + 1, image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), + kMedium_SkFilterQuality, + CreateMatrix(SkSize::Make(1.f, 1.f)), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = @@ -1428,14 +1410,11 @@ TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) { TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image( - image, SkIRect::MakeXYWH(0, 0, image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + SkIRect src_rect = SkIRect::MakeXYWH(0, 0, image.width(), image.height()); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.f, 1.f)), nullptr /* color_space */, + kMedium_SkFilterQuality, &src_rect); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1454,14 +1433,9 @@ TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) { TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); { ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); @@ -1515,15 +1489,10 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) { TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create a downscaled image. PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1535,10 +1504,8 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { // Create a larger version of |first_image|, this should immediately free the // memory used by |first_image| for the smaller scale. - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f))); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1563,15 +1530,10 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create a downscaled image. PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1587,10 +1549,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { // Create a larger version of |first_image|, this should immediately free the // memory used by |first_image| for the smaller scale. - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1610,14 +1569,11 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { auto cache = CreateCache(); PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); + SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f)); // Create an image with kLow_FilterQuality. - DrawImage low_draw_image(image, - SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage low_draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef( low_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(low_result.need_unref); @@ -1625,21 +1581,16 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { // Get the same image at kMedium_SkFilterQuality. We can't re-use low, so we // should get a new task/ref. - DrawImage medium_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + DrawImage medium_draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef( medium_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(medium_result.need_unref); EXPECT_TRUE(medium_result.task.get()); EXPECT_FALSE(low_result.task.get() == medium_result.task.get()); - // Get the same image at kHigh_FilterQuality. We should re-use medium. - DrawImage high_quality_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, - DefaultColorSpace()); + // Get the same image at kHigh_SkFilterQuality. We should re-use medium. + DrawImage high_quality_draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kHigh_SkFilterQuality); ImageDecodeCache::TaskResult high_quality_result = cache->GetTaskForImageAndRef(high_quality_draw_image, ImageDecodeCache::TracingInfo()); @@ -1660,15 +1611,9 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { // cache entry creation doesn't cause a buffer overflow/crash. TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create an image decode task and cache entry that does not need mips. PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1687,10 +1632,8 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { viz::ContextProvider::ScopedContextLock context_lock(context_provider()); // Do an at-raster decode of the above image that *does* require mips. - DrawImage draw_image_mips( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image_mips = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f))); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image_mips)); cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image); @@ -1698,13 +1641,10 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) { auto cache = CreateCache(); - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - bool is_decomposable = true; - SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f)); + DrawImage draw_image = CreateDrawImageInternal( + image, matrix, nullptr /* color_space */, kLow_SkFilterQuality); ImageDecodeCache::TaskResult result = cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); @@ -1723,16 +1663,10 @@ TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) { TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) { SetCachedTexturesLimit(0); auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Add an image to the cache-> Due to normal working set, this should produce // a task and a ref. PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1776,19 +1710,13 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) { // Cache will fit one image. SetCachedTexturesLimit(1); auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); PaintImage image2 = CreatePaintImageInternal(GetNormalImageSize()); DrawImage draw_image2( - image2, SkIRect::MakeWH(image2.width(), image2.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + image2, SkIRect::MakeWH(image2.width(), image2.height()), + kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // Add an image to the cache and un-ref it. @@ -1858,15 +1786,9 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) { TEST_P(GpuImageDecodeCacheTest, ClearCache) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - for (int i = 0; i < 10; ++i) { PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1888,15 +1810,9 @@ TEST_P(GpuImageDecodeCacheTest, ClearCache) { TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create an image but keep it reffed so it can't be immediately freed. PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1923,36 +1839,27 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) { TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB(); gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50(); PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100)); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_a); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); EXPECT_TRUE(first_result.task); - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_b); + DrawImage second_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_b); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); - DrawImage third_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space_a); + DrawImage third_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -1970,15 +1877,10 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) { TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); - PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1992,7 +1894,6 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) { TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { auto cache = CreateCache(); - std::vector<FrameMetadata> frames = { FrameMetadata(true, base::TimeDelta::FromMilliseconds(2)), FrameMetadata(true, base::TimeDelta::FromMilliseconds(3)), @@ -2014,12 +1915,10 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { viz::ContextProvider::ScopedContextLock context_lock(context_provider()); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; + SkFilterQuality quality = kMedium_SkFilterQuality; DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - 1u, DefaultColorSpace()); + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), 1u, + DefaultColorSpace()); auto decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2046,8 +1945,7 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { ASSERT_LT(subset_height, test_image_size.height()); DrawImage subset_draw_image( image, SkIRect::MakeWH(subset_width, subset_height), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u, - DefaultColorSpace()); + CreateMatrix(SkSize::Make(1.0f, 1.0f)), 3u, DefaultColorSpace()); decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(subset_draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2059,15 +1957,10 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - // Create a downscaled image. PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage first_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage first_draw_image = CreateDrawImageInternal( + first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -2078,10 +1971,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { // Create a larger version of |first_image|, this should immediately free // the memory used by |first_image| for the smaller scale. - DrawImage second_draw_image( - first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage second_draw_image = CreateDrawImageInternal(first_image); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -2114,15 +2004,10 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); const size_t bytes_for_test_image = GetBytesNeededForSingleImage(test_image_size); @@ -2155,8 +2040,6 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) { TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); // Allow a single image by count. Use a high byte limit as we want to test the @@ -2166,10 +2049,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { cache->SetWorkingSetLimitsForTesting( bytes_for_test_image * 100 /* max_bytes */, 1u /* max_items */); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); // The image counts against our budget. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); @@ -2179,11 +2059,9 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { EXPECT_TRUE(decoded_draw_image.is_budgeted()); // Try another image, it shouldn't be budgeted and should be at-raster. - DrawImage second_draw_image( - CreatePaintImageInternal(GetNormalImageSize()), - SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage second_paint_image = + CreatePaintImageInternal(GetNormalImageSize()); + DrawImage second_draw_image = CreateDrawImageInternal(second_paint_image); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( @@ -2202,15 +2080,10 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; const gfx::Size test_image_size = GetNormalImageSize(); PaintImage image = CreatePaintImageInternal(test_image_size); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); const size_t bytes_for_test_image = GetBytesNeededForSingleImage(test_image_size); @@ -2228,11 +2101,8 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { EXPECT_TRUE(decoded_draw_image.is_budgeted()); // Try another image, it shouldn't be budgeted and should be at-raster. - DrawImage second_draw_image( - CreatePaintImageInternal(test_image_size), - SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + PaintImage test_paint_image = CreatePaintImageInternal(test_image_size); + DrawImage second_draw_image = CreateDrawImageInternal(test_paint_image); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( @@ -2252,15 +2122,11 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); PaintImage image = CreateLargePaintImageForSoftwareFallback(); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2307,15 +2173,11 @@ TEST_P(GpuImageDecodeCacheTest, TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) { auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12)); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2341,9 +2203,11 @@ TEST_P(GpuImageDecodeCacheTest, EXPECT_EQ(image.width(), service_image->width()); EXPECT_EQ(image.height(), service_image->height()); - // Color space should be logically equal to the original color space. - EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(), - target_color_space.get())); + if (!do_yuv_decode_) { + // Color space should be logically equal to the original color space. + EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(), + target_color_space.get())); + } } else { // Ensure that the HW uploaded image had color space conversion applied. EXPECT_TRUE(SkColorSpace::Equals(decoded_draw_image.image()->colorSpace(), @@ -2360,14 +2224,9 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScale) { return; } auto cache = CreateCache(); - bool is_decomposable = true; - const SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2385,14 +2244,9 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskHasNoDeps) { return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); auto result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2409,14 +2263,9 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskCancelled) { return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); auto result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2437,14 +2286,10 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { const bool should_cache_sw_image = cache->SupportsColorSpaceConversion() && !use_transfer_cache_; - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; - PaintImage image = CreateBitmapImageInternal(GetLargeImageSize()); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, gfx::ColorSpace::CreateDisplayP3D65()); + gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2456,9 +2301,8 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { auto sw_image = cache->GetSWImageDecodeForTesting(draw_image); ASSERT_EQ(!!sw_image, should_cache_sw_image); if (should_cache_sw_image) { - EXPECT_TRUE(SkColorSpace::Equals( - sw_image->colorSpace(), - gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace().get())); + EXPECT_TRUE(SkColorSpace::Equals(sw_image->colorSpace(), + color_space.ToSkColorSpace().get())); } } @@ -2468,14 +2312,10 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) { return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2486,8 +2326,6 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) { TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) { auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; viz::ContextProvider::ScopedContextLock context_lock(context_provider()); const PaintImage::Id paint_image_id = PaintImage::GetNextId(); @@ -2497,10 +2335,8 @@ TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) { for (int i = 0; i < 10; ++i) { PaintImage image = CreatePaintImageInternal( GetNormalImageSize(), SkColorSpace::MakeSRGB(), paint_image_id); - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f))); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2536,8 +2372,6 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScale) { return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kMedium_SkFilterQuality; viz::ContextProvider::ScopedContextLock context_lock(context_provider()); const SkISize full_size = SkISize::Make(100, 100); @@ -2554,10 +2388,8 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScale) { .set_paint_image_generator(generator) .TakePaintImage(); - DrawImage draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal( + paint_image, CreateMatrix(SkSize::Make(0.5, 0.5))); DecodedDrawImage decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); const int expected_width = @@ -2583,8 +2415,6 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) { return; } auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kNone_SkFilterQuality; viz::ContextProvider::ScopedContextLock context_lock(context_provider()); SkISize full_size = SkISize::Make(100, 100); @@ -2601,10 +2431,9 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) { .set_paint_image_generator(generator) .TakePaintImage(); - DrawImage draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(paint_image, CreateMatrix(SkSize::Make(0.5, 0.5)), + nullptr /* color_space */, kNone_SkFilterQuality); DecodedDrawImage decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2627,12 +2456,10 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) { SkSize scale, gfx::ColorSpace color_space, bool should_have_mips) { auto cache = CreateCache(); - bool is_decomposable = true; PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - filter_quality, CreateMatrix(scale, is_decomposable), - PaintImage::kDefaultFrameIndex, color_space); + DrawImage draw_image = CreateDrawImageInternal( + image, CreateMatrix(scale), &color_space, filter_quality); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2644,23 +2471,23 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) { // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + // Pull out transfer cache ID from the DecodedDrawImage while it still has + // it attached. + DecodedDrawImage serialized_decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + const base::Optional<uint32_t> transfer_cache_entry_id = + serialized_decoded_draw_image.transfer_cache_entry_id(); DecodedDrawImage decoded_draw_image = - EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); + EnsureImageBacked(std::move(serialized_decoded_draw_image)); EXPECT_TRUE(decoded_draw_image.image()); EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked()); if (do_yuv_decode_) { - // As of M74, Skia will flatten a YUV SkImage upon calling - // makeTextureImage. Thus, we must separately request mips for each - // plane and compare to the original uploaded planes. - CompareAllPlanesToMippedVersions(cache.get(), draw_image, - should_have_mips); - EXPECT_TRUE( - SkColorSpace::Equals(cache->SupportsColorSpaceConversion() - ? color_space.ToSkColorSpace().get() - : nullptr, - decoded_draw_image.image()->colorSpace())); - + // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, + // we must separately request mips for each plane and compare to the + // original uploaded planes. + CompareAllPlanesToMippedVersions( + cache.get(), draw_image, transfer_cache_entry_id, should_have_mips); } else { sk_sp<SkImage> image_with_mips = decoded_draw_image.image()->makeTextureImage( @@ -2688,9 +2515,6 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) { // Medium filter quality == mips decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(0.6f, 0.6f), DefaultColorSpace(), true); - // High filter quality == mips - decode_and_check_mips(kHigh_SkFilterQuality, SkSize::Make(0.6f, 0.6f), - DefaultColorSpace(), true); // Color conversion preserves mips decode_and_check_mips(kMedium_SkFilterQuality, SkSize::Make(0.6f, 0.6f), gfx::ColorSpace::CreateXYZD50(), true); @@ -2698,17 +2522,12 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) { TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { auto cache = CreateCache(); - bool is_decomposable = true; - auto filter_quality = kMedium_SkFilterQuality; PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); // Create an image with no scaling. It will not have mips. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2720,17 +2539,24 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + // Pull out transfer cache ID from the DecodedDrawImage while it still has + // it attached. + DecodedDrawImage serialized_decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + const base::Optional<uint32_t> transfer_cache_entry_id = + serialized_decoded_draw_image.transfer_cache_entry_id(); DecodedDrawImage decoded_draw_image = - EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); + EnsureImageBacked(std::move(serialized_decoded_draw_image)); EXPECT_TRUE(decoded_draw_image.image()); EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked()); // No mips should be generated. if (do_yuv_decode_) { - // As of M74, Skia will flatten a YUV SkImage upon calling - // makeTextureImage. Thus, we must separately request mips for each - // plane and compare to the original uploaded planes. + // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, + // we must separately request mips for each plane and compare to the + // original uploaded planes. CompareAllPlanesToMippedVersions(cache.get(), draw_image, + transfer_cache_entry_id, false /* should_have_mips */); } else { sk_sp<SkImage> image_with_mips = @@ -2750,10 +2576,8 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { // no new task (re-uses the existing image), but mips should have been // added. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2762,21 +2586,26 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + // Pull out transfer cache ID from the DecodedDrawImage while it still has + // it attached. + DecodedDrawImage serialized_decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + const base::Optional<uint32_t> transfer_cache_entry_id = + serialized_decoded_draw_image.transfer_cache_entry_id(); DecodedDrawImage decoded_draw_image = - EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); + EnsureImageBacked(std::move(serialized_decoded_draw_image)); EXPECT_TRUE(decoded_draw_image.image()); EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked()); // Mips should be generated if (do_yuv_decode_) { + // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, + // we must separately request mips for each plane and compare to the + // original uploaded planes. CompareAllPlanesToMippedVersions(cache.get(), draw_image, + transfer_cache_entry_id, true /* should_have_mips */); - EXPECT_TRUE( - SkColorSpace::Equals(cache->SupportsColorSpaceConversion() - ? DefaultColorSpace().ToSkColorSpace().get() - : nullptr, - decoded_draw_image.image()->colorSpace())); } else { sk_sp<SkImage> image_with_mips = decoded_draw_image.image()->makeTextureImage( @@ -2790,9 +2619,6 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { auto cache = CreateCache(); - bool is_decomposable = true; - auto filter_quality = kMedium_SkFilterQuality; - PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); struct Decode { @@ -2803,10 +2629,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { // Create an image with no scaling. It will not have mips. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2818,17 +2641,24 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + // Pull out transfer cache ID from the DecodedDrawImage while it still has + // it attached. + DecodedDrawImage serialized_decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + const base::Optional<uint32_t> transfer_cache_entry_id = + serialized_decoded_draw_image.transfer_cache_entry_id(); DecodedDrawImage decoded_draw_image = - EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); + EnsureImageBacked(std::move(serialized_decoded_draw_image)); ASSERT_TRUE(decoded_draw_image.image()); ASSERT_TRUE(decoded_draw_image.image()->isTextureBacked()); // No mips should be generated. if (do_yuv_decode_) { - // As of M74, Skia will flatten a YUV SkImage upon calling - // makeTextureImage. Thus, we must separately request mips for each - // plane and compare to the original uploaded planes. + // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, + // we must separately request mips for each plane and compare to the + // original uploaded planes. CompareAllPlanesToMippedVersions(cache.get(), draw_image, + transfer_cache_entry_id, false /* should_have_mips */); } else { sk_sp<SkImage> image_with_mips = @@ -2841,10 +2671,8 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { // Second decode with mips. { - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, - CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = + CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f))); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2853,21 +2681,26 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + // Pull out transfer cache ID from the DecodedDrawImage while it still has + // it attached. + DecodedDrawImage serialized_decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + const base::Optional<uint32_t> transfer_cache_entry_id = + serialized_decoded_draw_image.transfer_cache_entry_id(); DecodedDrawImage decoded_draw_image = - EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); + EnsureImageBacked(std::move(serialized_decoded_draw_image)); ASSERT_TRUE(decoded_draw_image.image()); ASSERT_TRUE(decoded_draw_image.image()->isTextureBacked()); // Mips should be generated. if (do_yuv_decode_) { + // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, + // we must separately request mips for each plane and compare to the + // original uploaded planes. CompareAllPlanesToMippedVersions(cache.get(), draw_image, + transfer_cache_entry_id, true /* should_have_mips */); - EXPECT_TRUE( - SkColorSpace::Equals(cache->SupportsColorSpaceConversion() - ? DefaultColorSpace().ToSkColorSpace().get() - : nullptr, - decoded_draw_image.image()->colorSpace())); } else { sk_sp<SkImage> image_with_mips = decoded_draw_image.image()->makeTextureImage( @@ -2911,21 +2744,139 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { } } +TEST_P(GpuImageDecodeCacheTest, + OriginalYUVDecodeScaledDrawCorrectlyMipsPlanes) { + // This test creates an image that will be YUV decoded and drawn at 80% scale. + // Because the final size is between mip levels, we expect the image to be + // decoded and uploaded at original size (mip level 0 for all planes) but to + // have mips attached since kMedium_SkFilterQuality uses bilinear filtering + // between mip levels. + if (!do_yuv_decode_) { + // The YUV case may choose different mip levels between chroma and luma + // planes. + return; + } + auto cache = CreateCache(); + SkFilterQuality filter_quality = kMedium_SkFilterQuality; + SkSize requires_decode_at_original_scale = SkSize::Make(0.8f, 0.8f); + + PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + filter_quality, + CreateMatrix(requires_decode_at_original_scale), + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + EXPECT_TRUE(result.task); + + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + // Pull out transfer cache ID from the DecodedDrawImage while it still has + // it attached. + DecodedDrawImage serialized_decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + const base::Optional<uint32_t> transfer_cache_entry_id = + serialized_decoded_draw_image.transfer_cache_entry_id(); + DecodedDrawImage decoded_draw_image = + EnsureImageBacked(std::move(serialized_decoded_draw_image)); + EXPECT_TRUE(decoded_draw_image.image()); + EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked()); + + // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, we + // must separately request mips for each plane and compare to the original + // uploaded planes. + CompareAllPlanesToMippedVersions(cache.get(), draw_image, + transfer_cache_entry_id, + true /* should_have_mips */); + SkYUVASizeInfo yuv_size_info = GetYUV420SizeInfo(GetNormalImageSize()); + VerifyUploadedPlaneSizes(cache.get(), draw_image, transfer_cache_entry_id, + yuv_size_info.fSizes); + + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheTest, ScaledYUVDecodeScaledDrawCorrectlyMipsPlanes) { + // This test creates an image that will be YUV decoded and drawn at 45% scale. + // Because the final size is between mip levels, we expect the image to be + // decoded and uploaded at half its original size (mip level 1 for Y plane but + // level 0 for chroma planes) and to have mips attached since + // kMedium_SkFilterQuality uses bilinear filtering between mip levels. + if (!do_yuv_decode_) { + // The YUV case may choose different mip levels between chroma and luma + // planes. + return; + } + auto cache = CreateCache(); + SkFilterQuality filter_quality = kMedium_SkFilterQuality; + SkSize less_than_half_scale = SkSize::Make(0.45f, 0.45f); + + gfx::Size image_size = GetNormalImageSize(); + PaintImage image = CreatePaintImageInternal(image_size); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + filter_quality, CreateMatrix(less_than_half_scale), + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + EXPECT_TRUE(result.task); + + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + // Pull out transfer cache ID from the DecodedDrawImage while it still has + // it attached. + DecodedDrawImage serialized_decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + const base::Optional<uint32_t> transfer_cache_entry_id = + serialized_decoded_draw_image.transfer_cache_entry_id(); + DecodedDrawImage decoded_draw_image = + EnsureImageBacked(std::move(serialized_decoded_draw_image)); + EXPECT_TRUE(decoded_draw_image.image()); + EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked()); + + // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, we + // must separately request mips for each plane and compare to the original + // uploaded planes. + CompareAllPlanesToMippedVersions(cache.get(), draw_image, + transfer_cache_entry_id, + true /* should_have_mips */); + + // Because we intend to draw this image at 0.45 x 0.45 scale, we will upload + // the Y plane at mip level 1 (corresponding to half the original size). The + // chroma planes (U and V) should be uploaded at the same size as the Y plane, + // corresponding to mip level 0, because the largest dimensions greater than + // or equal to target dimensions for them is their original size. + SkISize mipped_plane_sizes[SkYUVASizeInfo::kMaxCount]; + mipped_plane_sizes[SkYUVAIndex::kY_Index] = SkISize::Make( + (image_size.width() + 1) / 2, (image_size.height() + 1) / 2); + mipped_plane_sizes[SkYUVAIndex::kU_Index] = + mipped_plane_sizes[SkYUVAIndex::kY_Index]; + mipped_plane_sizes[SkYUVAIndex::kV_Index] = + mipped_plane_sizes[SkYUVAIndex::kY_Index]; + VerifyUploadedPlaneSizes(cache.get(), draw_image, transfer_cache_entry_id, + mipped_plane_sizes); + + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + TEST_P(GpuImageDecodeCacheTest, GetBorderlineLargeDecodedImageForDraw) { // We will create a texture that's at the maximum size the GPU says it can // support for uploads. auto cache = CreateCache(); - bool is_decomposable = true; - SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage almost_too_large_image = CreatePaintImageInternal(gfx::Size(max_texture_size_, max_texture_size_)); - DrawImage draw_image(almost_too_large_image, - SkIRect::MakeWH(almost_too_large_image.width(), - almost_too_large_image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + DrawImage draw_image = CreateDrawImageInternal(almost_too_large_image); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -2959,16 +2910,326 @@ bool true_array[] = {true}; INSTANTIATE_TEST_SUITE_P( GpuImageDecodeCacheTestsInProcessRaster, GpuImageDecodeCacheTest, - testing::Combine(testing::ValuesIn(test_color_types), - testing::ValuesIn(false_array) /* use_transfer_cache */, - testing::Bool() /* do_yuv_decode */)); + testing::Combine( + testing::ValuesIn(test_color_types), + testing::ValuesIn(false_array) /* use_transfer_cache */, + testing::Bool() /* do_yuv_decode */, + testing::ValuesIn(false_array) /* advertise_accelerated_decoding */)); INSTANTIATE_TEST_SUITE_P( GpuImageDecodeCacheTestsOOPR, GpuImageDecodeCacheTest, - testing::Combine(testing::ValuesIn(test_color_types), - testing::ValuesIn(true_array) /* use_transfer_cache */, - testing::ValuesIn(false_array) /* do_yuv_decode */)); + testing::Combine( + testing::ValuesIn(test_color_types), + testing::ValuesIn(true_array) /* use_transfer_cache */, + testing::Bool() /* do_yuv_decode */, + testing::ValuesIn(false_array) /* advertise_accelerated_decoding */)); + +class GpuImageDecodeCacheWithAcceleratedDecodesTest + : public GpuImageDecodeCacheTest { + public: + PaintImage CreatePaintImageForDecodeAcceleration( + const gfx::Size& size, + sk_sp<SkColorSpace> color_space = nullptr, + bool is_eligible_for_accelerated_decoding = true) { + SkImageInfo info = + SkImageInfo::Make(size.width(), size.height(), color_type_, + kPremul_SkAlphaType, color_space); + sk_sp<FakePaintImageGenerator> generator; + if (do_yuv_decode_) { + generator = + sk_make_sp<FakePaintImageGenerator>(info, GetYUV420SizeInfo(size)); + } else { + generator = sk_make_sp<FakePaintImageGenerator>(info); + } + if (is_eligible_for_accelerated_decoding) + generator->SetEligibleForAcceleratedDecoding(); + PaintImage image = PaintImageBuilder::WithDefault() + .set_id(PaintImage::GetNextId()) + .set_paint_image_generator(generator) + .TakePaintImage(); + return image; + } + + StrictMock<MockRasterImplementation>* raster_implementation() const { + return static_cast<StrictMock<MockRasterImplementation>*>( + context_provider_->RasterInterface()); + } +}; + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + RequestAcceleratedDecodeSuccessfully) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _)) + .Times(1); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + RequestAcceleratedDecodeSuccessfullyWithColorSpaceConversion) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, + cache->SupportsColorSpaceConversion() + ? target_color_space + : gfx::ColorSpace(), + _)) + .Times(1); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + AcceleratedDecodeRequestFails) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + raster_implementation()->SetAcceleratedDecodingFailed(); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, + cache->SupportsColorSpaceConversion() + ? target_color_space + : gfx::ColorSpace(), + _)) + .Times(1); + TestTileTaskRunner::ProcessTask(result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_FALSE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfStandAloneDecode) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated standalone decode should produce only a decode task. + ASSERT_TRUE(result.task->dependencies().empty()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfNonZeroUploadMipLevel) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.5f, 0.5f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated normal decode should produce a decode dependency. + ASSERT_EQ(result.task->dependencies().size(), 1u); + ASSERT_TRUE(result.task->dependencies()[0]); + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfIneligiblePaintImage) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = CreatePaintImageForDecodeAcceleration( + image_size, image_color_space, + false /* is_eligible_for_accelerated_decoding */); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated normal decode should produce a decode dependency. + ASSERT_EQ(result.task->dependencies().size(), 1u); + ASSERT_TRUE(result.task->dependencies()[0]); + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + CannotRequestAcceleratedDecodeBecauseOfNonSRGBColorSpace) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = + SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // A non-accelerated normal decode should produce a decode dependency. + ASSERT_EQ(result.task->dependencies().size(), 1u); + ASSERT_TRUE(result.task->dependencies()[0]); + TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(result.task.get()); + cache->UnrefImage(draw_image); +} + +TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest, + RequestAcceleratedDecodeSuccessfullyAfterCancellation) { + auto cache = CreateCache(); + const gfx::Size image_size = GetNormalImageSize(); + const sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB(); + const gfx::ColorSpace target_color_space(*image_color_space); + ASSERT_TRUE(target_color_space.IsValid()); + const PaintImage image = + CreatePaintImageForDecodeAcceleration(image_size, image_color_space); + const SkFilterQuality quality = kHigh_SkFilterQuality; + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)), + PaintImage::kDefaultFrameIndex, target_color_space); + ImageDecodeCache::TaskResult result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(result.need_unref); + ASSERT_TRUE(result.task); + + // Accelerated decodes should not produce decode tasks. + ASSERT_TRUE(result.task->dependencies().empty()); + + // Cancel the upload. + TestTileTaskRunner::CancelTask(result.task.get()); + TestTileTaskRunner::CompleteTask(result.task.get()); + + // Get the image again - we should have an upload task. + ImageDecodeCache::TaskResult another_result = + cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(another_result.need_unref); + ASSERT_TRUE(another_result.task); + EXPECT_EQ(another_result.task->dependencies().size(), 0u); + EXPECT_CALL(*raster_implementation(), + DoScheduleImageDecode(image_size, _, gfx::ColorSpace(), _)) + .Times(1); + TestTileTaskRunner::ProcessTask(another_result.task.get()); + + // Must hold context lock before calling GetDecodedImageForDraw / + // DrawWithImageFinished. + viz::ContextProvider::ScopedContextLock context_lock(context_provider()); + const DecodedDrawImage decoded_draw_image = + cache->GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value()); + cache->DrawWithImageFinished(draw_image, decoded_draw_image); + cache->UnrefImage(draw_image); + cache->UnrefImage(draw_image); +} + +INSTANTIATE_TEST_SUITE_P( + GpuImageDecodeCacheTestsOOPR, + GpuImageDecodeCacheWithAcceleratedDecodesTest, + testing::Combine( + testing::ValuesIn(test_color_types), + testing::ValuesIn(true_array) /* use_transfer_cache */, + testing::Bool() /* do_yuv_decode */, + testing::ValuesIn(true_array) /* advertise_accelerated_decoding */)); #undef EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE #undef EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE diff --git a/chromium/cc/tiles/image_controller.cc b/chromium/cc/tiles/image_controller.cc index 919be166e5f..9f600462eb8 100644 --- a/chromium/cc/tiles/image_controller.cc +++ b/chromium/cc/tiles/image_controller.cc @@ -21,8 +21,7 @@ ImageController::ImageController( base::SequencedTaskRunner* origin_task_runner, scoped_refptr<base::SequencedTaskRunner> worker_task_runner) : worker_task_runner_(std::move(worker_task_runner)), - origin_task_runner_(origin_task_runner), - weak_ptr_factory_(this) { + origin_task_runner_(origin_task_runner) { weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); } @@ -129,11 +128,6 @@ void ImageController::StopWorkerTasks() { image_decode_queue_.clear(); } -void ImageController::SetPaintWorkletLayerPainter( - std::unique_ptr<PaintWorkletLayerPainter> painter) { - paint_worklet_image_cache_.SetPaintWorkletLayerPainter(std::move(painter)); -} - void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) { DCHECK(!cache_ || !cache); @@ -152,27 +146,7 @@ void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) { } } -void ImageController::ConvertPaintWorkletImagesToTask( - std::vector<DrawImage>* sync_decoded_images, - std::vector<scoped_refptr<TileTask>>* tasks) { - for (auto it = sync_decoded_images->begin(); - it != sync_decoded_images->end();) { - if (!it->paint_image().IsPaintWorklet()) { - ++it; - continue; - } - scoped_refptr<TileTask> result = - paint_worklet_image_cache_.GetTaskForPaintWorkletImage(*it); - if (result) - tasks->push_back(std::move(result)); - // Remove it so that there is no need to check whether an image is - // PaintWorklet generated or not in TileManager's - // work_to_schedule->extra_prepaint_images.insert. - it = sync_decoded_images->erase(it); - } -} - -void ImageController::ConvertDataImagesToTasks( +void ImageController::ConvertImagesToTasks( std::vector<DrawImage>* sync_decoded_images, std::vector<scoped_refptr<TileTask>>* tasks, bool* has_at_raster_images, @@ -181,10 +155,10 @@ void ImageController::ConvertDataImagesToTasks( *has_at_raster_images = false; for (auto it = sync_decoded_images->begin(); it != sync_decoded_images->end();) { - if (it->paint_image().IsPaintWorklet()) { - ++it; - continue; - } + // PaintWorklet images should not be included in this set; they have already + // been painted before raster and so do not need raster-time work. + DCHECK(!it->paint_image().IsPaintWorklet()); + ImageDecodeCache::TaskResult result = cache_->GetTaskForImageAndRef(*it, tracing_info); *has_at_raster_images |= result.IsAtRaster(); @@ -212,8 +186,8 @@ std::vector<scoped_refptr<TileTask>> ImageController::SetPredecodeImages( const ImageDecodeCache::TracingInfo& tracing_info) { std::vector<scoped_refptr<TileTask>> new_tasks; bool has_at_raster_images = false; - ConvertDataImagesToTasks(&images, &new_tasks, &has_at_raster_images, - tracing_info); + ConvertImagesToTasks(&images, &new_tasks, &has_at_raster_images, + tracing_info); UnrefImages(predecode_locked_images_); predecode_locked_images_ = std::move(images); return new_tasks; diff --git a/chromium/cc/tiles/image_controller.h b/chromium/cc/tiles/image_controller.h index 2533b6e50f2..1ec832d13c1 100644 --- a/chromium/cc/tiles/image_controller.h +++ b/chromium/cc/tiles/image_controller.h @@ -19,7 +19,6 @@ #include "cc/paint/draw_image.h" #include "cc/raster/tile_task.h" #include "cc/tiles/image_decode_cache.h" -#include "cc/tiles/paint_worklet_image_cache.h" namespace cc { @@ -39,32 +38,17 @@ class CC_EXPORT ImageController { ImageController& operator=(const ImageController&) = delete; void SetImageDecodeCache(ImageDecodeCache* cache); - void SetPaintWorkletLayerPainter( - std::unique_ptr<PaintWorkletLayerPainter> painter); - // The name "Data images" are the images that are not generated by - // PaintWorklet. - // Build tile tasks for synchronously decoded images that are not generated by - // PaintWorklet. + // Build tile tasks for synchronously decoded images. // |sync_decoded_images| is the input. These are the images from a particular // tile, retrieved by the DiscardableImageMap. Images can be removed from the // vector under certain conditions. // |tasks| is an output, which are the built tile tasks. // |has_at_raster_images| is an output parameter. // |tracing_info| is used in tracing or UMA only. - void ConvertDataImagesToTasks( - std::vector<DrawImage>* sync_decoded_images, - std::vector<scoped_refptr<TileTask>>* tasks, - bool* has_at_raster_images, - const ImageDecodeCache::TracingInfo& tracing_info); - // TODO(crbug.com/915566): bundle all tasks into a big TaskBag. - // Build tile tasks for images that are generated by PaintWorklet. - // |sync_decoded_images| is the input, which are the images from a particular - // tile, retrieved by DiscardableImageMap. Images are removed from the vector - // once the tile task is built. - // |tasks| is an output, which are the built tile tasks. - void ConvertPaintWorkletImagesToTask( - std::vector<DrawImage>* sync_decoded_images, - std::vector<scoped_refptr<TileTask>>* tasks); + void ConvertImagesToTasks(std::vector<DrawImage>* sync_decoded_images, + std::vector<scoped_refptr<TileTask>>* tasks, + bool* has_at_raster_images, + const ImageDecodeCache::TracingInfo& tracing_info); void UnrefImages(const std::vector<DrawImage>& images); void ReduceMemoryUsage(); std::vector<scoped_refptr<TileTask>> SetPredecodeImages( @@ -90,9 +74,6 @@ class CC_EXPORT ImageController { } ImageDecodeCache* cache() const { return cache_; } - PaintWorkletImageCache* paint_worklet_image_cache() { - return &paint_worklet_image_cache_; - } protected: scoped_refptr<base::SequencedTaskRunner> worker_task_runner_; @@ -128,7 +109,6 @@ class CC_EXPORT ImageController { base::WeakPtr<ImageController> weak_ptr_; ImageDecodeCache* cache_ = nullptr; - PaintWorkletImageCache paint_worklet_image_cache_; std::vector<DrawImage> predecode_locked_images_; static ImageDecodeRequestId s_next_image_decode_queue_id_; @@ -151,7 +131,7 @@ class CC_EXPORT ImageController { // from generating new tasks, this vector should be empty. std::vector<ImageDecodeRequest> orphaned_decode_requests_; - base::WeakPtrFactory<ImageController> weak_ptr_factory_; + base::WeakPtrFactory<ImageController> weak_ptr_factory_{this}; }; } // namespace cc diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc index 1c3e0d3b215..17b20018fb2 100644 --- a/chromium/cc/tiles/image_controller_unittest.cc +++ b/chromium/cc/tiles/image_controller_unittest.cc @@ -244,9 +244,7 @@ DrawImage CreateBitmapDrawImage(gfx::Size size) { class ImageControllerTest : public testing::Test { public: - ImageControllerTest() - : task_runner_(base::SequencedTaskRunnerHandle::Get()), - weak_ptr_factory_(this) { + ImageControllerTest() : task_runner_(base::SequencedTaskRunnerHandle::Get()) { image_ = CreateDiscardableDrawImage(gfx::Size(1, 1)); } ~ImageControllerTest() override = default; @@ -314,31 +312,9 @@ class ImageControllerTest : public testing::Test { std::unique_ptr<ImageController> controller_; DrawImage image_; - base::WeakPtrFactory<ImageControllerTest> weak_ptr_factory_; + base::WeakPtrFactory<ImageControllerTest> weak_ptr_factory_{this}; }; -// Test that GetTasksForImagesAndRef does not generate task for PaintWorklet -// images. -TEST_F(ImageControllerTest, GetTasksForImagesAndRefForPaintWorkletImages) { - std::vector<DrawImage> images(1); - ImageDecodeCache::TracingInfo tracing_info; - - PaintImage paint_image = CreatePaintImage(100, 100); - DrawImage draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - kNone_SkFilterQuality, CreateMatrix(SkSize::Make(1.f, 1.f), true), - PaintImage::kDefaultFrameIndex); - images[0] = draw_image; - - ASSERT_EQ(1u, images.size()); - - std::vector<scoped_refptr<TileTask>> tasks; - bool has_at_raster_images = false; - controller()->ConvertDataImagesToTasks(&images, &tasks, &has_at_raster_images, - tracing_info); - EXPECT_EQ(tasks.size(), 0u); -} - TEST_F(ImageControllerTest, NullControllerUnrefsImages) { std::vector<DrawImage> images(10); ImageDecodeCache::TracingInfo tracing_info; diff --git a/chromium/cc/tiles/image_decode_cache.cc b/chromium/cc/tiles/image_decode_cache.cc index 7c83ee45a15..9c68e3cc26c 100644 --- a/chromium/cc/tiles/image_decode_cache.cc +++ b/chromium/cc/tiles/image_decode_cache.cc @@ -4,7 +4,6 @@ #include "cc/tiles/image_decode_cache.h" -#include "base/metrics/histogram_macros.h" #include "cc/raster/tile_task.h" namespace cc { @@ -19,11 +18,4 @@ ImageDecodeCache::TaskResult::TaskResult(const TaskResult& result) = default; ImageDecodeCache::TaskResult::~TaskResult() = default; -void ImageDecodeCache::RecordImageMipLevelUMA(int mip_level) { - DCHECK_GE(mip_level, 0); - DCHECK_LT(mip_level, 32); - UMA_HISTOGRAM_EXACT_LINEAR("Renderer4.ImageDecodeMipLevel", mip_level + 1, - 33); -} - } // namespace cc diff --git a/chromium/cc/tiles/image_decode_cache.h b/chromium/cc/tiles/image_decode_cache.h index 6d7d339ee28..241f5772b02 100644 --- a/chromium/cc/tiles/image_decode_cache.h +++ b/chromium/cc/tiles/image_decode_cache.h @@ -143,9 +143,6 @@ class CC_EXPORT ImageDecodeCache { // image can directly be used for raster (for instance bitmaps in a software // draw). virtual bool UseCacheForDrawImage(const DrawImage& image) const = 0; - - protected: - void RecordImageMipLevelUMA(int mip_level); }; } // namespace cc diff --git a/chromium/cc/tiles/paint_worklet_image_cache.cc b/chromium/cc/tiles/paint_worklet_image_cache.cc deleted file mode 100644 index d0bd702cae7..00000000000 --- a/chromium/cc/tiles/paint_worklet_image_cache.cc +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/tiles/paint_worklet_image_cache.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "cc/paint/paint_worklet_layer_painter.h" - -namespace cc { - -class PaintWorkletTaskImpl : public TileTask { - public: - PaintWorkletTaskImpl(PaintWorkletImageCache* cache, - const PaintImage& paint_image) - : TileTask(true), cache_(cache), paint_image_(paint_image) {} - PaintWorkletTaskImpl(const PaintWorkletTaskImpl&) = delete; - - PaintWorkletTaskImpl& operator=(const PaintWorkletTaskImpl&) = delete; - - // Overridden from Task: - void RunOnWorkerThread() override { cache_->PaintImageInTask(paint_image_); } - - // Overridden from TileTask: - void OnTaskCompleted() override {} - - protected: - ~PaintWorkletTaskImpl() override = default; - - private: - PaintWorkletImageCache* cache_; - PaintImage paint_image_; -}; - -PaintWorkletImageCache::PaintWorkletImageCache() {} - -PaintWorkletImageCache::~PaintWorkletImageCache() { - for (const auto& pair : records_) - DCHECK_EQ(pair.second.used_ref_count, 0u); -} - -void PaintWorkletImageCache::SetPaintWorkletLayerPainter( - std::unique_ptr<PaintWorkletLayerPainter> painter) { - DCHECK(!painter_); - painter_ = std::move(painter); -} - -scoped_refptr<TileTask> PaintWorkletImageCache::GetTaskForPaintWorkletImage( - const DrawImage& image) { - DCHECK(painter_); - DCHECK(image.paint_image().IsPaintWorklet()); - return base::MakeRefCounted<PaintWorkletTaskImpl>(this, image.paint_image()); -} - -// TODO(xidachen): we might need to consider the animated property value and the -// PaintWorkletInput to decide whether we need to call Paint() function or not. -void PaintWorkletImageCache::PaintImageInTask(const PaintImage& paint_image) { - // TODO(crbug.com/939009): When creating a TileTask for a given PaintImage at - // GetTaskForPaintWorkletImage, we should not create a new TileTask if there - // is already a TileTask for this PaintImage. - { - base::AutoLock hold(records_lock_); - if (records_.find(paint_image.paint_worklet_input()) != records_.end()) - return; - } - // Because the compositor could be waiting on the lock in NotifyPrepareTiles, - // we unlock here such that the compositor won't be blocked on potentially - // slow Paint function. - // TODO(xidachen): ensure that the canvas operations in the PaintRecord - // matches the PaintGeneratedImage::Draw. - sk_sp<PaintRecord> record = - painter_->Paint(paint_image.paint_worklet_input()); - if (!record) - return; - { - base::AutoLock hold(records_lock_); - // It is possible for two or more threads to both pass through the first - // lock and arrive here. To avoid ref-count issues caused by potential - // racing among threads, we use insert such that if an entry already exists - // for a particular key, the value won't be overridden. - records_.insert( - std::make_pair(paint_image.paint_worklet_input(), - PaintWorkletImageCacheValue(std::move(record), 0))); - } -} - -std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>> -PaintWorkletImageCache::GetPaintRecordAndRef(PaintWorkletInput* input) { - base::AutoLock hold(records_lock_); - DCHECK(records_.find(input) != records_.end()); - records_[input].used_ref_count++; - records_[input].num_of_frames_not_accessed = 0u; - // The PaintWorkletImageCache object lives as long as the LayerTreeHostImpl, - // and that ensures that this pointer and the input will be alive when this - // callback is executed. - auto callback = - base::BindOnce(&PaintWorkletImageCache::DecrementCacheRefCount, - base::Unretained(this), base::Unretained(input)); - return std::make_pair(records_[input].record, std::move(callback)); -} - -void PaintWorkletImageCache::SetNumOfFramesToPurgeCacheEntryForTest( - size_t num) { - num_of_frames_to_purge_cache_entry_ = num; -} - -void PaintWorkletImageCache::DecrementCacheRefCount(PaintWorkletInput* input) { - base::AutoLock hold(records_lock_); - auto it = records_.find(input); - DCHECK(it != records_.end()); - - auto& pair = it->second; - DCHECK_GT(pair.used_ref_count, 0u); - pair.used_ref_count--; -} - -void PaintWorkletImageCache::NotifyDidPrepareTiles() { - base::AutoLock hold(records_lock_); - base::EraseIf( - records_, - [this]( - const std::pair<PaintWorkletInput*, PaintWorkletImageCacheValue>& t) { - return t.second.num_of_frames_not_accessed >= - num_of_frames_to_purge_cache_entry_ && - t.second.used_ref_count == 0; - }); - for (auto& pair : records_) - pair.second.num_of_frames_not_accessed++; -} - -PaintWorkletImageCache::PaintWorkletImageCacheValue:: - PaintWorkletImageCacheValue() = default; - -PaintWorkletImageCache::PaintWorkletImageCacheValue:: - PaintWorkletImageCacheValue(sk_sp<PaintRecord> record, size_t ref_count) - : record(std::move(record)), used_ref_count(ref_count) {} - -PaintWorkletImageCache::PaintWorkletImageCacheValue:: - PaintWorkletImageCacheValue(const PaintWorkletImageCacheValue& other) - : record(other.record), used_ref_count(other.used_ref_count) {} - -PaintWorkletImageCache::PaintWorkletImageCacheValue:: - ~PaintWorkletImageCacheValue() = default; - -} // namespace cc diff --git a/chromium/cc/tiles/paint_worklet_image_cache.h b/chromium/cc/tiles/paint_worklet_image_cache.h deleted file mode 100644 index f9b976f357b..00000000000 --- a/chromium/cc/tiles/paint_worklet_image_cache.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_TILES_PAINT_WORKLET_IMAGE_CACHE_H_ -#define CC_TILES_PAINT_WORKLET_IMAGE_CACHE_H_ - -#include <utility> - -#include "base/containers/flat_map.h" -#include "base/synchronization/lock.h" -#include "cc/cc_export.h" -#include "cc/paint/draw_image.h" -#include "cc/paint/paint_record.h" -#include "cc/paint/paint_worklet_layer_painter.h" -#include "cc/raster/tile_task.h" -#include "cc/tiles/image_decode_cache.h" - -namespace cc { - -// PaintWorkletImageCache is responsible for generating tasks of executing -// PaintWorklet JS paint callbacks, and being able to return the generated -// results when requested. -class CC_EXPORT PaintWorkletImageCache { - public: - struct CC_EXPORT PaintWorkletImageCacheValue { - PaintWorkletImageCacheValue(); - PaintWorkletImageCacheValue(sk_sp<PaintRecord> record, size_t ref_count); - PaintWorkletImageCacheValue(const PaintWorkletImageCacheValue&); - ~PaintWorkletImageCacheValue(); - - sk_sp<PaintRecord> record; - size_t used_ref_count; - // Indicates how many continuous frames that this cache is never accessed or - // updated. A cache entry should be purged if this number is larger than - // |num_of_frames_to_purge_cache_entry_|. - size_t num_of_frames_not_accessed = 0u; - }; - - PaintWorkletImageCache(); - - ~PaintWorkletImageCache(); - - void SetPaintWorkletLayerPainter( - std::unique_ptr<PaintWorkletLayerPainter> painter); - - scoped_refptr<TileTask> GetTaskForPaintWorkletImage(const DrawImage& image); - - void PaintImageInTask(const PaintImage& paint_image); - - void NotifyDidPrepareTiles(); - - // Returns a callback to decrement the ref count for the corresponding entry. - std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>> - GetPaintRecordAndRef(PaintWorkletInput* input); - - const base::flat_map<PaintWorkletInput*, PaintWorkletImageCacheValue>& - GetRecordsForTest() { - return records_; - } - - void SetNumOfFramesToPurgeCacheEntryForTest(size_t); - - private: - void DecrementCacheRefCount(PaintWorkletInput* input); - - // This is a map of paint worklet inputs to a pair of paint record and a - // reference count. The paint record is the representation of the worklet - // output based on the input, and the reference count is the number of times - // that it is used for tile rasterization. - base::flat_map<PaintWorkletInput*, PaintWorkletImageCacheValue> records_; - - // The |records_| can be accessed from compositor and raster worker threads at - // the same time. To prevent race, we need to lock on it. - base::Lock records_lock_; - - // The PaintWorkletImageCache is owned by ImageController, which has the same - // life time as the LayerTreeHostImpl, that guarantees that the painter will - // live as long as the LayerTreeHostImpl. - std::unique_ptr<PaintWorkletLayerPainter> painter_; - - size_t num_of_frames_to_purge_cache_entry_ = 5u; -}; - -} // namespace cc - -#endif // CC_TILES_PAINT_WORKLET_IMAGE_CACHE_H_ diff --git a/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc b/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc deleted file mode 100644 index 7af4b9340c6..00000000000 --- a/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <memory> -#include <utility> - -#include "cc/tiles/paint_worklet_image_cache.h" - -#include "cc/paint/draw_image.h" -#include "cc/raster/paint_worklet_image_provider.h" -#include "cc/test/skia_common.h" -#include "cc/test/test_paint_worklet_input.h" -#include "cc/test/test_paint_worklet_layer_painter.h" -#include "cc/test/test_tile_task_runner.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { -namespace { - -class TestPaintWorkletImageCache : public PaintWorkletImageCache { - public: - TestPaintWorkletImageCache() {} -}; - -SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) { - SkMatrix matrix; - matrix.setScale(scale.width(), scale.height()); - - if (!is_decomposable) { - // Perspective is not decomposable, add it. - matrix[SkMatrix::kMPersp0] = 0.1f; - } - - return matrix; -} - -PaintImage CreatePaintImage(int width, int height) { - scoped_refptr<TestPaintWorkletInput> input = - base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(width, height)); - return CreatePaintWorkletPaintImage(input); -} - -scoped_refptr<TileTask> GetTaskForPaintWorkletImage( - const PaintImage& paint_image, - TestPaintWorkletImageCache* cache) { - DrawImage draw_image( - paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), - kNone_SkFilterQuality, CreateMatrix(SkSize::Make(1.f, 1.f), true), - PaintImage::kDefaultFrameIndex); - return cache->GetTaskForPaintWorkletImage(draw_image); -} - -void TestPaintRecord(const PaintRecord* record) { - EXPECT_EQ(record->total_op_count(), 1u); - - // GetOpAtForTesting check whether the type is the same as DrawImageOp or not. - // If not, it returns a nullptr. - auto* paint_op = record->GetOpAtForTesting<DrawImageOp>(0); - EXPECT_TRUE(paint_op); -} - -TEST(PaintWorkletImageCacheTest, GetTaskForImage) { - TestPaintWorkletImageCache cache; - std::unique_ptr<TestPaintWorkletLayerPainter> painter = - std::make_unique<TestPaintWorkletLayerPainter>(); - cache.SetPaintWorkletLayerPainter(std::move(painter)); - PaintImage paint_image = CreatePaintImage(100, 100); - scoped_refptr<TileTask> task = - GetTaskForPaintWorkletImage(paint_image, &cache); - EXPECT_TRUE(task); - PaintWorkletImageProvider provider(&cache); - - TestTileTaskRunner::ProcessTask(task.get()); - - { - ImageProvider::ScopedResult result = - provider.GetPaintRecordResult(paint_image.paint_worklet_input()); - EXPECT_TRUE(result.paint_record()); - TestPaintRecord(result.paint_record()); - - base::flat_map<PaintWorkletInput*, - PaintWorkletImageCache::PaintWorkletImageCacheValue> - records = cache.GetRecordsForTest(); - // Test the ref count. - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u); - } - base::flat_map<PaintWorkletInput*, - PaintWorkletImageCache::PaintWorkletImageCacheValue> - records = cache.GetRecordsForTest(); - // Test the ref count, which should have been decremented when the result - // goes out of the scope. - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 0u); - - { - ImageProvider::ScopedResult result = - provider.GetPaintRecordResult(paint_image.paint_worklet_input()); - - base::flat_map<PaintWorkletInput*, - PaintWorkletImageCache::PaintWorkletImageCacheValue> - records = cache.GetRecordsForTest(); - // Test the ref count. - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u); - - ImageProvider::ScopedResult moved_result = std::move(result); - - EXPECT_FALSE(result); - - EXPECT_TRUE(moved_result.paint_record()); - TestPaintRecord(moved_result.paint_record()); - - // Once moved, the ref count from |result| should have been transferred to - // |moved_result|, so there should be only one un-ref when they both go out - // of scope. - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u); - } - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 0u); -} - -TEST(PaintWorkletImageCacheTest, EntryWithNonZeroRefCountNotPurged) { - TestPaintWorkletImageCache cache; - std::unique_ptr<TestPaintWorkletLayerPainter> painter = - std::make_unique<TestPaintWorkletLayerPainter>(); - cache.SetPaintWorkletLayerPainter(std::move(painter)); - PaintImage paint_image = CreatePaintImage(100, 100); - scoped_refptr<TileTask> task = - GetTaskForPaintWorkletImage(paint_image, &cache); - EXPECT_TRUE(task); - - TestTileTaskRunner::ProcessTask(task.get()); - - PaintWorkletImageProvider provider(&cache); - ImageProvider::ScopedResult result = - provider.GetPaintRecordResult(paint_image.paint_worklet_input()); - base::flat_map<PaintWorkletInput*, - PaintWorkletImageCache::PaintWorkletImageCacheValue> - records = cache.GetRecordsForTest(); - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u); - - cache.NotifyDidPrepareTiles(); - cache.NotifyDidPrepareTiles(); - cache.NotifyDidPrepareTiles(); - - records = cache.GetRecordsForTest(); - EXPECT_EQ(records.size(), 1u); -} - -TEST(PaintWorkletImageCacheTest, MultipleRecordsInCache) { - TestPaintWorkletImageCache cache; - std::unique_ptr<TestPaintWorkletLayerPainter> painter = - std::make_unique<TestPaintWorkletLayerPainter>(); - cache.SetPaintWorkletLayerPainter(std::move(painter)); - PaintImage paint_image1 = CreatePaintImage(100, 100); - scoped_refptr<TileTask> task1 = - GetTaskForPaintWorkletImage(paint_image1, &cache); - EXPECT_TRUE(task1); - PaintImage paint_image2 = CreatePaintImage(200, 200); - scoped_refptr<TileTask> task2 = - GetTaskForPaintWorkletImage(paint_image2, &cache); - EXPECT_TRUE(task2); - - TestTileTaskRunner::ProcessTask(task1.get()); - TestTileTaskRunner::ProcessTask(task2.get()); - - base::flat_map<PaintWorkletInput*, - PaintWorkletImageCache::PaintWorkletImageCacheValue> - records = cache.GetRecordsForTest(); - EXPECT_EQ(records.size(), 2u); - - cache.SetNumOfFramesToPurgeCacheEntryForTest(2u); - PaintRecord* record1 = - records[paint_image1.paint_worklet_input()].record.get(); - EXPECT_TRUE(record1); - // Test the |num_of_frames_not_accessed| for this cache entry. - EXPECT_EQ( - records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed, - 0u); - TestPaintRecord(record1); - - PaintRecord* record2 = - records[paint_image2.paint_worklet_input()].record.get(); - EXPECT_TRUE(record2); - // Test the |num_of_frames_not_accessed| for this cache entry. - EXPECT_EQ( - records[paint_image2.paint_worklet_input()].num_of_frames_not_accessed, - 0u); - TestPaintRecord(record2); - - // NotifyDidPrepareTiles is called by TileManager::PrepareTiles() which is - // called at each new impl frame. Here we test that a paint record with - // |num_of_frames_not_accessed| >= 2 is purged from the cache. - cache.NotifyDidPrepareTiles(); - records = cache.GetRecordsForTest(); - EXPECT_EQ( - records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed, - 1u); - EXPECT_EQ( - records[paint_image2.paint_worklet_input()].num_of_frames_not_accessed, - 1u); - - std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>> pair = - cache.GetPaintRecordAndRef(paint_image1.paint_worklet_input()); - // Run the callback to decrement the ref count. - std::move(pair.second).Run(); - records = cache.GetRecordsForTest(); - EXPECT_EQ( - records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed, - 0u); - - cache.NotifyDidPrepareTiles(); - cache.NotifyDidPrepareTiles(); - records = cache.GetRecordsForTest(); - // The cache entry for paint_image2 should have been purged because it was - // never accessed/updated in the last 2 frames. - EXPECT_EQ(records.size(), 1u); - EXPECT_EQ( - records[paint_image1.paint_worklet_input()].num_of_frames_not_accessed, - 2u); -} - -// This test ensures that if an entry already exist, then the PaintImageInTask -// will not replace it with a new entry and reset its ref count. -TEST(PaintWorkletImageCacheTest, CacheEntryLookup) { - TestPaintWorkletImageCache cache; - std::unique_ptr<TestPaintWorkletLayerPainter> painter = - std::make_unique<TestPaintWorkletLayerPainter>(); - cache.SetPaintWorkletLayerPainter(std::move(painter)); - PaintImage paint_image = CreatePaintImage(100, 100); - scoped_refptr<TileTask> task = - GetTaskForPaintWorkletImage(paint_image, &cache); - EXPECT_TRUE(task); - PaintWorkletImageProvider provider(&cache); - - TestTileTaskRunner::ProcessTask(task.get()); - - { - ImageProvider::ScopedResult result = - provider.GetPaintRecordResult(paint_image.paint_worklet_input()); - EXPECT_TRUE(result.paint_record()); - TestPaintRecord(result.paint_record()); - - base::flat_map<PaintWorkletInput*, - PaintWorkletImageCache::PaintWorkletImageCacheValue> - records = cache.GetRecordsForTest(); - // Test the ref count. - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u); - - // Create a new task with the same PaintWorkletInput as the previous task. - // Then ProcessTask will invoke PaintWorkletImageCache::PaintImageInTask, - // and it should early exit, without replacing the existing PaintRecord and - // resetting the ref count. - scoped_refptr<TileTask> task_with_the_same_input = - GetTaskForPaintWorkletImage(paint_image, &cache); - EXPECT_TRUE(task); - TestTileTaskRunner::ProcessTask(task_with_the_same_input.get()); - EXPECT_EQ(records[paint_image.paint_worklet_input()].used_ref_count, 1u); - } -} - -} // namespace -} // namespace cc diff --git a/chromium/cc/tiles/picture_layer_tiling.h b/chromium/cc/tiles/picture_layer_tiling.h index 4f66d992b35..253fdea09ac 100644 --- a/chromium/cc/tiles/picture_layer_tiling.h +++ b/chromium/cc/tiles/picture_layer_tiling.h @@ -17,6 +17,7 @@ #include "cc/base/region.h" #include "cc/base/tiling_data.h" #include "cc/cc_export.h" +#include "cc/paint/paint_worklet_input.h" #include "cc/tiles/tile.h" #include "cc/tiles/tile_priority.h" #include "cc/trees/occlusion.h" @@ -40,8 +41,7 @@ class CC_EXPORT PictureLayerTilingClient { // Create a tile at the given content_rect (in the contents scale of the // tiling) This might return null if the client cannot create such a tile. virtual std::unique_ptr<Tile> CreateTile(const Tile::CreateInfo& info) = 0; - virtual gfx::Size CalculateTileSize( - const gfx::Size& content_bounds) const = 0; + virtual gfx::Size CalculateTileSize(const gfx::Size& content_bounds) = 0; // This invalidation region defines the area (if any, it can by null) that // tiles can not be shared between pending and active trees. virtual const Region* GetPendingInvalidation() = 0; @@ -49,6 +49,7 @@ class CC_EXPORT PictureLayerTilingClient { const PictureLayerTiling* tiling) const = 0; virtual bool HasValidTilePriorities() const = 0; virtual bool RequiresHighResToDraw() const = 0; + virtual const PaintWorkletRecordMap& GetPaintWorkletRecords() const = 0; protected: virtual ~PictureLayerTilingClient() {} @@ -135,6 +136,9 @@ class CC_EXPORT PictureLayerTiling { const scoped_refptr<RasterSource>& raster_source() const { return raster_source_; } + const PaintWorkletRecordMap& GetPaintWorkletRecords() const { + return client_->GetPaintWorkletRecords(); + } gfx::Size tiling_size() const { return tiling_data_.tiling_size(); } gfx::Rect live_tiles_rect() const { return live_tiles_rect_; } gfx::Size tile_size() const { return tiling_data_.max_texture_size(); } diff --git a/chromium/cc/tiles/picture_layer_tiling_set.cc b/chromium/cc/tiles/picture_layer_tiling_set.cc index 38d7ad0e9fa..5a2bcb740a0 100644 --- a/chromium/cc/tiles/picture_layer_tiling_set.cc +++ b/chromium/cc/tiles/picture_layer_tiling_set.cc @@ -242,7 +242,7 @@ void PictureLayerTilingSet::CleanUpTilings( continue; // Don't remove tilings that are required. - if (base::ContainsValue(needed_tilings, tiling.get())) { + if (base::Contains(needed_tilings, tiling.get())) { continue; } diff --git a/chromium/cc/tiles/prioritized_tile.h b/chromium/cc/tiles/prioritized_tile.h index a2996602c7f..54538898271 100644 --- a/chromium/cc/tiles/prioritized_tile.h +++ b/chromium/cc/tiles/prioritized_tile.h @@ -6,6 +6,7 @@ #define CC_TILES_PRIORITIZED_TILE_H_ #include "cc/cc_export.h" +#include "cc/paint/paint_worklet_input.h" #include "cc/raster/raster_source.h" #include "cc/tiles/picture_layer_tiling.h" #include "cc/tiles/tile.h" @@ -32,6 +33,9 @@ class CC_EXPORT PrioritizedTile { const scoped_refptr<RasterSource>& raster_source() const { return source_tiling_->raster_source(); } + const PaintWorkletRecordMap& GetPaintWorkletRecords() const { + return source_tiling_->GetPaintWorkletRecords(); + } const TilePriority& priority() const { return priority_; } bool is_occluded() const { return is_occluded_; } bool is_process_for_images_only() const { diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc index f858a180756..6aa420ce0b5 100644 --- a/chromium/cc/tiles/software_image_decode_cache.cc +++ b/chromium/cc/tiles/software_image_decode_cache.cc @@ -76,7 +76,12 @@ class SoftwareImageDecodeTaskImpl : public TileTask { paint_image_.GetSkImage().get(), devtools_instrumentation::ScopedImageDecodeTask::kSoftware, ImageDecodeCache::ToScopedTaskType(tracing_info_.task_type)); - cache_->DecodeImageInTask(image_key_, paint_image_, task_type_); + SoftwareImageDecodeCache::TaskProcessingResult result = + cache_->DecodeImageInTask(image_key_, paint_image_, task_type_); + + // Do not log timing UMAs if we did not perform a full decode. + if (result != SoftwareImageDecodeCache::TaskProcessingResult::kFullDecode) + image_decode_task.SuppressMetrics(); } // Overridden from TileTask: @@ -300,9 +305,10 @@ void SoftwareImageDecodeCache::UnrefImage(const CacheKey& key) { } } -void SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key, - const PaintImage& paint_image, - DecodeTaskType task_type) { +SoftwareImageDecodeCache::TaskProcessingResult +SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key, + const PaintImage& paint_image, + DecodeTaskType task_type) { TRACE_EVENT1("cc,benchmark", "SoftwareImageDecodeCache::DecodeImageInTask", "key", key.ToString()); base::AutoLock lock(lock_); @@ -316,16 +322,16 @@ void SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key, DCHECK_GT(cache_entry->ref_count, 0); DCHECK(cache_entry->is_budgeted); - DecodeImageIfNecessary(key, paint_image, cache_entry); + TaskProcessingResult result = + DecodeImageIfNecessary(key, paint_image, cache_entry); DCHECK(cache_entry->decode_failed || cache_entry->is_locked); - RecordImageMipLevelUMA( - MipMapUtil::GetLevelForSize(key.src_rect().size(), key.target_size())); + return result; } -void SoftwareImageDecodeCache::DecodeImageIfNecessary( - const CacheKey& key, - const PaintImage& paint_image, - CacheEntry* entry) { +SoftwareImageDecodeCache::TaskProcessingResult +SoftwareImageDecodeCache::DecodeImageIfNecessary(const CacheKey& key, + const PaintImage& paint_image, + CacheEntry* entry) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::DecodeImageIfNecessary", "key", key.ToString()); @@ -336,18 +342,18 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( entry->decode_failed = true; if (entry->decode_failed) - return; + return TaskProcessingResult::kCancelled; if (entry->memory) { if (entry->is_locked) - return; + return TaskProcessingResult::kLockOnly; bool lock_succeeded = entry->Lock(); // TODO(vmpstr): Deprecate the prepaint split, since it doesn't matter. RecordLockExistingCachedImageHistogram(TilePriority::NOW, lock_succeeded); if (lock_succeeded) - return; + return TaskProcessingResult::kLockOnly; } std::unique_ptr<CacheEntry> local_cache_entry; @@ -439,7 +445,7 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( if (!local_cache_entry) { entry->decode_failed = true; - return; + return TaskProcessingResult::kCancelled; } // Just in case someone else did this already, just unlock our work. @@ -457,6 +463,8 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( local_cache_entry->MoveImageMemoryTo(entry); DCHECK(entry->is_locked); } + + return TaskProcessingResult::kFullDecode; } base::Optional<SoftwareImageDecodeCache::CacheKey> diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h index c3b7c03303d..176adeec8ed 100644 --- a/chromium/cc/tiles/software_image_decode_cache.h +++ b/chromium/cc/tiles/software_image_decode_cache.h @@ -32,6 +32,10 @@ class CC_EXPORT SoftwareImageDecodeCache enum class DecodeTaskType { USE_IN_RASTER_TASKS, USE_OUT_OF_RASTER_TASKS }; + // Identifies whether a decode task performed decode work, or was fulfilled / + // failed trivially. + enum class TaskProcessingResult { kFullDecode, kLockOnly, kCancelled }; + SoftwareImageDecodeCache(SkColorType color_type, size_t locked_memory_limit_bytes, PaintImage::GeneratorClientId generator_client_id); @@ -56,9 +60,9 @@ class CC_EXPORT SoftwareImageDecodeCache // Decode the given image and store it in the cache. This is only called by an // image decode task from a worker thread. - void DecodeImageInTask(const CacheKey& key, - const PaintImage& paint_image, - DecodeTaskType task_type); + TaskProcessingResult DecodeImageInTask(const CacheKey& key, + const PaintImage& paint_image, + DecodeTaskType task_type); void OnImageDecodeTaskCompleted(const CacheKey& key, DecodeTaskType task_type); @@ -123,9 +127,9 @@ class CC_EXPORT SoftwareImageDecodeCache CacheEntry* AddCacheEntry(const CacheKey& key); - void DecodeImageIfNecessary(const CacheKey& key, - const PaintImage& paint_image, - CacheEntry* cache_entry); + TaskProcessingResult DecodeImageIfNecessary(const CacheKey& key, + const PaintImage& paint_image, + CacheEntry* cache_entry); void AddBudgetForImage(const CacheKey& key, CacheEntry* entry); void RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry); base::Optional<CacheKey> FindCachedCandidate(const CacheKey& key); diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.h b/chromium/cc/tiles/software_image_decode_cache_utils.h index 835d68c8492..3293d8b4cc9 100644 --- a/chromium/cc/tiles/software_image_decode_cache_utils.h +++ b/chromium/cc/tiles/software_image_decode_cache_utils.h @@ -50,12 +50,11 @@ class SoftwareImageDecodeCacheUtils { bool operator==(const CacheKey& other) const { // The frame_key always has to be the same. However, after that all // original decodes are the same, so if we can use the original decode, - // return true. If not, then we have to compare every field. Note we don't - // compare |nearest_neighbor_| because we would only use kOriginal type in - // that case (dchecked below), which implies no scale. The returned scale - // to Skia would respect the nearest neighbor value of the requested - // image. - DCHECK(!is_nearest_neighbor_ || type_ == kOriginal); + // return true. If not, then we have to compare every field. + // |nearest_neighbor_| is not compared below since it is not used for + // scaled decodes and does not affect the contents of the cache entry + // (just passed to skia for the filtering to be done at raster time). + DCHECK(!is_nearest_neighbor_ || type_ != kSubrectAndScale); return frame_key_ == other.frame_key_ && type_ == other.type_ && target_color_space_ == other.target_color_space_ && (type_ == kOriginal || (src_rect_ == other.src_rect_ && diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc index 165bb015145..032b487ef5e 100644 --- a/chromium/cc/tiles/tile_manager.cc +++ b/chromium/cc/tiles/tile_manager.cc @@ -402,9 +402,7 @@ TileManager::TileManager( base::Unretained(this))), has_scheduled_tile_tasks_(false), prepare_tiles_count_(0u), - next_tile_id_(0u), - task_set_finished_weak_ptr_factory_(this), - ready_to_draw_callback_weak_ptr_factory_(this) {} + next_tile_id_(0u) {} TileManager::~TileManager() { FinishTasksAndCleanUp(); @@ -550,8 +548,6 @@ bool TileManager::PrepareTiles( // Schedule tile tasks. ScheduleTasks(std::move(prioritized_work)); - image_controller_.paint_worklet_image_cache()->NotifyDidPrepareTiles(); - TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD, "state", BasicStateAsValue()); return true; @@ -779,8 +775,12 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { // If we couldn't fit the tile into our current memory limit, then we're // done. if (!memory_usage_is_within_limit) { - if (tile_is_needed_now) + if (tile_is_needed_now) { + LOG(ERROR) << "WARNING: tile memory limits exceeded, some content may " + "not draw"; + had_enough_memory_to_schedule_tiles_needed_now = false; + } all_tiles_that_need_to_be_rasterized_are_scheduled_ = false; break; } @@ -1190,10 +1190,8 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( prepare_tiles_count_, prioritized_tile.priority().priority_bin, ImageDecodeCache::TaskType::kInRaster); bool has_at_raster_images = false; - image_controller_.ConvertDataImagesToTasks( - &sync_decoded_images, &decode_tasks, &has_at_raster_images, tracing_info); - image_controller_.ConvertPaintWorkletImagesToTask(&sync_decoded_images, - &decode_tasks); + image_controller_.ConvertImagesToTasks(&sync_decoded_images, &decode_tasks, + &has_at_raster_images, tracing_info); // Notify |decoded_image_tracker_| after |image_controller_| to ensure we've // taken new refs on the images before releasing the predecode API refs. decoded_image_tracker_.OnImagesUsedInDraw(sync_decoded_images); @@ -1246,8 +1244,13 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( PlaybackImageProvider image_provider(image_controller_.cache(), raster_color_space, std::move(settings)); + // We make a deliberate copy of the PaintWorklet map here, as the + // PictureLayerImpl's map could be mutated or destroyed whilst raster from an + // earlier snapshot is still ongoing on the raster worker threads. + PaintWorkletRecordMap paint_worklet_records = + prioritized_tile.GetPaintWorkletRecords(); PaintWorkletImageProvider paint_worklet_image_provider( - image_controller_.paint_worklet_image_cache()); + std::move(paint_worklet_records)); DispatchingImageProvider dispatching_image_provider( std::move(image_provider), std::move(paint_worklet_image_provider)); @@ -1711,11 +1714,6 @@ TileManager::ActivationStateAsValue() { return std::move(state); } -void TileManager::SetPaintWorkletLayerPainter( - std::unique_ptr<PaintWorkletLayerPainter> painter) { - image_controller_.SetPaintWorkletLayerPainter(std::move(painter)); -} - void TileManager::ActivationStateAsValueInto( base::trace_event::TracedValue* state) { state->SetString("tree_priority", diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h index 015ce53e837..afa7d42ef37 100644 --- a/chromium/cc/tiles/tile_manager.h +++ b/chromium/cc/tiles/tile_manager.h @@ -294,9 +294,6 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { void set_active_url(const GURL& url) { active_url_ = url; } - void SetPaintWorkletLayerPainter( - std::unique_ptr<PaintWorkletLayerPainter> painter); - protected: friend class Tile; // Must be called by tile during destruction. @@ -473,9 +470,10 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { // different. The |task_set_finished_weak_ptr_factory_| is invalidated any // time new tasks are scheduled, preventing a race when the callback has // been scheduled but not yet executed. - base::WeakPtrFactory<TileManager> task_set_finished_weak_ptr_factory_; + base::WeakPtrFactory<TileManager> task_set_finished_weak_ptr_factory_{this}; // The |ready_to_draw_callback_weak_ptr_factory_| is never invalidated. - base::WeakPtrFactory<TileManager> ready_to_draw_callback_weak_ptr_factory_; + base::WeakPtrFactory<TileManager> ready_to_draw_callback_weak_ptr_factory_{ + this}; }; } // namespace cc diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc index 9c6d1e0516b..7b4e57f2e2c 100644 --- a/chromium/cc/tiles/tile_manager_unittest.cc +++ b/chromium/cc/tiles/tile_manager_unittest.cc @@ -2583,7 +2583,7 @@ TEST_F(TileManagerReadyToDrawTest, TilePrioritiesUpdated) { final_num_prepaint++; } else { final_num_required++; - if (base::ContainsValue(prepaint_tiles, tile)) { + if (base::Contains(prepaint_tiles, tile)) { found_one_prepaint_to_required_transition = true; } } diff --git a/chromium/cc/tiles/tile_task_manager.cc b/chromium/cc/tiles/tile_task_manager.cc index 2bfdd9e88ef..476a7d7a965 100644 --- a/chromium/cc/tiles/tile_task_manager.cc +++ b/chromium/cc/tiles/tile_task_manager.cc @@ -5,6 +5,7 @@ #include "cc/tiles/tile_task_manager.h" #include "base/memory/ptr_util.h" +#include "base/threading/thread_restrictions.h" #include "base/trace_event/trace_event.h" namespace cc { @@ -50,7 +51,10 @@ void TileTaskManagerImpl::Shutdown() { // Cancel non-scheduled tasks and wait for running tasks to finish. TaskGraph empty; task_graph_runner_->ScheduleTasks(namespace_token_, &empty); - task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); + { + base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; + task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); + } } } // namespace cc |