1 // Copyright 2017 The Chromium Authors. All rights reserved.
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 <memory>
6 #include <vector>
7 
8 #include "base/timer/lap_timer.h"
9 #include "cc/paint/draw_image.h"
10 #include "cc/paint/paint_image_builder.h"
11 #include "cc/raster/tile_task.h"
12 #include "cc/tiles/gpu_image_decode_cache.h"
13 #include "components/viz/test/test_in_process_context_provider.h"
14 #include "gpu/command_buffer/client/raster_interface.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/perf/perf_result_reporter.h"
17 #include "third_party/skia/include/core/SkSurface.h"
18 
19 namespace cc {
20 namespace {
21 
22 static const int kTimeLimitMillis = 2000;
23 static const int kWarmupRuns = 5;
24 static const int kTimeCheckInterval = 10;
25 static const int kCacheSize = 128 * 1024 * 1024;
26 
CreateImage(int width,int height)27 sk_sp<SkImage> CreateImage(int width, int height) {
28   SkBitmap bitmap;
29   bitmap.allocPixels(SkImageInfo::MakeS32(width, height, kPremul_SkAlphaType));
30   return SkImage::MakeFromBitmap(bitmap);
31 }
32 
CreateMatrix(const SkSize & scale)33 SkMatrix CreateMatrix(const SkSize& scale) {
34   SkMatrix matrix;
35   matrix.setScale(scale.width(), scale.height());
36   return matrix;
37 }
38 
39 enum class TestMode { kGpu, kTransferCache, kSw };
40 
41 class GpuImageDecodeCachePerfTest
42     : public testing::Test,
43       public testing::WithParamInterface<TestMode> {
44  public:
GpuImageDecodeCachePerfTest()45   GpuImageDecodeCachePerfTest()
46       : timer_(kWarmupRuns,
47                base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
48                kTimeCheckInterval),
49         context_provider_(
50             base::MakeRefCounted<viz::TestInProcessContextProvider>(
51                 /*gpu_rasterization=*/GetParam() != TestMode::kSw,
52                 /*oop_rasterization=*/UseTransferCache(),
53                 /*support_locking=*/false)) {}
54 
SetUp()55   void SetUp() override {
56     gpu::ContextResult result = context_provider_->BindToCurrentThread();
57     ASSERT_EQ(result, gpu::ContextResult::kSuccess);
58     cache_ = std::make_unique<GpuImageDecodeCache>(
59         context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType,
60         kCacheSize, MaxTextureSize(), PaintImage::kDefaultGeneratorClientId);
61   }
62 
63  protected:
MaxTextureSize() const64   size_t MaxTextureSize() const {
65     switch (GetParam()) {
66       case TestMode::kGpu:
67       case TestMode::kTransferCache:
68         return 4096;
69       case TestMode::kSw:
70         return 0;
71     }
72   }
73 
UseTransferCache() const74   bool UseTransferCache() const {
75     return GetParam() == TestMode::kTransferCache;
76   }
77 
ParamName() const78   const char* ParamName() const {
79     switch (GetParam()) {
80       case TestMode::kGpu:
81         return "GPU";
82       case TestMode::kTransferCache:
83         return "TransferCache";
84       case TestMode::kSw:
85         return "SW";
86     }
87   }
88 
SetUpReporter(const std::string & metric_suffix)89   perf_test::PerfResultReporter SetUpReporter(
90       const std::string& metric_suffix) {
91     perf_test::PerfResultReporter reporter("gpu_image_decode_cache",
92                                            ParamName());
93     reporter.RegisterImportantMetric(metric_suffix, "runs/s");
94     return reporter;
95   }
96 
97   base::LapTimer timer_;
98   scoped_refptr<viz::TestInProcessContextProvider> context_provider_;
99   std::unique_ptr<GpuImageDecodeCache> cache_;
100 };
101 
102 INSTANTIATE_TEST_SUITE_P(P,
103                          GpuImageDecodeCachePerfTest,
104                          testing::Values(TestMode::kGpu,
105                                          TestMode::kTransferCache,
106                                          TestMode::kSw));
107 
TEST_P(GpuImageDecodeCachePerfTest,DecodeWithColorConversion)108 TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) {
109   timer_.Reset();
110   do {
111     DrawImage image(
112         PaintImageBuilder::WithDefault()
113             .set_id(PaintImage::GetNextId())
114             .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
115             .TakePaintImage(),
116         SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
117         CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
118         gfx::ColorSpace::CreateXYZD50());
119 
120     DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
121     cache_->DrawWithImageFinished(image, decoded_image);
122     timer_.NextLap();
123   } while (!timer_.HasTimeLimitExpired());
124 
125   perf_test::PerfResultReporter reporter =
126       SetUpReporter("_with_color_conversion");
127   reporter.AddResult("_with_color_conversion", timer_.LapsPerSecond());
128 }
129 
130 using GpuImageDecodeCachePerfTestNoSw = GpuImageDecodeCachePerfTest;
131 INSTANTIATE_TEST_SUITE_P(P,
132                          GpuImageDecodeCachePerfTestNoSw,
133                          testing::Values(TestMode::kGpu,
134                                          TestMode::kTransferCache));
135 
TEST_P(GpuImageDecodeCachePerfTestNoSw,DecodeWithMips)136 TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) {
137   // Surface to render into.
138   auto surface = SkSurface::MakeRenderTarget(
139       context_provider_->GrContext(), SkBudgeted::kNo,
140       SkImageInfo::MakeN32Premul(2048, 2048));
141 
142   timer_.Reset();
143   do {
144     DrawImage image(
145         PaintImageBuilder::WithDefault()
146             .set_id(PaintImage::GetNextId())
147             .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
148             .TakePaintImage(),
149         SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
150         CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u, gfx::ColorSpace());
151 
152     DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
153 
154     if (GetParam() == TestMode::kGpu) {
155       SkPaint paint;
156       paint.setFilterQuality(kMedium_SkFilterQuality);
157       surface->getCanvas()->drawImageRect(decoded_image.image().get(),
158                                           SkRect::MakeWH(1024, 2048),
159                                           SkRect::MakeWH(614, 1229), &paint);
160       surface->flush();
161     }
162 
163     cache_->DrawWithImageFinished(image, decoded_image);
164     timer_.NextLap();
165   } while (!timer_.HasTimeLimitExpired());
166 
167   perf_test::PerfResultReporter reporter = SetUpReporter("_with_mips");
168   reporter.AddResult("_with_mips", timer_.LapsPerSecond());
169 }
170 
TEST_P(GpuImageDecodeCachePerfTest,AcquireExistingImages)171 TEST_P(GpuImageDecodeCachePerfTest, AcquireExistingImages) {
172   timer_.Reset();
173   DrawImage image(
174       PaintImageBuilder::WithDefault()
175           .set_id(PaintImage::GetNextId())
176           .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId())
177           .TakePaintImage(),
178       SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality,
179       CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u,
180       gfx::ColorSpace::CreateXYZD50());
181 
182   DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
183   cache_->DrawWithImageFinished(image, decoded_image);
184 
185   do {
186     decoded_image = cache_->GetDecodedImageForDraw(image);
187     cache_->DrawWithImageFinished(image, decoded_image);
188     timer_.NextLap();
189   } while (!timer_.HasTimeLimitExpired());
190 
191   perf_test::PerfResultReporter reporter =
192       SetUpReporter("_acquire_existing_images");
193   reporter.AddResult("_acquire_existing_images", timer_.LapsPerSecond());
194 }
195 
196 }  // namespace
197 }  // namespace cc
198