• 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)276 TexturesParams D3D11Params(bool webglCompat)
277 {
278     TexturesParams params;
279     params.eglParameters = egl_platform::D3D11_NULL();
280     params.webgl         = webglCompat;
281     return params;
282 }
283 
D3D9Params(bool webglCompat)284 TexturesParams D3D9Params(bool webglCompat)
285 {
286     TexturesParams params;
287     params.eglParameters = egl_platform::D3D9_NULL();
288     params.webgl         = webglCompat;
289     return params;
290 }
291 
OpenGLOrGLESParams(bool webglCompat)292 TexturesParams OpenGLOrGLESParams(bool webglCompat)
293 {
294     TexturesParams params;
295     params.eglParameters = egl_platform::OPENGL_OR_GLES_NULL();
296     params.webgl         = webglCompat;
297     return params;
298 }
299 
TEST_P(TexturesBenchmark,Run)300 TEST_P(TexturesBenchmark, Run)
301 {
302     run();
303 }
304 
305 ANGLE_INSTANTIATE_TEST(TexturesBenchmark,
306                        D3D11Params(false),
307                        D3D11Params(true),
308                        D3D9Params(true),
309                        OpenGLOrGLESParams(false),
310                        OpenGLOrGLESParams(true));
311 }  // namespace angle
312