1 // Copyright (c) 2012 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 // This file looks like a unit test, but it contains benchmarks and test
6 // utilities intended for manual evaluation of the scalers in
7 // gl_helper*. These tests produce output in the form of files and printouts,
8 // but cannot really "fail". There is no point in making these tests part
9 // of any test automation run.
10 
11 #include <GLES2/gl2.h>
12 #include <GLES2/gl2ext.h>
13 #include <GLES2/gl2extchromium.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 
17 #include <cmath>
18 #include <string>
19 #include <vector>
20 
21 #include "base/at_exit.h"
22 #include "base/command_line.h"
23 #include "base/files/file_util.h"
24 #include "base/run_loop.h"
25 #include "base/stl_util.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/test/task_environment.h"
28 #include "base/threading/thread_task_runner_handle.h"
29 #include "base/time/time.h"
30 #include "components/viz/test/test_gpu_service_holder.h"
31 #include "gpu/command_buffer/client/gl_helper.h"
32 #include "gpu/command_buffer/client/gl_helper_scaling.h"
33 #include "gpu/command_buffer/client/gles2_implementation.h"
34 #include "gpu/command_buffer/client/shared_memory_limits.h"
35 #include "gpu/ipc/gl_in_process_context.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37 #include "third_party/skia/include/core/SkBitmap.h"
38 #include "ui/gfx/codec/png_codec.h"
39 
40 namespace gpu {
41 
42 namespace {
43 
44 GLHelper::ScalerQuality kQualities[] = {
45     GLHelper::SCALER_QUALITY_BEST,
46     GLHelper::SCALER_QUALITY_GOOD,
47     GLHelper::SCALER_QUALITY_FAST,
48 };
49 
50 const char* const kQualityNames[] = {
51     "best",
52     "good",
53     "fast",
54 };
55 
56 }  // namespace
57 
58 class GLHelperBenchmark : public testing::Test {
59  protected:
SetUp()60   void SetUp() override {
61     ContextCreationAttribs attributes;
62     attributes.alpha_size = 8;
63     attributes.depth_size = 24;
64     attributes.red_size = 8;
65     attributes.green_size = 8;
66     attributes.blue_size = 8;
67     attributes.stencil_size = 8;
68     attributes.samples = 4;
69     attributes.sample_buffers = 1;
70     attributes.bind_generates_resource = false;
71     attributes.gpu_preference = gl::GpuPreference::kHighPerformance;
72 
73     context_ = std::make_unique<GLInProcessContext>();
74     auto result = context_->Initialize(
75         viz::TestGpuServiceHolder::GetInstance()->task_executor(),
76         nullptr,            /* surface */
77         true,               /* offscreen */
78         kNullSurfaceHandle, /* window */
79         attributes, SharedMemoryLimits(),
80         nullptr, /* gpu_memory_buffer_manager */
81         nullptr, /* image_factory */
82         nullptr, /* gpu_task_helper */
83         nullptr, /* display_compositor_memory_and_task_controller */
84         base::ThreadTaskRunnerHandle::Get());
85     DCHECK_EQ(result, ContextResult::kSuccess);
86     gl_ = context_->GetImplementation();
87     ContextSupport* support = context_->GetImplementation();
88 
89     helper_.reset(new GLHelper(gl_, support));
90     helper_scaling_.reset(new GLHelperScaling(gl_, helper_.get()));
91   }
92 
TearDown()93   void TearDown() override {
94     helper_scaling_.reset(nullptr);
95     helper_.reset(nullptr);
96     context_.reset(nullptr);
97   }
98 
LoadPngFileToSkBitmap(const base::FilePath & filename,SkBitmap * bitmap)99   void LoadPngFileToSkBitmap(const base::FilePath& filename, SkBitmap* bitmap) {
100     std::string compressed;
101     base::ReadFileToString(base::MakeAbsoluteFilePath(filename), &compressed);
102     ASSERT_TRUE(compressed.size());
103     ASSERT_TRUE(gfx::PNGCodec::Decode(
104         reinterpret_cast<const unsigned char*>(compressed.data()),
105         compressed.size(), bitmap));
106   }
107 
108   // Save the image to a png file. Used to create the initial test files.
SaveToFile(SkBitmap * bitmap,const base::FilePath & filename)109   void SaveToFile(SkBitmap* bitmap, const base::FilePath& filename) {
110     std::vector<unsigned char> compressed;
111     ASSERT_TRUE(gfx::PNGCodec::Encode(
112         static_cast<unsigned char*>(bitmap->getPixels()),
113         gfx::PNGCodec::FORMAT_BGRA,
114         gfx::Size(bitmap->width(), bitmap->height()),
115         static_cast<int>(bitmap->rowBytes()), true,
116         std::vector<gfx::PNGCodec::Comment>(), &compressed));
117     ASSERT_TRUE(compressed.size());
118     FILE* f = base::OpenFile(filename, "wb");
119     ASSERT_TRUE(f);
120     ASSERT_EQ(fwrite(&*compressed.begin(), 1, compressed.size(), f),
121               compressed.size());
122     base::CloseFile(f);
123   }
124 
125   base::test::TaskEnvironment task_environment_;
126   std::unique_ptr<GLInProcessContext> context_;
127   gles2::GLES2Interface* gl_;
128   std::unique_ptr<GLHelper> helper_;
129   std::unique_ptr<GLHelperScaling> helper_scaling_;
130   base::circular_deque<GLHelperScaling::ScaleOp> x_ops_, y_ops_;
131 };
132 
TEST_F(GLHelperBenchmark,ScaleBenchmark)133 TEST_F(GLHelperBenchmark, ScaleBenchmark) {
134   int output_sizes[] = {1920, 1080, 1249, 720,  // Output size on pixel
135                         256,  144};
136   int input_sizes[] = {3200, 2040, 2560, 1476,  // Pixel tab size
137                        1920, 1080, 1280, 720,  800, 480, 256, 144};
138 
139   for (size_t q = 0; q < base::size(kQualities); q++) {
140     for (size_t outsize = 0; outsize < base::size(output_sizes); outsize += 2) {
141       for (size_t insize = 0; insize < base::size(input_sizes); insize += 2) {
142         uint32_t src_texture;
143         gl_->GenTextures(1, &src_texture);
144         uint32_t dst_texture;
145         gl_->GenTextures(1, &dst_texture);
146         uint32_t framebuffer;
147         gl_->GenFramebuffers(1, &framebuffer);
148         const gfx::Size src_size(input_sizes[insize], input_sizes[insize + 1]);
149         const gfx::Size dst_size(output_sizes[outsize],
150                                  output_sizes[outsize + 1]);
151         SkBitmap input;
152         input.allocN32Pixels(src_size.width(), src_size.height());
153 
154         SkBitmap output_pixels;
155         output_pixels.allocN32Pixels(dst_size.width(), dst_size.height());
156 
157         gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
158         gl_->BindTexture(GL_TEXTURE_2D, dst_texture);
159         gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dst_size.width(),
160                         dst_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
161                         nullptr);
162         gl_->BindTexture(GL_TEXTURE_2D, src_texture);
163         gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_size.width(),
164                         src_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
165                         input.getPixels());
166 
167         std::unique_ptr<GLHelper::ScalerInterface> scaler =
168             helper_->CreateScaler(
169                 kQualities[q],
170                 gfx::Vector2d(src_size.width(), src_size.height()),
171                 gfx::Vector2d(dst_size.width(), dst_size.height()), false,
172                 false, false);
173         // Scale once beforehand before we start measuring.
174         const gfx::Rect output_rect(dst_size);
175         scaler->Scale(src_texture, src_size, gfx::Vector2dF(), dst_texture,
176                       output_rect);
177         gl_->Finish();
178 
179         base::TimeTicks start_time = base::TimeTicks::Now();
180         int iterations = 0;
181         base::TimeTicks end_time;
182         while (true) {
183           for (int i = 0; i < 50; i++) {
184             iterations++;
185             scaler->Scale(src_texture, src_size, gfx::Vector2dF(), dst_texture,
186                           output_rect);
187             gl_->Flush();
188           }
189           gl_->Finish();
190           end_time = base::TimeTicks::Now();
191           if (iterations > 2000) {
192             break;
193           }
194           if ((end_time - start_time) > base::TimeDelta::FromSeconds(1)) {
195             break;
196           }
197         }
198         gl_->DeleteTextures(1, &dst_texture);
199         gl_->DeleteTextures(1, &src_texture);
200         gl_->DeleteFramebuffers(1, &framebuffer);
201 
202         std::string name;
203         name = base::StringPrintf("scale_%dx%d_to_%dx%d_%s", src_size.width(),
204                                   src_size.height(), dst_size.width(),
205                                   dst_size.height(), kQualityNames[q]);
206 
207         float ms = (end_time - start_time).InMillisecondsF() / iterations;
208         VLOG(0) << base::StringPrintf("*RESULT gpu_scale_time: %s=%.2f ms\n",
209                                       name.c_str(), ms);
210       }
211     }
212   }
213 }
214 
215 }  // namespace gpu
216