[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / tiles / gpu_image_decode_cache_unittest.cc
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.
4
5 #include "cc/tiles/gpu_image_decode_cache.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <map>
10 #include <memory>
11 #include <string>
12 #include <tuple>
13 #include <vector>
14
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"
41
42 using testing::_;
43 using testing::StrictMock;
44
45 namespace cc {
46 namespace {
47
48 class FakeDiscardableManager {
49  public:
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_++;
55   }
56   void Unlock(GLuint texture_id) {
57     EXPECT_NE(textures_.end(), textures_.find(texture_id));
58     ExpectLocked(texture_id);
59     textures_[texture_id]--;
60   }
61   bool Lock(GLuint texture_id) {
62     EnforceLimit();
63
64     EXPECT_NE(textures_.end(), textures_.find(texture_id));
65     if (textures_[texture_id] >= kHandleUnlocked) {
66       textures_[texture_id]++;
67       return true;
68     }
69     return false;
70   }
71
72   void DeleteTexture(GLuint texture_id) {
73     if (textures_.end() == textures_.find(texture_id))
74       return;
75
76     ExpectLocked(texture_id);
77     textures_[texture_id] = kHandleDeleted;
78     live_textures_count_--;
79   }
80
81   void set_cached_textures_limit(size_t limit) {
82     cached_textures_limit_ = limit;
83   }
84
85   void ExpectLocked(GLuint texture_id) {
86     EXPECT_TRUE(textures_.end() != textures_.find(texture_id));
87
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);
93   }
94
95  private:
96   void EnforceLimit() {
97     for (auto it = textures_.begin(); it != textures_.end(); ++it) {
98       if (live_textures_count_ <= cached_textures_limit_)
99         return;
100       if (it->second != kHandleUnlocked)
101         continue;
102
103       it->second = kHandleDeleted;
104       gl_->TestGLES2Interface::DeleteTextures(1, &it->first);
105       live_textures_count_--;
106     }
107   }
108
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();
113
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;
118 };
119
120 class FakeGPUImageDecodeTestGLES2Interface : public viz::TestGLES2Interface,
121                                              public viz::TestContextSupport {
122  public:
123   explicit FakeGPUImageDecodeTestGLES2Interface(
124       FakeDiscardableManager* discardable_manager,
125       TransferCacheTestHelper* transfer_cache_helper,
126       bool advertise_accelerated_decoding)
127       : extension_string_(
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) {}
135
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());
141   }
142
143   void InitializeDiscardableTextureCHROMIUM(GLuint texture_id) override {
144     discardable_manager_->Initialize(texture_id);
145   }
146   void UnlockDiscardableTextureCHROMIUM(GLuint texture_id) override {
147     discardable_manager_->Unlock(texture_id);
148   }
149   bool LockDiscardableTextureCHROMIUM(GLuint texture_id) override {
150     return discardable_manager_->Lock(texture_id);
151   }
152
153   bool ThreadSafeShallowLockDiscardableTexture(uint32_t texture_id) override {
154     return discardable_manager_->Lock(texture_id);
155   }
156   void CompleteLockDiscardableTexureOnContextThread(
157       uint32_t texture_id) override {}
158
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();
163   }
164
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;
171   }
172
173   bool ThreadsafeLockTransferCacheEntry(uint32_t type, uint32_t id) override {
174     return transfer_cache_helper_->LockEntryDirect(MakeEntryKey(type, id));
175   }
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);
183   }
184   void DeleteTransferCacheEntry(uint32_t type, uint32_t id) override {
185     transfer_cache_helper_->DeleteEntryDirect(MakeEntryKey(type, id));
186   }
187
188   bool IsJpegDecodeAccelerationSupported() const override {
189     return advertise_accelerated_decoding_;
190   }
191
192   bool IsWebPDecodeAccelerationSupported() const override {
193     return advertise_accelerated_decoding_;
194   }
195
196   bool CanDecodeWithHardwareAcceleration(
197       const ImageHeaderMetadata* image_metadata) const override {
198     // Only advertise hardware accelerated decoding for the current use cases
199     // (JPEG and WebP).
200     if (image_metadata && (image_metadata->image_type == ImageType::kJPEG ||
201                            image_metadata->image_type == ImageType::kWEBP)) {
202       return advertise_accelerated_decoding_;
203     }
204     return false;
205   }
206
207   std::pair<TransferCacheEntryType, uint32_t> MakeEntryKey(uint32_t type,
208                                                            uint32_t id) {
209     DCHECK_LE(type, static_cast<uint32_t>(TransferCacheEntryType::kLast));
210     return std::make_pair(static_cast<TransferCacheEntryType>(type), id);
211   }
212
213   // viz::TestGLES2Interface:
214   const GLubyte* GetString(GLenum name) override {
215     switch (name) {
216       case GL_EXTENSIONS:
217         return reinterpret_cast<const GLubyte*>(extension_string_.c_str());
218       case GL_VERSION:
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");
222       case GL_VENDOR:
223         return reinterpret_cast<const GLubyte*>("Null Vendor");
224       case GL_RENDERER:
225         return reinterpret_cast<const GLubyte*>("The Null (Non-)Renderer");
226     }
227     return nullptr;
228   }
229   void GetIntegerv(GLenum name, GLint* params) override {
230     switch (name) {
231       case GL_MAX_TEXTURE_IMAGE_UNITS:
232         *params = 8;
233         return;
234       case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
235         *params = 8;
236         return;
237       case GL_MAX_RENDERBUFFER_SIZE:
238         *params = 2048;
239         return;
240       case GL_MAX_VERTEX_ATTRIBS:
241         *params = 8;
242         return;
243       default:
244         break;
245     }
246     TestGLES2Interface::GetIntegerv(name, params);
247   }
248   void DeleteTextures(GLsizei n, const GLuint* textures) override {
249     for (GLsizei i = 0; i < n; i++) {
250       discardable_manager_->DeleteTexture(textures[i]);
251     }
252     TestGLES2Interface::DeleteTextures(n, textures);
253   }
254
255  private:
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_;
262 };
263
264 class MockRasterImplementation : public gpu::raster::RasterImplementationGLES {
265  public:
266   explicit MockRasterImplementation(gpu::gles2::GLES2Interface* gl,
267                                     gpu::ContextSupport* support)
268       : RasterImplementationGLES(gl, support) {}
269   ~MockRasterImplementation() override = default;
270
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_++);
282     }
283     return gpu::SyncToken();
284   }
285
286   void SetAcceleratedDecodingFailed() { next_accelerated_decode_fails_ = true; }
287
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 */));
293
294  private:
295   bool next_accelerated_decode_fails_ = false;
296   uint64_t next_release_count_ = 1u;
297 };
298
299 class GPUImageDecodeTestMockContextProvider : public viz::TestContextProvider {
300  public:
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));
315   }
316
317   void SetContextCapabilitiesOverride(absl::optional<gpu::Capabilities> caps) {
318     capabilities_override_ = caps;
319   }
320
321   const gpu::Capabilities& ContextCapabilities() const override {
322     if (capabilities_override_.has_value())
323       return *capabilities_override_;
324
325     return viz::TestContextProvider::ContextCapabilities();
326   }
327
328  private:
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),
335                             std::move(gl),
336                             std::move(raster),
337                             nullptr /* sii */,
338                             true) {}
339
340   absl::optional<gpu::Capabilities> capabilities_override_;
341 };
342
343 class FakeRasterDarkModeFilter : public RasterDarkModeFilter {
344  public:
345   FakeRasterDarkModeFilter() {
346     SkHighContrastConfig config;
347     config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
348     color_filter_ = SkHighContrastFilter::Make(config);
349   }
350
351   sk_sp<SkColorFilter> ApplyToImage(const SkPixmap& pixmap,
352                                     const SkIRect& src) const override {
353     return color_filter_;
354   }
355
356   const sk_sp<SkColorFilter> GetFilter() const { return color_filter_; }
357
358  private:
359   sk_sp<SkColorFilter> color_filter_;
360 };
361
362 SkM44 CreateMatrix(const SkSize& scale) {
363   return SkM44::Scale(scale.width(), scale.height());
364 }
365
366 #define EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(condition) \
367   if (!use_transfer_cache_)                                \
368     EXPECT_TRUE(condition);
369
370 #define EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE(condition) \
371   if (!use_transfer_cache_)                                 \
372     EXPECT_FALSE(condition);
373
374 size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024;
375
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 */>> {
386  public:
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);
407     }
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();
414     {
415       viz::RasterContextProvider::ScopedRasterContextLock context_lock(
416           context_provider_.get());
417       transfer_cache_helper_.SetGrContext(context_provider_->GrContext());
418       max_texture_size_ =
419           context_provider_->ContextCapabilities().max_texture_size;
420     }
421     color_type_ = std::get<0>(GetParam());
422     use_transfer_cache_ = std::get<1>(GetParam());
423     do_yuv_decode_ = std::get<2>(GetParam());
424   }
425
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);
432   }
433
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);
438   }
439
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);
444   }
445
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;
451
452     if (do_yuv_decode_) {
453       return CreateDiscardablePaintImage(
454           size, color_space, allocate_encoded_memory, id, color_type_,
455           yuv_format_, yuv_data_type_);
456     }
457     return CreateDiscardablePaintImage(
458         size, color_space, allocate_encoded_memory, id, color_type_);
459   }
460
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(),
466                                             image_color_space);
467   }
468
469   PaintImage CreatePaintImageForFallbackToRGB(
470       const gfx::Size test_image_size,
471       sk_sp<SkColorSpace> image_color_space = SkColorSpace::MakeSRGB()) {
472     SkImageInfo info =
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();
481     } else {
482       generator = sk_make_sp<FakePaintImageGenerator>(info);
483     }
484     PaintImage image = PaintImageBuilder::WithDefault()
485                            .set_id(PaintImage::GetNextId())
486                            .set_paint_image_generator(generator)
487                            .TakePaintImage();
488     return image;
489   }
490
491   PaintImage CreateBitmapImageInternal(const gfx::Size& size) {
492     return CreateBitmapImage(size, color_type_);
493   }
494
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);
500   }
501
502   TargetColorParams DefaultTargetColorParams() {
503     return TargetColorParams(DefaultColorSpace());
504   }
505
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;
517     if (!src_rect) {
518       src_rectangle =
519           SkIRect::MakeWH(paint_image.width(), paint_image.height());
520       src_rect = &src_rectangle;
521     }
522     TargetColorParams target_color_params = DefaultTargetColorParams();
523     if (color_space)
524       target_color_params.color_space = *color_space;
525     target_color_params.sdr_max_luminance_nits = sdr_white_level;
526
527     return DrawImage(paint_image, use_dark_mode, *src_rect, filter_quality,
528                      matrix, frame_index, target_color_params);
529   }
530
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);
543   }
544
545   void GetImageAndDrawFinishedForDarkMode(
546       GpuImageDecodeCache* cache,
547       const DrawImage& draw_image,
548       FakeRasterDarkModeFilter* dark_mode_filter) {
549     DCHECK(cache);
550     DCHECK(dark_mode_filter);
551
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);
560   }
561
562   GPUImageDecodeTestMockContextProvider* context_provider() {
563     return context_provider_.get();
564   }
565
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_);
570
571       return yuva_pixmap_info.computeTotalBytes();
572     }
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();
579   }
580
581   void SetCachedTexturesLimit(size_t limit) {
582     discardable_manager_.set_cached_textures_limit(limit);
583     transfer_cache_helper_.SetCachedItemsLimit(limit);
584   }
585
586   // If this is an image-backed DecodedDrawImage, does nothing. Otherwise this
587   // retreives the image from the transfer cache and builds a new
588   // DecodedDrawImage.
589   DecodedDrawImage EnsureImageBacked(DecodedDrawImage&& draw_image) {
590     if (draw_image.transfer_cache_entry_id()) {
591       EXPECT_TRUE(use_transfer_cache_);
592       auto* image_entry =
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;
602     }
603
604     return std::move(draw_image);
605   }
606
607   sk_sp<SkImage> GetLastTransferredImage() {
608     auto& key = transfer_cache_helper_.GetLastAddedEntry();
609     ServiceTransferCacheEntry* entry =
610         transfer_cache_helper_.GetEntryInternal(key.first, key.second);
611     if (!entry)
612       return nullptr;
613     CHECK_EQ(TransferCacheEntryType::kImage, entry->Type());
614     return static_cast<ServiceImageTransferCacheEntry*>(entry)->image();
615   }
616
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();
627         auto* image_entry =
628             transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
629                 id);
630         original_uploaded_plane = image_entry->GetPlaneImage(i);
631       } else {
632         original_uploaded_plane = cache->GetUploadedPlaneForTesting(
633             draw_image, static_cast<YUVIndex>(i));
634       }
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);
640     }
641   }
642
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();
658         auto* image_entry =
659             transfer_cache_helper_.GetEntryAs<ServiceImageTransferCacheEntry>(
660                 id);
661         uploaded_plane = image_entry->GetPlaneImage(i);
662       } else {
663         uploaded_plane = cache->GetUploadedPlaneForTesting(
664             draw_image, static_cast<YUVIndex>(i));
665       }
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_) {
670         EXPECT_TRUE(
671             SkColorSpace::Equals(expected_cs, uploaded_plane->colorSpace()));
672       } else if (expected_cs) {
673         // In-process raster sets the ColorSpace on the composite SkImage.
674       }
675     }
676   }
677
678  protected:
679   base::test::ScopedFeatureList feature_list_;
680
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_;
686
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;
691
692   bool use_transfer_cache_;
693   SkColorType color_type_;
694   bool do_yuv_decode_;
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;
701 };
702
703 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
704   auto cache = CreateCache();
705   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
706
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);
713
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());
720
721   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
722   TestTileTaskRunner::ProcessTask(result.task.get());
723
724   cache->UnrefImage(draw_image);
725   cache->UnrefImage(draw_image);
726 }
727
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);
737
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]);
741
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());
746
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]);
752
753   EXPECT_TRUE(another_result.need_unref);
754   EXPECT_TRUE(result.task.get() == another_result.task.get());
755
756   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
757   TestTileTaskRunner::ProcessTask(result.task.get());
758
759   cache->UnrefImage(draw_image);
760   cache->UnrefImage(another_draw_image);
761 }
762
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);
772
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());
780
781   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
782   TestTileTaskRunner::ProcessTask(result.task.get());
783
784   cache->UnrefImage(draw_image);
785   cache->UnrefImage(another_draw_image);
786 }
787
788 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
789   auto cache = CreateCache();
790
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);
798
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());
807
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());
812
813   cache->UnrefImage(first_draw_image);
814   cache->UnrefImage(second_draw_image);
815 }
816
817 TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
818   auto cache = CreateCache();
819
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);
827
828   TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
829   TestTileTaskRunner::ProcessTask(first_result.task.get());
830
831   cache->UnrefImage(first_draw_image);
832
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());
839
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());
846
847   TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
848   TestTileTaskRunner::ProcessTask(second_result.task.get());
849
850   cache->UnrefImage(second_draw_image);
851   cache->UnrefImage(third_draw_image);
852 }
853
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);
863
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());
870
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());
877
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());
882
883   cache->UnrefImage(first_draw_image);
884   cache->UnrefImage(second_draw_image);
885   cache->UnrefImage(third_draw_image);
886 }
887
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);
899
900   TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
901   TestTileTaskRunner::ProcessTask(first_result.task.get());
902
903   cache->UnrefImage(first_draw_image);
904
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);
911
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);
917 }
918
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]);
930
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());
934
935   // Cancel the upload.
936   TestTileTaskRunner::CancelTask(result.task.get());
937   TestTileTaskRunner::CompleteTask(result.task.get());
938
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);
946
947   TestTileTaskRunner::ProcessTask(another_result.task.get());
948
949   // Finally, complete the original decode task.
950   TestTileTaskRunner::CompleteTask(result.task->dependencies()[0].get());
951
952   cache->UnrefImage(draw_image);
953   cache->UnrefImage(draw_image);
954 }
955
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]);
967
968   // Run the decode.
969   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
970
971   // Cancel the upload.
972   TestTileTaskRunner::CancelTask(result.task.get());
973   TestTileTaskRunner::CompleteTask(result.task.get());
974
975   // Unref the image.
976   cache->UnrefImage(draw_image);
977
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]);
986
987   TestTileTaskRunner::ProcessTask(another_result.task->dependencies()[0].get());
988   TestTileTaskRunner::ProcessTask(another_result.task.get());
989
990   cache->UnrefImage(draw_image);
991 }
992
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]);
1004
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());
1009
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);
1014
1015   cache->UnrefImage(draw_image);
1016   cache->UnrefImage(draw_image);
1017 }
1018
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);
1028
1029   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1030
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());
1035
1036   // Didn't run the task, so cancel it.
1037   TestTileTaskRunner::CancelTask(result.task.get());
1038   TestTileTaskRunner::CompleteTask(result.task.get());
1039
1040   // Fully cancel everything (so the raster would unref things).
1041   cache->UnrefImage(draw_image);
1042   cache->UnrefImage(draw_image);
1043
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());
1050
1051   TestTileTaskRunner::ProcessTask(third_result.task->dependencies()[0].get());
1052   TestTileTaskRunner::ProcessTask(third_result.task.get());
1053
1054   cache->UnrefImage(draw_image);
1055 }
1056
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);
1066
1067   ASSERT_GT(result.task->dependencies().size(), 0u);
1068   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1069
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());
1074
1075   // Didn't run the task, so cancel it.
1076   TestTileTaskRunner::CancelTask(result.task.get());
1077   TestTileTaskRunner::CompleteTask(result.task.get());
1078
1079   // 2 Unrefs, so that the decode is unlocked as well.
1080   cache->UnrefImage(draw_image);
1081   cache->UnrefImage(draw_image);
1082
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());
1090
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());
1094
1095   // Unref!
1096   cache->UnrefImage(draw_image);
1097 }
1098
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]);
1110
1111   // Cancel the upload.
1112   TestTileTaskRunner::CancelTask(result.task.get());
1113   TestTileTaskRunner::CompleteTask(result.task.get());
1114
1115   // Unref the image.
1116   cache->UnrefImage(draw_image);
1117
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());
1121 }
1122
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);
1132
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());
1137
1138   cache->SetImageDecodingFailedForTesting(draw_image);
1139
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);
1144
1145   cache->UnrefImage(draw_image);
1146 }
1147
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]);
1159
1160   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1161   TestTileTaskRunner::ProcessTask(result.task.get());
1162
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));
1172
1173   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1174   cache->UnrefImage(draw_image);
1175 }
1176
1177 TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToHdr) {
1178   auto cache = CreateCache();
1179   auto color_space = gfx::ColorSpace::CreateHDR10();
1180   auto size = GetNormalImageSize();
1181   auto info =
1182       SkImageInfo::Make(size.width(), size.height(), kRGBA_F16_SkColorType,
1183                         kPremul_SkAlphaType, color_space.ToSkColorSpace());
1184   SkBitmap bitmap;
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())
1191                          .TakePaintImage();
1192
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]);
1205
1206   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1207   TestTileTaskRunner::ProcessTask(result.task.get());
1208
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());
1217
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);
1223
1224   EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1225
1226   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1227   cache->UnrefImage(draw_image);
1228 }
1229
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());
1237   SkBitmap bitmap;
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())
1244                          .TakePaintImage();
1245
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]);
1256
1257   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1258   TestTileTaskRunner::ProcessTask(result.task.get());
1259
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);
1269
1270   EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1271
1272   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1273   cache->UnrefImage(draw_image);
1274 }
1275
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);
1285
1286   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1287   TestTileTaskRunner::ProcessTask(result.task.get());
1288
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));
1299
1300   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1301   cache->UnrefImage(draw_image);
1302   EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1303 }
1304
1305 TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
1306   auto cache = CreateCache();
1307   cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
1308
1309   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1310   DrawImage draw_image =
1311       CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
1312
1313   ImageDecodeCache::TaskResult result =
1314       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1315   EXPECT_FALSE(result.need_unref);
1316   EXPECT_FALSE(result.task);
1317
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));
1328
1329   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1330
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);
1334 }
1335
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);
1346
1347   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1348   TestTileTaskRunner::ProcessTask(result.task.get());
1349
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);
1356
1357   TestTileTaskRunner::ProcessTask(larger_result.task->dependencies()[0].get());
1358   TestTileTaskRunner::ProcessTask(larger_result.task.get());
1359
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));
1369
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));
1376
1377   EXPECT_FALSE(decoded_draw_image.image() == larger_decoded_draw_image.image());
1378
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);
1383 }
1384
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);
1396
1397   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1398   TestTileTaskRunner::ProcessTask(result.task.get());
1399
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());
1407
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));
1417
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));
1423
1424   EXPECT_FALSE(decoded_draw_image.image() == larger_decoded_draw_image.image());
1425
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);
1431 }
1432
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);
1442
1443   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1444   TestTileTaskRunner::ProcessTask(result.task.get());
1445
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));
1461
1462   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1463   cache->UnrefImage(draw_image);
1464 }
1465
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);
1477
1478   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1479   TestTileTaskRunner::ProcessTask(result.task.get());
1480
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());
1491
1492   EXPECT_EQ(decoded_draw_image.filter_quality(),
1493             PaintFlags::FilterQuality::kMedium);
1494
1495   EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
1496   EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
1497       cache->DiscardableIsLockedForTesting(draw_image));
1498
1499   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1500   cache->UnrefImage(draw_image);
1501   EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1502 }
1503
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 */);
1508
1509   PaintImage image = CreatePaintImageInternal(test_image_size);
1510   DrawImage draw_image = CreateDrawImageInternal(image);
1511
1512   ImageDecodeCache::TaskResult result =
1513       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1514   EXPECT_FALSE(result.need_unref);
1515   EXPECT_FALSE(result.task);
1516
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);
1527
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);
1539 }
1540
1541 TEST_P(GpuImageDecodeCacheTest,
1542        GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
1543   auto cache = CreateCache();
1544   cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
1545
1546   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1547   DrawImage draw_image =
1548       CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
1549
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));
1559
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());
1565
1566   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1567   cache->DrawWithImageFinished(draw_image, another_decoded_draw_image);
1568
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);
1572 }
1573
1574 TEST_P(GpuImageDecodeCacheTest,
1575        GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) {
1576   auto cache = CreateCache();
1577   cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
1578
1579   PaintImage image = CreateLargePaintImageForSoftwareFallback();
1580   DrawImage draw_image = CreateDrawImageInternal(image);
1581
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));
1592
1593   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1594   EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1595
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));
1603
1604   cache->DrawWithImageFinished(draw_image, second_decoded_draw_image);
1605   EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
1606 }
1607
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)));
1613
1614   ImageDecodeCache::TaskResult result =
1615       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1616   EXPECT_FALSE(result.task);
1617   EXPECT_FALSE(result.need_unref);
1618
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());
1625
1626   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1627 }
1628
1629 TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
1630   auto cache = CreateCache();
1631   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1632   DrawImage draw_image(
1633       image, false,
1634       SkIRect::MakeXYWH(image.width() + 1, image.height() + 1, image.width(),
1635                         image.height()),
1636       PaintFlags::FilterQuality::kMedium, CreateMatrix(SkSize::Make(1.f, 1.f)),
1637       PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
1638
1639   ImageDecodeCache::TaskResult result =
1640       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
1641   EXPECT_FALSE(result.task);
1642   EXPECT_FALSE(result.need_unref);
1643
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());
1650
1651   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
1652 }
1653
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);
1661
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);
1667
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());
1672
1673   cache->UnrefImage(draw_image);
1674   EXPECT_EQ(0u, cache->GetWorkingSetBytesForTesting());
1675 }
1676
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)));
1682   {
1683     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1684         draw_image, ImageDecodeCache::TracingInfo());
1685     EXPECT_TRUE(result.need_unref);
1686     EXPECT_TRUE(result.task);
1687
1688     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1689     TestTileTaskRunner::ProcessTask(result.task.get());
1690
1691     cache->UnrefImage(draw_image);
1692
1693     // We should now have data image in our cache.
1694     EXPECT_GT(cache->GetNumCacheEntriesForTesting(), 0u);
1695
1696     // Tell our cache to aggressively free resources.
1697     cache->SetShouldAggressivelyFreeResources(true);
1698     EXPECT_EQ(0u, cache->GetNumCacheEntriesForTesting());
1699   }
1700
1701   // Attempting to upload a new image should succeed, but the image should not
1702   // be cached past its use.
1703   {
1704     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1705         draw_image, ImageDecodeCache::TracingInfo());
1706     EXPECT_TRUE(result.need_unref);
1707     EXPECT_TRUE(result.task);
1708
1709     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1710     TestTileTaskRunner::ProcessTask(result.task.get());
1711     cache->UnrefImage(draw_image);
1712
1713     EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
1714   }
1715
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);
1719   {
1720     ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
1721         draw_image, ImageDecodeCache::TracingInfo());
1722     EXPECT_TRUE(result.need_unref);
1723     EXPECT_TRUE(result.task);
1724
1725     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1726     TestTileTaskRunner::ProcessTask(result.task.get());
1727     cache->UnrefImage(draw_image);
1728
1729     EXPECT_GT(cache->GetNumCacheEntriesForTesting(), 0u);
1730   }
1731 }
1732
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);
1743
1744   // The budget should account for exactly one image.
1745   EXPECT_EQ(cache->GetWorkingSetBytesForTesting(),
1746             cache->GetDrawImageSizeForTesting(first_draw_image));
1747
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());
1757
1758   TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
1759   TestTileTaskRunner::ProcessTask(second_result.task.get());
1760
1761   cache->UnrefImage(second_draw_image);
1762
1763   // Unref the first image, it was orphaned, so it should be immediately
1764   // deleted.
1765   TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
1766   TestTileTaskRunner::ProcessTask(first_result.task.get());
1767   cache->UnrefImage(first_draw_image);
1768
1769   // The cache should have exactly one image.
1770   EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
1771   EXPECT_EQ(0u, cache->GetInUseCacheEntriesForTesting());
1772 }
1773
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);
1784
1785   TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get());
1786   TestTileTaskRunner::ProcessTask(first_result.task.get());
1787   cache->UnrefImage(first_draw_image);
1788
1789   // The budget should account for exactly one image.
1790   EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
1791   EXPECT_EQ(cache->GetInUseCacheEntriesForTesting(), 0u);
1792
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());
1801
1802   TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get());
1803   TestTileTaskRunner::ProcessTask(second_result.task.get());
1804
1805   cache->UnrefImage(second_draw_image);
1806
1807   // The budget should account for exactly one image.
1808   EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
1809   EXPECT_EQ(cache->GetInUseCacheEntriesForTesting(), 0u);
1810 }
1811
1812 TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
1813   auto cache = CreateCache();
1814   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
1815   SkM44 matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
1816
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);
1825
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());
1834
1835   // Get the same image at PaintFlags::FilterQuality::kHigh. We should re-use
1836   // medium.
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());
1845
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());
1850
1851   cache->UnrefImage(low_draw_image);
1852   cache->UnrefImage(medium_draw_image);
1853   cache->UnrefImage(high_quality_draw_image);
1854 }
1855
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);
1867
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());
1873
1874   cache->UnrefImage(draw_image);
1875
1876   // Must hold context lock before calling GetDecodedImageForDraw /
1877   // DrawWithImageFinished.
1878   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
1879
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);
1886 }
1887
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);
1895
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));
1901
1902   // Run the decode task.
1903   TestTileTaskRunner::ProcessTask(result.task.get());
1904
1905   // The image should remain in the cache till we unref it.
1906   EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
1907   cache->UnrefImage(draw_image);
1908 }
1909
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]);
1923
1924   // Run the task.
1925   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
1926   TestTileTaskRunner::ProcessTask(result.task.get());
1927
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);
1933
1934   // Unref both images.
1935   cache->UnrefImage(draw_image);
1936   cache->UnrefImage(draw_image);
1937
1938   // Ensure the unref is processed:
1939   cache->ReduceCacheUsage();
1940
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]);
1949
1950   TestTileTaskRunner::ProcessTask(third_result.task->dependencies()[0].get());
1951   TestTileTaskRunner::ProcessTask(third_result.task.get());
1952
1953   cache->UnrefImage(draw_image);
1954 }
1955
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);
1962
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());
1969
1970   // Add an image to the cache and un-ref it.
1971   {
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]);
1978
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);
1983   }
1984
1985   // Request the same image - it should be cached.
1986   {
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);
1992   }
1993
1994   // Add a new image to the cache It should push out the old one.
1995   {
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]);
2002
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);
2007   }
2008
2009   // Request the second image - it should be cached.
2010   {
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);
2016   }
2017
2018   // Request the first image - it should have been evicted and return a new
2019   // task.
2020   {
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]);
2027
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);
2032   }
2033 }
2034
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);
2047   }
2048
2049   // We should now have images in our cache.
2050   EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 10u);
2051
2052   // Tell our cache to clear resources.
2053   cache->ClearCache();
2054
2055   // We should now have nothing in our cache.
2056   EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u);
2057 }
2058
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());
2070
2071   // We should now have data image in our cache.
2072   EXPECT_GT(cache->GetWorkingSetBytesForTesting(), 0u);
2073   EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
2074
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);
2081
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);
2086 }
2087
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();
2092
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);
2100
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());
2108
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());
2115
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());
2120
2121   cache->UnrefImage(first_draw_image);
2122   cache->UnrefImage(second_draw_image);
2123   cache->UnrefImage(third_draw_image);
2124 }
2125
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);
2136
2137   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2138   TestTileTaskRunner::ProcessTask(result.task.get());
2139
2140   cache->UnrefImage(draw_image);
2141 }
2142
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)),
2150   };
2151   const gfx::Size test_image_size = GetNormalImageSize();
2152   SkImageInfo info =
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_);
2159     generator =
2160         sk_make_sp<FakePaintImageGenerator>(info, yuva_pixmap_info, frames);
2161   } else {
2162     generator = sk_make_sp<FakePaintImageGenerator>(info, frames);
2163   }
2164   PaintImage image = PaintImageBuilder::WithDefault()
2165                          .set_id(PaintImage::GetNextId())
2166                          .set_paint_image_generator(generator)
2167                          .TakePaintImage();
2168
2169   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2170
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);
2182
2183   // Scaled.
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);
2187   decoded_image =
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);
2194
2195   // Subset.
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());
2203   decoded_image =
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);
2210 }
2211
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);
2222
2223   // The cache should have exactly one image.
2224   EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2225
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());
2234
2235   // The cache should have two images.
2236   EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2237
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);
2245
2246   // The cache should have exactly one image.
2247   EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2248
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);
2253
2254   // The cache should have exactly one image.
2255   EXPECT_EQ(1u, cache->GetNumCacheEntriesForTesting());
2256   EXPECT_EQ(0u, cache->GetInUseCacheEntriesForTesting());
2257 }
2258
2259 TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
2260   auto cache = CreateCache();
2261   const gfx::Size test_image_size = GetNormalImageSize();
2262
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);
2267
2268   // Allow a single small image and lock it.
2269   cache->SetWorkingSetLimitsForTesting(bytes_for_test_image,
2270                                        1u /* max_items */);
2271
2272   ImageDecodeCache::TaskResult result =
2273       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2274   EXPECT_TRUE(result.need_unref);
2275   EXPECT_TRUE(result.task);
2276
2277   // Try locking the same image again, its already budgeted so it shouldn't be
2278   // at-raster.
2279   result =
2280       cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
2281   EXPECT_TRUE(result.need_unref);
2282   EXPECT_TRUE(result.task);
2283
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);
2293 }
2294
2295 TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
2296   auto cache = CreateCache();
2297   const gfx::Size test_image_size = GetNormalImageSize();
2298
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);
2307
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());
2314
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);
2319
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());
2330
2331   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2332   cache->DrawWithImageFinished(second_draw_image, second_decoded_draw_image);
2333 }
2334
2335 TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
2336   auto cache = CreateCache();
2337   const gfx::Size test_image_size = GetNormalImageSize();
2338
2339   PaintImage image = CreatePaintImageInternal(test_image_size);
2340   DrawImage draw_image = CreateDrawImageInternal(image);
2341
2342   const size_t bytes_for_test_image =
2343       GetBytesNeededForSingleImage(test_image_size);
2344
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 */);
2349
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());
2356
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);
2360
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());
2371
2372   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2373   cache->DrawWithImageFinished(second_draw_image, second_decoded_draw_image);
2374 }
2375
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();
2382
2383   PaintImage image =
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);
2391
2392   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2393   TestTileTaskRunner::ProcessTask(result.task.get());
2394
2395   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2396   DecodedDrawImage decoded_draw_image =
2397       cache->GetDecodedImageForDraw(draw_image);
2398
2399   sk_sp<SkColorSpace> target_color_space = cache->SupportsColorSpaceConversion()
2400                                                ? color_space.ToSkColorSpace()
2401                                                : nullptr;
2402
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();
2407     ASSERT_TRUE(image);
2408     EXPECT_FALSE(service_image->isTextureBacked());
2409     EXPECT_EQ(image.width(), service_image->width());
2410     EXPECT_EQ(image.height(), service_image->height());
2411
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()));
2415   } else {
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()
2425                                          : nullptr));
2426   }
2427
2428   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2429   cache->UnrefImage(draw_image);
2430 }
2431
2432 TEST_P(GpuImageDecodeCacheTest,
2433        ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) {
2434   auto cache = CreateCache();
2435   gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
2436
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);
2444
2445   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2446   TestTileTaskRunner::ProcessTask(result.task.get());
2447
2448   viz::ContextProvider::ScopedContextLock context_lock(context_provider());
2449   DecodedDrawImage decoded_draw_image =
2450       cache->GetDecodedImageForDraw(draw_image);
2451
2452   sk_sp<SkColorSpace> target_color_space = cache->SupportsColorSpaceConversion()
2453                                                ? color_space.ToSkColorSpace()
2454                                                : nullptr;
2455
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();
2460     ASSERT_TRUE(image);
2461     EXPECT_TRUE(service_image->isTextureBacked());
2462     EXPECT_EQ(image.width(), service_image->width());
2463     EXPECT_EQ(image.height(), service_image->height());
2464
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()));
2469     }
2470   } else {
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()));
2474   }
2475
2476   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2477   cache->UnrefImage(draw_image);
2478 }
2479
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.
2483     return;
2484   }
2485   auto cache = CreateCache();
2486
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
2496   // cached
2497   EXPECT_FALSE(cache->GetSWImageDecodeForTesting(draw_image));
2498 }
2499
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.
2503     return;
2504   }
2505   auto cache = CreateCache();
2506
2507   PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
2508   DrawImage draw_image = CreateDrawImageInternal(image);
2509   auto result =
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());
2515
2516   cache->UnrefImage(draw_image);
2517 }
2518
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.
2522     return;
2523   }
2524   auto cache = CreateCache();
2525
2526   PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
2527   DrawImage draw_image = CreateDrawImageInternal(image);
2528   auto result =
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());
2535
2536   cache->UnrefImage(draw_image);
2537 }
2538
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.
2542     return;
2543   }
2544   auto cache = CreateCache();
2545
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);
2558 }
2559
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.
2563     return;
2564   }
2565   auto cache = CreateCache();
2566
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);
2576 }
2577
2578 TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) {
2579   auto cache = CreateCache();
2580
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;
2585
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));
2593
2594     draw_images.push_back(draw_image);
2595     decoded_draw_images.push_back(decoded_draw_image);
2596
2597     if (i == 0)
2598       continue;
2599
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]));
2606   }
2607
2608   for (int i = 0; i < 10; ++i) {
2609     cache->DrawWithImageFinished(draw_images[i], decoded_draw_images[i]);
2610   }
2611
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);
2617 }
2618
2619 TEST_P(GpuImageDecodeCacheTest, DecodeToScale) {
2620   if (do_yuv_decode_) {
2621     // TODO(crbug.com/927437): Modify test after decoding to scale for YUV is
2622     // implemented.
2623     return;
2624   }
2625   auto cache = CreateCache();
2626
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)
2640                                .TakePaintImage();
2641
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);
2653
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);
2658
2659   cache->DrawWithImageFinished(draw_image, decoded_image);
2660 }
2661
2662 TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) {
2663   if (do_yuv_decode_) {
2664     // TODO(crbug.com/927437): Modify test after decoding to scale for YUV is
2665     // implemented.
2666     return;
2667   }
2668   auto cache = CreateCache();
2669
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)
2683                                .TakePaintImage();
2684
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);
2697
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);
2703 }
2704
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();
2710
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);
2718
2719     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2720     TestTileTaskRunner::ProcessTask(result.task.get());
2721
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
2726     // it attached.
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());
2735
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);
2742     } else {
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());
2748     }
2749     cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2750     cache->UnrefImage(draw_image);
2751   };
2752
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);
2772 }
2773
2774 TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
2775   auto cache = CreateCache();
2776
2777   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
2778
2779   // Create an image with no scaling. It will not have mips.
2780   {
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);
2786
2787     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2788     TestTileTaskRunner::ProcessTask(result.task.get());
2789
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
2794     // it attached.
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());
2803
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 */);
2812     } else {
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());
2818     }
2819     cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2820     cache->UnrefImage(draw_image);
2821   }
2822
2823   // Call ReduceCacheUsage to clean up.
2824   cache->ReduceCacheUsage();
2825
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
2828   // added.
2829   {
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);
2836
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
2841     // it attached.
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));
2848
2849     EXPECT_TRUE(decoded_draw_image.image());
2850     EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
2851
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 */);
2860     } else {
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());
2865     }
2866     cache->DrawWithImageFinished(draw_image, decoded_draw_image);
2867     cache->UnrefImage(draw_image);
2868   }
2869 }
2870
2871 TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
2872   auto cache = CreateCache();
2873   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
2874
2875   struct Decode {
2876     DrawImage image;
2877     DecodedDrawImage decoded_image;
2878   };
2879   std::vector<Decode> images_to_unlock;
2880
2881   // Create an image with no scaling. It will not have mips.
2882   {
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);
2888
2889     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
2890     TestTileTaskRunner::ProcessTask(result.task.get());
2891
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
2896     // it attached.
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());
2905
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 */);
2914     } else {
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());
2919     }
2920     images_to_unlock.push_back({draw_image, decoded_draw_image});
2921   }
2922
2923   // Second decode with mips.
2924   {
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);
2931
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
2936     // it attached.
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));
2943
2944     ASSERT_TRUE(decoded_draw_image.image());
2945     ASSERT_TRUE(decoded_draw_image.image()->isTextureBacked());
2946
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 */);
2955     } else {
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());
2960     }
2961     images_to_unlock.push_back({draw_image, decoded_draw_image});
2962   }
2963
2964   // Reduce cache usage to make sure anything marked for deletion is actually
2965   // deleted.
2966   cache->ReduceCacheUsage();
2967
2968   {
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))
2979                                        .get();
2980             discardable_manager_.ExpectLocked(
2981                 GpuImageDecodeCache::GlIdFromSkImage(plane_image));
2982           }
2983         } else {
2984           discardable_manager_.ExpectLocked(
2985               GpuImageDecodeCache::GlIdFromSkImage(
2986                   draw_and_decoded_draw_image.decoded_image.image().get()));
2987         }
2988       }
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);
2992     }
2993   }
2994 }
2995
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
3005     // planes.
3006     return;
3007   }
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);
3013
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);
3023
3024     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3025     TestTileTaskRunner::ProcessTask(result.task.get());
3026
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
3031     // it attached.
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());
3040
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
3043     // uploaded planes.
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,
3051                              plane_sizes);
3052
3053     cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3054     cache->UnrefImage(draw_image);
3055   };
3056
3057   yuv_format_ = YUVSubsampling::k420;
3058   decode_and_check_plane_sizes();
3059
3060   yuv_format_ = YUVSubsampling::k422;
3061   decode_and_check_plane_sizes();
3062
3063   yuv_format_ = YUVSubsampling::k444;
3064   decode_and_check_plane_sizes();
3065 }
3066
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
3075     // planes.
3076     return;
3077   }
3078
3079   auto decode_and_check_plane_sizes = [this](
3080                                           GpuImageDecodeCache* cache,
3081                                           bool decodes_to_yuv,
3082                                           SkYUVAPixmapInfo::DataType
3083                                               yuv_data_type = SkYUVAPixmapInfo::
3084                                                   DataType::kUnorm8,
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);
3090
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()
3098                              : nullptr;
3099
3100     // An unknown SkColorType means we expect fallback to RGB.
3101     PaintImage image =
3102         decodes_to_yuv ? CreatePaintImageInternal(GetNormalImageSize(),
3103                                                   decoded_cs.ToSkColorSpace())
3104                        : CreatePaintImageForFallbackToRGB(GetNormalImageSize());
3105
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;
3110
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);
3119
3120     TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3121     TestTileTaskRunner::ProcessTask(result.task.get());
3122
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
3127     // it attached.
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());
3136
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();
3142
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
3146       // uploaded planes.
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_);
3152
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());
3157
3158       auto expected_image_cs =
3159           cache->SupportsColorSpaceConversion() && sk_decoded_cs
3160               ? target_color_params.color_space.ToSkColorSpace()
3161               : nullptr;
3162       if (expected_image_cs) {
3163         EXPECT_TRUE(SkColorSpace::Equals(
3164             expected_image_cs.get(), decoded_draw_image.image()->colorSpace()));
3165       }
3166     } else {
3167       if (use_transfer_cache_) {
3168         EXPECT_FALSE(transfer_cache_helper_
3169                          .GetEntryAs<ServiceImageTransferCacheEntry>(
3170                              *transfer_cache_entry_id)
3171                          ->is_yuv());
3172       } else {
3173         for (size_t plane = 0; plane < kNumYUVPlanes; ++plane)
3174           EXPECT_FALSE(cache->GetUploadedPlaneForTesting(
3175               draw_image, static_cast<YUVIndex>(plane)));
3176       }
3177     }
3178
3179     cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3180     cache->UnrefImage(draw_image);
3181   };
3182
3183   gpu::Capabilities original_caps;
3184   {
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();
3189   }
3190
3191   const auto hdr_cs = gfx::ColorSpace::CreateHDR10();
3192
3193   // Test that decoding to R16 works when supported.
3194   {
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();
3200
3201     yuv_data_type_ = SkYUVAPixmapInfo::DataType::kUnorm16;
3202
3203     yuv_format_ = YUVSubsampling::k420;
3204     decode_and_check_plane_sizes(r16_cache.get(), true,
3205                                  SkYUVAPixmapInfo::DataType::kUnorm16,
3206                                  DefaultColorSpace());
3207
3208     yuv_format_ = YUVSubsampling::k422;
3209     decode_and_check_plane_sizes(r16_cache.get(), true,
3210                                  SkYUVAPixmapInfo::DataType::kUnorm16,
3211                                  DefaultColorSpace());
3212
3213     yuv_format_ = YUVSubsampling::k444;
3214     decode_and_check_plane_sizes(r16_cache.get(), true,
3215                                  SkYUVAPixmapInfo::DataType::kUnorm16,
3216                                  DefaultColorSpace());
3217
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);
3222
3223     yuv_format_ = YUVSubsampling::k422;
3224     decode_and_check_plane_sizes(r16_cache.get(), true,
3225                                  SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
3226
3227     yuv_format_ = YUVSubsampling::k444;
3228     decode_and_check_plane_sizes(r16_cache.get(), true,
3229                                  SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
3230   }
3231
3232   // Test that decoding to half-float works when supported.
3233   {
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();
3239
3240     yuv_data_type_ = SkYUVAPixmapInfo::DataType::kFloat16;
3241
3242     yuv_format_ = YUVSubsampling::k420;
3243     decode_and_check_plane_sizes(f16_cache.get(), true,
3244                                  SkYUVAPixmapInfo::DataType::kFloat16,
3245                                  DefaultColorSpace());
3246
3247     yuv_format_ = YUVSubsampling::k422;
3248     decode_and_check_plane_sizes(f16_cache.get(), true,
3249                                  SkYUVAPixmapInfo::DataType::kFloat16,
3250                                  DefaultColorSpace());
3251
3252     yuv_format_ = YUVSubsampling::k444;
3253     decode_and_check_plane_sizes(f16_cache.get(), true,
3254                                  SkYUVAPixmapInfo::DataType::kFloat16,
3255                                  DefaultColorSpace());
3256
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);
3261
3262     yuv_format_ = YUVSubsampling::k422;
3263     decode_and_check_plane_sizes(f16_cache.get(), true,
3264                                  SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
3265
3266     yuv_format_ = YUVSubsampling::k444;
3267     decode_and_check_plane_sizes(f16_cache.get(), true,
3268                                  SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
3269   }
3270
3271   // Verify YUV16 is unsupported when neither R16 or half-float are available.
3272   {
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();
3278
3279     yuv_data_type_ = SkYUVAPixmapInfo::DataType::kUnorm16;
3280
3281     yuv_format_ = YUVSubsampling::k420;
3282     decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3283
3284     yuv_format_ = YUVSubsampling::k422;
3285     decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3286
3287     yuv_format_ = YUVSubsampling::k444;
3288     decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3289
3290     yuv_data_type_ = SkYUVAPixmapInfo::DataType::kFloat16;
3291
3292     yuv_format_ = YUVSubsampling::k420;
3293     decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3294
3295     yuv_format_ = YUVSubsampling::k422;
3296     decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3297
3298     yuv_format_ = YUVSubsampling::k444;
3299     decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
3300   }
3301 }
3302
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
3309   // levels.
3310   if (!do_yuv_decode_) {
3311     // The YUV case may choose different mip levels between chroma and luma
3312     // planes.
3313     return;
3314   }
3315   auto owned_cache = CreateCache();
3316   auto decode_and_check_plane_sizes =
3317       [this, cache = owned_cache.get()](
3318           SkSize scaled_size,
3319           const SkISize mipped_plane_sizes[SkYUVAInfo::kMaxPlanes]) {
3320         PaintFlags::FilterQuality filter_quality =
3321             PaintFlags::FilterQuality::kMedium;
3322
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);
3333
3334         TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3335         TestTileTaskRunner::ProcessTask(result.task.get());
3336
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
3342         // has it attached.
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());
3351
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);
3360
3361         cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3362         cache->UnrefImage(draw_image);
3363       };
3364
3365   gfx::Size image_size = GetNormalImageSize();
3366   SkISize mipped_plane_sizes[kNumYUVPlanes];
3367
3368   SkSize less_than_half_scale = SkSize::Make(0.45f, 0.45f);
3369
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)];
3378
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
3381   // scaling.
3382   yuv_format_ = YUVSubsampling::k420;
3383   decode_and_check_plane_sizes(less_than_half_scale, mipped_plane_sizes);
3384
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);
3388
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);
3392
3393   // Now try at 1/4 scale.
3394   SkSize one_quarter_scale = SkSize::Make(0.20f, 0.20f);
3395
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)];
3404
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
3407   // scaling.
3408   yuv_format_ = YUVSubsampling::k420;
3409   decode_and_check_plane_sizes(one_quarter_scale, mipped_plane_sizes);
3410
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);
3414
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);
3418 }
3419
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();
3424
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());
3430
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]);
3435
3436   TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
3437   TestTileTaskRunner::ProcessTask(result.task.get());
3438
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));
3448
3449   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3450   cache->UnrefImage(draw_image);
3451 }
3452
3453 TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeForBitmaps) {
3454   auto cache = CreateCache();
3455
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);
3465 }
3466
3467 TEST_P(GpuImageDecodeCacheTest, DarkModeDecodedDrawImage) {
3468   // TODO(prashant.n): Remove this once dark mode is supported for YUV decodes.
3469   if (do_yuv_decode_)
3470     return;
3471
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);
3477
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);
3485 }
3486
3487 TEST_P(GpuImageDecodeCacheTest, DarkModeImageCacheSize) {
3488   // TODO(prashant.n): Remove this once dark mode is supported for YUV decodes.
3489   if (do_yuv_decode_)
3490     return;
3491
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));
3497
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);
3508
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);
3513
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);
3523
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);
3531
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);
3542
3543   // The cache for image1 related draw images should be intact.
3544   EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image13), 2u);
3545
3546   cache->UnrefImage(draw_image11);
3547   cache->UnrefImage(draw_image12);
3548   cache->UnrefImage(draw_image13);
3549   cache->UnrefImage(draw_image21);
3550 }
3551
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);
3557
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());
3563
3564   // Draw image without dark mode bit set should not need dark mode filter.
3565   EXPECT_FALSE(
3566       cache->NeedsDarkModeFilterForTesting(draw_image_without_dark_mode));
3567
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
3571     // decodes.
3572     EXPECT_FALSE(
3573         cache->NeedsDarkModeFilterForTesting(draw_image_with_dark_mode));
3574   } else {
3575     EXPECT_TRUE(
3576         cache->NeedsDarkModeFilterForTesting(draw_image_with_dark_mode));
3577   }
3578
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());
3582
3583   // Draw image with dark mode, but dark mode already applied.
3584   EXPECT_FALSE(cache->NeedsDarkModeFilterForTesting(draw_image_with_dark_mode));
3585
3586   cache->UnrefImage(draw_image_with_dark_mode);
3587 }
3588
3589 TEST_P(GpuImageDecodeCacheTest, ClippedAndScaledDrawImageRemovesCacheEntry) {
3590   auto cache = CreateCache();
3591   cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
3592
3593   PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
3594   DrawImage draw_image =
3595       CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
3596
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));
3605
3606   cache->DrawWithImageFinished(draw_image, decoded_draw_image);
3607   // One entry should be cached
3608   EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 1u);
3609
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());
3617
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);
3622 }
3623
3624 SkColorType test_color_types[] = {kN32_SkColorType, kARGB_4444_SkColorType,
3625                                   kRGBA_F16_SkColorType};
3626
3627 INSTANTIATE_TEST_SUITE_P(
3628     GpuImageDecodeCacheTestsInProcessRaster,
3629     GpuImageDecodeCacheTest,
3630     testing::Combine(
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 */));
3639
3640 INSTANTIATE_TEST_SUITE_P(
3641     GpuImageDecodeCacheTestsOOPR,
3642     GpuImageDecodeCacheTest,
3643     testing::Combine(
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 */));
3652
3653 class GpuImageDecodeCacheWithAcceleratedDecodesTest
3654     : public GpuImageDecodeCacheTest {
3655  public:
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;
3668
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);
3677     } else {
3678       generator = sk_make_sp<FakePaintImageGenerator>(info);
3679     }
3680     generator->SetImageHeaderMetadata(image_data);
3681     PaintImage image = PaintImageBuilder::WithDefault()
3682                            .set_id(PaintImage::GetNextId())
3683                            .set_paint_image_generator(generator)
3684                            .TakePaintImage();
3685     return image;
3686   }
3687
3688   StrictMock<MockRasterImplementation>* raster_implementation() const {
3689     return static_cast<StrictMock<MockRasterImplementation>*>(
3690         context_provider_->RasterInterface());
3691   }
3692 };
3693
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);
3717
3718     // Accelerated decodes should not produce decode tasks.
3719     ASSERT_TRUE(result.task->dependencies().empty());
3720     ASSERT_TRUE(image.GetImageHeaderMetadata());
3721     EXPECT_CALL(
3722         *raster_implementation(),
3723         DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size, _,
3724                               gfx::ColorSpace(), _))
3725         .Times(1);
3726     TestTileTaskRunner::ProcessTask(result.task.get());
3727
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);
3736   }
3737 }
3738
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);
3755
3756   // Accelerated decodes should not produce decode tasks.
3757   ASSERT_TRUE(result.task->dependencies().empty());
3758   ASSERT_TRUE(image.GetImageHeaderMetadata());
3759   EXPECT_CALL(
3760       *raster_implementation(),
3761       DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size, _,
3762                             cache->SupportsColorSpaceConversion()
3763                                 ? target_color_params.color_space
3764                                 : gfx::ColorSpace(),
3765                             _))
3766       .Times(1);
3767   TestTileTaskRunner::ProcessTask(result.task.get());
3768
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);
3777 }
3778
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);
3795
3796   // Accelerated decodes should not produce decode tasks.
3797   ASSERT_TRUE(result.task->dependencies().empty());
3798   raster_implementation()->SetAcceleratedDecodingFailed();
3799   ASSERT_TRUE(image.GetImageHeaderMetadata());
3800   EXPECT_CALL(
3801       *raster_implementation(),
3802       DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size, _,
3803                             cache->SupportsColorSpaceConversion()
3804                                 ? target_color_params.color_space
3805                                 : gfx::ColorSpace(),
3806                             _))
3807       .Times(1);
3808   TestTileTaskRunner::ProcessTask(result.task.get());
3809
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);
3817
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);
3826 }
3827
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);
3844
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);
3849 }
3850
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);
3867
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);
3874 }
3875
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);
3892
3893   // Accelerated decodes should not produce decode tasks.
3894   ASSERT_TRUE(result.task->dependencies().empty());
3895
3896   // Cancel the upload.
3897   TestTileTaskRunner::CancelTask(result.task.get());
3898   TestTileTaskRunner::CompleteTask(result.task.get());
3899
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(), _))
3911       .Times(1);
3912   TestTileTaskRunner::ProcessTask(another_result.task.get());
3913
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);
3923 }
3924
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);
3943
3944   // Must hold context lock before calling GetDecodedImageForDraw /
3945   // DrawWithImageFinished.
3946   EXPECT_CALL(*raster_implementation(),
3947               DoScheduleImageDecode(image.GetImageHeaderMetadata()->image_size,
3948                                     _, gfx::ColorSpace(), _))
3949       .Times(1);
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);
3955 }
3956
3957 INSTANTIATE_TEST_SUITE_P(
3958     GpuImageDecodeCacheTestsOOPR,
3959     GpuImageDecodeCacheWithAcceleratedDecodesTest,
3960     testing::Combine(
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 */));
3969
3970 class GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest
3971     : public GpuImageDecodeCacheWithAcceleratedDecodesTest {};
3972
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());
3979
3980   // Try a JPEG image.
3981   const PaintImage jpeg_image =
3982       CreatePaintImageForDecodeAcceleration(ImageType::kJPEG);
3983   DrawImage jpeg_draw_image(
3984       jpeg_image, false,
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());
4004     EXPECT_CALL(
4005         *raster_implementation(),
4006         DoScheduleImageDecode(jpeg_image.GetImageHeaderMetadata()->image_size,
4007                               _, gfx::ColorSpace(), _))
4008         .Times(1);
4009   } else {
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());
4013   }
4014   TestTileTaskRunner::ScheduleTask(jpeg_task.task.get());
4015
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);
4024
4025   TestTileTaskRunner::RunTask(jpeg_task.task.get());
4026   TestTileTaskRunner::CompleteTask(jpeg_task.task.get());
4027   testing::Mock::VerifyAndClearExpectations(raster_implementation());
4028
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);
4040
4041   // Try a WebP image.
4042   const PaintImage webp_image =
4043       CreatePaintImageForDecodeAcceleration(ImageType::kWEBP);
4044   DrawImage webp_draw_image(
4045       webp_image, false,
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());
4058     EXPECT_CALL(
4059         *raster_implementation(),
4060         DoScheduleImageDecode(webp_image.GetImageHeaderMetadata()->image_size,
4061                               _, gfx::ColorSpace(), _))
4062         .Times(1);
4063   } else {
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());
4067   }
4068   TestTileTaskRunner::ProcessTask(webp_task.task.get());
4069   testing::Mock::VerifyAndClearExpectations(raster_implementation());
4070
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);
4080
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(
4085       png_image, false,
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);
4099 }
4100
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 */));
4112
4113 #undef EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE
4114 #undef EXPECT_FALSE_IF_NOT_USING_TRANSFER_CACHE
4115
4116 }  // namespace
4117 }  // namespace cc