• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "util/shader_utils.h"
17 
18 namespace angle
19 {
20 constexpr unsigned int kIterationsPerStep = 256;
21 
22 struct TexturesParams final : public RenderTestParams
23 {
TexturesParamsangle::TexturesParams24     TexturesParams()
25     {
26         iterationsPerStep = kIterationsPerStep;
27 
28         // Common default params
29         majorVersion = 2;
30         minorVersion = 0;
31         windowWidth  = 720;
32         windowHeight = 720;
33 
34         numTextures                 = 8;
35         textureRebindFrequency      = 5;
36         textureStateUpdateFrequency = 3;
37         textureMipCount             = 8;
38 
39         webgl = false;
40     }
41 
42     std::string story() const override;
43     size_t numTextures;
44     size_t textureRebindFrequency;
45     size_t textureStateUpdateFrequency;
46     size_t textureMipCount;
47 
48     bool webgl;
49 };
50 
operator <<(std::ostream & os,const TexturesParams & params)51 std::ostream &operator<<(std::ostream &os, const TexturesParams &params)
52 {
53     os << params.backendAndStory().substr(1);
54     return os;
55 }
56 
story() const57 std::string TexturesParams::story() const
58 {
59     std::stringstream strstr;
60 
61     strstr << RenderTestParams::story();
62     strstr << "_" << numTextures << "_textures";
63     strstr << "_" << textureRebindFrequency << "_rebind";
64     strstr << "_" << textureStateUpdateFrequency << "_state";
65     strstr << "_" << textureMipCount << "_mips";
66 
67     if (webgl)
68     {
69         strstr << "_webgl";
70     }
71 
72     return strstr.str();
73 }
74 
75 class TexturesBenchmark : public ANGLERenderTest,
76                           public ::testing::WithParamInterface<TexturesParams>
77 {
78   public:
79     TexturesBenchmark();
80 
81     void initializeBenchmark() override;
82     void destroyBenchmark() override;
83     void drawBenchmark() override;
84 
85   private:
86     void initShaders();
87     void initTextures();
88 
89     std::vector<GLuint> mTextures;
90 
91     GLuint mProgram;
92     std::vector<GLuint> mUniformLocations;
93 };
94 
TexturesBenchmark()95 TexturesBenchmark::TexturesBenchmark() : ANGLERenderTest("Textures", GetParam()), mProgram(0u)
96 {
97     setWebGLCompatibilityEnabled(GetParam().webgl);
98     setRobustResourceInit(GetParam().webgl);
99 }
100 
initializeBenchmark()101 void TexturesBenchmark::initializeBenchmark()
102 {
103     const auto &params = GetParam();
104 
105     // Verify the uniform counts are within the limits
106     GLint maxTextureUnits;
107     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
108     if (params.numTextures > static_cast<size_t>(maxTextureUnits))
109     {
110         FAIL() << "Texture count (" << params.numTextures << ")"
111                << " exceeds maximum texture unit count: " << maxTextureUnits << std::endl;
112     }
113 
114     initShaders();
115     initTextures();
116     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
117     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
118 
119     ASSERT_GL_NO_ERROR();
120 }
121 
GetUniformLocationName(size_t idx,bool vertexShader)122 std::string GetUniformLocationName(size_t idx, bool vertexShader)
123 {
124     std::stringstream strstr;
125     strstr << (vertexShader ? "vs" : "fs") << "_u_" << idx;
126     return strstr.str();
127 }
128 
initShaders()129 void TexturesBenchmark::initShaders()
130 {
131     const auto &params = GetParam();
132 
133     std::string vs =
134         "void main()\n"
135         "{\n"
136         "    gl_Position = vec4(0, 0, 0, 0);\n"
137         "}\n";
138 
139     std::stringstream fstrstr;
140     for (size_t i = 0; i < params.numTextures; i++)
141     {
142         fstrstr << "uniform sampler2D tex" << i << ";";
143     }
144     fstrstr << "void main()\n"
145                "{\n"
146                "    gl_FragColor = vec4(0, 0, 0, 0)";
147     for (size_t i = 0; i < params.numTextures; i++)
148     {
149         fstrstr << "+ texture2D(tex" << i << ", vec2(0, 0))";
150     }
151     fstrstr << ";\n"
152                "}\n";
153 
154     mProgram = CompileProgram(vs.c_str(), fstrstr.str().c_str());
155     ASSERT_NE(0u, mProgram);
156 
157     for (size_t i = 0; i < params.numTextures; ++i)
158     {
159         std::stringstream uniformName;
160         uniformName << "tex" << i;
161 
162         GLint location = glGetUniformLocation(mProgram, uniformName.str().c_str());
163         ASSERT_NE(-1, location);
164         mUniformLocations.push_back(location);
165     }
166 
167     // Use the program object
168     glUseProgram(mProgram);
169 }
170 
initTextures()171 void TexturesBenchmark::initTextures()
172 {
173     const auto &params = GetParam();
174 
175     size_t textureSize = static_cast<size_t>(1) << params.textureMipCount;
176     std::vector<GLubyte> textureData(textureSize * textureSize * 4);
177     for (auto &byte : textureData)
178     {
179         byte = rand() % 255u;
180     }
181 
182     for (size_t texIndex = 0; texIndex < params.numTextures; texIndex++)
183     {
184         GLuint tex = 0;
185         glGenTextures(1, &tex);
186 
187         glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + texIndex));
188         glBindTexture(GL_TEXTURE_2D, tex);
189         for (size_t mip = 0; mip < params.textureMipCount; mip++)
190         {
191             GLsizei levelSize = static_cast<GLsizei>(textureSize >> mip);
192             glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(mip), GL_RGBA, levelSize, levelSize, 0,
193                          GL_RGBA, GL_UNSIGNED_BYTE, textureData.data());
194         }
195         mTextures.push_back(tex);
196 
197         glUniform1i(mUniformLocations[texIndex], static_cast<GLint>(texIndex));
198     }
199 }
200 
destroyBenchmark()201 void TexturesBenchmark::destroyBenchmark()
202 {
203     glDeleteProgram(mProgram);
204 }
205 
drawBenchmark()206 void TexturesBenchmark::drawBenchmark()
207 {
208     const auto &params = GetParam();
209 
210     for (size_t it = 0; it < params.iterationsPerStep; ++it)
211     {
212         if (it % params.textureRebindFrequency == 0)
213         {
214             // Swap two textures
215             size_t swapTexture = (it / params.textureRebindFrequency) % (params.numTextures - 1);
216 
217             glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + swapTexture));
218             glBindTexture(GL_TEXTURE_2D, mTextures[swapTexture]);
219             glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + swapTexture + 1));
220             glBindTexture(GL_TEXTURE_2D, mTextures[swapTexture + 1]);
221             std::swap(mTextures[swapTexture], mTextures[swapTexture + 1]);
222         }
223 
224         if (it % params.textureStateUpdateFrequency == 0)
225         {
226             // Update a texture's state
227             size_t stateUpdateCount = it / params.textureStateUpdateFrequency;
228 
229             const size_t numUpdateTextures = 4;
230             ASSERT_LE(numUpdateTextures, params.numTextures);
231 
232             size_t firstTexture = stateUpdateCount % (params.numTextures - numUpdateTextures);
233 
234             for (size_t updateTextureIdx = 0; updateTextureIdx < numUpdateTextures;
235                  updateTextureIdx++)
236             {
237                 size_t updateTexture = firstTexture + updateTextureIdx;
238                 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + updateTexture));
239 
240                 const GLenum minFilters[] = {
241                     GL_NEAREST,
242                     GL_LINEAR,
243                     GL_NEAREST_MIPMAP_NEAREST,
244                     GL_LINEAR_MIPMAP_NEAREST,
245                     GL_NEAREST_MIPMAP_LINEAR,
246                     GL_LINEAR_MIPMAP_LINEAR,
247                 };
248                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
249                                 minFilters[stateUpdateCount % ArraySize(minFilters)]);
250 
251                 const GLenum magFilters[] = {
252                     GL_NEAREST,
253                     GL_LINEAR,
254                 };
255                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
256                                 magFilters[stateUpdateCount % ArraySize(magFilters)]);
257 
258                 const GLenum wrapParameters[] = {
259                     GL_CLAMP_TO_EDGE,
260                     GL_REPEAT,
261                     GL_MIRRORED_REPEAT,
262                 };
263                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
264                                 wrapParameters[stateUpdateCount % ArraySize(wrapParameters)]);
265                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
266                                 wrapParameters[stateUpdateCount % ArraySize(wrapParameters)]);
267             }
268         }
269 
270         glDrawArrays(GL_TRIANGLES, 0, 3);
271     }
272 
273     ASSERT_GL_NO_ERROR();
274 }
275 
D3D11Params(bool webglCompat,bool frequentUpdate)276 TexturesParams D3D11Params(bool webglCompat, bool frequentUpdate)
277 {
278     TexturesParams params;
279     params.eglParameters = egl_platform::D3D11_NULL();
280     params.webgl         = webglCompat;
281     if (frequentUpdate)
282     {
283         params.textureRebindFrequency      = 1;
284         params.textureStateUpdateFrequency = 1;
285     }
286     return params;
287 }
288 
OpenGLOrGLESParams(bool webglCompat,bool frequentUpdate)289 TexturesParams OpenGLOrGLESParams(bool webglCompat, bool frequentUpdate)
290 {
291     TexturesParams params;
292     params.eglParameters = egl_platform::OPENGL_OR_GLES_NULL();
293     params.webgl         = webglCompat;
294     if (frequentUpdate)
295     {
296         params.textureRebindFrequency      = 1;
297         params.textureStateUpdateFrequency = 1;
298     }
299     return params;
300 }
301 
VulkanParams(bool webglCompat,bool frequentUpdate)302 TexturesParams VulkanParams(bool webglCompat, bool frequentUpdate)
303 {
304     TexturesParams params;
305     params.eglParameters = egl_platform::VULKAN_NULL();
306     params.webgl         = webglCompat;
307     if (frequentUpdate)
308     {
309         params.textureRebindFrequency      = 1;
310         params.textureStateUpdateFrequency = 1;
311     }
312     return params;
313 }
314 
TEST_P(TexturesBenchmark,Run)315 TEST_P(TexturesBenchmark, Run)
316 {
317     run();
318 }
319 
320 ANGLE_INSTANTIATE_TEST(TexturesBenchmark,
321                        D3D11Params(false, false),
322                        D3D11Params(true, false),
323                        D3D11Params(false, true),
324                        D3D11Params(true, true),
325                        OpenGLOrGLESParams(false, false),
326                        OpenGLOrGLESParams(true, false),
327                        OpenGLOrGLESParams(false, true),
328                        OpenGLOrGLESParams(true, true),
329                        VulkanParams(false, false),
330                        VulkanParams(true, false),
331                        VulkanParams(false, true),
332                        VulkanParams(true, true));
333 }  // namespace angle
334