1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/tiles/gpu_image_decode_cache.h"
15 #include "base/command_line.h"
16 #include "base/feature_list.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/test/scoped_feature_list.h"
19 #include "cc/base/switches.h"
20 #include "cc/paint/draw_image.h"
21 #include "cc/paint/image_transfer_cache_entry.h"
22 #include "cc/paint/paint_image_builder.h"
23 #include "cc/test/fake_paint_image_generator.h"
24 #include "cc/test/skia_common.h"
25 #include "cc/test/test_tile_task_runner.h"
26 #include "cc/test/transfer_cache_test_helper.h"
27 #include "cc/tiles/raster_dark_mode_filter.h"
28 #include "components/viz/test/test_context_provider.h"
29 #include "components/viz/test/test_gles2_interface.h"
30 #include "gpu/command_buffer/client/raster_implementation_gles.h"
31 #include "gpu/command_buffer/common/command_buffer_id.h"
32 #include "gpu/command_buffer/common/constants.h"
33 #include "gpu/config/gpu_finch_features.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "third_party/skia/include/core/SkImageGenerator.h"
37 #include "third_party/skia/include/core/SkRefCnt.h"
38 #include "third_party/skia/include/effects/SkHighContrastFilter.h"
39 #include "third_party/skia/include/gpu/GrBackendSurface.h"
40 #include "third_party/skia/include/gpu/GrDirectContext.h"
43 using testing::StrictMock;
48 class FakeDiscardableManager {
50 void SetGLES2Interface(viz::TestGLES2Interface* gl) { gl_ = gl; }
51 void Initialize(GLuint texture_id) {
52 EXPECT_EQ(textures_.end(), textures_.find(texture_id));
53 textures_[texture_id] = kHandleLockedStart;
54 live_textures_count_++;
56 void Unlock(GLuint texture_id) {
57 EXPECT_NE(textures_.end(), textures_.find(texture_id));
58 ExpectLocked(texture_id);
59 textures_[texture_id]--;
61 bool Lock(GLuint texture_id) {
64 EXPECT_NE(textures_.end(), textures_.find(texture_id));
65 if (textures_[texture_id] >= kHandleUnlocked) {
66 textures_[texture_id]++;
72 void DeleteTexture(GLuint texture_id) {
73 if (textures_.end() == textures_.find(texture_id))
76 ExpectLocked(texture_id);
77 textures_[texture_id] = kHandleDeleted;
78 live_textures_count_--;
81 void set_cached_textures_limit(size_t limit) {
82 cached_textures_limit_ = limit;
85 void ExpectLocked(GLuint texture_id) {
86 EXPECT_TRUE(textures_.end() != textures_.find(texture_id));
88 // Any value > kHandleLockedStart represents a locked texture. As we
89 // increment this value with each lock, we need the entire range and can't
90 // add additional values > kHandleLockedStart in the future.
91 EXPECT_GE(textures_[texture_id], kHandleLockedStart);
92 EXPECT_LE(textures_[texture_id], kHandleLockedEnd);
97 for (auto it = textures_.begin(); it != textures_.end(); ++it) {
98 if (live_textures_count_ <= cached_textures_limit_)
100 if (it->second != kHandleUnlocked)
103 it->second = kHandleDeleted;
104 gl_->TestGLES2Interface::DeleteTextures(1, &it->first);
105 live_textures_count_--;
109 const int32_t kHandleDeleted = 0;
110 const int32_t kHandleUnlocked = 1;
111 const int32_t kHandleLockedStart = 2;
112 const int32_t kHandleLockedEnd = std::numeric_limits<int32_t>::max();
114 std::map<GLuint, int32_t> textures_;
115 size_t live_textures_count_ = 0;
116 size_t cached_textures_limit_ = std::numeric_limits<size_t>::max();
117 raw_ptr<viz::TestGLES2Interface> gl_ = nullptr;
120 class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface,
121 public viz::TestContextSupport {
123 explicit FakeGPUImageDecodeTestGLES2Interface(
124 FakeDiscardableManager* discardable_manager,
125 TransferCacheTestHelper* transfer_cache_helper,
126 bool advertise_accelerated_decoding)
128 "GL_EXT_texture_format_BGRA8888 GL_OES_rgb8_rgba8 "
129 "GL_OES_texture_npot GL_EXT_texture_rg "
130 "GL_OES_texture_half_float GL_OES_texture_half_float_linear "
131 "GL_EXT_texture_norm16"),
132 discardable_manager_(discardable_manager),
133 transfer_cache_helper_(transfer_cache_helper),
134 advertise_accelerated_decoding_(advertise_accelerated_decoding) {}
136 ~FakeGPUImageDecodeTestGLES2Interface() override {
137 // All textures / framebuffers / renderbuffers should be cleaned up.
138 EXPECT_EQ(0u, NumTextures());
139 EXPECT_EQ(0u, NumFramebuffers());
140 EXPECT_EQ(0u, NumRenderbuffers());
143 void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override {
144 discardable_manager_->Initialize(texture_id);
146 void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) override {
147 discardable_manager_->Unlock(texture_id);
149 bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override {
150 return discardable_manager_->Lock(texture_id);
153 bool ThreadSafeShallowLockDiscardableTexture(uint32_t texture_id) override {
154 return discardable_manager_->Lock(texture_id);
156 void CompleteLockDiscardableTexureOnContextThread(
157 uint32_t texture_id) override {}
159 void* MapTransferCacheEntry(uint32_t serialized_size) override {
160 mapped_entry_size_ = serialized_size;
161 mapped_entry_.reset(new uint8_t[serialized_size]);
162 return mapped_entry_.get();
165 void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override {
166 transfer_cache_helper_->CreateEntryDirect(
167 MakeEntryKey(type, id),
168 base::make_span(mapped_entry_.get(), mapped_entry_size_));
169 mapped_entry_ = nullptr;
170 mapped_entry_size_ = 0;
173 bool ThreadsafeLockTransferCacheEntry(uint32_t type, uint32_t id) override {
174 return transfer_cache_helper_->LockEntryDirect(MakeEntryKey(type, id));
176 void UnlockTransferCacheEntries(
177 const std::vector<std::pair<uint32_t, uint32_t>>& entries) override {
178 std::vector<std::pair<TransferCacheEntryType, uint32_t>> keys;
179 keys.reserve(entries.size());
180 for (const auto& e : entries)
181 keys.emplace_back(MakeEntryKey(e.first, e.second));
182 transfer_cache_helper_->UnlockEntriesDirect(keys);
184 void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override {
185 transfer_cache_helper_->DeleteEntryDirect(MakeEntryKey(type, id));
188 bool IsJpegDecodeAccelerationSupported() const override {
189 return advertise_accelerated_decoding_;
192 bool IsWebPDecodeAccelerationSupported() const override {
193 return advertise_accelerated_decoding_;
196 bool CanDecodeWithHardwareAcceleration(
197 const ImageHeaderMetadata* image_metadata) const override {
198 // Only advertise hardware accelerated decoding for the current use cases
200 if (image_metadata && (image_metadata->image_type == ImageType::kJPEG ||
201 image_metadata->image_type == ImageType::kWEBP)) {
202 return advertise_accelerated_decoding_;
207 std::pair<TransferCacheEntryType, uint32_t> MakeEntryKey(uint32_t type,
209 DCHECK_LE(type, static_cast<uint32_t>(TransferCacheEntryType::kLast));
210 return std::make_pair(static_cast<TransferCacheEntryType>(type), id);
213 // viz::TestGLES2Interface:
214 const GLubyte* GetString(GLenum name) override {
217 return reinterpret_cast<const GLubyte*>(extension_string_.c_str());
219 return reinterpret_cast<const GLubyte*>("4.0 Null GL");
220 case GL_SHADING_LANGUAGE_VERSION:
221 return reinterpret_cast<const GLubyte*>("4.20.8 Null GLSL");
223 return reinterpret_cast<const GLubyte*>("Null Vendor");
225 return reinterpret_cast<const GLubyte*>("The Null (Non-)Renderer");
229 void GetIntegerv(GLenum name, GLint* params) override {
231 case GL_MAX_TEXTURE_IMAGE_UNITS:
234 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
237 case GL_MAX_RENDERBUFFER_SIZE:
240 case GL_MAX_VERTEX_ATTRIBS:
246 TestGLES2Interface::GetIntegerv(name, params);
248 void DeleteTextures(GLsizei n, const GLuint* textures) override {
249 for (GLsizei i = 0; i < n; i++) {
250 discardable_manager_->DeleteTexture(textures[i]);
252 TestGLES2Interface::DeleteTextures(n, textures);
256 const std::string extension_string_;
257 raw_ptr<FakeDiscardableManager> discardable_manager_;
258 raw_ptr<TransferCacheTestHelper> transfer_cache_helper_;
259 bool advertise_accelerated_decoding_ = false;
260 size_t mapped_entry_size_ = 0;
261 std::unique_ptr<uint8_t[]> mapped_entry_;
264 class MockRasterImplementation : public gpu::raster::RasterImplementationGLES {
266 explicit MockRasterImplementation(gpu::gles2::GLES2Interface* gl,
267 gpu::ContextSupport* support)
268 : RasterImplementationGLES(gl, support) {}
269 ~MockRasterImplementation() override = default;
271 gpu::SyncToken ScheduleImageDecode(base::span<const uint8_t> encoded_data,
272 const gfx::Size& output_size,
273 uint32_t transfer_cache_entry_id,
274 const gfx::ColorSpace& target_color_space,
275 bool needs_mips) override {
276 DoScheduleImageDecode(output_size, transfer_cache_entry_id,
277 target_color_space, needs_mips);
278 if (!next_accelerated_decode_fails_) {
279 return gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO,
280 gpu::CommandBufferId::FromUnsafeValue(1u),
281 next_release_count_++);
283 return gpu::SyncToken();
286 void SetAcceleratedDecodingFailed() { next_accelerated_decode_fails_ = true; }
288 MOCK_METHOD4(DoScheduleImageDecode,
289 void(const gfx::Size& /* output_size */,
290 uint32_t /* transfer_cache_entry_id */,
291 const gfx::ColorSpace& /* target_color_space */,
292 bool /* needs_mips */));
295 bool next_accelerated_decode_fails_ = false;
296 uint64_t next_release_count_ = 1u;
299 class GPUImageDecodeTestMockContextProvider : public viz::TestContextProvider {
301 static scoped_refptr<GPUImageDecodeTestMockContextProvider> Create(
302 FakeDiscardableManager* discardable_manager,
303 TransferCacheTestHelper* transfer_cache_helper,
304 bool advertise_accelerated_decoding) {
305 auto support = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
306 discardable_manager, transfer_cache_helper,
307 advertise_accelerated_decoding);
308 auto gl = std::make_unique<FakeGPUImageDecodeTestGLES2Interface>(
309 discardable_manager, transfer_cache_helper,
310 false /* advertise_accelerated_decoding */);
311 auto raster = std::make_unique<StrictMock<MockRasterImplementation>>(
312 gl.get(), support.get());
313 return new GPUImageDecodeTestMockContextProvider(
314 std::move(support), std::move(gl), std::move(raster));
317 void SetContextCapabilitiesOverride(absl::optional<gpu::Capabilities> caps) {
318 capabilities_override_ = caps;
321 const gpu::Capabilities& ContextCapabilities() const override {
322 if (capabilities_override_.has_value())
323 return *capabilities_override_;
325 return viz::TestContextProvider::ContextCapabilities();
329 ~GPUImageDecodeTestMockContextProvider() override = default;
330 GPUImageDecodeTestMockContextProvider(
331 std::unique_ptr<viz::TestContextSupport> support,
332 std::unique_ptr<viz::TestGLES2Interface> gl,
333 std::unique_ptr<gpu::raster::RasterInterface> raster)
334 : TestContextProvider(std::move(support),
340 absl::optional<gpu::Capabilities> capabilities_override_;
343 class FakeRasterDarkModeFilter : public RasterDarkModeFilter {
345 FakeRasterDarkModeFilter() {
346 SkHighContrastConfig config;
347 config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
348 color_filter_ = SkHighContrastFilter::Make(config);
351 sk_sp<SkColorFilter> ApplyToImage(const SkPixmap& pixmap,
352 const SkIRect& src) const override {
353 return color_filter_;
356 const sk_sp<SkColorFilter> GetFilter() const { return color_filter_; }
359 sk_sp<SkColorFilter> color_filter_;
362 SkM44 CreateMatrix(const SkSize& scale) {
363 return SkM44::Scale(scale.width(), scale.height());
366 #define EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(condition) \
367 if (!use_transfer_cache_) \
368 EXPECT_TRUE(condition);
370 #define EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE(condition) \
371 if (!use_transfer_cache_) \
372 EXPECT_FALSE(condition);
374 size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024;
376 class GpuImageDecodeCacheTest
377 : public ::testing::TestWithParam<
378 std::tuple<SkColorType,
379 bool /* use_transfer_cache */,
380 bool /* do_yuv_decode */,
381 bool /* allow_accelerated_jpeg_decoding */,
382 bool /* allow_accelerated_webp_decoding */,
383 bool /* advertise_accelerated_decoding */,
384 bool /* enable_clipped_image_scaling */,
385 bool /* no_discardable_memory */>> {
387 void SetUp() override {
388 std::vector<base::test::FeatureRef> enabled_features;
389 allow_accelerated_jpeg_decoding_ = std::get<3>(GetParam());
390 if (allow_accelerated_jpeg_decoding_)
391 enabled_features.push_back(features::kVaapiJpegImageDecodeAcceleration);
392 allow_accelerated_webp_decoding_ = std::get<4>(GetParam());
393 if (allow_accelerated_webp_decoding_)
394 enabled_features.push_back(features::kVaapiWebPImageDecodeAcceleration);
395 no_discardable_memory_ = std::get<7>(GetParam());
396 if (no_discardable_memory_)
397 enabled_features.push_back(
398 features::kNoDiscardableMemoryForGpuDecodePath);
399 feature_list_.InitWithFeatures(enabled_features,
400 {} /* disabled_features */);
401 advertise_accelerated_decoding_ = std::get<5>(GetParam());
402 enable_clipped_image_scaling_ = std::get<6>(GetParam());
403 if (enable_clipped_image_scaling_) {
404 auto* command_line = base::CommandLine::ForCurrentProcess();
405 ASSERT_TRUE(command_line != nullptr);
406 command_line->AppendSwitch(switches::kEnableClippedImageScaling);
408 context_provider_ = GPUImageDecodeTestMockContextProvider::Create(
409 &discardable_manager_, &transfer_cache_helper_,
410 advertise_accelerated_decoding_);
411 discardable_manager_.SetGLES2Interface(
412 context_provider_->UnboundTestContextGL());
413 context_provider_->BindToCurrentThread();
415 viz::RasterContextProvider::ScopedRasterContextLock context_lock(
416 context_provider_.get());
417 transfer_cache_helper_.SetGrContext(context_provider_->GrContext());
419 context_provider_->ContextCapabilities().max_texture_size;
421 color_type_ = std::get<0>(GetParam());
422 use_transfer_cache_ = std::get<1>(GetParam());
423 do_yuv_decode_ = std::get<2>(GetParam());
426 std::unique_ptr<GpuImageDecodeCache> CreateCache(
427 size_t memory_limit_bytes = kGpuMemoryLimitBytes,
428 RasterDarkModeFilter* const dark_mode_filter = nullptr) {
429 return std::make_unique<GpuImageDecodeCache>(
430 context_provider_.get(), use_transfer_cache_, color_type_,
431 memory_limit_bytes, max_texture_size_, dark_mode_filter);
434 // Returns dimensions for an image that will not fit in GPU memory and hence
435 // triggers software fallback.
436 gfx::Size GetLargeImageSize() const {
437 return gfx::Size(1, max_texture_size_ + 1);
440 // Returns dimensions for an image that will fit in GPU memory.
441 gfx::Size GetNormalImageSize() const {
442 int dimension = std::min(100, max_texture_size_ - 1);
443 return gfx::Size(dimension, dimension);
446 PaintImage CreatePaintImageInternal(
447 const gfx::Size& size,
448 sk_sp<SkColorSpace> color_space = nullptr,
449 PaintImage::Id id = PaintImage::kInvalidId) {
450 const bool allocate_encoded_memory = true;
452 if (do_yuv_decode_) {
453 return CreateDiscardablePaintImage(
454 size, color_space, allocate_encoded_memory, id, color_type_,
455 yuv_format_, yuv_data_type_);
457 return CreateDiscardablePaintImage(
458 size, color_space, allocate_encoded_memory, id, color_type_);
461 // Create an image that's too large to upload and will trigger falling back to
462 // software rendering and decoded data storage.
463 PaintImage CreateLargePaintImageForSoftwareFallback(
464 sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB()) {
465 return CreatePaintImageForFallbackToRGB(GetLargeImageSize(),
469 PaintImage CreatePaintImageForFallbackToRGB(
470 const gfx::Size test_image_size,
471 sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB()) {
473 SkImageInfo::Make(test_image_size.width(), test_image_size.height(),
474 color_type_, kPremul_SkAlphaType, image_color_space);
475 sk_sp<FakePaintImageGenerator> generator;
476 if (do_yuv_decode_) {
477 SkYUVAPixmapInfo yuva_pixmap_info =
478 GetYUVAPixmapInfo(test_image_size, yuv_format_, yuv_data_type_);
479 generator = sk_make_sp<FakePaintImageGenerator>(info, yuva_pixmap_info);
480 generator->SetExpectFallbackToRGB();
482 generator = sk_make_sp<FakePaintImageGenerator>(info);
484 PaintImage image = PaintImageBuilder::WithDefault()
485 .set_id(PaintImage::GetNextId())
486 .set_paint_image_generator(generator)
491 PaintImage CreateBitmapImageInternal(const gfx::Size& size) {
492 return CreateBitmapImage(size, color_type_);
495 gfx::ColorSpace DefaultColorSpace() {
496 if (color_type_ != kRGBA_F16_SkColorType)
497 return gfx::ColorSpace::CreateSRGB();
498 return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::P3,
499 gfx::ColorSpace::TransferID::LINEAR);
502 TargetColorParams DefaultTargetColorParams() {
503 return TargetColorParams(DefaultColorSpace());
506 DrawImage CreateDrawImageInternal(
507 const PaintImage& paint_image,
508 const SkM44& matrix = SkM44(),
509 gfx::ColorSpace* color_space = nullptr,
510 PaintFlags::FilterQuality filter_quality =
511 PaintFlags::FilterQuality::kMedium,
512 SkIRect* src_rect = nullptr,
513 size_t frame_index = PaintImage::kDefaultFrameIndex,
514 float sdr_white_level = gfx::ColorSpace::kDefaultSDRWhiteLevel,
515 bool use_dark_mode = false) {
516 SkIRect src_rectangle;
519 SkIRect::MakeWH(paint_image.width(), paint_image.height());
520 src_rect = &src_rectangle;
522 TargetColorParams target_color_params = DefaultTargetColorParams();
524 target_color_params.color_space = *color_space;
525 target_color_params.sdr_max_luminance_nits = sdr_white_level;
527 return DrawImage(paint_image, use_dark_mode, *src_rect, filter_quality,
528 matrix, frame_index, target_color_params);
531 DrawImage CreateDrawImageWithDarkModeInternal(
532 const PaintImage& paint_image,
533 const SkM44& matrix = SkM44(),
534 gfx::ColorSpace* color_space = nullptr,
535 PaintFlags::FilterQuality filter_quality =
536 PaintFlags::FilterQuality::kMedium,
537 SkIRect* src_rect = nullptr,
538 size_t frame_index = PaintImage::kDefaultFrameIndex,
539 float sdr_white_level = gfx::ColorSpace::kDefaultSDRWhiteLevel) {
540 return CreateDrawImageInternal(paint_image, matrix, color_space,
541 filter_quality, src_rect, frame_index,
542 sdr_white_level, true);
545 void GetImageAndDrawFinishedForDarkMode(
546 GpuImageDecodeCache* cache,
547 const DrawImage& draw_image,
548 FakeRasterDarkModeFilter* dark_mode_filter) {
550 DCHECK(dark_mode_filter);
552 // Must hold context lock before calling GetDecodedImageForDraw /
553 // DrawWithImageFinished.
554 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
555 DecodedDrawImage decoded_draw_image =
556 cache->GetDecodedImageForDraw(draw_image);
557 EXPECT_EQ(decoded_draw_image.dark_mode_color_filter(),
558 dark_mode_filter->GetFilter());
559 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
562 GPUImageDecodeTestMockContextProvider* context_provider() {
563 return context_provider_.get();
566 size_t GetBytesNeededForSingleImage(gfx::Size image_dimensions) {
567 if (do_yuv_decode_) {
568 SkYUVAPixmapInfo yuva_pixmap_info =
569 GetYUVAPixmapInfo(image_dimensions, yuv_format_, yuv_data_type_);
571 return yuva_pixmap_info.computeTotalBytes();
573 const size_t test_image_area_bytes =
574 base::checked_cast<size_t>(image_dimensions.GetArea());
575 base::CheckedNumeric<size_t> bytes_for_rgb_image_safe(
576 test_image_area_bytes);
577 bytes_for_rgb_image_safe *= SkColorTypeBytesPerPixel(color_type_);
578 return bytes_for_rgb_image_safe.ValueOrDie();
581 void SetCachedTexturesLimit(size_t limit) {
582 discardable_manager_.set_cached_textures_limit(limit);
583 transfer_cache_helper_.SetCachedItemsLimit(limit);
586 // If this is an image-backed DecodedDrawImage, does nothing. Otherwise this
587 // retreives the image from the transfer cache and builds a new
589 DecodedDrawImage EnsureImageBacked(DecodedDrawImage&& draw_image) {
590 if (draw_image.transfer_cache_entry_id()) {
591 EXPECT_TRUE(use_transfer_cache_);
593 transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
594 *draw_image.transfer_cache_entry_id());
595 if (draw_image.transfer_cache_entry_needs_mips())
596 image_entry->EnsureMips();
597 DecodedDrawImage new_draw_image(
598 image_entry->image(), draw_image.dark_mode_color_filter(),
599 draw_image.src_rect_offset(), draw_image.scale_adjustment(),
600 draw_image.filter_quality(), draw_image.is_budgeted());
601 return new_draw_image;
604 return std::move(draw_image);
607 sk_sp<SkImage> GetLastTransferredImage() {
608 auto& key = transfer_cache_helper_.GetLastAddedEntry();
609 ServiceTransferCacheEntry* entry =
610 transfer_cache_helper_.GetEntryInternal(key.first, key.second);
613 CHECK_EQ(TransferCacheEntryType::kImage, entry->Type());
614 return static_cast<ServiceImageTransferCacheEntry*>(entry)->image();
617 void CompareAllPlanesToMippedVersions(
618 GpuImageDecodeCache* cache,
619 const DrawImage& draw_image,
620 const absl::optional<uint32_t> transfer_cache_id,
621 bool should_have_mips) {
622 for (size_t i = 0; i < kNumYUVPlanes; ++i) {
623 sk_sp<SkImage> original_uploaded_plane;
624 if (use_transfer_cache_) {
625 DCHECK(transfer_cache_id.has_value());
626 const uint32_t id = transfer_cache_id.value();
628 transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
630 original_uploaded_plane = image_entry->GetPlaneImage(i);
632 original_uploaded_plane = cache->GetUploadedPlaneForTesting(
633 draw_image, static_cast<YUVIndex>(i));
635 ASSERT_TRUE(original_uploaded_plane);
636 auto plane_with_mips = original_uploaded_plane->makeTextureImage(
637 context_provider()->GrContext(), GrMipMapped::kYes);
638 ASSERT_TRUE(plane_with_mips);
639 EXPECT_EQ(should_have_mips, original_uploaded_plane == plane_with_mips);
643 void VerifyUploadedPlaneSizes(
644 GpuImageDecodeCache* cache,
645 const DrawImage& draw_image,
646 const absl::optional<uint32_t> transfer_cache_id,
647 const SkISize plane_sizes[SkYUVAInfo::kMaxPlanes],
648 SkYUVAPixmapInfo::DataType expected_type =
649 SkYUVAPixmapInfo::DataType::kUnorm8,
650 const SkColorSpace* expected_cs = nullptr) {
651 SkColorType expected_color_type =
652 SkYUVAPixmapInfo::DefaultColorTypeForDataType(expected_type, 1);
653 for (size_t i = 0; i < kNumYUVPlanes; ++i) {
654 sk_sp<SkImage> uploaded_plane;
655 if (use_transfer_cache_) {
656 DCHECK(transfer_cache_id.has_value());
657 const uint32_t id = transfer_cache_id.value();
659 transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
661 uploaded_plane = image_entry->GetPlaneImage(i);
663 uploaded_plane = cache->GetUploadedPlaneForTesting(
664 draw_image, static_cast<YUVIndex>(i));
666 ASSERT_TRUE(uploaded_plane);
667 EXPECT_EQ(plane_sizes[i], uploaded_plane->dimensions());
668 EXPECT_EQ(expected_color_type, uploaded_plane->colorType());
669 if (expected_cs && use_transfer_cache_) {
671 SkColorSpace::Equals(expected_cs, uploaded_plane->colorSpace()));
672 } else if (expected_cs) {
673 // In-process raster sets the ColorSpace on the composite SkImage.
679 base::test::ScopedFeatureList feature_list_;
681 // The order of these members is important because |context_provider_| depends
682 // on |discardable_manager_| and |transfer_cache_helper_|.
683 FakeDiscardableManager discardable_manager_;
684 TransferCacheTestHelper transfer_cache_helper_;
685 scoped_refptr<GPUImageDecodeTestMockContextProvider> context_provider_;
687 // Only used when |do_yuv_decode_| is true.
688 SkYUVAPixmapInfo::DataType yuv_data_type_ =
689 SkYUVAPixmapInfo::DataType::kUnorm8;
690 YUVSubsampling yuv_format_ = YUVSubsampling::k420;
692 bool use_transfer_cache_;
693 SkColorType color_type_;
695 bool allow_accelerated_jpeg_decoding_;
696 bool allow_accelerated_webp_decoding_;
697 bool advertise_accelerated_decoding_;
698 bool enable_clipped_image_scaling_;
699 bool no_discardable_memory_;
700 int max_texture_size_ = 0;
703 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
704 auto cache = CreateCache();
705 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
707 DrawImage draw_image =
708 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
709 ImageDecodeCache::TaskResult result =
710 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
711 EXPECT_TRUE(result.need_unref);
712 EXPECT_TRUE(result.task);
714 DrawImage another_draw_image =
715 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
716 ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
717 another_draw_image, ImageDecodeCache::TracingInfo());
718 EXPECT_TRUE(another_result.need_unref);
719 EXPECT_TRUE(result.task.get() == another_result.task.get());
721 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
722 TestTileTaskRunner::ProcessTask(result.task.get());
724 cache->UnrefImage(draw_image);
725 cache->UnrefImage(draw_image);
728 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
729 auto cache = CreateCache();
730 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
731 DrawImage draw_image =
732 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
733 ImageDecodeCache::TaskResult result =
734 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
735 EXPECT_TRUE(result.need_unref);
736 EXPECT_TRUE(result.task);
738 // |result| is an upload task which depends on a decode task.
739 EXPECT_EQ(result.task->dependencies().size(), 1u);
740 EXPECT_TRUE(result.task->dependencies()[0]);
742 DrawImage another_draw_image =
743 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
744 ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
745 another_draw_image, ImageDecodeCache::TracingInfo());
747 // |another_draw_image| represents previous image but at a different scale.
748 // It still has one dependency (decoding), and its upload task is equivalent
749 // to the larger decoded textures being uploaded.
750 EXPECT_EQ(another_result.task->dependencies().size(), 1u);
751 EXPECT_TRUE(another_result.task->dependencies()[0]);
753 EXPECT_TRUE(another_result.need_unref);
754 EXPECT_TRUE(result.task.get() == another_result.task.get());
756 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
757 TestTileTaskRunner::ProcessTask(result.task.get());
759 cache->UnrefImage(draw_image);
760 cache->UnrefImage(another_draw_image);
763 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
764 auto cache = CreateCache();
765 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
766 SkM44 matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
767 DrawImage draw_image = CreateDrawImageInternal(image, matrix);
768 ImageDecodeCache::TaskResult result =
769 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
770 EXPECT_TRUE(result.need_unref);
771 EXPECT_TRUE(result.task);
773 DrawImage another_draw_image =
774 CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
775 PaintFlags::FilterQuality::kLow);
776 ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
777 another_draw_image, ImageDecodeCache::TracingInfo());
778 EXPECT_TRUE(another_result.need_unref);
779 EXPECT_TRUE(result.task.get() == another_result.task.get());
781 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
782 TestTileTaskRunner::ProcessTask(result.task.get());
784 cache->UnrefImage(draw_image);
785 cache->UnrefImage(another_draw_image);
788 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
789 auto cache = CreateCache();
791 PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
792 DrawImage first_draw_image = CreateDrawImageInternal(
793 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
794 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
795 first_draw_image, ImageDecodeCache::TracingInfo());
796 EXPECT_TRUE(first_result.need_unref);
797 EXPECT_TRUE(first_result.task);
799 PaintImage second_image = CreatePaintImageInternal(GetNormalImageSize());
800 DrawImage second_draw_image = CreateDrawImageInternal(
801 second_image, CreateMatrix(SkSize::Make(0.25f, 0.25f)));
802 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
803 second_draw_image, ImageDecodeCache::TracingInfo());
804 EXPECT_TRUE(second_result.need_unref);
805 EXPECT_TRUE(second_result.task);
806 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
808 TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
809 TestTileTaskRunner::ProcessTask(first_result.task.get());
810 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
811 TestTileTaskRunner::ProcessTask(second_result.task.get());
813 cache->UnrefImage(first_draw_image);
814 cache->UnrefImage(second_draw_image);
817 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
818 auto cache = CreateCache();
820 PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
821 DrawImage first_draw_image = CreateDrawImageInternal(
822 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
823 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
824 first_draw_image, ImageDecodeCache::TracingInfo());
825 EXPECT_TRUE(first_result.need_unref);
826 EXPECT_TRUE(first_result.task);
828 TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
829 TestTileTaskRunner::ProcessTask(first_result.task.get());
831 cache->UnrefImage(first_draw_image);
833 DrawImage second_draw_image = CreateDrawImageInternal(first_image);
834 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
835 second_draw_image, ImageDecodeCache::TracingInfo());
836 EXPECT_TRUE(second_result.need_unref);
837 EXPECT_TRUE(second_result.task);
838 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
840 DrawImage third_draw_image = CreateDrawImageInternal(
841 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
842 ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
843 third_draw_image, ImageDecodeCache::TracingInfo());
844 EXPECT_TRUE(third_result.need_unref);
845 EXPECT_TRUE(third_result.task.get() == second_result.task.get());
847 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
848 TestTileTaskRunner::ProcessTask(second_result.task.get());
850 cache->UnrefImage(second_draw_image);
851 cache->UnrefImage(third_draw_image);
854 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
855 auto cache = CreateCache();
856 PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
857 DrawImage first_draw_image = CreateDrawImageInternal(
858 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
859 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
860 first_draw_image, ImageDecodeCache::TracingInfo());
861 EXPECT_TRUE(first_result.need_unref);
862 EXPECT_TRUE(first_result.task);
864 DrawImage second_draw_image = CreateDrawImageInternal(first_image);
865 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
866 second_draw_image, ImageDecodeCache::TracingInfo());
867 EXPECT_TRUE(second_result.need_unref);
868 EXPECT_TRUE(second_result.task);
869 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
871 DrawImage third_draw_image = CreateDrawImageInternal(
872 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
873 ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
874 third_draw_image, ImageDecodeCache::TracingInfo());
875 EXPECT_TRUE(third_result.need_unref);
876 EXPECT_TRUE(third_result.task.get() == first_result.task.get());
878 TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
879 TestTileTaskRunner::ProcessTask(first_result.task.get());
880 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
881 TestTileTaskRunner::ProcessTask(second_result.task.get());
883 cache->UnrefImage(first_draw_image);
884 cache->UnrefImage(second_draw_image);
885 cache->UnrefImage(third_draw_image);
888 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
889 auto cache = CreateCache();
890 SkM44 matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
891 PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
892 DrawImage first_draw_image =
893 CreateDrawImageInternal(first_image, matrix, nullptr /* color_space */,
894 PaintFlags::FilterQuality::kLow);
895 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
896 first_draw_image, ImageDecodeCache::TracingInfo());
897 EXPECT_TRUE(first_result.need_unref);
898 EXPECT_TRUE(first_result.task);
900 TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
901 TestTileTaskRunner::ProcessTask(first_result.task.get());
903 cache->UnrefImage(first_draw_image);
905 DrawImage second_draw_image =
906 CreateDrawImageInternal(first_image, matrix, nullptr /* color_space */,
907 PaintFlags::FilterQuality::kMedium);
908 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
909 second_draw_image, ImageDecodeCache::TracingInfo());
910 EXPECT_TRUE(second_result.need_unref);
912 EXPECT_TRUE(second_result.task);
913 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
914 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
915 TestTileTaskRunner::ProcessTask(second_result.task.get());
916 cache->UnrefImage(second_draw_image);
919 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
920 auto cache = CreateCache();
921 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
922 DrawImage draw_image =
923 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
924 ImageDecodeCache::TaskResult result =
925 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
926 EXPECT_TRUE(result.need_unref);
927 EXPECT_TRUE(result.task);
928 EXPECT_EQ(result.task->dependencies().size(), 1u);
929 EXPECT_TRUE(result.task->dependencies()[0]);
931 // Run the decode but don't complete it (this will keep the decode locked).
932 TestTileTaskRunner::ScheduleTask(result.task->dependencies()[0].get());
933 TestTileTaskRunner::RunTask(result.task->dependencies()[0].get());
935 // Cancel the upload.
936 TestTileTaskRunner::CancelTask(result.task.get());
937 TestTileTaskRunner::CompleteTask(result.task.get());
939 // Get the image again - we should have an upload task, but no dependent
940 // decode task, as the decode was already locked.
941 ImageDecodeCache::TaskResult another_result =
942 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
943 EXPECT_TRUE(another_result.need_unref);
944 EXPECT_TRUE(another_result.task);
945 EXPECT_EQ(another_result.task->dependencies().size(), 0u);
947 TestTileTaskRunner::ProcessTask(another_result.task.get());
949 // Finally, complete the original decode task.
950 TestTileTaskRunner::CompleteTask(result.task->dependencies()[0].get());
952 cache->UnrefImage(draw_image);
953 cache->UnrefImage(draw_image);
956 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
957 auto cache = CreateCache();
958 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
959 DrawImage draw_image =
960 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
961 ImageDecodeCache::TaskResult result =
962 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
963 EXPECT_TRUE(result.need_unref);
964 EXPECT_TRUE(result.task);
965 EXPECT_EQ(result.task->dependencies().size(), 1u);
966 EXPECT_TRUE(result.task->dependencies()[0]);
969 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
971 // Cancel the upload.
972 TestTileTaskRunner::CancelTask(result.task.get());
973 TestTileTaskRunner::CompleteTask(result.task.get());
976 cache->UnrefImage(draw_image);
978 // Get the image again - we should have an upload task and a dependent decode
979 // task - this dependent task will typically just re-lock the image.
980 ImageDecodeCache::TaskResult another_result =
981 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
982 EXPECT_TRUE(another_result.need_unref);
983 EXPECT_TRUE(another_result.task);
984 EXPECT_EQ(another_result.task->dependencies().size(), 1u);
985 EXPECT_TRUE(result.task->dependencies()[0]);
987 TestTileTaskRunner::ProcessTask(another_result.task->dependencies()[0].get());
988 TestTileTaskRunner::ProcessTask(another_result.task.get());
990 cache->UnrefImage(draw_image);
993 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
994 auto cache = CreateCache();
995 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
996 DrawImage draw_image =
997 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
998 ImageDecodeCache::TaskResult result =
999 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1000 EXPECT_TRUE(result.need_unref);
1001 EXPECT_TRUE(result.task);
1002 EXPECT_EQ(result.task->dependencies().size(), 1u);
1003 EXPECT_TRUE(result.task->dependencies()[0]);
1005 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1006 TestTileTaskRunner::ScheduleTask(result.task.get());
1007 TestTileTaskRunner::RunTask(result.task.get());
1008 TestTileTaskRunner::CompleteTask(result.task.get());
1010 ImageDecodeCache::TaskResult another_result =
1011 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1012 EXPECT_TRUE(another_result.need_unref);
1013 EXPECT_FALSE(another_result.task);
1015 cache->UnrefImage(draw_image);
1016 cache->UnrefImage(draw_image);
1019 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
1020 auto cache = CreateCache();
1021 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1022 DrawImage draw_image =
1023 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1024 ImageDecodeCache::TaskResult result =
1025 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1026 EXPECT_TRUE(result.need_unref);
1027 EXPECT_TRUE(result.task);
1029 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1031 ImageDecodeCache::TaskResult another_result =
1032 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1033 EXPECT_TRUE(result.need_unref);
1034 EXPECT_TRUE(another_result.task.get() == result.task.get());
1036 // Didn't run the task, so cancel it.
1037 TestTileTaskRunner::CancelTask(result.task.get());
1038 TestTileTaskRunner::CompleteTask(result.task.get());
1040 // Fully cancel everything (so the raster would unref things).
1041 cache->UnrefImage(draw_image);
1042 cache->UnrefImage(draw_image);
1044 // Here a new task is created.
1045 ImageDecodeCache::TaskResult third_result =
1046 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1047 EXPECT_TRUE(third_result.need_unref);
1048 EXPECT_TRUE(third_result.task);
1049 EXPECT_FALSE(third_result.task.get() == result.task.get());
1051 TestTileTaskRunner::ProcessTask(third_result.task->dependencies()[0].get());
1052 TestTileTaskRunner::ProcessTask(third_result.task.get());
1054 cache->UnrefImage(draw_image);
1057 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
1058 auto cache = CreateCache();
1059 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1060 DrawImage draw_image =
1061 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1062 ImageDecodeCache::TaskResult result =
1063 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1064 EXPECT_TRUE(result.need_unref);
1065 EXPECT_TRUE(result.task);
1067 ASSERT_GT(result.task->dependencies().size(), 0u);
1068 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1070 ImageDecodeCache::TaskResult another_result =
1071 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1072 EXPECT_TRUE(another_result.need_unref);
1073 EXPECT_TRUE(another_result.task.get() == result.task.get());
1075 // Didn't run the task, so cancel it.
1076 TestTileTaskRunner::CancelTask(result.task.get());
1077 TestTileTaskRunner::CompleteTask(result.task.get());
1079 // 2 Unrefs, so that the decode is unlocked as well.
1080 cache->UnrefImage(draw_image);
1081 cache->UnrefImage(draw_image);
1083 // Note that here, everything is reffed, but a new task is created. This is
1084 // possible with repeated schedule/cancel operations.
1085 ImageDecodeCache::TaskResult third_result =
1086 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1087 EXPECT_TRUE(third_result.need_unref);
1088 EXPECT_TRUE(third_result.task);
1089 EXPECT_FALSE(third_result.task.get() == result.task.get());
1091 ASSERT_GT(third_result.task->dependencies().size(), 0u);
1092 TestTileTaskRunner::ProcessTask(third_result.task->dependencies()[0].get());
1093 TestTileTaskRunner::ProcessTask(third_result.task.get());
1096 cache->UnrefImage(draw_image);
1099 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) {
1100 auto cache = CreateCache();
1101 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1102 DrawImage draw_image =
1103 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1104 ImageDecodeCache::TaskResult result =
1105 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1106 EXPECT_TRUE(result.need_unref);
1107 EXPECT_TRUE(result.task);
1108 EXPECT_EQ(result.task->dependencies().size(), 1u);
1109 EXPECT_TRUE(result.task->dependencies()[0]);
1111 // Cancel the upload.
1112 TestTileTaskRunner::CancelTask(result.task.get());
1113 TestTileTaskRunner::CompleteTask(result.task.get());
1116 cache->UnrefImage(draw_image);
1118 // Run the decode task. Even though the image only has a decode ref at this
1119 // point, this should complete successfully.
1120 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1123 TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
1124 auto cache = CreateCache();
1125 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1126 DrawImage draw_image =
1127 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1128 ImageDecodeCache::TaskResult result =
1129 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1130 EXPECT_TRUE(result.need_unref);
1131 EXPECT_TRUE(result.task);
1133 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1134 // Didn't run the task, so cancel it.
1135 TestTileTaskRunner::CancelTask(result.task.get());
1136 TestTileTaskRunner::CompleteTask(result.task.get());
1138 cache->SetImageDecodingFailedForTesting(draw_image);
1140 ImageDecodeCache::TaskResult another_result =
1141 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1142 EXPECT_FALSE(another_result.need_unref);
1143 EXPECT_EQ(another_result.task.get(), nullptr);
1145 cache->UnrefImage(draw_image);
1148 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
1149 auto cache = CreateCache();
1150 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1151 DrawImage draw_image =
1152 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1153 ImageDecodeCache::TaskResult result =
1154 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1155 EXPECT_TRUE(result.need_unref);
1156 EXPECT_TRUE(result.task);
1157 EXPECT_EQ(result.task->dependencies().size(), 1u);
1158 EXPECT_TRUE(result.task->dependencies()[0]);
1160 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1161 TestTileTaskRunner::ProcessTask(result.task.get());
1163 // Must hold context lock before calling GetDecodedImageForDraw /
1164 // DrawWithImageFinished.
1165 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1166 DecodedDrawImage decoded_draw_image =
1167 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1168 EXPECT_TRUE(decoded_draw_image.image());
1169 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1170 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1171 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1173 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1174 cache->UnrefImage(draw_image);
1177 TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToHdr) {
1178 auto cache = CreateCache();
1179 auto color_space = gfx::ColorSpace::CreateHDR10();
1180 auto size = GetNormalImageSize();
1182 SkImageInfo::Make(size.width(), size.height(), kRGBA_F16_SkColorType,
1183 kPremul_SkAlphaType, color_space.ToSkColorSpace());
1185 bitmap.allocPixels(info);
1186 PaintImage image = PaintImageBuilder::WithDefault()
1187 .set_id(PaintImage::kInvalidId)
1188 .set_is_high_bit_depth(true)
1189 .set_image(SkImage::MakeFromBitmap(bitmap),
1190 PaintImage::GetNextContentId())
1193 constexpr float kCustomWhiteLevel = 200.f;
1194 DrawImage draw_image = CreateDrawImageInternal(
1195 image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), &color_space,
1196 PaintFlags::FilterQuality::kMedium, nullptr,
1197 PaintImage::kDefaultFrameIndex, kCustomWhiteLevel);
1198 ImageDecodeCache::TaskResult result =
1199 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1200 EXPECT_EQ(draw_image.target_color_space(), color_space);
1201 EXPECT_TRUE(result.need_unref);
1202 EXPECT_TRUE(result.task);
1203 EXPECT_EQ(result.task->dependencies().size(), 1u);
1204 EXPECT_TRUE(result.task->dependencies()[0]);
1206 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1207 TestTileTaskRunner::ProcessTask(result.task.get());
1209 // Must hold context lock before calling GetDecodedImageForDraw /
1210 // DrawWithImageFinished.
1211 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1212 DecodedDrawImage decoded_draw_image =
1213 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1214 EXPECT_TRUE(decoded_draw_image.image());
1215 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1216 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1218 // When testing in configurations that do not support rendering to F16, this
1219 // will fall back to N32.
1220 EXPECT_TRUE(decoded_draw_image.image()->colorType() ==
1221 kRGBA_F16_SkColorType ||
1222 decoded_draw_image.image()->colorType() == kN32_SkColorType);
1224 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1226 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1227 cache->UnrefImage(draw_image);
1230 TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToSdr) {
1231 auto cache = CreateCache();
1232 auto image_color_space = gfx::ColorSpace::CreateHDR10();
1233 auto size = GetNormalImageSize();
1234 auto info = SkImageInfo::Make(size.width(), size.height(),
1235 kRGBA_F16_SkColorType, kPremul_SkAlphaType,
1236 image_color_space.ToSkColorSpace());
1238 bitmap.allocPixels(info);
1239 PaintImage image = PaintImageBuilder::WithDefault()
1240 .set_id(PaintImage::kInvalidId)
1241 .set_is_high_bit_depth(true)
1242 .set_image(SkImage::MakeFromBitmap(bitmap),
1243 PaintImage::GetNextContentId())
1246 auto raster_color_space = gfx::ColorSpace::CreateSRGB();
1247 DrawImage draw_image = CreateDrawImageInternal(
1248 image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), &raster_color_space);
1249 ImageDecodeCache::TaskResult result =
1250 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1251 EXPECT_EQ(draw_image.target_color_space(), raster_color_space);
1252 EXPECT_TRUE(result.need_unref);
1253 EXPECT_TRUE(result.task);
1254 EXPECT_EQ(result.task->dependencies().size(), 1u);
1255 EXPECT_TRUE(result.task->dependencies()[0]);
1257 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1258 TestTileTaskRunner::ProcessTask(result.task.get());
1260 // Must hold context lock before calling GetDecodedImageForDraw /
1261 // DrawWithImageFinished.
1262 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1263 DecodedDrawImage decoded_draw_image =
1264 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1265 EXPECT_TRUE(decoded_draw_image.image());
1266 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1267 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1268 EXPECT_NE(decoded_draw_image.image()->colorType(), kRGBA_F16_SkColorType);
1270 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1272 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1273 cache->UnrefImage(draw_image);
1276 TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
1277 auto cache = CreateCache();
1278 PaintImage image = CreateLargePaintImageForSoftwareFallback();
1279 DrawImage draw_image =
1280 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
1281 ImageDecodeCache::TaskResult result =
1282 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1283 EXPECT_TRUE(result.need_unref);
1284 EXPECT_TRUE(result.task);
1286 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1287 TestTileTaskRunner::ProcessTask(result.task.get());
1289 // Must hold context lock before calling GetDecodedImageForDraw /
1290 // DrawWithImageFinished.
1291 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1292 DecodedDrawImage decoded_draw_image =
1293 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1294 EXPECT_TRUE(decoded_draw_image.image());
1295 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1296 EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
1297 EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
1298 cache->DiscardableIsLockedForTesting(draw_image));
1300 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1301 cache->UnrefImage(draw_image);
1302 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1305 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
1306 auto cache = CreateCache();
1307 cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
1309 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1310 DrawImage draw_image =
1311 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
1313 ImageDecodeCache::TaskResult result =
1314 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1315 EXPECT_FALSE(result.need_unref);
1316 EXPECT_FALSE(result.task);
1318 // Must hold context lock before calling GetDecodedImageForDraw /
1319 // DrawWithImageFinished.
1320 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1321 DecodedDrawImage decoded_draw_image =
1322 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1323 EXPECT_TRUE(decoded_draw_image.image());
1324 EXPECT_FALSE(decoded_draw_image.is_budgeted());
1325 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1326 EXPECT_FALSE(decoded_draw_image.is_budgeted());
1327 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1329 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1331 // Our 0 working set size shouldn't prevent caching of unlocked discardable,
1332 // so our single entry should be cached.
1333 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
1336 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
1337 auto cache = CreateCache();
1338 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1339 DrawImage draw_image = CreateDrawImageInternal(
1340 image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), nullptr /* color_space */,
1341 PaintFlags::FilterQuality::kLow);
1342 ImageDecodeCache::TaskResult result =
1343 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1344 EXPECT_TRUE(result.need_unref);
1345 EXPECT_TRUE(result.task);
1347 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1348 TestTileTaskRunner::ProcessTask(result.task.get());
1350 DrawImage larger_draw_image =
1351 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
1352 ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef(
1353 larger_draw_image, ImageDecodeCache::TracingInfo());
1354 EXPECT_TRUE(larger_result.need_unref);
1355 EXPECT_TRUE(larger_result.task);
1357 TestTileTaskRunner::ProcessTask(larger_result.task->dependencies()[0].get());
1358 TestTileTaskRunner::ProcessTask(larger_result.task.get());
1360 // Must hold context lock before calling GetDecodedImageForDraw /
1361 // DrawWithImageFinished.
1362 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1363 DecodedDrawImage decoded_draw_image =
1364 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1365 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1366 EXPECT_TRUE(decoded_draw_image.image());
1367 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1368 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1370 DecodedDrawImage larger_decoded_draw_image =
1371 EnsureImageBacked(cache->GetDecodedImageForDraw(larger_draw_image));
1372 EXPECT_TRUE(larger_decoded_draw_image.image());
1373 EXPECT_TRUE(larger_decoded_draw_image.is_budgeted());
1374 EXPECT_TRUE(larger_decoded_draw_image.image()->isTextureBacked());
1375 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1377 EXPECT_FALSE(decoded_draw_image.image() == larger_decoded_draw_image.image());
1379 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1380 cache->UnrefImage(draw_image);
1381 cache->DrawWithImageFinished(larger_draw_image, larger_decoded_draw_image);
1382 cache->UnrefImage(larger_draw_image);
1385 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
1386 auto cache = CreateCache();
1387 SkM44 matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f));
1388 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1389 DrawImage draw_image =
1390 CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
1391 PaintFlags::FilterQuality::kLow);
1392 ImageDecodeCache::TaskResult result =
1393 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1394 EXPECT_TRUE(result.need_unref);
1395 EXPECT_TRUE(result.task);
1397 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1398 TestTileTaskRunner::ProcessTask(result.task.get());
1400 DrawImage higher_quality_draw_image = CreateDrawImageInternal(image, matrix);
1401 ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef(
1402 higher_quality_draw_image, ImageDecodeCache::TracingInfo());
1403 EXPECT_TRUE(hq_result.need_unref);
1404 EXPECT_TRUE(hq_result.task);
1405 TestTileTaskRunner::ProcessTask(hq_result.task->dependencies()[0].get());
1406 TestTileTaskRunner::ProcessTask(hq_result.task.get());
1408 // Must hold context lock before calling GetDecodedImageForDraw /
1409 // DrawWithImageFinished.
1410 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1411 DecodedDrawImage decoded_draw_image =
1412 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1413 EXPECT_TRUE(decoded_draw_image.image());
1414 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1415 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1416 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1418 DecodedDrawImage larger_decoded_draw_image = EnsureImageBacked(
1419 cache->GetDecodedImageForDraw(higher_quality_draw_image));
1420 EXPECT_TRUE(larger_decoded_draw_image.image());
1421 EXPECT_TRUE(larger_decoded_draw_image.image()->isTextureBacked());
1422 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1424 EXPECT_FALSE(decoded_draw_image.image() == larger_decoded_draw_image.image());
1426 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1427 cache->UnrefImage(draw_image);
1428 cache->DrawWithImageFinished(higher_quality_draw_image,
1429 larger_decoded_draw_image);
1430 cache->UnrefImage(higher_quality_draw_image);
1433 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
1434 auto cache = CreateCache();
1435 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1436 DrawImage draw_image =
1437 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(-0.5f, 0.5f)));
1438 ImageDecodeCache::TaskResult result =
1439 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1440 EXPECT_TRUE(result.need_unref);
1441 EXPECT_TRUE(result.task);
1443 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1444 TestTileTaskRunner::ProcessTask(result.task.get());
1446 // Must hold context lock before calling GetDecodedImageForDraw /
1447 // DrawWithImageFinished.
1448 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1449 DecodedDrawImage decoded_draw_image =
1450 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1451 EXPECT_TRUE(decoded_draw_image.image());
1452 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1453 const int expected_width =
1454 image.width() * std::abs(draw_image.scale().width());
1455 const int expected_height =
1456 image.height() * std::abs(draw_image.scale().height());
1457 EXPECT_EQ(decoded_draw_image.image()->width(), expected_width);
1458 EXPECT_EQ(decoded_draw_image.image()->height(), expected_height);
1459 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1460 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1462 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1463 cache->UnrefImage(draw_image);
1466 TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
1467 auto cache = CreateCache();
1468 PaintImage image = CreatePaintImageForFallbackToRGB(
1469 gfx::Size(GetLargeImageSize().width(), GetLargeImageSize().height() * 2));
1470 DrawImage draw_image = CreateDrawImageInternal(
1471 image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), nullptr /* color_space */,
1472 PaintFlags::FilterQuality::kHigh);
1473 ImageDecodeCache::TaskResult result =
1474 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1475 EXPECT_TRUE(result.need_unref);
1476 EXPECT_TRUE(result.task);
1478 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1479 TestTileTaskRunner::ProcessTask(result.task.get());
1481 // Must hold context lock before calling GetDecodedImageForDraw /
1482 // DrawWithImageFinished.
1483 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1484 DecodedDrawImage decoded_draw_image =
1485 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1486 EXPECT_TRUE(decoded_draw_image.image());
1487 EXPECT_TRUE(decoded_draw_image.is_budgeted());
1488 // The mip level scale should never go below 0 in any dimension.
1489 EXPECT_EQ(GetLargeImageSize().width(), decoded_draw_image.image()->width());
1490 EXPECT_EQ(GetLargeImageSize().height(), decoded_draw_image.image()->height());
1492 EXPECT_EQ(decoded_draw_image.filter_quality(),
1493 PaintFlags::FilterQuality::kMedium);
1495 EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
1496 EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
1497 cache->DiscardableIsLockedForTesting(draw_image));
1499 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1500 cache->UnrefImage(draw_image);
1501 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1504 TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
1505 auto cache = CreateCache();
1506 const gfx::Size test_image_size = GetNormalImageSize();
1507 cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
1509 PaintImage image = CreatePaintImageInternal(test_image_size);
1510 DrawImage draw_image = CreateDrawImageInternal(image);
1512 ImageDecodeCache::TaskResult result =
1513 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1514 EXPECT_FALSE(result.need_unref);
1515 EXPECT_FALSE(result.task);
1517 // Must hold context lock before calling GetDecodedImageForDraw /
1518 // DrawWithImageFinished.
1519 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1520 DecodedDrawImage decoded_draw_image =
1521 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1522 EXPECT_TRUE(decoded_draw_image.image());
1523 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1524 EXPECT_FALSE(decoded_draw_image.is_budgeted());
1525 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1526 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1528 // Increase memory limit to allow the image and attempt to use the same image.
1529 // It should be available for ref.
1530 const size_t bytes_for_test_image =
1531 GetBytesNeededForSingleImage(test_image_size);
1532 cache->SetWorkingSetLimitsForTesting(bytes_for_test_image /* max_bytes */,
1533 256 /* max_items */);
1534 ImageDecodeCache::TaskResult another_result =
1535 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1536 EXPECT_TRUE(another_result.need_unref);
1537 EXPECT_FALSE(another_result.task);
1538 cache->UnrefImage(draw_image);
1541 TEST_P(GpuImageDecodeCacheTest,
1542 GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
1543 auto cache = CreateCache();
1544 cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
1546 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1547 DrawImage draw_image =
1548 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1550 // Must hold context lock before calling GetDecodedImageForDraw /
1551 // DrawWithImageFinished.
1552 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1553 DecodedDrawImage decoded_draw_image =
1554 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1555 EXPECT_TRUE(decoded_draw_image.image());
1556 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
1557 EXPECT_FALSE(decoded_draw_image.is_budgeted());
1558 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1560 DecodedDrawImage another_decoded_draw_image =
1561 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1562 EXPECT_FALSE(another_decoded_draw_image.is_budgeted());
1563 EXPECT_EQ(decoded_draw_image.image()->uniqueID(),
1564 another_decoded_draw_image.image()->uniqueID());
1566 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1567 cache->DrawWithImageFinished(draw_image, another_decoded_draw_image);
1569 // Our 0 working set size shouldn't prevent caching of unlocked discardable,
1570 // so our single entry should be cached.
1571 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
1574 TEST_P(GpuImageDecodeCacheTest,
1575 GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) {
1576 auto cache = CreateCache();
1577 cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
1579 PaintImage image = CreateLargePaintImageForSoftwareFallback();
1580 DrawImage draw_image = CreateDrawImageInternal(image);
1582 // Must hold context lock before calling GetDecodedImageForDraw /
1583 // DrawWithImageFinished.
1584 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1585 DecodedDrawImage decoded_draw_image =
1586 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1587 EXPECT_TRUE(decoded_draw_image.image());
1588 EXPECT_FALSE(decoded_draw_image.is_budgeted());
1589 EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
1590 EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
1591 cache->DiscardableIsLockedForTesting(draw_image));
1593 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1594 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1596 DecodedDrawImage second_decoded_draw_image =
1597 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1598 EXPECT_TRUE(second_decoded_draw_image.image());
1599 EXPECT_FALSE(decoded_draw_image.is_budgeted());
1600 EXPECT_FALSE(second_decoded_draw_image.image()->isTextureBacked());
1601 EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
1602 cache->DiscardableIsLockedForTesting(draw_image));
1604 cache->DrawWithImageFinished(draw_image, second_decoded_draw_image);
1605 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1608 TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
1609 auto cache = CreateCache();
1610 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1611 DrawImage draw_image =
1612 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.f, 0.f)));
1614 ImageDecodeCache::TaskResult result =
1615 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1616 EXPECT_FALSE(result.task);
1617 EXPECT_FALSE(result.need_unref);
1619 // Must hold context lock before calling GetDecodedImageForDraw /
1620 // DrawWithImageFinished.
1621 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1622 DecodedDrawImage decoded_draw_image =
1623 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1624 EXPECT_FALSE(decoded_draw_image.image());
1626 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1629 TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
1630 auto cache = CreateCache();
1631 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1632 DrawImage draw_image(
1634 SkIRect::MakeXYWH(image.width() + 1, image.height() + 1, image.width(),
1636 PaintFlags::FilterQuality::kMedium, CreateMatrix(SkSize::Make(1.f, 1.f)),
1637 PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
1639 ImageDecodeCache::TaskResult result =
1640 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1641 EXPECT_FALSE(result.task);
1642 EXPECT_FALSE(result.need_unref);
1644 // Must hold context lock before calling GetDecodedImageForDraw /
1645 // DrawWithImageFinished.
1646 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1647 DecodedDrawImage decoded_draw_image =
1648 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
1649 EXPECT_FALSE(decoded_draw_image.image());
1651 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1654 TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
1655 auto cache = CreateCache();
1656 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1657 SkIRect src_rect = SkIRect::MakeXYWH(0, 0, image.width(), image.height());
1658 DrawImage draw_image = CreateDrawImageInternal(
1659 image, CreateMatrix(SkSize::Make(1.f, 1.f)), nullptr /* color_space */,
1660 PaintFlags::FilterQuality::kMedium, &src_rect);
1662 ImageDecodeCache::TaskResult result =
1663 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1664 EXPECT_NE(0u, cache->GetNumCacheEntriesForTesting());
1665 EXPECT_TRUE(result.task);
1666 EXPECT_TRUE(result.need_unref);
1668 TestTileTaskRunner::CancelTask(result.task->dependencies()[0].get());
1669 TestTileTaskRunner::CompleteTask(result.task->dependencies()[0].get());
1670 TestTileTaskRunner::CancelTask(result.task.get());
1671 TestTileTaskRunner::CompleteTask(result.task.get());
1673 cache->UnrefImage(draw_image);
1674 EXPECT_EQ(0u, cache->GetWorkingSetBytesForTesting());
1677 TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
1678 auto cache = CreateCache();
1679 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1680 DrawImage draw_image =
1681 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1683 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1684 draw_image, ImageDecodeCache::TracingInfo());
1685 EXPECT_TRUE(result.need_unref);
1686 EXPECT_TRUE(result.task);
1688 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1689 TestTileTaskRunner::ProcessTask(result.task.get());
1691 cache->UnrefImage(draw_image);
1693 // We should now have data image in our cache.
1694 EXPECT_GT(cache->GetNumCacheEntriesForTesting(), 0u);
1696 // Tell our cache to aggressively free resources.
1697 cache->SetShouldAggressivelyFreeResources(true);
1698 EXPECT_EQ(0u, cache->GetNumCacheEntriesForTesting());
1701 // Attempting to upload a new image should succeed, but the image should not
1702 // be cached past its use.
1704 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1705 draw_image, ImageDecodeCache::TracingInfo());
1706 EXPECT_TRUE(result.need_unref);
1707 EXPECT_TRUE(result.task);
1709 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1710 TestTileTaskRunner::ProcessTask(result.task.get());
1711 cache->UnrefImage(draw_image);
1713 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
1716 // We now tell the cache to not aggressively free resources. The image may
1717 // now be cached past its use.
1718 cache->SetShouldAggressivelyFreeResources(false);
1720 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1721 draw_image, ImageDecodeCache::TracingInfo());
1722 EXPECT_TRUE(result.need_unref);
1723 EXPECT_TRUE(result.task);
1725 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1726 TestTileTaskRunner::ProcessTask(result.task.get());
1727 cache->UnrefImage(draw_image);
1729 EXPECT_GT(cache->GetNumCacheEntriesForTesting(), 0u);
1733 TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
1734 auto cache = CreateCache();
1735 // Create a downscaled image.
1736 PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
1737 DrawImage first_draw_image = CreateDrawImageInternal(
1738 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1739 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
1740 first_draw_image, ImageDecodeCache::TracingInfo());
1741 EXPECT_TRUE(first_result.need_unref);
1742 EXPECT_TRUE(first_result.task);
1744 // The budget should account for exactly one image.
1745 EXPECT_EQ(cache->GetWorkingSetBytesForTesting(),
1746 cache->GetDrawImageSizeForTesting(first_draw_image));
1748 // Create a larger version of |first_image|, this should immediately free the
1749 // memory used by |first_image| for the smaller scale.
1750 DrawImage second_draw_image = CreateDrawImageInternal(
1751 first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
1752 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
1753 second_draw_image, ImageDecodeCache::TracingInfo());
1754 EXPECT_TRUE(second_result.need_unref);
1755 EXPECT_TRUE(second_result.task);
1756 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
1758 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
1759 TestTileTaskRunner::ProcessTask(second_result.task.get());
1761 cache->UnrefImage(second_draw_image);
1763 // Unref the first image, it was orphaned, so it should be immediately
1765 TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
1766 TestTileTaskRunner::ProcessTask(first_result.task.get());
1767 cache->UnrefImage(first_draw_image);
1769 // The cache should have exactly one image.
1770 EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
1771 EXPECT_EQ(0u, cache->GetInUseCacheEntriesForTesting());
1774 TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
1775 auto cache = CreateCache();
1776 // Create a downscaled image.
1777 PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
1778 DrawImage first_draw_image = CreateDrawImageInternal(
1779 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1780 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
1781 first_draw_image, ImageDecodeCache::TracingInfo());
1782 EXPECT_TRUE(first_result.need_unref);
1783 EXPECT_TRUE(first_result.task);
1785 TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
1786 TestTileTaskRunner::ProcessTask(first_result.task.get());
1787 cache->UnrefImage(first_draw_image);
1789 // The budget should account for exactly one image.
1790 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
1791 EXPECT_EQ(cache->GetInUseCacheEntriesForTesting(), 0u);
1793 // Create a larger version of |first_image|, this should immediately free the
1794 // memory used by |first_image| for the smaller scale.
1795 DrawImage second_draw_image = CreateDrawImageInternal(first_image);
1796 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
1797 second_draw_image, ImageDecodeCache::TracingInfo());
1798 EXPECT_TRUE(second_result.need_unref);
1799 EXPECT_TRUE(second_result.task);
1800 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
1802 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
1803 TestTileTaskRunner::ProcessTask(second_result.task.get());
1805 cache->UnrefImage(second_draw_image);
1807 // The budget should account for exactly one image.
1808 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
1809 EXPECT_EQ(cache->GetInUseCacheEntriesForTesting(), 0u);
1812 TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
1813 auto cache = CreateCache();
1814 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1815 SkM44 matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
1817 // Create an image with kLow_FilterQuality.
1818 DrawImage low_draw_image =
1819 CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
1820 PaintFlags::FilterQuality::kLow);
1821 ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef(
1822 low_draw_image, ImageDecodeCache::TracingInfo());
1823 EXPECT_TRUE(low_result.need_unref);
1824 EXPECT_TRUE(low_result.task);
1826 // Get the same image at PaintFlags::FilterQuality::kMedium. We can't re-use
1827 // low, so we should get a new task/ref.
1828 DrawImage medium_draw_image = CreateDrawImageInternal(image);
1829 ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef(
1830 medium_draw_image, ImageDecodeCache::TracingInfo());
1831 EXPECT_TRUE(medium_result.need_unref);
1832 EXPECT_TRUE(medium_result.task.get());
1833 EXPECT_FALSE(low_result.task.get() == medium_result.task.get());
1835 // Get the same image at PaintFlags::FilterQuality::kHigh. We should re-use
1837 DrawImage high_quality_draw_image =
1838 CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
1839 PaintFlags::FilterQuality::kHigh);
1840 ImageDecodeCache::TaskResult high_quality_result =
1841 cache->GetTaskForImageAndRef(high_quality_draw_image,
1842 ImageDecodeCache::TracingInfo());
1843 EXPECT_TRUE(high_quality_result.need_unref);
1844 EXPECT_TRUE(medium_result.task.get() == high_quality_result.task.get());
1846 TestTileTaskRunner::ProcessTask(low_result.task->dependencies()[0].get());
1847 TestTileTaskRunner::ProcessTask(low_result.task.get());
1848 TestTileTaskRunner::ProcessTask(medium_result.task->dependencies()[0].get());
1849 TestTileTaskRunner::ProcessTask(medium_result.task.get());
1851 cache->UnrefImage(low_draw_image);
1852 cache->UnrefImage(medium_draw_image);
1853 cache->UnrefImage(high_quality_draw_image);
1856 // Ensure that switching to a mipped version of an image after the initial
1857 // cache entry creation doesn't cause a buffer overflow/crash.
1858 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
1859 auto cache = CreateCache();
1860 // Create an image decode task and cache entry that does not need mips.
1861 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1862 DrawImage draw_image = CreateDrawImageInternal(image);
1863 ImageDecodeCache::TaskResult result =
1864 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1865 EXPECT_TRUE(result.need_unref);
1866 EXPECT_TRUE(result.task);
1868 // Cancel the task without ever using it.
1869 TestTileTaskRunner::CancelTask(result.task->dependencies()[0].get());
1870 TestTileTaskRunner::CompleteTask(result.task->dependencies()[0].get());
1871 TestTileTaskRunner::CancelTask(result.task.get());
1872 TestTileTaskRunner::CompleteTask(result.task.get());
1874 cache->UnrefImage(draw_image);
1876 // Must hold context lock before calling GetDecodedImageForDraw /
1877 // DrawWithImageFinished.
1878 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1880 // Do an at-raster decode of the above image that *does* require mips.
1881 DrawImage draw_image_mips =
1882 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
1883 DecodedDrawImage decoded_draw_image =
1884 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image_mips));
1885 cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image);
1888 TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
1889 auto cache = CreateCache();
1890 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1891 SkM44 matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f));
1892 DrawImage draw_image =
1893 CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
1894 PaintFlags::FilterQuality::kLow);
1896 ImageDecodeCache::TaskResult result =
1897 cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
1898 EXPECT_TRUE(result.need_unref);
1899 EXPECT_TRUE(result.task);
1900 EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
1902 // Run the decode task.
1903 TestTileTaskRunner::ProcessTask(result.task.get());
1905 // The image should remain in the cache till we unref it.
1906 EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
1907 cache->UnrefImage(draw_image);
1910 TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
1911 SetCachedTexturesLimit(0);
1912 auto cache = CreateCache();
1913 // Add an image to the cache-> Due to normal working set, this should produce
1914 // a task and a ref.
1915 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1916 DrawImage draw_image = CreateDrawImageInternal(image);
1917 ImageDecodeCache::TaskResult result =
1918 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1919 EXPECT_TRUE(result.need_unref);
1920 EXPECT_TRUE(result.task);
1921 EXPECT_EQ(result.task->dependencies().size(), 1u);
1922 EXPECT_TRUE(result.task->dependencies()[0]);
1925 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1926 TestTileTaskRunner::ProcessTask(result.task.get());
1928 // Request the same image - it should be cached.
1929 ImageDecodeCache::TaskResult second_result =
1930 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1931 EXPECT_TRUE(second_result.need_unref);
1932 EXPECT_FALSE(second_result.task);
1934 // Unref both images.
1935 cache->UnrefImage(draw_image);
1936 cache->UnrefImage(draw_image);
1938 // Ensure the unref is processed:
1939 cache->ReduceCacheUsage();
1941 // Get the image again. As it was fully unreffed, it is no longer in the
1942 // working set and will be evicted due to 0 cache size.
1943 ImageDecodeCache::TaskResult third_result =
1944 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1945 EXPECT_TRUE(third_result.need_unref);
1946 EXPECT_TRUE(third_result.task);
1947 EXPECT_EQ(third_result.task->dependencies().size(), 1u);
1948 EXPECT_TRUE(third_result.task->dependencies()[0]);
1950 TestTileTaskRunner::ProcessTask(third_result.task->dependencies()[0].get());
1951 TestTileTaskRunner::ProcessTask(third_result.task.get());
1953 cache->UnrefImage(draw_image);
1956 TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
1957 // Cache will fit one image.
1958 SetCachedTexturesLimit(1);
1959 auto cache = CreateCache();
1960 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1961 DrawImage draw_image = CreateDrawImageInternal(image);
1963 PaintImage image2 = CreatePaintImageInternal(GetNormalImageSize());
1964 DrawImage draw_image2(
1965 image2, false, SkIRect::MakeWH(image2.width(), image2.height()),
1966 PaintFlags::FilterQuality::kMedium,
1967 CreateMatrix(SkSize::Make(1.0f, 1.0f)), PaintImage::kDefaultFrameIndex,
1968 DefaultTargetColorParams());
1970 // Add an image to the cache and un-ref it.
1972 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1973 draw_image, ImageDecodeCache::TracingInfo());
1974 EXPECT_TRUE(result.need_unref);
1975 EXPECT_TRUE(result.task);
1976 EXPECT_EQ(result.task->dependencies().size(), 1u);
1977 EXPECT_TRUE(result.task->dependencies()[0]);
1979 // Run the task and unref the image.
1980 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1981 TestTileTaskRunner::ProcessTask(result.task.get());
1982 cache->UnrefImage(draw_image);
1985 // Request the same image - it should be cached.
1987 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1988 draw_image, ImageDecodeCache::TracingInfo());
1989 EXPECT_TRUE(result.need_unref);
1990 EXPECT_FALSE(result.task);
1991 cache->UnrefImage(draw_image);
1994 // Add a new image to the cache It should push out the old one.
1996 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1997 draw_image2, ImageDecodeCache::TracingInfo());
1998 EXPECT_TRUE(result.need_unref);
1999 EXPECT_TRUE(result.task);
2000 EXPECT_EQ(result.task->dependencies().size(), 1u);
2001 EXPECT_TRUE(result.task->dependencies()[0]);
2003 // Run the task and unref the image.
2004 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2005 TestTileTaskRunner::ProcessTask(result.task.get());
2006 cache->UnrefImage(draw_image2);
2009 // Request the second image - it should be cached.
2011 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2012 draw_image2, ImageDecodeCache::TracingInfo());
2013 EXPECT_TRUE(result.need_unref);
2014 EXPECT_FALSE(result.task);
2015 cache->UnrefImage(draw_image2);
2018 // Request the first image - it should have been evicted and return a new
2021 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2022 draw_image, ImageDecodeCache::TracingInfo());
2023 EXPECT_TRUE(result.need_unref);
2024 EXPECT_TRUE(result.task);
2025 EXPECT_EQ(result.task->dependencies().size(), 1u);
2026 EXPECT_TRUE(result.task->dependencies()[0]);
2028 // Run the task and unref the image.
2029 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2030 TestTileTaskRunner::ProcessTask(result.task.get());
2031 cache->UnrefImage(draw_image);
2035 TEST_P(GpuImageDecodeCacheTest, ClearCache) {
2036 auto cache = CreateCache();
2037 for (int i = 0; i < 10; ++i) {
2038 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
2039 DrawImage draw_image = CreateDrawImageInternal(image);
2040 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2041 draw_image, ImageDecodeCache::TracingInfo());
2042 EXPECT_TRUE(result.need_unref);
2043 EXPECT_TRUE(result.task);
2044 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2045 TestTileTaskRunner::ProcessTask(result.task.get());
2046 cache->UnrefImage(draw_image);
2049 // We should now have images in our cache.
2050 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 10u);
2052 // Tell our cache to clear resources.
2053 cache->ClearCache();
2055 // We should now have nothing in our cache.
2056 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
2059 TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) {
2060 auto cache = CreateCache();
2061 // Create an image but keep it reffed so it can't be immediately freed.
2062 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
2063 DrawImage draw_image = CreateDrawImageInternal(image);
2064 ImageDecodeCache::TaskResult result =
2065 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2066 EXPECT_TRUE(result.need_unref);
2067 EXPECT_TRUE(result.task);
2068 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2069 TestTileTaskRunner::ProcessTask(result.task.get());
2071 // We should now have data image in our cache.
2072 EXPECT_GT(cache->GetWorkingSetBytesForTesting(), 0u);
2073 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
2075 // Tell our cache to clear resources.
2076 cache->ClearCache();
2077 // We should still have data, as we can't clear the in-use entry.
2078 EXPECT_GT(cache->GetWorkingSetBytesForTesting(), 0u);
2079 // But the num (persistent) entries should be 0, as the entry is orphaned.
2080 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
2082 // Unref the image, it should immidiately delete, leaving our cache empty.
2083 cache->UnrefImage(draw_image);
2084 EXPECT_EQ(cache->GetWorkingSetBytesForTesting(), 0u);
2085 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
2088 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
2089 auto cache = CreateCache();
2090 gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB();
2091 gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50();
2093 PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100));
2094 DrawImage first_draw_image = CreateDrawImageInternal(
2095 first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a);
2096 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
2097 first_draw_image, ImageDecodeCache::TracingInfo());
2098 EXPECT_TRUE(first_result.need_unref);
2099 EXPECT_TRUE(first_result.task);
2101 DrawImage second_draw_image = CreateDrawImageInternal(
2102 first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_b);
2103 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
2104 second_draw_image, ImageDecodeCache::TracingInfo());
2105 EXPECT_TRUE(second_result.need_unref);
2106 EXPECT_TRUE(second_result.task);
2107 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
2109 DrawImage third_draw_image = CreateDrawImageInternal(
2110 first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a);
2111 ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
2112 third_draw_image, ImageDecodeCache::TracingInfo());
2113 EXPECT_TRUE(third_result.need_unref);
2114 EXPECT_TRUE(third_result.task.get() == first_result.task.get());
2116 TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
2117 TestTileTaskRunner::ProcessTask(first_result.task.get());
2118 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
2119 TestTileTaskRunner::ProcessTask(second_result.task.get());
2121 cache->UnrefImage(first_draw_image);
2122 cache->UnrefImage(second_draw_image);
2123 cache->UnrefImage(third_draw_image);
2126 TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) {
2127 auto cache = CreateCache();
2128 gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
2129 PaintImage image = CreateLargePaintImageForSoftwareFallback();
2130 DrawImage draw_image = CreateDrawImageInternal(
2131 image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
2132 ImageDecodeCache::TaskResult result =
2133 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2134 EXPECT_TRUE(result.need_unref);
2135 EXPECT_TRUE(result.task);
2137 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2138 TestTileTaskRunner::ProcessTask(result.task.get());
2140 cache->UnrefImage(draw_image);
2143 TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) {
2144 auto cache = CreateCache();
2145 std::vector<FrameMetadata> frames = {
2146 FrameMetadata(true, base::Milliseconds(2)),
2147 FrameMetadata(true, base::Milliseconds(3)),
2148 FrameMetadata(true, base::Milliseconds(4)),
2149 FrameMetadata(true, base::Milliseconds(5)),
2151 const gfx::Size test_image_size = GetNormalImageSize();
2153 SkImageInfo::Make(test_image_size.width(), test_image_size.height(),
2154 color_type_, kPremul_SkAlphaType);
2155 sk_sp<FakePaintImageGenerator> generator;
2156 if (do_yuv_decode_) {
2157 SkYUVAPixmapInfo yuva_pixmap_info =
2158 GetYUVAPixmapInfo(test_image_size, yuv_format_, yuv_data_type_);
2160 sk_make_sp<FakePaintImageGenerator>(info, yuva_pixmap_info, frames);
2162 generator = sk_make_sp<FakePaintImageGenerator>(info, frames);
2164 PaintImage image = PaintImageBuilder::WithDefault()
2165 .set_id(PaintImage::GetNextId())
2166 .set_paint_image_generator(generator)
2169 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2171 PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
2172 DrawImage draw_image(
2173 image, false, SkIRect::MakeWH(image.width(), image.height()), quality,
2174 CreateMatrix(SkSize::Make(1.0f, 1.0f)), 1u, DefaultTargetColorParams());
2175 auto decoded_image =
2176 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2177 ASSERT_TRUE(decoded_image.image());
2178 ASSERT_EQ(generator->frames_decoded().size(), 1u);
2179 EXPECT_EQ(generator->frames_decoded().count(1u), 1u);
2180 generator->reset_frames_decoded();
2181 cache->DrawWithImageFinished(draw_image, decoded_image);
2184 TargetColorParams target_color_params;
2185 target_color_params.color_space = draw_image.target_color_space();
2186 DrawImage scaled_draw_image(draw_image, 0.5f, 2u, target_color_params);
2188 EnsureImageBacked(cache->GetDecodedImageForDraw(scaled_draw_image));
2189 ASSERT_TRUE(decoded_image.image());
2190 ASSERT_EQ(generator->frames_decoded().size(), 1u);
2191 EXPECT_EQ(generator->frames_decoded().count(2u), 1u);
2192 generator->reset_frames_decoded();
2193 cache->DrawWithImageFinished(scaled_draw_image, decoded_image);
2196 const int32_t subset_width = 5;
2197 const int32_t subset_height = 5;
2198 ASSERT_LT(subset_width, test_image_size.width());
2199 ASSERT_LT(subset_height, test_image_size.height());
2200 DrawImage subset_draw_image(
2201 image, false, SkIRect::MakeWH(subset_width, subset_height), quality,
2202 CreateMatrix(SkSize::Make(1.0f, 1.0f)), 3u, DefaultTargetColorParams());
2204 EnsureImageBacked(cache->GetDecodedImageForDraw(subset_draw_image));
2205 ASSERT_TRUE(decoded_image.image());
2206 ASSERT_EQ(generator->frames_decoded().size(), 1u);
2207 EXPECT_EQ(generator->frames_decoded().count(3u), 1u);
2208 generator->reset_frames_decoded();
2209 cache->DrawWithImageFinished(subset_draw_image, decoded_image);
2212 TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) {
2213 auto cache = CreateCache();
2214 // Create a downscaled image.
2215 PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
2216 DrawImage first_draw_image = CreateDrawImageInternal(
2217 first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
2218 ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
2219 first_draw_image, ImageDecodeCache::TracingInfo());
2220 EXPECT_TRUE(first_result.need_unref);
2221 EXPECT_TRUE(first_result.task);
2223 // The cache should have exactly one image.
2224 EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2226 // Create a larger version of |first_image|, this should immediately free
2227 // the memory used by |first_image| for the smaller scale.
2228 DrawImage second_draw_image = CreateDrawImageInternal(first_image);
2229 ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
2230 second_draw_image, ImageDecodeCache::TracingInfo());
2231 EXPECT_TRUE(second_result.need_unref);
2232 EXPECT_TRUE(second_result.task);
2233 EXPECT_TRUE(first_result.task.get() != second_result.task.get());
2235 // The cache should have two images.
2236 EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2238 // Cancel and unref the first image, it was orphaned, so it should be
2239 // immediately deleted.
2240 TestTileTaskRunner::CancelTask(first_result.task->dependencies()[0].get());
2241 TestTileTaskRunner::CompleteTask(first_result.task->dependencies()[0].get());
2242 TestTileTaskRunner::CancelTask(first_result.task.get());
2243 TestTileTaskRunner::CompleteTask(first_result.task.get());
2244 cache->UnrefImage(first_draw_image);
2246 // The cache should have exactly one image.
2247 EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2249 // Unref the second image. It is persistent, and should remain in the cache.
2250 TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
2251 TestTileTaskRunner::ProcessTask(second_result.task.get());
2252 cache->UnrefImage(second_draw_image);
2254 // The cache should have exactly one image.
2255 EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2256 EXPECT_EQ(0u, cache->GetInUseCacheEntriesForTesting());
2259 TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
2260 auto cache = CreateCache();
2261 const gfx::Size test_image_size = GetNormalImageSize();
2263 PaintImage image = CreatePaintImageInternal(test_image_size);
2264 DrawImage draw_image = CreateDrawImageInternal(image);
2265 const size_t bytes_for_test_image =
2266 GetBytesNeededForSingleImage(test_image_size);
2268 // Allow a single small image and lock it.
2269 cache->SetWorkingSetLimitsForTesting(bytes_for_test_image,
2270 1u /* max_items */);
2272 ImageDecodeCache::TaskResult result =
2273 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2274 EXPECT_TRUE(result.need_unref);
2275 EXPECT_TRUE(result.task);
2277 // Try locking the same image again, its already budgeted so it shouldn't be
2280 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2281 EXPECT_TRUE(result.need_unref);
2282 EXPECT_TRUE(result.task);
2284 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2285 TestTileTaskRunner::ProcessTask(result.task.get());
2286 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2287 DecodedDrawImage decoded_draw_image =
2288 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2289 EXPECT_TRUE(decoded_draw_image.is_budgeted());
2290 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2291 cache->UnrefImage(draw_image);
2292 cache->UnrefImage(draw_image);
2295 TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
2296 auto cache = CreateCache();
2297 const gfx::Size test_image_size = GetNormalImageSize();
2299 // Allow a single image by count. Use a high byte limit as we want to test the
2300 // count restriction.
2301 const size_t bytes_for_test_image =
2302 GetBytesNeededForSingleImage(test_image_size);
2303 cache->SetWorkingSetLimitsForTesting(
2304 bytes_for_test_image * 100 /* max_bytes */, 1u /* max_items */);
2305 PaintImage image = CreatePaintImageInternal(test_image_size);
2306 DrawImage draw_image = CreateDrawImageInternal(image);
2308 // The image counts against our budget.
2309 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2310 DecodedDrawImage decoded_draw_image =
2311 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2312 EXPECT_TRUE(decoded_draw_image.image());
2313 EXPECT_TRUE(decoded_draw_image.is_budgeted());
2315 // Try another image, it shouldn't be budgeted and should be at-raster.
2316 PaintImage second_paint_image =
2317 CreatePaintImageInternal(GetNormalImageSize());
2318 DrawImage second_draw_image = CreateDrawImageInternal(second_paint_image);
2320 // Should be at raster.
2321 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2322 second_draw_image, ImageDecodeCache::TracingInfo());
2323 EXPECT_FALSE(result.need_unref);
2324 EXPECT_FALSE(result.task);
2325 // Image retrieved from at-raster decode should not be budgeted.
2326 DecodedDrawImage second_decoded_draw_image =
2327 EnsureImageBacked(cache->GetDecodedImageForDraw(second_draw_image));
2328 EXPECT_TRUE(second_decoded_draw_image.image());
2329 EXPECT_FALSE(second_decoded_draw_image.is_budgeted());
2331 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2332 cache->DrawWithImageFinished(second_draw_image, second_decoded_draw_image);
2335 TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
2336 auto cache = CreateCache();
2337 const gfx::Size test_image_size = GetNormalImageSize();
2339 PaintImage image = CreatePaintImageInternal(test_image_size);
2340 DrawImage draw_image = CreateDrawImageInternal(image);
2342 const size_t bytes_for_test_image =
2343 GetBytesNeededForSingleImage(test_image_size);
2345 // Allow a single small image by size. Don't restrict the
2346 // items limit as we want to test the size limit.
2347 cache->SetWorkingSetLimitsForTesting(bytes_for_test_image,
2348 256 /* max_items */);
2350 // The image counts against our budget.
2351 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2352 DecodedDrawImage decoded_draw_image =
2353 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2354 EXPECT_TRUE(decoded_draw_image.image());
2355 EXPECT_TRUE(decoded_draw_image.is_budgeted());
2357 // Try another image, it shouldn't be budgeted and should be at-raster.
2358 PaintImage test_paint_image = CreatePaintImageInternal(test_image_size);
2359 DrawImage second_draw_image = CreateDrawImageInternal(test_paint_image);
2361 // Should be at raster.
2362 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2363 second_draw_image, ImageDecodeCache::TracingInfo());
2364 EXPECT_FALSE(result.need_unref);
2365 EXPECT_FALSE(result.task);
2366 // Image retrieved from at-raster decode should not be budgeted.
2367 DecodedDrawImage second_decoded_draw_image =
2368 EnsureImageBacked(cache->GetDecodedImageForDraw(second_draw_image));
2369 EXPECT_TRUE(second_decoded_draw_image.image());
2370 EXPECT_FALSE(second_decoded_draw_image.is_budgeted());
2372 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2373 cache->DrawWithImageFinished(second_draw_image, second_decoded_draw_image);
2376 TEST_P(GpuImageDecodeCacheTest,
2377 ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) {
2378 auto cache = CreateCache();
2379 sk_sp<SkColorSpace> image_color_space =
2380 gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace();
2381 gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
2384 CreateLargePaintImageForSoftwareFallback(image_color_space);
2385 DrawImage draw_image = CreateDrawImageInternal(
2386 image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
2387 ImageDecodeCache::TaskResult result =
2388 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2389 EXPECT_TRUE(result.need_unref);
2390 EXPECT_TRUE(result.task);
2392 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2393 TestTileTaskRunner::ProcessTask(result.task.get());
2395 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2396 DecodedDrawImage decoded_draw_image =
2397 cache->GetDecodedImageForDraw(draw_image);
2399 sk_sp<SkColorSpace> target_color_space = cache->SupportsColorSpaceConversion()
2400 ? color_space.ToSkColorSpace()
2403 if (use_transfer_cache_) {
2404 // If using the transfer cache, the color conversion should be applied
2405 // there as well, even if it is a software image.
2406 sk_sp<SkImage> service_image = GetLastTransferredImage();
2408 EXPECT_FALSE(service_image->isTextureBacked());
2409 EXPECT_EQ(image.width(), service_image->width());
2410 EXPECT_EQ(image.height(), service_image->height());
2412 // Color space should be logically equal to the original color space.
2413 EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(),
2414 target_color_space.get()));
2416 sk_sp<SkImage> decoded_image =
2417 cache->GetSWImageDecodeForTesting(draw_image);
2418 // Ensure that the "uploaded" image we get back is the same as the decoded
2419 // image we've cached.
2420 EXPECT_TRUE(decoded_image == decoded_draw_image.image());
2421 // Ensure that the SW decoded image had colorspace conversion applied.
2422 EXPECT_TRUE(SkColorSpace::Equals(decoded_image->colorSpace(),
2423 cache->SupportsColorSpaceConversion()
2424 ? image_color_space.get()
2428 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2429 cache->UnrefImage(draw_image);
2432 TEST_P(GpuImageDecodeCacheTest,
2433 ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) {
2434 auto cache = CreateCache();
2435 gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
2437 PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12));
2438 DrawImage draw_image = CreateDrawImageInternal(
2439 image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
2440 ImageDecodeCache::TaskResult result =
2441 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2442 EXPECT_TRUE(result.need_unref);
2443 EXPECT_TRUE(result.task);
2445 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2446 TestTileTaskRunner::ProcessTask(result.task.get());
2448 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2449 DecodedDrawImage decoded_draw_image =
2450 cache->GetDecodedImageForDraw(draw_image);
2452 sk_sp<SkColorSpace> target_color_space = cache->SupportsColorSpaceConversion()
2453 ? color_space.ToSkColorSpace()
2456 if (use_transfer_cache_) {
2457 // If using the transfer cache, the color conversion should be applied
2458 // there during upload.
2459 sk_sp<SkImage> service_image = GetLastTransferredImage();
2461 EXPECT_TRUE(service_image->isTextureBacked());
2462 EXPECT_EQ(image.width(), service_image->width());
2463 EXPECT_EQ(image.height(), service_image->height());
2465 if (!do_yuv_decode_) {
2466 // Color space should be logically equal to the original color space.
2467 EXPECT_TRUE(SkColorSpace::Equals(service_image->colorSpace(),
2468 target_color_space.get()));
2471 // Ensure that the HW uploaded image had color space conversion applied.
2472 EXPECT_TRUE(SkColorSpace::Equals(decoded_draw_image.image()->colorSpace(),
2473 target_color_space.get()));
2476 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2477 cache->UnrefImage(draw_image);
2480 TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScale) {
2481 if (do_yuv_decode_) {
2482 // YUV bitmap images do not happen, so this test will always skip for YUV.
2485 auto cache = CreateCache();
2487 PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
2488 DrawImage draw_image = CreateDrawImageInternal(image);
2489 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2490 DecodedDrawImage decoded_draw_image =
2491 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2492 EXPECT_TRUE(decoded_draw_image.image());
2493 EXPECT_TRUE(decoded_draw_image.is_budgeted());
2494 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2495 // For non-lazy images used at the original scale, no cpu component should be
2497 EXPECT_FALSE(cache->GetSWImageDecodeForTesting(draw_image));
2500 TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskHasNoDeps) {
2501 if (do_yuv_decode_) {
2502 // YUV bitmap images do not happen, so this test will always skip for YUV.
2505 auto cache = CreateCache();
2507 PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
2508 DrawImage draw_image = CreateDrawImageInternal(image);
2510 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2511 EXPECT_TRUE(result.need_unref);
2512 EXPECT_TRUE(result.task);
2513 EXPECT_TRUE(result.task->dependencies().empty());
2514 TestTileTaskRunner::ProcessTask(result.task.get());
2516 cache->UnrefImage(draw_image);
2519 TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskCancelled) {
2520 if (do_yuv_decode_) {
2521 // YUV bitmap images do not happen, so this test will always skip for YUV.
2524 auto cache = CreateCache();
2526 PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
2527 DrawImage draw_image = CreateDrawImageInternal(image);
2529 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2530 EXPECT_TRUE(result.need_unref);
2531 EXPECT_TRUE(result.task);
2532 EXPECT_TRUE(result.task->dependencies().empty());
2533 TestTileTaskRunner::CancelTask(result.task.get());
2534 TestTileTaskRunner::CompleteTask(result.task.get());
2536 cache->UnrefImage(draw_image);
2539 TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageNotColorConverted) {
2540 if (do_yuv_decode_) {
2541 // YUV bitmap images do not happen, so this test will always skip for YUV.
2544 auto cache = CreateCache();
2546 PaintImage image = CreateBitmapImageInternal(GetLargeImageSize());
2547 gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateDisplayP3D65();
2548 DrawImage draw_image = CreateDrawImageInternal(
2549 image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &target_color_space);
2550 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2551 DecodedDrawImage decoded_draw_image =
2552 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2553 EXPECT_TRUE(decoded_draw_image.image());
2554 EXPECT_TRUE(decoded_draw_image.is_budgeted());
2555 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2556 auto sw_image = cache->GetSWImageDecodeForTesting(draw_image);
2557 ASSERT_EQ(!!sw_image, false);
2560 TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) {
2561 if (do_yuv_decode_) {
2562 // YUV bitmap images do not happen, so this test will always skip for YUV.
2565 auto cache = CreateCache();
2567 PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
2568 DrawImage draw_image =
2569 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
2570 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2571 DecodedDrawImage decoded_draw_image =
2572 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2573 EXPECT_TRUE(decoded_draw_image.image());
2574 EXPECT_TRUE(decoded_draw_image.is_budgeted());
2575 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2578 TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) {
2579 auto cache = CreateCache();
2581 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2582 const PaintImage::Id paint_image_id = PaintImage::GetNextId();
2583 std::vector<DrawImage> draw_images;
2584 std::vector<DecodedDrawImage> decoded_draw_images;
2586 for (int i = 0; i < 10; ++i) {
2587 PaintImage image = CreatePaintImageInternal(
2588 GetNormalImageSize(), SkColorSpace::MakeSRGB(), paint_image_id);
2589 DrawImage draw_image =
2590 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
2591 DecodedDrawImage decoded_draw_image =
2592 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2594 draw_images.push_back(draw_image);
2595 decoded_draw_images.push_back(decoded_draw_image);
2600 // We should only have the last 2 entries in the persistent cache, even
2601 // though everything is in the in use cache.
2602 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 2u);
2603 EXPECT_EQ(cache->GetInUseCacheEntriesForTesting(), i + 1u);
2604 EXPECT_TRUE(cache->IsInPersistentCacheForTesting(draw_images[i]));
2605 EXPECT_TRUE(cache->IsInPersistentCacheForTesting(draw_images[i - 1]));
2608 for (int i = 0; i < 10; ++i) {
2609 cache->DrawWithImageFinished(draw_images[i], decoded_draw_images[i]);
2612 // We have a single tracked entry, that gets cleared once we purge the cache.
2613 EXPECT_EQ(cache->paint_image_entries_count_for_testing(), 1u);
2614 cache->OnMemoryPressure(
2615 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
2616 EXPECT_EQ(cache->paint_image_entries_count_for_testing(), 0u);
2619 TEST_P(GpuImageDecodeCacheTest, DecodeToScale) {
2620 if (do_yuv_decode_) {
2621 // TODO(crbug.com/927437): Modify test after decoding to scale for YUV is
2625 auto cache = CreateCache();
2627 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2628 const SkISize full_size = SkISize::Make(100, 100);
2629 const std::vector<SkISize> supported_sizes = {SkISize::Make(25, 25),
2630 SkISize::Make(50, 50)};
2631 const std::vector<FrameMetadata> frames = {FrameMetadata()};
2632 const SkImageInfo info =
2633 SkImageInfo::MakeN32Premul(full_size.width(), full_size.height(),
2634 DefaultColorSpace().ToSkColorSpace());
2635 sk_sp<FakePaintImageGenerator> generator =
2636 sk_make_sp<FakePaintImageGenerator>(info, frames, true, supported_sizes);
2637 PaintImage paint_image = PaintImageBuilder::WithDefault()
2638 .set_id(PaintImage::GetNextId())
2639 .set_paint_image_generator(generator)
2642 DrawImage draw_image = CreateDrawImageInternal(
2643 paint_image, CreateMatrix(SkSize::Make(0.5, 0.5)));
2644 DecodedDrawImage decoded_image =
2645 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2646 const int expected_width =
2647 paint_image.width() * std::abs(draw_image.scale().width());
2648 const int expected_height =
2649 paint_image.height() * std::abs(draw_image.scale().height());
2650 ASSERT_TRUE(decoded_image.image());
2651 EXPECT_EQ(decoded_image.image()->width(), expected_width);
2652 EXPECT_EQ(decoded_image.image()->height(), expected_height);
2654 // We should have requested a scaled decode from the generator.
2655 ASSERT_EQ(generator->decode_infos().size(), 1u);
2656 EXPECT_EQ(generator->decode_infos().at(0).width(), expected_width);
2657 EXPECT_EQ(generator->decode_infos().at(0).height(), expected_height);
2659 cache->DrawWithImageFinished(draw_image, decoded_image);
2662 TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) {
2663 if (do_yuv_decode_) {
2664 // TODO(crbug.com/927437): Modify test after decoding to scale for YUV is
2668 auto cache = CreateCache();
2670 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2671 SkISize full_size = SkISize::Make(100, 100);
2672 std::vector<SkISize> supported_sizes = {SkISize::Make(25, 25),
2673 SkISize::Make(50, 50)};
2674 std::vector<FrameMetadata> frames = {FrameMetadata()};
2675 sk_sp<FakePaintImageGenerator> generator =
2676 sk_make_sp<FakePaintImageGenerator>(
2677 SkImageInfo::MakeN32Premul(full_size.width(), full_size.height(),
2678 DefaultColorSpace().ToSkColorSpace()),
2679 frames, true, supported_sizes);
2680 PaintImage paint_image = PaintImageBuilder::WithDefault()
2681 .set_id(PaintImage::GetNextId())
2682 .set_paint_image_generator(generator)
2685 DrawImage draw_image = CreateDrawImageInternal(
2686 paint_image, CreateMatrix(SkSize::Make(0.5, 0.5)),
2687 nullptr /* color_space */, PaintFlags::FilterQuality::kNone);
2688 DecodedDrawImage decoded_image =
2689 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
2690 ASSERT_TRUE(decoded_image.image());
2691 const int expected_drawn_width =
2692 paint_image.width() * std::abs(draw_image.scale().width());
2693 const int expected_drawn_height =
2694 paint_image.height() * std::abs(draw_image.scale().height());
2695 EXPECT_EQ(decoded_image.image()->width(), expected_drawn_width);
2696 EXPECT_EQ(decoded_image.image()->height(), expected_drawn_height);
2698 // We should have requested the original decode from the generator.
2699 ASSERT_EQ(generator->decode_infos().size(), 1u);
2700 EXPECT_EQ(generator->decode_infos().at(0).width(), full_size.width());
2701 EXPECT_EQ(generator->decode_infos().at(0).height(), full_size.height());
2702 cache->DrawWithImageFinished(draw_image, decoded_image);
2705 TEST_P(GpuImageDecodeCacheTest, BasicMips) {
2706 auto decode_and_check_mips = [this](PaintFlags::FilterQuality filter_quality,
2707 SkSize scale, gfx::ColorSpace color_space,
2708 bool should_have_mips) {
2709 auto cache = CreateCache();
2711 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
2712 DrawImage draw_image = CreateDrawImageInternal(
2713 image, CreateMatrix(scale), &color_space, filter_quality);
2714 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2715 draw_image, ImageDecodeCache::TracingInfo());
2716 EXPECT_TRUE(result.need_unref);
2717 EXPECT_TRUE(result.task);
2719 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2720 TestTileTaskRunner::ProcessTask(result.task.get());
2722 // Must hold context lock before calling GetDecodedImageForDraw /
2723 // DrawWithImageFinished.
2724 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2725 // Pull out transfer cache ID from the DecodedDrawImage while it still has
2727 DecodedDrawImage serialized_decoded_draw_image =
2728 cache->GetDecodedImageForDraw(draw_image);
2729 const absl::optional<uint32_t> transfer_cache_entry_id =
2730 serialized_decoded_draw_image.transfer_cache_entry_id();
2731 DecodedDrawImage decoded_draw_image =
2732 EnsureImageBacked(std::move(serialized_decoded_draw_image));
2733 EXPECT_TRUE(decoded_draw_image.image());
2734 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
2736 if (do_yuv_decode_) {
2737 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
2738 // we must separately request mips for each plane and compare to the
2739 // original uploaded planes.
2740 CompareAllPlanesToMippedVersions(
2741 cache.get(), draw_image, transfer_cache_entry_id, should_have_mips);
2743 sk_sp<SkImage> image_with_mips =
2744 decoded_draw_image.image()->makeTextureImage(
2745 context_provider()->GrContext(), GrMipMapped::kYes);
2746 EXPECT_EQ(should_have_mips,
2747 image_with_mips == decoded_draw_image.image());
2749 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2750 cache->UnrefImage(draw_image);
2753 // No scale == no mips.
2754 decode_and_check_mips(PaintFlags::FilterQuality::kMedium,
2755 SkSize::Make(1.0f, 1.0f), DefaultColorSpace(), false);
2756 // Full mip level scale == no mips
2757 decode_and_check_mips(PaintFlags::FilterQuality::kMedium,
2758 SkSize::Make(0.5f, 0.5f), DefaultColorSpace(), false);
2759 // Low filter quality == no mips
2760 decode_and_check_mips(PaintFlags::FilterQuality::kLow,
2761 SkSize::Make(0.6f, 0.6f), DefaultColorSpace(), false);
2762 // None filter quality == no mips
2763 decode_and_check_mips(PaintFlags::FilterQuality::kNone,
2764 SkSize::Make(0.6f, 0.6f), DefaultColorSpace(), false);
2765 // Medium filter quality == mips
2766 decode_and_check_mips(PaintFlags::FilterQuality::kMedium,
2767 SkSize::Make(0.6f, 0.6f), DefaultColorSpace(), true);
2768 // Color conversion preserves mips
2769 decode_and_check_mips(PaintFlags::FilterQuality::kMedium,
2770 SkSize::Make(0.6f, 0.6f),
2771 gfx::ColorSpace::CreateXYZD50(), true);
2774 TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
2775 auto cache = CreateCache();
2777 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
2779 // Create an image with no scaling. It will not have mips.
2781 DrawImage draw_image = CreateDrawImageInternal(image);
2782 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2783 draw_image, ImageDecodeCache::TracingInfo());
2784 EXPECT_TRUE(result.need_unref);
2785 EXPECT_TRUE(result.task);
2787 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2788 TestTileTaskRunner::ProcessTask(result.task.get());
2790 // Must hold context lock before calling GetDecodedImageForDraw /
2791 // DrawWithImageFinished.
2792 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2793 // Pull out transfer cache ID from the DecodedDrawImage while it still has
2795 DecodedDrawImage serialized_decoded_draw_image =
2796 cache->GetDecodedImageForDraw(draw_image);
2797 const absl::optional<uint32_t> transfer_cache_entry_id =
2798 serialized_decoded_draw_image.transfer_cache_entry_id();
2799 DecodedDrawImage decoded_draw_image =
2800 EnsureImageBacked(std::move(serialized_decoded_draw_image));
2801 EXPECT_TRUE(decoded_draw_image.image());
2802 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
2804 // No mips should be generated.
2805 if (do_yuv_decode_) {
2806 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
2807 // we must separately request mips for each plane and compare to the
2808 // original uploaded planes.
2809 CompareAllPlanesToMippedVersions(cache.get(), draw_image,
2810 transfer_cache_entry_id,
2811 false /* should_have_mips */);
2813 sk_sp<SkImage> image_with_mips =
2814 decoded_draw_image.image()->makeTextureImage(
2815 context_provider()->GrContext(), GrMipMapped::kYes);
2816 ASSERT_TRUE(image_with_mips);
2817 EXPECT_NE(image_with_mips, decoded_draw_image.image());
2819 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2820 cache->UnrefImage(draw_image);
2823 // Call ReduceCacheUsage to clean up.
2824 cache->ReduceCacheUsage();
2826 // Request the same image again, but this time with a scale. We should get
2827 // no new task (re-uses the existing image), but mips should have been
2830 DrawImage draw_image =
2831 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
2832 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2833 draw_image, ImageDecodeCache::TracingInfo());
2834 EXPECT_TRUE(result.need_unref);
2835 EXPECT_FALSE(result.task);
2837 // Must hold context lock before calling GetDecodedImageForDraw /
2838 // DrawWithImageFinished.
2839 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2840 // Pull out transfer cache ID from the DecodedDrawImage while it still has
2842 DecodedDrawImage serialized_decoded_draw_image =
2843 cache->GetDecodedImageForDraw(draw_image);
2844 const absl::optional<uint32_t> transfer_cache_entry_id =
2845 serialized_decoded_draw_image.transfer_cache_entry_id();
2846 DecodedDrawImage decoded_draw_image =
2847 EnsureImageBacked(std::move(serialized_decoded_draw_image));
2849 EXPECT_TRUE(decoded_draw_image.image());
2850 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
2852 // Mips should be generated
2853 if (do_yuv_decode_) {
2854 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
2855 // we must separately request mips for each plane and compare to the
2856 // original uploaded planes.
2857 CompareAllPlanesToMippedVersions(cache.get(), draw_image,
2858 transfer_cache_entry_id,
2859 true /* should_have_mips */);
2861 sk_sp<SkImage> image_with_mips =
2862 decoded_draw_image.image()->makeTextureImage(
2863 context_provider()->GrContext(), GrMipMapped::kYes);
2864 EXPECT_EQ(image_with_mips, decoded_draw_image.image());
2866 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2867 cache->UnrefImage(draw_image);
2871 TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
2872 auto cache = CreateCache();
2873 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
2877 DecodedDrawImage decoded_image;
2879 std::vector<Decode> images_to_unlock;
2881 // Create an image with no scaling. It will not have mips.
2883 DrawImage draw_image = CreateDrawImageInternal(image);
2884 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2885 draw_image, ImageDecodeCache::TracingInfo());
2886 EXPECT_TRUE(result.need_unref);
2887 EXPECT_TRUE(result.task);
2889 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2890 TestTileTaskRunner::ProcessTask(result.task.get());
2892 // Must hold context lock before calling GetDecodedImageForDraw /
2893 // DrawWithImageFinished.
2894 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2895 // Pull out transfer cache ID from the DecodedDrawImage while it still has
2897 DecodedDrawImage serialized_decoded_draw_image =
2898 cache->GetDecodedImageForDraw(draw_image);
2899 const absl::optional<uint32_t> transfer_cache_entry_id =
2900 serialized_decoded_draw_image.transfer_cache_entry_id();
2901 DecodedDrawImage decoded_draw_image =
2902 EnsureImageBacked(std::move(serialized_decoded_draw_image));
2903 ASSERT_TRUE(decoded_draw_image.image());
2904 ASSERT_TRUE(decoded_draw_image.image()->isTextureBacked());
2906 // No mips should be generated.
2907 if (do_yuv_decode_) {
2908 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
2909 // we must separately request mips for each plane and compare to the
2910 // original uploaded planes.
2911 CompareAllPlanesToMippedVersions(cache.get(), draw_image,
2912 transfer_cache_entry_id,
2913 false /* should_have_mips */);
2915 sk_sp<SkImage> image_with_mips =
2916 decoded_draw_image.image()->makeTextureImage(
2917 context_provider()->GrContext(), GrMipMapped::kYes);
2918 EXPECT_NE(image_with_mips, decoded_draw_image.image());
2920 images_to_unlock.push_back({draw_image, decoded_draw_image});
2923 // Second decode with mips.
2925 DrawImage draw_image =
2926 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
2927 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
2928 draw_image, ImageDecodeCache::TracingInfo());
2929 EXPECT_TRUE(result.need_unref);
2930 EXPECT_FALSE(result.task);
2932 // Must hold context lock before calling GetDecodedImageForDraw /
2933 // DrawWithImageFinished.
2934 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2935 // Pull out transfer cache ID from the DecodedDrawImage while it still has
2937 DecodedDrawImage serialized_decoded_draw_image =
2938 cache->GetDecodedImageForDraw(draw_image);
2939 const absl::optional<uint32_t> transfer_cache_entry_id =
2940 serialized_decoded_draw_image.transfer_cache_entry_id();
2941 DecodedDrawImage decoded_draw_image =
2942 EnsureImageBacked(std::move(serialized_decoded_draw_image));
2944 ASSERT_TRUE(decoded_draw_image.image());
2945 ASSERT_TRUE(decoded_draw_image.image()->isTextureBacked());
2947 // Mips should be generated.
2948 if (do_yuv_decode_) {
2949 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
2950 // we must separately request mips for each plane and compare to the
2951 // original uploaded planes.
2952 CompareAllPlanesToMippedVersions(cache.get(), draw_image,
2953 transfer_cache_entry_id,
2954 true /* should_have_mips */);
2956 sk_sp<SkImage> image_with_mips =
2957 decoded_draw_image.image()->makeTextureImage(
2958 context_provider()->GrContext(), GrMipMapped::kYes);
2959 EXPECT_EQ(image_with_mips, decoded_draw_image.image());
2961 images_to_unlock.push_back({draw_image, decoded_draw_image});
2964 // Reduce cache usage to make sure anything marked for deletion is actually
2966 cache->ReduceCacheUsage();
2969 // All images which are currently ref-ed must have locked textures.
2970 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2971 for (const auto& draw_and_decoded_draw_image : images_to_unlock) {
2972 if (!use_transfer_cache_) {
2973 if (do_yuv_decode_) {
2974 DrawImage draw_image = draw_and_decoded_draw_image.image;
2975 for (size_t i = 0; i < kNumYUVPlanes; ++i) {
2976 SkImage* plane_image = cache
2977 ->GetUploadedPlaneForTesting(
2978 draw_image, static_cast<YUVIndex>(i))
2980 discardable_manager_.ExpectLocked(
2981 GpuImageDecodeCache::GlIdFromSkImage(plane_image));
2984 discardable_manager_.ExpectLocked(
2985 GpuImageDecodeCache::GlIdFromSkImage(
2986 draw_and_decoded_draw_image.decoded_image.image().get()));
2989 cache->DrawWithImageFinished(draw_and_decoded_draw_image.image,
2990 draw_and_decoded_draw_image.decoded_image);
2991 cache->UnrefImage(draw_and_decoded_draw_image.image);
2996 TEST_P(GpuImageDecodeCacheTest,
2997 OriginalYUVDecodeScaledDrawCorrectlyMipsPlanes) {
2998 // This test creates an image that will be YUV decoded and drawn at 80% scale.
2999 // Because the final size is between mip levels, we expect the image to be
3000 // decoded and uploaded at original size (mip level 0 for all planes) but to
3001 // have mips attached since PaintFlags::FilterQuality::kMedium uses bilinear
3002 // filtering between mip levels.
3003 if (!do_yuv_decode_) {
3004 // The YUV case may choose different mip levels between chroma and luma
3008 auto owned_cache = CreateCache();
3009 auto decode_and_check_plane_sizes = [this, cache = owned_cache.get()]() {
3010 PaintFlags::FilterQuality filter_quality =
3011 PaintFlags::FilterQuality::kMedium;
3012 SkSize requires_decode_at_original_scale = SkSize::Make(0.8f, 0.8f);
3014 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
3015 DrawImage draw_image(
3016 image, false, SkIRect::MakeWH(image.width(), image.height()),
3017 filter_quality, CreateMatrix(requires_decode_at_original_scale),
3018 PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
3019 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
3020 draw_image, ImageDecodeCache::TracingInfo());
3021 EXPECT_TRUE(result.need_unref);
3022 EXPECT_TRUE(result.task);
3024 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3025 TestTileTaskRunner::ProcessTask(result.task.get());
3027 // Must hold context lock before calling GetDecodedImageForDraw /
3028 // DrawWithImageFinished.
3029 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3030 // Pull out transfer cache ID from the DecodedDrawImage while it still has
3032 DecodedDrawImage serialized_decoded_draw_image =
3033 cache->GetDecodedImageForDraw(draw_image);
3034 const absl::optional<uint32_t> transfer_cache_entry_id =
3035 serialized_decoded_draw_image.transfer_cache_entry_id();
3036 DecodedDrawImage decoded_draw_image =
3037 EnsureImageBacked(std::move(serialized_decoded_draw_image));
3038 EXPECT_TRUE(decoded_draw_image.image());
3039 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
3041 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, we
3042 // must separately request mips for each plane and compare to the original
3044 CompareAllPlanesToMippedVersions(cache, draw_image, transfer_cache_entry_id,
3045 true /* should_have_mips */);
3046 SkYUVAPixmapInfo yuva_pixmap_info =
3047 GetYUVAPixmapInfo(GetNormalImageSize(), yuv_format_, yuv_data_type_);
3048 SkISize plane_sizes[SkYUVAInfo::kMaxPlanes];
3049 yuva_pixmap_info.yuvaInfo().planeDimensions(plane_sizes);
3050 VerifyUploadedPlaneSizes(cache, draw_image, transfer_cache_entry_id,
3053 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3054 cache->UnrefImage(draw_image);
3057 yuv_format_ = YUVSubsampling::k420;
3058 decode_and_check_plane_sizes();
3060 yuv_format_ = YUVSubsampling::k422;
3061 decode_and_check_plane_sizes();
3063 yuv_format_ = YUVSubsampling::k444;
3064 decode_and_check_plane_sizes();
3067 TEST_P(GpuImageDecodeCacheTest, HighBitDepthYUVDecoding) {
3068 // This test creates a high bit depth image that will be YUV decoded and drawn
3069 // at 80% scale. Because the final size is between mip levels, we expect the
3070 // image to be decoded and uploaded at original size (mip level 0 for all
3071 // planes) but to have mips attached since PaintFlags::FilterQuality::kMedium
3072 // uses bilinear filtering between mip levels.
3073 if (!do_yuv_decode_) {
3074 // The YUV case may choose different mip levels between chroma and luma
3079 auto decode_and_check_plane_sizes = [this](
3080 GpuImageDecodeCache* cache,
3081 bool decodes_to_yuv,
3082 SkYUVAPixmapInfo::DataType
3083 yuv_data_type = SkYUVAPixmapInfo::
3085 gfx::ColorSpace target_cs =
3086 gfx::ColorSpace::CreateSRGB()) {
3087 PaintFlags::FilterQuality filter_quality =
3088 PaintFlags::FilterQuality::kMedium;
3089 SkSize requires_decode_at_original_scale = SkSize::Make(0.8f, 0.8f);
3091 // When we're targeting HDR output, select a reasonable HDR color space for
3092 // the decoded content.
3093 gfx::ColorSpace decoded_cs;
3094 if (target_cs.IsHDR())
3095 decoded_cs = gfx::ColorSpace::CreateHDR10();
3096 auto sk_decoded_cs = cache->SupportsColorSpaceConversion()
3097 ? decoded_cs.ToSkColorSpace()
3100 // An unknown SkColorType means we expect fallback to RGB.
3102 decodes_to_yuv ? CreatePaintImageInternal(GetNormalImageSize(),
3103 decoded_cs.ToSkColorSpace())
3104 : CreatePaintImageForFallbackToRGB(GetNormalImageSize());
3106 TargetColorParams target_color_params;
3107 target_color_params.color_space = target_cs;
3108 target_color_params.sdr_max_luminance_nits =
3109 gfx::ColorSpace::kDefaultSDRWhiteLevel;
3111 DrawImage draw_image(
3112 image, false, SkIRect::MakeWH(image.width(), image.height()),
3113 filter_quality, CreateMatrix(requires_decode_at_original_scale),
3114 PaintImage::kDefaultFrameIndex, target_color_params);
3115 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
3116 draw_image, ImageDecodeCache::TracingInfo());
3117 EXPECT_TRUE(result.need_unref);
3118 EXPECT_TRUE(result.task);
3120 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3121 TestTileTaskRunner::ProcessTask(result.task.get());
3123 // Must hold context lock before calling GetDecodedImageForDraw /
3124 // DrawWithImageFinished.
3125 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3126 // Pull out transfer cache ID from the DecodedDrawImage while it still has
3128 DecodedDrawImage serialized_decoded_draw_image =
3129 cache->GetDecodedImageForDraw(draw_image);
3130 const absl::optional<uint32_t> transfer_cache_entry_id =
3131 serialized_decoded_draw_image.transfer_cache_entry_id();
3132 DecodedDrawImage decoded_draw_image =
3133 EnsureImageBacked(std::move(serialized_decoded_draw_image));
3134 EXPECT_TRUE(decoded_draw_image.image());
3135 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
3137 // If `draw_image` is tone mapped, then it will be converted to RGBA
3138 // during tone mapping.
3139 bool color_converted_to_rgba = use_transfer_cache_ &&
3140 decoded_cs.IsToneMappedByDefault() &&
3141 cache->SupportsColorSpaceConversion();
3143 if (decodes_to_yuv && !color_converted_to_rgba) {
3144 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus, we
3145 // must separately request mips for each plane and compare to the original
3147 CompareAllPlanesToMippedVersions(cache, draw_image,
3148 transfer_cache_entry_id,
3149 true /* should_have_mips */);
3150 SkYUVAPixmapInfo yuva_pixmap_info =
3151 GetYUVAPixmapInfo(GetNormalImageSize(), yuv_format_, yuv_data_type_);
3153 SkISize plane_sizes[SkYUVAInfo::kMaxPlanes];
3154 yuva_pixmap_info.yuvaInfo().planeDimensions(plane_sizes);
3155 VerifyUploadedPlaneSizes(cache, draw_image, transfer_cache_entry_id,
3156 plane_sizes, yuv_data_type, sk_decoded_cs.get());
3158 auto expected_image_cs =
3159 cache->SupportsColorSpaceConversion() && sk_decoded_cs
3160 ? target_color_params.color_space.ToSkColorSpace()
3162 if (expected_image_cs) {
3163 EXPECT_TRUE(SkColorSpace::Equals(
3164 expected_image_cs.get(), decoded_draw_image.image()->colorSpace()));
3167 if (use_transfer_cache_) {
3168 EXPECT_FALSE(transfer_cache_helper_
3169 .GetEntryAs<ServiceImageTransferCacheEntry>(
3170 *transfer_cache_entry_id)
3173 for (size_t plane = 0; plane < kNumYUVPlanes; ++plane)
3174 EXPECT_FALSE(cache->GetUploadedPlaneForTesting(
3175 draw_image, static_cast<YUVIndex>(plane)));
3179 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3180 cache->UnrefImage(draw_image);
3183 gpu::Capabilities original_caps;
3185 // TODO(crbug.com/1110007): We shouldn't need to lock to get capabilities.
3186 viz::RasterContextProvider::ScopedRasterContextLock auto_lock(
3187 context_provider_.get());
3188 original_caps = context_provider_->ContextCapabilities();
3191 const auto hdr_cs = gfx::ColorSpace::CreateHDR10();
3193 // Test that decoding to R16 works when supported.
3195 auto r16_caps = original_caps;
3196 r16_caps.texture_norm16 = true;
3197 r16_caps.texture_half_float_linear = true;
3198 context_provider_->SetContextCapabilitiesOverride(r16_caps);
3199 auto r16_cache = CreateCache();
3201 yuv_data_type_ = SkYUVAPixmapInfo::DataType::kUnorm16;
3203 yuv_format_ = YUVSubsampling::k420;
3204 decode_and_check_plane_sizes(r16_cache.get(), true,
3205 SkYUVAPixmapInfo::DataType::kUnorm16,
3206 DefaultColorSpace());
3208 yuv_format_ = YUVSubsampling::k422;
3209 decode_and_check_plane_sizes(r16_cache.get(), true,
3210 SkYUVAPixmapInfo::DataType::kUnorm16,
3211 DefaultColorSpace());
3213 yuv_format_ = YUVSubsampling::k444;
3214 decode_and_check_plane_sizes(r16_cache.get(), true,
3215 SkYUVAPixmapInfo::DataType::kUnorm16,
3216 DefaultColorSpace());
3218 // Verify HDR decoding has white level adjustment.
3219 yuv_format_ = YUVSubsampling::k420;
3220 decode_and_check_plane_sizes(r16_cache.get(), true,
3221 SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
3223 yuv_format_ = YUVSubsampling::k422;
3224 decode_and_check_plane_sizes(r16_cache.get(), true,
3225 SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
3227 yuv_format_ = YUVSubsampling::k444;
3228 decode_and_check_plane_sizes(r16_cache.get(), true,
3229 SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
3232 // Test that decoding to half-float works when supported.
3234 auto f16_caps = original_caps;
3235 f16_caps.texture_norm16 = false;
3236 f16_caps.texture_half_float_linear = true;
3237 context_provider_->SetContextCapabilitiesOverride(f16_caps);
3238 auto f16_cache = CreateCache();
3240 yuv_data_type_ = SkYUVAPixmapInfo::DataType::kFloat16;
3242 yuv_format_ = YUVSubsampling::k420;
3243 decode_and_check_plane_sizes(f16_cache.get(), true,
3244 SkYUVAPixmapInfo::DataType::kFloat16,
3245 DefaultColorSpace());
3247 yuv_format_ = YUVSubsampling::k422;
3248 decode_and_check_plane_sizes(f16_cache.get(), true,
3249 SkYUVAPixmapInfo::DataType::kFloat16,
3250 DefaultColorSpace());
3252 yuv_format_ = YUVSubsampling::k444;
3253 decode_and_check_plane_sizes(f16_cache.get(), true,
3254 SkYUVAPixmapInfo::DataType::kFloat16,
3255 DefaultColorSpace());
3257 // Verify HDR decoding.
3258 yuv_format_ = YUVSubsampling::k420;
3259 decode_and_check_plane_sizes(f16_cache.get(), true,
3260 SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
3262 yuv_format_ = YUVSubsampling::k422;
3263 decode_and_check_plane_sizes(f16_cache.get(), true,
3264 SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
3266 yuv_format_ = YUVSubsampling::k444;
3267 decode_and_check_plane_sizes(f16_cache.get(), true,
3268 SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
3271 // Verify YUV16 is unsupported when neither R16 or half-float are available.
3273 auto no_yuv16_caps = original_caps;
3274 no_yuv16_caps.texture_norm16 = false;
3275 no_yuv16_caps.texture_half_float_linear = false;
3276 context_provider_->SetContextCapabilitiesOverride(no_yuv16_caps);
3277 auto no_yuv16_cache = CreateCache();
3279 yuv_data_type_ = SkYUVAPixmapInfo::DataType::kUnorm16;
3281 yuv_format_ = YUVSubsampling::k420;
3282 decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3284 yuv_format_ = YUVSubsampling::k422;
3285 decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3287 yuv_format_ = YUVSubsampling::k444;
3288 decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3290 yuv_data_type_ = SkYUVAPixmapInfo::DataType::kFloat16;
3292 yuv_format_ = YUVSubsampling::k420;
3293 decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3295 yuv_format_ = YUVSubsampling::k422;
3296 decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3298 yuv_format_ = YUVSubsampling::k444;
3299 decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3303 TEST_P(GpuImageDecodeCacheTest, ScaledYUVDecodeScaledDrawCorrectlyMipsPlanes) {
3304 // This test creates an image that will be YUV decoded and drawn at 45% scale.
3305 // Because the final size is between mip levels, we expect the image to be
3306 // decoded and uploaded at half its original size (mip level 1 for Y plane but
3307 // level 0 for chroma planes) and to have mips attached since
3308 // PaintFlags::FilterQuality::kMedium uses bilinear filtering between mip
3310 if (!do_yuv_decode_) {
3311 // The YUV case may choose different mip levels between chroma and luma
3315 auto owned_cache = CreateCache();
3316 auto decode_and_check_plane_sizes =
3317 [this, cache = owned_cache.get()](
3319 const SkISize mipped_plane_sizes[SkYUVAInfo::kMaxPlanes]) {
3320 PaintFlags::FilterQuality filter_quality =
3321 PaintFlags::FilterQuality::kMedium;
3323 gfx::Size image_size = GetNormalImageSize();
3324 PaintImage image = CreatePaintImageInternal(image_size);
3325 DrawImage draw_image(
3326 image, false, SkIRect::MakeWH(image.width(), image.height()),
3327 filter_quality, CreateMatrix(scaled_size),
3328 PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
3329 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
3330 draw_image, ImageDecodeCache::TracingInfo());
3331 EXPECT_TRUE(result.need_unref);
3332 EXPECT_TRUE(result.task);
3334 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3335 TestTileTaskRunner::ProcessTask(result.task.get());
3337 // Must hold context lock before calling GetDecodedImageForDraw /
3338 // DrawWithImageFinished.
3339 viz::ContextProvider::ScopedContextLock context_lock(
3340 context_provider());
3341 // Pull out transfer cache ID from the DecodedDrawImage while it still
3343 DecodedDrawImage serialized_decoded_draw_image =
3344 cache->GetDecodedImageForDraw(draw_image);
3345 const absl::optional<uint32_t> transfer_cache_entry_id =
3346 serialized_decoded_draw_image.transfer_cache_entry_id();
3347 DecodedDrawImage decoded_draw_image =
3348 EnsureImageBacked(std::move(serialized_decoded_draw_image));
3349 EXPECT_TRUE(decoded_draw_image.image());
3350 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
3352 // Skia will flatten a YUV SkImage upon calling makeTextureImage. Thus,
3353 // we must separately request mips for each plane and compare to the
3354 // original uploaded planes.
3355 CompareAllPlanesToMippedVersions(cache, draw_image,
3356 transfer_cache_entry_id,
3357 true /* should_have_mips */);
3358 VerifyUploadedPlaneSizes(cache, draw_image, transfer_cache_entry_id,
3359 mipped_plane_sizes);
3361 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3362 cache->UnrefImage(draw_image);
3365 gfx::Size image_size = GetNormalImageSize();
3366 SkISize mipped_plane_sizes[kNumYUVPlanes];
3368 SkSize less_than_half_scale = SkSize::Make(0.45f, 0.45f);
3370 // Because we intend to draw this image at 0.45 x 0.45 scale, we will upload
3371 // the Y plane at mip level 1 (corresponding to 1/2 the original size).
3372 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kY)] = SkISize::Make(
3373 (image_size.width() + 1) / 2, (image_size.height() + 1) / 2);
3374 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kU)] =
3375 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kY)];
3376 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kV)] =
3377 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kY)];
3379 // For 4:2:0, the chroma planes (U and V) should be uploaded at the same size
3380 // as the Y plane since they get promoted to 4:4:4 to avoid blurriness from
3382 yuv_format_ = YUVSubsampling::k420;
3383 decode_and_check_plane_sizes(less_than_half_scale, mipped_plane_sizes);
3385 // For 4:2:2, only the UV height plane should be scaled.
3386 yuv_format_ = YUVSubsampling::k422;
3387 decode_and_check_plane_sizes(less_than_half_scale, mipped_plane_sizes);
3389 // For 4:4:4, all planes should be the same size.
3390 yuv_format_ = YUVSubsampling::k444;
3391 decode_and_check_plane_sizes(less_than_half_scale, mipped_plane_sizes);
3393 // Now try at 1/4 scale.
3394 SkSize one_quarter_scale = SkSize::Make(0.20f, 0.20f);
3396 // Because we intend to draw this image at 0.20 x 0.20 scale, we will upload
3397 // the Y plane at mip level 2 (corresponding to 1/4 the original size).
3398 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kY)] = SkISize::Make(
3399 (image_size.width() + 1) / 4, (image_size.height() + 1) / 4);
3400 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kU)] =
3401 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kY)];
3402 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kV)] =
3403 mipped_plane_sizes[static_cast<size_t>(YUVIndex::kY)];
3405 // For 4:2:0, the chroma planes (U and V) should be uploaded at the same size
3406 // as the Y plane since they get promoted to 4:4:4 to avoid blurriness from
3408 yuv_format_ = YUVSubsampling::k420;
3409 decode_and_check_plane_sizes(one_quarter_scale, mipped_plane_sizes);
3411 // For 4:2:2, only the UV height plane should be scaled.
3412 yuv_format_ = YUVSubsampling::k422;
3413 decode_and_check_plane_sizes(one_quarter_scale, mipped_plane_sizes);
3415 // For 4:4:4, all planes should be the same size.
3416 yuv_format_ = YUVSubsampling::k444;
3417 decode_and_check_plane_sizes(one_quarter_scale, mipped_plane_sizes);
3420 TEST_P(GpuImageDecodeCacheTest, GetBorderlineLargeDecodedImageForDraw) {
3421 // We will create a texture that's at the maximum size the GPU says it can
3422 // support for uploads.
3423 auto cache = CreateCache();
3425 PaintImage almost_too_large_image =
3426 CreatePaintImageInternal(gfx::Size(max_texture_size_, max_texture_size_));
3427 DrawImage draw_image = CreateDrawImageInternal(almost_too_large_image);
3428 ImageDecodeCache::TaskResult result =
3429 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3431 EXPECT_TRUE(result.need_unref);
3432 ASSERT_TRUE(result.task);
3433 ASSERT_EQ(result.task->dependencies().size(), 1u);
3434 ASSERT_TRUE(result.task->dependencies()[0]);
3436 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3437 TestTileTaskRunner::ProcessTask(result.task.get());
3439 // Must hold context lock before calling GetDecodedImageForDraw /
3440 // DrawWithImageFinished.
3441 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3442 DecodedDrawImage decoded_draw_image =
3443 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
3444 EXPECT_TRUE(decoded_draw_image.image());
3445 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
3446 EXPECT_TRUE(decoded_draw_image.is_budgeted());
3447 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
3449 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3450 cache->UnrefImage(draw_image);
3453 TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeForBitmaps) {
3454 auto cache = CreateCache();
3456 PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
3457 DrawImage draw_image = CreateDrawImageInternal(image);
3458 ImageDecodeCache::TaskResult result =
3459 cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
3460 EXPECT_TRUE(result.need_unref);
3461 EXPECT_FALSE(result.task);
3462 EXPECT_FALSE(result.is_at_raster_decode);
3463 EXPECT_FALSE(result.can_do_hardware_accelerated_decode);
3464 cache->UnrefImage(draw_image);
3467 TEST_P(GpuImageDecodeCacheTest, DarkModeDecodedDrawImage) {
3468 // TODO(prashant.n): Remove this once dark mode is supported for YUV decodes.
3472 std::unique_ptr<FakeRasterDarkModeFilter> dark_mode_filter =
3473 std::make_unique<FakeRasterDarkModeFilter>();
3474 auto cache = CreateCache(kGpuMemoryLimitBytes, dark_mode_filter.get());
3475 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
3476 DrawImage draw_image = CreateDrawImageWithDarkModeInternal(image);
3478 ImageDecodeCache::TaskResult result =
3479 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3480 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3481 TestTileTaskRunner::ProcessTask(result.task.get());
3482 GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image,
3483 dark_mode_filter.get());
3484 cache->UnrefImage(draw_image);
3487 TEST_P(GpuImageDecodeCacheTest, DarkModeImageCacheSize) {
3488 // TODO(prashant.n): Remove this once dark mode is supported for YUV decodes.
3492 std::unique_ptr<FakeRasterDarkModeFilter> dark_mode_filter =
3493 std::make_unique<FakeRasterDarkModeFilter>();
3494 auto cache = CreateCache(kGpuMemoryLimitBytes, dark_mode_filter.get());
3495 PaintImage image1 = CreatePaintImageInternal(GetNormalImageSize());
3496 PaintImage image2 = CreatePaintImageInternal(gfx::Size(50, 50));
3498 // DrawImage with full src rect for image1.
3499 DrawImage draw_image11 = CreateDrawImageWithDarkModeInternal(image1);
3500 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image11), 0u);
3501 ImageDecodeCache::TaskResult result11 = cache->GetTaskForImageAndRef(
3502 draw_image11, ImageDecodeCache::TracingInfo());
3503 TestTileTaskRunner::ProcessTask(result11.task->dependencies()[0].get());
3504 TestTileTaskRunner::ProcessTask(result11.task.get());
3505 GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image11,
3506 dark_mode_filter.get());
3507 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image11), 1u);
3509 // Another decoded draw image from same draw image for image1.
3510 GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image11,
3511 dark_mode_filter.get());
3512 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image11), 1u);
3514 // Another draw image with smaller src rect for image1.
3515 SkIRect src = SkIRect::MakeWH(10, 10);
3516 DrawImage draw_image12 = CreateDrawImageWithDarkModeInternal(
3517 image1, SkM44(), nullptr, PaintFlags::FilterQuality::kMedium, &src);
3518 ImageDecodeCache::TaskResult result12 = cache->GetTaskForImageAndRef(
3519 draw_image12, ImageDecodeCache::TracingInfo());
3520 GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image12,
3521 dark_mode_filter.get());
3522 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image12), 2u);
3524 // Another draw image with full src rect for image1.
3525 DrawImage draw_image13 = CreateDrawImageWithDarkModeInternal(image1);
3526 ImageDecodeCache::TaskResult result13 = cache->GetTaskForImageAndRef(
3527 draw_image13, ImageDecodeCache::TracingInfo());
3528 GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image13,
3529 dark_mode_filter.get());
3530 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image13), 2u);
3532 // DrawImage with full src rect for image2.
3533 DrawImage draw_image21 = CreateDrawImageWithDarkModeInternal(image2);
3534 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image21), 0u);
3535 ImageDecodeCache::TaskResult result21 = cache->GetTaskForImageAndRef(
3536 draw_image21, ImageDecodeCache::TracingInfo());
3537 TestTileTaskRunner::ProcessTask(result21.task->dependencies()[0].get());
3538 TestTileTaskRunner::ProcessTask(result21.task.get());
3539 GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image21,
3540 dark_mode_filter.get());
3541 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image21), 1u);
3543 // The cache for image1 related draw images should be intact.
3544 EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image13), 2u);
3546 cache->UnrefImage(draw_image11);
3547 cache->UnrefImage(draw_image12);
3548 cache->UnrefImage(draw_image13);
3549 cache->UnrefImage(draw_image21);
3552 TEST_P(GpuImageDecodeCacheTest, DarkModeNeedsDarkModeFilter) {
3553 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
3554 DrawImage draw_image_without_dark_mode = CreateDrawImageInternal(image);
3555 DrawImage draw_image_with_dark_mode =
3556 CreateDrawImageWithDarkModeInternal(image);
3558 std::unique_ptr<FakeRasterDarkModeFilter> dark_mode_filter =
3559 std::make_unique<FakeRasterDarkModeFilter>();
3560 auto cache = CreateCache(kGpuMemoryLimitBytes, dark_mode_filter.get());
3561 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
3562 draw_image_with_dark_mode, ImageDecodeCache::TracingInfo());
3564 // Draw image without dark mode bit set should not need dark mode filter.
3566 cache->NeedsDarkModeFilterForTesting(draw_image_without_dark_mode));
3568 // Draw image with dark mode bit set should need dark mode filter.
3569 if (do_yuv_decode_) {
3570 // TODO(prashant.n): Remove this once dark mode is supported for YUV
3573 cache->NeedsDarkModeFilterForTesting(draw_image_with_dark_mode));
3576 cache->NeedsDarkModeFilterForTesting(draw_image_with_dark_mode));
3579 // Generate dark mode color filter for |draw_image_with_dark_mode|.
3580 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3581 TestTileTaskRunner::ProcessTask(result.task.get());
3583 // Draw image with dark mode, but dark mode already applied.
3584 EXPECT_FALSE(cache->NeedsDarkModeFilterForTesting(draw_image_with_dark_mode));
3586 cache->UnrefImage(draw_image_with_dark_mode);
3589 TEST_P(GpuImageDecodeCacheTest, ClippedAndScaledDrawImageRemovesCacheEntry) {
3590 auto cache = CreateCache();
3591 cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
3593 PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
3594 DrawImage draw_image =
3595 CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
3597 // Must hold context lock before calling GetDecodedImageForDraw /
3598 // DrawWithImageFinished.
3599 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3600 DecodedDrawImage decoded_draw_image =
3601 EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
3602 EXPECT_TRUE(decoded_draw_image.image());
3603 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
3604 EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
3606 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3607 // One entry should be cached
3608 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
3610 // Get task for clipped and scaled image.
3611 auto clipped_rect = SkIRect::MakeWH(image.width() * 0.9f, image.height());
3612 DrawImage clipped_draw_image = CreateDrawImageInternal(
3613 image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), nullptr,
3614 PaintFlags::FilterQuality::kMedium, &clipped_rect);
3615 ImageDecodeCache::TaskResult clipped_result = cache->GetTaskForImageAndRef(
3616 clipped_draw_image, ImageDecodeCache::TracingInfo());
3618 // Unless |enable_clipped_image_scaling_| is true, we throw away the
3619 // previously cached entry.
3620 EXPECT_EQ(cache->GetNumCacheEntriesForTesting(),
3621 enable_clipped_image_scaling_ ? 1u : 0u);
3624 SkColorType test_color_types[] = {kN32_SkColorType, kARGB_4444_SkColorType,
3625 kRGBA_F16_SkColorType};
3627 INSTANTIATE_TEST_SUITE_P(
3628 GpuImageDecodeCacheTestsInProcessRaster,
3629 GpuImageDecodeCacheTest,
3631 testing::ValuesIn(test_color_types),
3632 testing::Values(false) /* use_transfer_cache */,
3633 testing::Bool() /* do_yuv_decode */,
3634 testing::Values(false) /* allow_accelerated_jpeg_decoding */,
3635 testing::Values(false) /* allow_accelerated_webp_decoding */,
3636 testing::Values(false) /* advertise_accelerated_decoding */,
3637 testing::Bool() /* enable_clipped_image_scaling */,
3638 testing::Values(false) /* no_discardable_memory */));
3640 INSTANTIATE_TEST_SUITE_P(
3641 GpuImageDecodeCacheTestsOOPR,
3642 GpuImageDecodeCacheTest,
3644 testing::ValuesIn(test_color_types),
3645 testing::Values(true) /* use_transfer_cache */,
3646 testing::Bool() /* do_yuv_decode */,
3647 testing::Values(false) /* allow_accelerated_jpeg_decoding */,
3648 testing::Values(false) /* allow_accelerated_webp_decoding */,
3649 testing::Values(false) /* advertise_accelerated_decoding */,
3650 testing::Values(false) /* enable_clipped_image_scaling */,
3651 testing::Values(false) /* no_discardable_memory */));
3653 class GpuImageDecodeCacheWithAcceleratedDecodesTest
3654 : public GpuImageDecodeCacheTest {
3656 PaintImage CreatePaintImageForDecodeAcceleration(
3657 ImageType image_type = ImageType::kJPEG,
3658 YUVSubsampling yuv_subsampling = YUVSubsampling::k420) {
3659 // Create a valid image metadata for hardware acceleration.
3660 ImageHeaderMetadata image_data{};
3661 image_data.image_size = gfx::Size(123, 45);
3662 image_data.image_type = image_type;
3663 image_data.yuv_subsampling = yuv_subsampling;
3664 image_data.all_data_received_prior_to_decode = true;
3665 image_data.has_embedded_color_profile = false;
3666 image_data.jpeg_is_progressive = false;
3667 image_data.webp_is_non_extended_lossy = true;
3669 SkImageInfo info = SkImageInfo::Make(
3670 image_data.image_size.width(), image_data.image_size.height(),
3671 color_type_, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
3672 sk_sp<FakePaintImageGenerator> generator;
3673 if (do_yuv_decode_) {
3674 SkYUVAPixmapInfo yuva_pixmap_info =
3675 GetYUVAPixmapInfo(image_data.image_size, yuv_format_, yuv_data_type_);
3676 generator = sk_make_sp<FakePaintImageGenerator>(info, yuva_pixmap_info);
3678 generator = sk_make_sp<FakePaintImageGenerator>(info);
3680 generator->SetImageHeaderMetadata(image_data);
3681 PaintImage image = PaintImageBuilder::WithDefault()
3682 .set_id(PaintImage::GetNextId())
3683 .set_paint_image_generator(generator)
3688 StrictMock<MockRasterImplementation>* raster_implementation() const {
3689 return static_cast<StrictMock<MockRasterImplementation>*>(
3690 context_provider_->RasterInterface());
3694 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
3695 RequestAcceleratedDecodeSuccessfully) {
3696 std::vector<std::pair<YUVSubsampling, size_t>>
3697 subsamplings_and_expected_data_sizes{{YUVSubsampling::k420, 8387u},
3698 {YUVSubsampling::k422, 11115u},
3699 {YUVSubsampling::k444, 16605u}};
3700 for (const auto& subsampling_and_expected_data_size :
3701 subsamplings_and_expected_data_sizes) {
3702 auto cache = CreateCache();
3703 const PaintImage image = CreatePaintImageForDecodeAcceleration(
3704 ImageType::kJPEG, subsampling_and_expected_data_size.first);
3705 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3706 DrawImage draw_image(image, false,
3707 SkIRect::MakeWH(image.width(), image.height()),
3708 quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
3709 PaintImage::kDefaultFrameIndex, TargetColorParams());
3710 ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
3711 draw_image, ImageDecodeCache::TracingInfo());
3712 EXPECT_TRUE(result.need_unref);
3713 ASSERT_TRUE(result.task);
3714 EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
3715 EXPECT_EQ(cache->GetWorkingSetBytesForTesting(),
3716 subsampling_and_expected_data_size.second);
3718 // Accelerated decodes should not produce decode tasks.
3719 ASSERT_TRUE(result.task->dependencies().empty());
3720 ASSERT_TRUE(image.GetImageHeaderMetadata());
3722 *raster_implementation(),
3723 DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size, _,
3724 gfx::ColorSpace(), _))
3726 TestTileTaskRunner::ProcessTask(result.task.get());
3728 // Must hold context lock before calling GetDecodedImageForDraw /
3729 // DrawWithImageFinished.
3730 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3731 const DecodedDrawImage decoded_draw_image =
3732 cache->GetDecodedImageForDraw(draw_image);
3733 EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value());
3734 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3735 cache->UnrefImage(draw_image);
3739 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
3740 RequestAcceleratedDecodeSuccessfullyWithColorSpaceConversion) {
3741 auto cache = CreateCache();
3742 const TargetColorParams target_color_params(gfx::ColorSpace::CreateXYZD50());
3743 ASSERT_TRUE(target_color_params.color_space.IsValid());
3744 const PaintImage image = CreatePaintImageForDecodeAcceleration();
3745 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3746 DrawImage draw_image(image, false,
3747 SkIRect::MakeWH(image.width(), image.height()), quality,
3748 CreateMatrix(SkSize::Make(0.75f, 0.75f)),
3749 PaintImage::kDefaultFrameIndex, target_color_params);
3750 ImageDecodeCache::TaskResult result =
3751 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3752 EXPECT_TRUE(result.need_unref);
3753 ASSERT_TRUE(result.task);
3754 EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
3756 // Accelerated decodes should not produce decode tasks.
3757 ASSERT_TRUE(result.task->dependencies().empty());
3758 ASSERT_TRUE(image.GetImageHeaderMetadata());
3760 *raster_implementation(),
3761 DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size, _,
3762 cache->SupportsColorSpaceConversion()
3763 ? target_color_params.color_space
3764 : gfx::ColorSpace(),
3767 TestTileTaskRunner::ProcessTask(result.task.get());
3769 // Must hold context lock before calling GetDecodedImageForDraw /
3770 // DrawWithImageFinished.
3771 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3772 const DecodedDrawImage decoded_draw_image =
3773 cache->GetDecodedImageForDraw(draw_image);
3774 EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value());
3775 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3776 cache->UnrefImage(draw_image);
3779 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
3780 AcceleratedDecodeRequestFails) {
3781 auto cache = CreateCache();
3782 const TargetColorParams target_color_params(gfx::ColorSpace::CreateXYZD50());
3783 ASSERT_TRUE(target_color_params.color_space.IsValid());
3784 const PaintImage image = CreatePaintImageForDecodeAcceleration();
3785 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3786 DrawImage draw_image(image, false,
3787 SkIRect::MakeWH(image.width(), image.height()), quality,
3788 CreateMatrix(SkSize::Make(0.75f, 0.75f)),
3789 PaintImage::kDefaultFrameIndex, target_color_params);
3790 ImageDecodeCache::TaskResult result =
3791 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3792 EXPECT_TRUE(result.need_unref);
3793 ASSERT_TRUE(result.task);
3794 EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
3796 // Accelerated decodes should not produce decode tasks.
3797 ASSERT_TRUE(result.task->dependencies().empty());
3798 raster_implementation()->SetAcceleratedDecodingFailed();
3799 ASSERT_TRUE(image.GetImageHeaderMetadata());
3801 *raster_implementation(),
3802 DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size, _,
3803 cache->SupportsColorSpaceConversion()
3804 ? target_color_params.color_space
3805 : gfx::ColorSpace(),
3808 TestTileTaskRunner::ProcessTask(result.task.get());
3810 // Attempting to get another task for the image should result in no task
3811 // because the decode is considered to have failed before.
3812 ImageDecodeCache::TaskResult result_after_run =
3813 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3814 EXPECT_FALSE(result_after_run.need_unref);
3815 EXPECT_FALSE(result_after_run.task);
3816 EXPECT_TRUE(result_after_run.can_do_hardware_accelerated_decode);
3818 // Must hold context lock before calling GetDecodedImageForDraw /
3819 // DrawWithImageFinished.
3820 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3821 const DecodedDrawImage decoded_draw_image =
3822 cache->GetDecodedImageForDraw(draw_image);
3823 EXPECT_FALSE(decoded_draw_image.transfer_cache_entry_id().has_value());
3824 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3825 cache->UnrefImage(draw_image);
3828 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
3829 CannotRequestAcceleratedDecodeBecauseOfStandAloneDecode) {
3830 auto cache = CreateCache();
3831 const TargetColorParams target_color_params;
3832 ASSERT_TRUE(target_color_params.color_space.IsValid());
3833 const PaintImage image = CreatePaintImageForDecodeAcceleration();
3834 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3835 DrawImage draw_image(image, false,
3836 SkIRect::MakeWH(image.width(), image.height()), quality,
3837 CreateMatrix(SkSize::Make(1.0f, 1.0f)),
3838 PaintImage::kDefaultFrameIndex, target_color_params);
3839 ImageDecodeCache::TaskResult result =
3840 cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
3841 EXPECT_TRUE(result.need_unref);
3842 ASSERT_TRUE(result.task);
3843 EXPECT_FALSE(result.can_do_hardware_accelerated_decode);
3845 // A non-accelerated standalone decode should produce only a decode task.
3846 ASSERT_TRUE(result.task->dependencies().empty());
3847 TestTileTaskRunner::ProcessTask(result.task.get());
3848 cache->UnrefImage(draw_image);
3851 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
3852 CannotRequestAcceleratedDecodeBecauseOfNonZeroUploadMipLevel) {
3853 auto cache = CreateCache();
3854 const TargetColorParams target_color_params;
3855 ASSERT_TRUE(target_color_params.color_space.IsValid());
3856 const PaintImage image = CreatePaintImageForDecodeAcceleration();
3857 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3858 DrawImage draw_image(image, false,
3859 SkIRect::MakeWH(image.width(), image.height()), quality,
3860 CreateMatrix(SkSize::Make(0.5f, 0.5f)),
3861 PaintImage::kDefaultFrameIndex, target_color_params);
3862 ImageDecodeCache::TaskResult result =
3863 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3864 EXPECT_TRUE(result.need_unref);
3865 ASSERT_TRUE(result.task);
3866 EXPECT_FALSE(result.can_do_hardware_accelerated_decode);
3868 // A non-accelerated normal decode should produce a decode dependency.
3869 ASSERT_EQ(result.task->dependencies().size(), 1u);
3870 ASSERT_TRUE(result.task->dependencies()[0]);
3871 TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3872 TestTileTaskRunner::ProcessTask(result.task.get());
3873 cache->UnrefImage(draw_image);
3876 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
3877 RequestAcceleratedDecodeSuccessfullyAfterCancellation) {
3878 auto cache = CreateCache();
3879 const TargetColorParams target_color_params;
3880 ASSERT_TRUE(target_color_params.color_space.IsValid());
3881 const PaintImage image = CreatePaintImageForDecodeAcceleration();
3882 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3883 DrawImage draw_image(image, false,
3884 SkIRect::MakeWH(image.width(), image.height()), quality,
3885 CreateMatrix(SkSize::Make(0.75f, 0.75f)),
3886 PaintImage::kDefaultFrameIndex, target_color_params);
3887 ImageDecodeCache::TaskResult result =
3888 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3889 EXPECT_TRUE(result.need_unref);
3890 ASSERT_TRUE(result.task);
3891 EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
3893 // Accelerated decodes should not produce decode tasks.
3894 ASSERT_TRUE(result.task->dependencies().empty());
3896 // Cancel the upload.
3897 TestTileTaskRunner::CancelTask(result.task.get());
3898 TestTileTaskRunner::CompleteTask(result.task.get());
3900 // Get the image again - we should have an upload task.
3901 ImageDecodeCache::TaskResult another_result =
3902 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3903 EXPECT_TRUE(another_result.need_unref);
3904 ASSERT_TRUE(another_result.task);
3905 EXPECT_TRUE(another_result.can_do_hardware_accelerated_decode);
3906 EXPECT_EQ(another_result.task->dependencies().size(), 0u);
3907 ASSERT_TRUE(image.GetImageHeaderMetadata());
3908 EXPECT_CALL(*raster_implementation(),
3909 DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size,
3910 _, gfx::ColorSpace(), _))
3912 TestTileTaskRunner::ProcessTask(another_result.task.get());
3914 // Must hold context lock before calling GetDecodedImageForDraw /
3915 // DrawWithImageFinished.
3916 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3917 const DecodedDrawImage decoded_draw_image =
3918 cache->GetDecodedImageForDraw(draw_image);
3919 EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value());
3920 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3921 cache->UnrefImage(draw_image);
3922 cache->UnrefImage(draw_image);
3925 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
3926 RequestAcceleratedDecodeSuccessfullyAtRasterTime) {
3927 // We force at-raster decodes by setting the cache memory limit to 0 bytes.
3928 auto cache = CreateCache(0u /* memory_limit_bytes */);
3929 const TargetColorParams target_color_params;
3930 ASSERT_TRUE(target_color_params.color_space.IsValid());
3931 const PaintImage image = CreatePaintImageForDecodeAcceleration();
3932 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3933 DrawImage draw_image(image, false,
3934 SkIRect::MakeWH(image.width(), image.height()), quality,
3935 CreateMatrix(SkSize::Make(0.75f, 0.75f)),
3936 PaintImage::kDefaultFrameIndex, target_color_params);
3937 ImageDecodeCache::TaskResult result =
3938 cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
3939 EXPECT_FALSE(result.need_unref);
3940 EXPECT_FALSE(result.task);
3941 EXPECT_TRUE(result.is_at_raster_decode);
3942 EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
3944 // Must hold context lock before calling GetDecodedImageForDraw /
3945 // DrawWithImageFinished.
3946 EXPECT_CALL(*raster_implementation(),
3947 DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size,
3948 _, gfx::ColorSpace(), _))
3950 viz::ContextProvider::ScopedContextLock context_lock(context_provider());
3951 const DecodedDrawImage decoded_draw_image =
3952 cache->GetDecodedImageForDraw(draw_image);
3953 EXPECT_TRUE(decoded_draw_image.transfer_cache_entry_id().has_value());
3954 cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3957 INSTANTIATE_TEST_SUITE_P(
3958 GpuImageDecodeCacheTestsOOPR,
3959 GpuImageDecodeCacheWithAcceleratedDecodesTest,
3961 testing::ValuesIn(test_color_types),
3962 testing::Values(true) /* use_transfer_cache */,
3963 testing::Bool() /* do_yuv_decode */,
3964 testing::Values(true) /* allow_accelerated_jpeg_decoding */,
3965 testing::Values(true) /* allow_accelerated_webp_decoding */,
3966 testing::Values(true) /* advertise_accelerated_decoding */,
3967 testing::Values(false) /* enable_clipped_image_scaling */,
3968 testing::Bool() /* no_discardable_memory */));
3970 class GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest
3971 : public GpuImageDecodeCacheWithAcceleratedDecodesTest {};
3973 TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
3974 RequestAcceleratedDecodeSuccessfully) {
3975 auto cache = CreateCache();
3976 const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
3977 const TargetColorParams target_color_params;
3978 ASSERT_TRUE(target_color_params.color_space.IsValid());
3980 // Try a JPEG image.
3981 const PaintImage jpeg_image =
3982 CreatePaintImageForDecodeAcceleration(ImageType::kJPEG);
3983 DrawImage jpeg_draw_image(
3985 SkIRect::MakeWH(jpeg_image.width(), jpeg_image.height()), quality,
3986 CreateMatrix(SkSize::Make(0.75f, 0.75f)), PaintImage::kDefaultFrameIndex,
3987 target_color_params);
3988 ImageDecodeCache::TaskResult jpeg_task = cache->GetTaskForImageAndRef(
3989 jpeg_draw_image, ImageDecodeCache::TracingInfo());
3990 EXPECT_TRUE(jpeg_task.need_unref);
3991 ASSERT_TRUE(jpeg_task.task);
3992 // If the hardware decoder claims support for the image (i.e.,
3993 // |advertise_accelerated_decoding_| is true) and the feature flag for the
3994 // image type is on (i.e., |allow_accelerated_jpeg_decoding_| is true), we
3995 // should expect hardware acceleration. In that path, there is only an upload
3996 // task without a decode dependency since the decode will be done in the GPU
3997 // process. In the alternative path (software decoding), the upload task
3998 // depends on a decode task that runs in the renderer.
3999 EXPECT_EQ(advertise_accelerated_decoding_,
4000 jpeg_task.can_do_hardware_accelerated_decode);
4001 if (advertise_accelerated_decoding_ && allow_accelerated_jpeg_decoding_) {
4002 ASSERT_TRUE(jpeg_task.task->dependencies().empty());
4003 ASSERT_TRUE(jpeg_image.GetImageHeaderMetadata());
4005 *raster_implementation(),
4006 DoScheduleImageDecode(jpeg_image.GetImageHeaderMetadata()->image_size,
4007 _, gfx::ColorSpace(), _))
4010 ASSERT_EQ(jpeg_task.task->dependencies().size(), 1u);
4011 ASSERT_TRUE(jpeg_task.task->dependencies()[0]);
4012 TestTileTaskRunner::ProcessTask(jpeg_task.task->dependencies()[0].get());
4014 TestTileTaskRunner::ScheduleTask(jpeg_task.task.get());
4016 // After scheduling the task, trying to get another task for the image should
4017 // result in the original task.
4018 ImageDecodeCache::TaskResult jpeg_task_again = cache->GetTaskForImageAndRef(
4019 jpeg_draw_image, ImageDecodeCache::TracingInfo());
4020 EXPECT_TRUE(jpeg_task_again.need_unref);
4021 EXPECT_EQ(jpeg_task_again.task.get(), jpeg_task.task.get());
4022 EXPECT_EQ(advertise_accelerated_decoding_,
4023 jpeg_task_again.can_do_hardware_accelerated_decode);
4025 TestTileTaskRunner::RunTask(jpeg_task.task.get());
4026 TestTileTaskRunner::CompleteTask(jpeg_task.task.get());
4027 testing::Mock::VerifyAndClearExpectations(raster_implementation());
4029 // After running the tasks, trying to get another task for the image should
4030 // result in no task.
4031 jpeg_task = cache->GetTaskForImageAndRef(jpeg_draw_image,
4032 ImageDecodeCache::TracingInfo());
4033 EXPECT_TRUE(jpeg_task.need_unref);
4034 EXPECT_FALSE(jpeg_task.task);
4035 EXPECT_EQ(advertise_accelerated_decoding_,
4036 jpeg_task.can_do_hardware_accelerated_decode);
4037 cache->UnrefImage(jpeg_draw_image);
4038 cache->UnrefImage(jpeg_draw_image);
4039 cache->UnrefImage(jpeg_draw_image);
4041 // Try a WebP image.
4042 const PaintImage webp_image =
4043 CreatePaintImageForDecodeAcceleration(ImageType::kWEBP);
4044 DrawImage webp_draw_image(
4046 SkIRect::MakeWH(webp_image.width(), webp_image.height()), quality,
4047 CreateMatrix(SkSize::Make(0.75f, 0.75f)), PaintImage::kDefaultFrameIndex,
4048 target_color_params);
4049 ImageDecodeCache::TaskResult webp_task = cache->GetTaskForImageAndRef(
4050 webp_draw_image, ImageDecodeCache::TracingInfo());
4051 EXPECT_TRUE(webp_task.need_unref);
4052 ASSERT_TRUE(webp_task.task);
4053 EXPECT_EQ(advertise_accelerated_decoding_,
4054 webp_task.can_do_hardware_accelerated_decode);
4055 if (advertise_accelerated_decoding_ && allow_accelerated_webp_decoding_) {
4056 ASSERT_TRUE(webp_task.task->dependencies().empty());
4057 ASSERT_TRUE(webp_image.GetImageHeaderMetadata());
4059 *raster_implementation(),
4060 DoScheduleImageDecode(webp_image.GetImageHeaderMetadata()->image_size,
4061 _, gfx::ColorSpace(), _))
4064 ASSERT_EQ(webp_task.task->dependencies().size(), 1u);
4065 ASSERT_TRUE(webp_task.task->dependencies()[0]);
4066 TestTileTaskRunner::ProcessTask(webp_task.task->dependencies()[0].get());
4068 TestTileTaskRunner::ProcessTask(webp_task.task.get());
4069 testing::Mock::VerifyAndClearExpectations(raster_implementation());
4071 // The image should have been cached.
4072 webp_task = cache->GetTaskForImageAndRef(webp_draw_image,
4073 ImageDecodeCache::TracingInfo());
4074 EXPECT_TRUE(webp_task.need_unref);
4075 EXPECT_FALSE(webp_task.task);
4076 EXPECT_EQ(advertise_accelerated_decoding_,
4077 webp_task.can_do_hardware_accelerated_decode);
4078 cache->UnrefImage(webp_draw_image);
4079 cache->UnrefImage(webp_draw_image);
4081 // Try a PNG image (which should not be hardware accelerated).
4082 const PaintImage png_image =
4083 CreatePaintImageForDecodeAcceleration(ImageType::kPNG);
4084 DrawImage png_draw_image(
4086 SkIRect::MakeWH(jpeg_image.width(), jpeg_image.height()), quality,
4087 CreateMatrix(SkSize::Make(0.75f, 0.75f)), PaintImage::kDefaultFrameIndex,
4088 target_color_params);
4089 ImageDecodeCache::TaskResult png_task = cache->GetTaskForImageAndRef(
4090 png_draw_image, ImageDecodeCache::TracingInfo());
4091 EXPECT_TRUE(png_task.need_unref);
4092 ASSERT_TRUE(png_task.task);
4093 EXPECT_FALSE(png_task.can_do_hardware_accelerated_decode);
4094 ASSERT_EQ(png_task.task->dependencies().size(), 1u);
4095 ASSERT_TRUE(png_task.task->dependencies()[0]);
4096 TestTileTaskRunner::ProcessTask(png_task.task->dependencies()[0].get());
4097 TestTileTaskRunner::ProcessTask(png_task.task.get());
4098 cache->UnrefImage(png_draw_image);
4101 INSTANTIATE_TEST_SUITE_P(
4102 GpuImageDecodeCacheTestsOOPR,
4103 GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
4104 testing::Combine(testing::Values(kN32_SkColorType),
4105 testing::Values(true) /* use_transfer_cache */,
4106 testing::Bool() /* do_yuv_decode */,
4107 testing::Bool() /* allow_accelerated_jpeg_decoding */,
4108 testing::Bool() /* allow_accelerated_webp_decoding */,
4109 testing::Bool() /* advertise_accelerated_decoding */,
4110 testing::Values(false) /* enable_clipped_image_scaling */,
4111 testing::Bool() /* no_discardable_memory */));
4113 #undef EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE
4114 #undef EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE