xref: /aosp_15_r20/external/angle/src/tests/perf_tests/GenerateMipmapPerf.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // GenerateMipmapBenchmark:
7 //   Performance test for generating texture mipmaps.
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include <iostream>
13 #include <random>
14 #include <sstream>
15 
16 #include "test_utils/gl_raii.h"
17 #include "util/shader_utils.h"
18 
19 using namespace angle;
20 
21 namespace
22 {
23 constexpr unsigned int kIterationsPerStep = 5;
24 
25 struct GenerateMipmapParams final : public RenderTestParams
26 {
GenerateMipmapParams__anonb9e554b10111::GenerateMipmapParams27     GenerateMipmapParams()
28     {
29         iterationsPerStep = kIterationsPerStep;
30         trackGpuTime      = true;
31 
32         textureWidth  = 1920;
33         textureHeight = 1080;
34 
35         internalFormat = GL_RGBA;
36 
37         webgl = false;
38     }
39 
40     std::string story() const override;
41 
42     GLsizei textureWidth;
43     GLsizei textureHeight;
44 
45     GLenum internalFormat;
46 
47     bool webgl;
48 };
49 
operator <<(std::ostream & os,const GenerateMipmapParams & params)50 std::ostream &operator<<(std::ostream &os, const GenerateMipmapParams &params)
51 {
52     return os << params.backendAndStory().substr(1);
53 }
54 
story() const55 std::string GenerateMipmapParams::story() const
56 {
57     std::stringstream strstr;
58 
59     strstr << RenderTestParams::story();
60 
61     if (webgl)
62     {
63         strstr << "_webgl";
64     }
65 
66     if (internalFormat == GL_RGB)
67     {
68         strstr << "_rgb";
69     }
70 
71     return strstr.str();
72 }
73 
74 template <typename T>
FillWithRandomData(T * storage)75 void FillWithRandomData(T *storage)
76 {
77     for (uint8_t &u : *storage)
78     {
79         u = rand() & 0xFF;
80     }
81 }
82 
83 class GenerateMipmapBenchmarkBase : public ANGLERenderTest,
84                                     public ::testing::WithParamInterface<GenerateMipmapParams>
85 {
86   public:
87     GenerateMipmapBenchmarkBase(const char *benchmarkName);
88 
89     void initializeBenchmark() override;
90     void destroyBenchmark() override;
91 
92   protected:
93     void initShaders();
94 
95     GLuint mProgram = 0;
96     GLuint mTexture = 0;
97 
98     std::vector<uint8_t> mTextureData;
99 };
100 
101 class GenerateMipmapBenchmark : public GenerateMipmapBenchmarkBase
102 {
103   public:
GenerateMipmapBenchmark()104     GenerateMipmapBenchmark() : GenerateMipmapBenchmarkBase("GenerateMipmap") {}
105 
106     void initializeBenchmark() override;
107 
108     void drawBenchmark() override;
109 };
110 
111 class GenerateMipmapWithRedefineBenchmark : public GenerateMipmapBenchmarkBase
112 {
113   public:
GenerateMipmapWithRedefineBenchmark()114     GenerateMipmapWithRedefineBenchmark()
115         : GenerateMipmapBenchmarkBase("GenerateMipmapWithRedefine")
116     {}
117 
118     void drawBenchmark() override;
119 };
120 
GenerateMipmapBenchmarkBase(const char * benchmarkName)121 GenerateMipmapBenchmarkBase::GenerateMipmapBenchmarkBase(const char *benchmarkName)
122     : ANGLERenderTest(benchmarkName, GetParam())
123 {
124     setWebGLCompatibilityEnabled(GetParam().webgl);
125     setRobustResourceInit(GetParam().webgl);
126 
127     if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
128     {
129         skipTest("http://crbug.com/945415 Crashes on nvidia+d3d11");
130     }
131 
132     if (IsWindows7() && IsNVIDIA() &&
133         GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
134     {
135         skipTest(
136             "http://crbug.com/1096510 Fails on Windows7 NVIDIA Vulkan, presumably due to old "
137             "drivers");
138     }
139 }
140 
initializeBenchmark()141 void GenerateMipmapBenchmarkBase::initializeBenchmark()
142 {
143     const auto &params = GetParam();
144 
145     initShaders();
146     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
147     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
148 
149     glGenTextures(1, &mTexture);
150     glBindTexture(GL_TEXTURE_2D, mTexture);
151 
152     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
153     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
154     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
155     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
156 
157     mTextureData.resize(params.textureWidth * params.textureHeight * 4);
158     FillWithRandomData(&mTextureData);
159 
160     glTexImage2D(GL_TEXTURE_2D, 0, params.internalFormat, params.textureWidth, params.textureHeight,
161                  0, params.internalFormat, GL_UNSIGNED_BYTE, mTextureData.data());
162 
163     // Perform a draw so the image data is flushed.
164     glDrawArrays(GL_TRIANGLES, 0, 3);
165 
166     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
167 
168     ASSERT_GL_NO_ERROR();
169 }
170 
initShaders()171 void GenerateMipmapBenchmarkBase::initShaders()
172 {
173     constexpr char kVS[] = R"(void main()
174 {
175     gl_Position = vec4(0, 0, 0, 1);
176 })";
177 
178     constexpr char kFS[] = R"(precision mediump float;
179 void main()
180 {
181     gl_FragColor = vec4(0);
182 })";
183 
184     mProgram = CompileProgram(kVS, kFS);
185     ASSERT_NE(0u, mProgram);
186 
187     glUseProgram(mProgram);
188 
189     glDisable(GL_DEPTH_TEST);
190 
191     ASSERT_GL_NO_ERROR();
192 }
193 
destroyBenchmark()194 void GenerateMipmapBenchmarkBase::destroyBenchmark()
195 {
196     glDeleteTextures(1, &mTexture);
197     glDeleteProgram(mProgram);
198 }
199 
initializeBenchmark()200 void GenerateMipmapBenchmark::initializeBenchmark()
201 {
202     GenerateMipmapBenchmarkBase::initializeBenchmark();
203 
204     // Generate mipmaps once so the texture doesn't need to be redefined.
205     glGenerateMipmap(GL_TEXTURE_2D);
206 
207     // Perform a draw so the image data is flushed.
208     glDrawArrays(GL_TRIANGLES, 0, 3);
209 }
210 
drawBenchmark()211 void GenerateMipmapBenchmark::drawBenchmark()
212 {
213     const auto &params = GetParam();
214 
215     startGpuTimer();
216     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
217     {
218         // Slightly modify the base texture so the mipmap is definitely regenerated.
219         std::array<uint8_t, 4> randomData;
220         FillWithRandomData(&randomData);
221 
222         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, params.internalFormat, GL_UNSIGNED_BYTE,
223                         randomData.data());
224 
225         // Generate mipmaps
226         glGenerateMipmap(GL_TEXTURE_2D);
227 
228         // Perform a draw just so the texture data is flushed.  With the position attributes not
229         // set, a constant default value is used, resulting in a very cheap draw.
230         glDrawArrays(GL_TRIANGLES, 0, 3);
231     }
232     stopGpuTimer();
233 
234     ASSERT_GL_NO_ERROR();
235 }
236 
drawBenchmark()237 void GenerateMipmapWithRedefineBenchmark::drawBenchmark()
238 {
239     const auto &params = GetParam();
240 
241     // Create a new texture every time, so image redefinition happens every time.
242     GLTexture texture;
243     glBindTexture(GL_TEXTURE_2D, texture);
244 
245     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
246     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
247     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
248     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
249 
250     glTexImage2D(GL_TEXTURE_2D, 0, params.internalFormat, params.textureWidth, params.textureHeight,
251                  0, params.internalFormat, GL_UNSIGNED_BYTE, mTextureData.data());
252 
253     // Perform a draw so the image data is flushed.
254     glDrawArrays(GL_TRIANGLES, 0, 3);
255 
256     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
257 
258     startGpuTimer();
259 
260     // Do a single iteration, otherwise the cost of redefinition is amortized.
261     ASSERT_EQ(params.iterationsPerStep, 1u);
262 
263     // Generate mipmaps
264     glGenerateMipmap(GL_TEXTURE_2D);
265 
266     // Perform a draw just so the texture data is flushed.  With the position attributes not
267     // set, a constant default value is used, resulting in a very cheap draw.
268     glDrawArrays(GL_TRIANGLES, 0, 3);
269 
270     stopGpuTimer();
271 
272     ASSERT_GL_NO_ERROR();
273 }
274 
D3D11Params(bool webglCompat,bool singleIteration)275 GenerateMipmapParams D3D11Params(bool webglCompat, bool singleIteration)
276 {
277     GenerateMipmapParams params;
278     params.eglParameters = egl_platform::D3D11();
279     params.majorVersion  = 3;
280     params.minorVersion  = 0;
281     params.webgl         = webglCompat;
282     if (singleIteration)
283     {
284         params.iterationsPerStep = 1;
285     }
286     return params;
287 }
288 
MetalParams(bool webglCompat,bool singleIteration)289 GenerateMipmapParams MetalParams(bool webglCompat, bool singleIteration)
290 {
291     GenerateMipmapParams params;
292     params.eglParameters = egl_platform::METAL();
293     params.majorVersion  = 3;
294     params.minorVersion  = 0;
295     params.webgl         = webglCompat;
296     if (singleIteration)
297     {
298         params.iterationsPerStep = 1;
299     }
300     return params;
301 }
302 
OpenGLOrGLESParams(bool webglCompat,bool singleIteration)303 GenerateMipmapParams OpenGLOrGLESParams(bool webglCompat, bool singleIteration)
304 {
305     GenerateMipmapParams params;
306     params.eglParameters = egl_platform::OPENGL_OR_GLES();
307     params.majorVersion  = 3;
308     params.minorVersion  = 0;
309     params.webgl         = webglCompat;
310     if (singleIteration)
311     {
312         params.iterationsPerStep = 1;
313     }
314     return params;
315 }
316 
VulkanParams(bool webglCompat,bool singleIteration,bool emulatedFormat)317 GenerateMipmapParams VulkanParams(bool webglCompat, bool singleIteration, bool emulatedFormat)
318 {
319     GenerateMipmapParams params;
320     params.eglParameters = egl_platform::VULKAN();
321     params.majorVersion  = 3;
322     params.minorVersion  = 0;
323     params.webgl         = webglCompat;
324     if (emulatedFormat)
325     {
326         params.internalFormat = GL_RGB;
327     }
328     if (singleIteration)
329     {
330         params.iterationsPerStep = 1;
331     }
332     return params;
333 }
334 
335 }  // anonymous namespace
336 
TEST_P(GenerateMipmapBenchmark,Run)337 TEST_P(GenerateMipmapBenchmark, Run)
338 {
339     run();
340 }
341 
TEST_P(GenerateMipmapWithRedefineBenchmark,Run)342 TEST_P(GenerateMipmapWithRedefineBenchmark, Run)
343 {
344     run();
345 }
346 
347 using namespace params;
348 
349 ANGLE_INSTANTIATE_TEST(GenerateMipmapBenchmark,
350                        D3D11Params(false, false),
351                        D3D11Params(true, false),
352                        MetalParams(false, false),
353                        MetalParams(true, false),
354                        OpenGLOrGLESParams(false, false),
355                        OpenGLOrGLESParams(true, false),
356                        VulkanParams(false, false, false),
357                        VulkanParams(true, false, false),
358                        VulkanParams(false, false, true),
359                        VulkanParams(true, false, true));
360 
361 ANGLE_INSTANTIATE_TEST(GenerateMipmapWithRedefineBenchmark,
362                        D3D11Params(false, true),
363                        D3D11Params(true, true),
364                        MetalParams(false, true),
365                        MetalParams(true, true),
366                        OpenGLOrGLESParams(false, true),
367                        OpenGLOrGLESParams(true, true),
368                        VulkanParams(false, true, false),
369                        VulkanParams(true, true, false),
370                        VulkanParams(false, true, true),
371                        VulkanParams(true, true, true));
372