xref: /aosp_15_r20/external/angle/src/tests/perf_tests/TexturesPerf.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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 // TexturesPerf:
7 //   Performance test for setting texture state.
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include <iostream>
13 #include <random>
14 #include <sstream>
15 
16 #include "common/debug.h"
17 #include "util/shader_utils.h"
18 
19 namespace angle
20 {
21 constexpr unsigned int kIterationsPerStep = 256;
22 
23 enum class Frequency
24 {
25     Always,
26     Sometimes,
27     Never
28 };
29 
GetFrequencyValue(Frequency frequency,size_t sometimesValue)30 size_t GetFrequencyValue(Frequency frequency, size_t sometimesValue)
31 {
32     switch (frequency)
33     {
34         case Frequency::Always:
35             return 1;
36         case Frequency::Never:
37             return std::numeric_limits<size_t>::max();
38         case Frequency::Sometimes:
39             return sometimesValue;
40         default:
41             UNREACHABLE();
42             return 0;
43     }
44 }
45 
FrequencyToString(Frequency frequency)46 std::string FrequencyToString(Frequency frequency)
47 {
48     switch (frequency)
49     {
50         case Frequency::Always:
51             return "always";
52         case Frequency::Sometimes:
53             return "sometimes";
54         case Frequency::Never:
55             return "never";
56         default:
57             UNREACHABLE();
58             return "";
59     }
60 }
61 
62 constexpr size_t kRebindSometimesFrequency      = 5;
63 constexpr size_t kStateUpdateSometimesFrequency = 3;
64 
65 struct TexturesParams final : public RenderTestParams
66 {
TexturesParamsangle::TexturesParams67     TexturesParams()
68     {
69         iterationsPerStep = kIterationsPerStep;
70 
71         // Common default params
72         majorVersion = 2;
73         minorVersion = 0;
74         windowWidth  = 720;
75         windowHeight = 720;
76 
77         numTextures                 = 8;
78         textureRebindFrequency      = Frequency::Sometimes;
79         textureStateUpdateFrequency = Frequency::Sometimes;
80         textureMipCount             = 8;
81 
82         webgl = false;
83     }
84 
85     std::string story() const override;
86     size_t numTextures;
87     Frequency textureRebindFrequency;
88     Frequency textureStateUpdateFrequency;
89     size_t textureMipCount;
90 
91     bool webgl;
92 };
93 
operator <<(std::ostream & os,const TexturesParams & params)94 std::ostream &operator<<(std::ostream &os, const TexturesParams &params)
95 {
96     os << params.backendAndStory().substr(1);
97     return os;
98 }
99 
story() const100 std::string TexturesParams::story() const
101 {
102     std::stringstream strstr;
103 
104     strstr << RenderTestParams::story();
105     strstr << "_" << FrequencyToString(textureRebindFrequency) << "_rebind";
106     strstr << "_" << FrequencyToString(textureStateUpdateFrequency) << "_update";
107 
108     if (webgl)
109     {
110         strstr << "_webgl";
111     }
112 
113     return strstr.str();
114 }
115 
116 class TexturesBenchmark : public ANGLERenderTest,
117                           public ::testing::WithParamInterface<TexturesParams>
118 {
119   public:
120     TexturesBenchmark();
121 
122     void initializeBenchmark() override;
123     void destroyBenchmark() override;
124     void drawBenchmark() override;
125 
126   private:
127     void initShaders();
128     void initTextures();
129 
130     std::vector<GLuint> mTextures;
131 
132     GLuint mProgram;
133     std::vector<GLuint> mUniformLocations;
134 };
135 
TexturesBenchmark()136 TexturesBenchmark::TexturesBenchmark() : ANGLERenderTest("Textures", GetParam()), mProgram(0u)
137 {
138     setWebGLCompatibilityEnabled(GetParam().webgl);
139     setRobustResourceInit(GetParam().webgl);
140 }
141 
initializeBenchmark()142 void TexturesBenchmark::initializeBenchmark()
143 {
144     const auto &params = GetParam();
145 
146     // Verify the uniform counts are within the limits
147     GLint maxTextureUnits;
148     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
149     if (params.numTextures > static_cast<size_t>(maxTextureUnits))
150     {
151         FAIL() << "Texture count (" << params.numTextures << ")"
152                << " exceeds maximum texture unit count: " << maxTextureUnits << std::endl;
153     }
154 
155     initShaders();
156     initTextures();
157     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
158     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
159 
160     ASSERT_GL_NO_ERROR();
161 }
162 
GetUniformLocationName(size_t idx,bool vertexShader)163 std::string GetUniformLocationName(size_t idx, bool vertexShader)
164 {
165     std::stringstream strstr;
166     strstr << (vertexShader ? "vs" : "fs") << "_u_" << idx;
167     return strstr.str();
168 }
169 
initShaders()170 void TexturesBenchmark::initShaders()
171 {
172     const auto &params = GetParam();
173 
174     std::string vs =
175         "void main()\n"
176         "{\n"
177         "    gl_Position = vec4(0, 0, 0, 0);\n"
178         "}\n";
179 
180     std::stringstream fstrstr;
181     for (size_t i = 0; i < params.numTextures; i++)
182     {
183         fstrstr << "uniform sampler2D tex" << i << ";";
184     }
185     fstrstr << "void main()\n"
186                "{\n"
187                "    gl_FragColor = vec4(0, 0, 0, 0)";
188     for (size_t i = 0; i < params.numTextures; i++)
189     {
190         fstrstr << "+ texture2D(tex" << i << ", vec2(0, 0))";
191     }
192     fstrstr << ";\n"
193                "}\n";
194 
195     mProgram = CompileProgram(vs.c_str(), fstrstr.str().c_str());
196     ASSERT_NE(0u, mProgram);
197 
198     for (size_t i = 0; i < params.numTextures; ++i)
199     {
200         std::stringstream uniformName;
201         uniformName << "tex" << i;
202 
203         GLint location = glGetUniformLocation(mProgram, uniformName.str().c_str());
204         ASSERT_NE(-1, location);
205         mUniformLocations.push_back(location);
206     }
207 
208     // Use the program object
209     glUseProgram(mProgram);
210 }
211 
initTextures()212 void TexturesBenchmark::initTextures()
213 {
214     const auto &params = GetParam();
215 
216     size_t textureSize = static_cast<size_t>(1) << params.textureMipCount;
217     std::vector<GLubyte> textureData(textureSize * textureSize * 4);
218     for (auto &byte : textureData)
219     {
220         byte = rand() % 255u;
221     }
222 
223     for (size_t texIndex = 0; texIndex < params.numTextures; texIndex++)
224     {
225         GLuint tex = 0;
226         glGenTextures(1, &tex);
227 
228         glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + texIndex));
229         glBindTexture(GL_TEXTURE_2D, tex);
230         for (size_t mip = 0; mip < params.textureMipCount; mip++)
231         {
232             GLsizei levelSize = static_cast<GLsizei>(textureSize >> mip);
233             glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(mip), GL_RGBA, levelSize, levelSize, 0,
234                          GL_RGBA, GL_UNSIGNED_BYTE, textureData.data());
235         }
236         mTextures.push_back(tex);
237 
238         glUniform1i(mUniformLocations[texIndex], static_cast<GLint>(texIndex));
239     }
240 }
241 
destroyBenchmark()242 void TexturesBenchmark::destroyBenchmark()
243 {
244     glDeleteProgram(mProgram);
245 }
246 
drawBenchmark()247 void TexturesBenchmark::drawBenchmark()
248 {
249     const auto &params = GetParam();
250 
251     size_t textureRebindPeriod =
252         GetFrequencyValue(params.textureRebindFrequency, kRebindSometimesFrequency);
253     size_t textureStateUpdatePeriod =
254         GetFrequencyValue(params.textureStateUpdateFrequency, kStateUpdateSometimesFrequency);
255 
256     for (size_t it = 0; it < params.iterationsPerStep; ++it)
257     {
258         if (it % textureRebindPeriod == 0)
259         {
260             // Swap two textures
261             size_t swapTexture = (it / textureRebindPeriod) % (params.numTextures - 1);
262 
263             glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + swapTexture));
264             glBindTexture(GL_TEXTURE_2D, mTextures[swapTexture]);
265             glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + swapTexture + 1));
266             glBindTexture(GL_TEXTURE_2D, mTextures[swapTexture + 1]);
267             std::swap(mTextures[swapTexture], mTextures[swapTexture + 1]);
268         }
269 
270         if (it % textureStateUpdatePeriod == 0)
271         {
272             // Update a texture's state
273             size_t stateUpdateCount = it / textureStateUpdatePeriod;
274 
275             const size_t numUpdateTextures = 4;
276             ASSERT_LE(numUpdateTextures, params.numTextures);
277 
278             size_t firstTexture = stateUpdateCount % (params.numTextures - numUpdateTextures);
279 
280             for (size_t updateTextureIdx = 0; updateTextureIdx < numUpdateTextures;
281                  updateTextureIdx++)
282             {
283                 size_t updateTexture = firstTexture + updateTextureIdx;
284                 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + updateTexture));
285 
286                 const GLenum minFilters[] = {
287                     GL_NEAREST,
288                     GL_LINEAR,
289                     GL_NEAREST_MIPMAP_NEAREST,
290                     GL_LINEAR_MIPMAP_NEAREST,
291                     GL_NEAREST_MIPMAP_LINEAR,
292                     GL_LINEAR_MIPMAP_LINEAR,
293                 };
294                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
295                                 minFilters[stateUpdateCount % ArraySize(minFilters)]);
296 
297                 const GLenum magFilters[] = {
298                     GL_NEAREST,
299                     GL_LINEAR,
300                 };
301                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
302                                 magFilters[stateUpdateCount % ArraySize(magFilters)]);
303 
304                 const GLenum wrapParameters[] = {
305                     GL_CLAMP_TO_EDGE,
306                     GL_REPEAT,
307                     GL_MIRRORED_REPEAT,
308                 };
309                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
310                                 wrapParameters[stateUpdateCount % ArraySize(wrapParameters)]);
311                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
312                                 wrapParameters[stateUpdateCount % ArraySize(wrapParameters)]);
313             }
314         }
315 
316         glDrawArrays(GL_TRIANGLES, 0, 3);
317     }
318 
319     ASSERT_GL_NO_ERROR();
320 }
321 
ApplyFrequencies(const TexturesParams & paramsIn,Frequency rebindFrequency,Frequency stateUpdateFrequency)322 TexturesParams ApplyFrequencies(const TexturesParams &paramsIn,
323                                 Frequency rebindFrequency,
324                                 Frequency stateUpdateFrequency)
325 {
326     TexturesParams paramsOut              = paramsIn;
327     paramsOut.textureRebindFrequency      = rebindFrequency;
328     paramsOut.textureStateUpdateFrequency = stateUpdateFrequency;
329     return paramsOut;
330 }
331 
D3D11Params(bool webglCompat,Frequency rebindFrequency,Frequency stateUpdateFrequency)332 TexturesParams D3D11Params(bool webglCompat,
333                            Frequency rebindFrequency,
334                            Frequency stateUpdateFrequency)
335 {
336     TexturesParams params;
337     params.eglParameters = egl_platform::D3D11_NULL();
338     params.webgl         = webglCompat;
339     return ApplyFrequencies(params, rebindFrequency, stateUpdateFrequency);
340 }
341 
MetalParams(bool webglCompat,Frequency rebindFrequency,Frequency stateUpdateFrequency)342 TexturesParams MetalParams(bool webglCompat,
343                            Frequency rebindFrequency,
344                            Frequency stateUpdateFrequency)
345 {
346     TexturesParams params;
347     params.eglParameters = egl_platform::METAL();
348     params.webgl         = webglCompat;
349     return ApplyFrequencies(params, rebindFrequency, stateUpdateFrequency);
350 }
351 
OpenGLOrGLESParams(bool webglCompat,Frequency rebindFrequency,Frequency stateUpdateFrequency)352 TexturesParams OpenGLOrGLESParams(bool webglCompat,
353                                   Frequency rebindFrequency,
354                                   Frequency stateUpdateFrequency)
355 {
356     TexturesParams params;
357     params.eglParameters = egl_platform::OPENGL_OR_GLES_NULL();
358     params.webgl         = webglCompat;
359     return ApplyFrequencies(params, rebindFrequency, stateUpdateFrequency);
360 }
361 
VulkanParams(bool webglCompat,Frequency rebindFrequency,Frequency stateUpdateFrequency)362 TexturesParams VulkanParams(bool webglCompat,
363                             Frequency rebindFrequency,
364                             Frequency stateUpdateFrequency)
365 {
366     TexturesParams params;
367     params.eglParameters = egl_platform::VULKAN_NULL();
368     params.webgl         = webglCompat;
369     return ApplyFrequencies(params, rebindFrequency, stateUpdateFrequency);
370 }
371 
TEST_P(TexturesBenchmark,Run)372 TEST_P(TexturesBenchmark, Run)
373 {
374     run();
375 }
376 
377 ANGLE_INSTANTIATE_TEST(TexturesBenchmark,
378                        D3D11Params(false, Frequency::Sometimes, Frequency::Sometimes),
379                        D3D11Params(true, Frequency::Sometimes, Frequency::Sometimes),
380                        D3D11Params(false, Frequency::Always, Frequency::Always),
381                        D3D11Params(true, Frequency::Always, Frequency::Always),
382                        MetalParams(false, Frequency::Sometimes, Frequency::Sometimes),
383                        MetalParams(true, Frequency::Sometimes, Frequency::Sometimes),
384                        MetalParams(false, Frequency::Always, Frequency::Always),
385                        MetalParams(true, Frequency::Always, Frequency::Always),
386                        OpenGLOrGLESParams(false, Frequency::Sometimes, Frequency::Sometimes),
387                        OpenGLOrGLESParams(true, Frequency::Sometimes, Frequency::Sometimes),
388                        OpenGLOrGLESParams(false, Frequency::Always, Frequency::Always),
389                        OpenGLOrGLESParams(true, Frequency::Always, Frequency::Always),
390                        VulkanParams(false, Frequency::Sometimes, Frequency::Sometimes),
391                        VulkanParams(true, Frequency::Sometimes, Frequency::Sometimes),
392                        VulkanParams(false, Frequency::Always, Frequency::Always),
393                        VulkanParams(true, Frequency::Always, Frequency::Always),
394                        VulkanParams(false, Frequency::Always, Frequency::Never));
395 }  // namespace angle
396