• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 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 // TextureSamplingBenchmark:
7 //   Performance test for texture sampling. The test generates a texture containing random data
8 //   and then blurs it in a fragment shader using nearest neighbor sampling. The test is
9 //   specifically designed to test overhead of GLSL's builtin texture*() functions that may result
10 //   from how ANGLE translates them on each backend.
11 //
12 
13 #include "ANGLEPerfTest.h"
14 
15 #include <iostream>
16 #include <random>
17 #include <sstream>
18 
19 #include "util/shader_utils.h"
20 
21 using namespace angle;
22 
23 namespace
24 {
25 constexpr unsigned int kIterationsPerStep = 4;
26 
27 struct TextureSamplingParams final : public RenderTestParams
28 {
TextureSamplingParams__anon5a9153120111::TextureSamplingParams29     TextureSamplingParams()
30     {
31         iterationsPerStep = kIterationsPerStep;
32 
33         // Common default params
34         majorVersion = 3;
35         minorVersion = 0;
36         windowWidth  = 720;
37         windowHeight = 720;
38 
39         numSamplers = 2;
40         textureSize = 32;
41         kernelSize  = 3;
42     }
43 
44     std::string story() const override;
45     unsigned int numSamplers;
46     unsigned int textureSize;
47     unsigned int kernelSize;
48 };
49 
operator <<(std::ostream & os,const TextureSamplingParams & params)50 std::ostream &operator<<(std::ostream &os, const TextureSamplingParams &params)
51 {
52     os << params.backendAndStory().substr(1);
53     return os;
54 }
55 
story() const56 std::string TextureSamplingParams::story() const
57 {
58     std::stringstream strstr;
59 
60     strstr << RenderTestParams::story() << "_" << numSamplers << "samplers";
61 
62     return strstr.str();
63 }
64 
65 class TextureSamplingBenchmark : public ANGLERenderTest,
66                                  public ::testing::WithParamInterface<TextureSamplingParams>
67 {
68   public:
69     TextureSamplingBenchmark();
70 
71     void initializeBenchmark() override;
72     void destroyBenchmark() override;
73     void drawBenchmark() override;
74 
75   protected:
76     void initShaders();
77     void initVertexBuffer();
78     void initTextures();
79 
80     GLuint mProgram;
81     GLuint mBuffer;
82     std::vector<GLuint> mTextures;
83 };
84 
TextureSamplingBenchmark()85 TextureSamplingBenchmark::TextureSamplingBenchmark()
86     : ANGLERenderTest("TextureSampling", GetParam()), mProgram(0u), mBuffer(0u)
87 {}
88 
initializeBenchmark()89 void TextureSamplingBenchmark::initializeBenchmark()
90 {
91     const auto &params = GetParam();
92 
93     // Verify "numSamplers" is within MAX_TEXTURE_IMAGE_UNITS limit
94     GLint maxTextureImageUnits;
95     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits);
96 
97     if (params.numSamplers > static_cast<unsigned int>(maxTextureImageUnits))
98     {
99         FAIL() << "Sampler count (" << params.numSamplers << ")"
100                << " exceeds maximum texture count: " << maxTextureImageUnits << std::endl;
101     }
102     initShaders();
103     initVertexBuffer();
104     initTextures();
105     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
106     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
107 
108     ASSERT_GL_NO_ERROR();
109 }
110 
initShaders()111 void TextureSamplingBenchmark::initShaders()
112 {
113     const auto &params = GetParam();
114 
115     std::stringstream vstrstr;
116     vstrstr << "attribute vec2 aPosition;\n"
117                "varying vec2 vTextureCoordinates;\n"
118                "void main()\n"
119                "{\n"
120                "    vTextureCoordinates = (aPosition + vec2(1.0)) * 0.5;\n"
121                "    gl_Position = vec4(aPosition, 0, 1.0);\n"
122                "}";
123 
124     std::stringstream fstrstr;
125     fstrstr << "precision mediump float;\n"
126                "varying vec2 vTextureCoordinates;\n";
127     for (unsigned int count = 0; count < params.numSamplers; count++)
128     {
129         fstrstr << "uniform sampler2D uSampler" << count << ";\n";
130     }
131     fstrstr << "void main()\n"
132                "{\n"
133                "    const float inverseTextureSize = 1.0 / "
134             << params.textureSize
135             << ".0;\n"
136                "    vec4 colorOut = vec4(0.0, 0.0, 0.0, 1.0);\n";
137     for (unsigned int count = 0; count < params.numSamplers; count++)
138     {
139         fstrstr << "    for (int x = 0; x < " << params.kernelSize
140                 << "; ++x)\n"
141                    "    {\n"
142                    "        for (int y = 0; y < "
143                 << params.kernelSize
144                 << "; ++y)\n"
145                    "        {\n"
146                    "            colorOut += texture2D(uSampler"
147                 << count
148                 << ", vTextureCoordinates + vec2(x, y) * inverseTextureSize) * 0.1;\n"
149                    "        }\n"
150                    "    }\n";
151     }
152     fstrstr << "    gl_FragColor = colorOut;\n"
153                "}\n";
154 
155     mProgram = CompileProgram(vstrstr.str().c_str(), fstrstr.str().c_str());
156     ASSERT_NE(0u, mProgram);
157 
158     // Use the program object
159     glUseProgram(mProgram);
160 }
161 
initVertexBuffer()162 void TextureSamplingBenchmark::initVertexBuffer()
163 {
164     std::vector<float> vertexPositions(12);
165     {
166         // Bottom left triangle
167         vertexPositions[0] = -1.0f;
168         vertexPositions[1] = -1.0f;
169         vertexPositions[2] = 1.0f;
170         vertexPositions[3] = -1.0f;
171         vertexPositions[4] = -1.0f;
172         vertexPositions[5] = 1.0f;
173 
174         // Top right triangle
175         vertexPositions[6]  = -1.0f;
176         vertexPositions[7]  = 1.0f;
177         vertexPositions[8]  = 1.0f;
178         vertexPositions[9]  = -1.0f;
179         vertexPositions[10] = 1.0f;
180         vertexPositions[11] = 1.0f;
181     }
182 
183     glGenBuffers(1, &mBuffer);
184     glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
185     glBufferData(GL_ARRAY_BUFFER, vertexPositions.size() * sizeof(float), &vertexPositions[0],
186                  GL_STATIC_DRAW);
187 
188     GLint positionLocation = glGetAttribLocation(mProgram, "aPosition");
189     ASSERT_NE(-1, positionLocation);
190 
191     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
192     glEnableVertexAttribArray(positionLocation);
193 }
194 
initTextures()195 void TextureSamplingBenchmark::initTextures()
196 {
197     const auto &params = GetParam();
198 
199     unsigned int dataSize = params.textureSize * params.textureSize;
200     std::vector<unsigned int> randomTextureData;
201     randomTextureData.resize(dataSize);
202 
203     unsigned int pseudoRandom = 1u;
204     for (unsigned int i = 0; i < dataSize; ++i)
205     {
206         pseudoRandom         = pseudoRandom * 1664525u + 1013904223u;
207         randomTextureData[i] = pseudoRandom;
208     }
209 
210     mTextures.resize(params.numSamplers);
211     glGenTextures(params.numSamplers, mTextures.data());
212     for (unsigned int i = 0; i < params.numSamplers; ++i)
213     {
214         glActiveTexture(GL_TEXTURE0 + i);
215         glBindTexture(GL_TEXTURE_2D, mTextures[i]);
216         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
217         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
218         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
219         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
220         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, params.textureSize, params.textureSize, 0, GL_RGBA,
221                      GL_UNSIGNED_BYTE, randomTextureData.data());
222     }
223 
224     for (unsigned int count = 0; count < params.numSamplers; count++)
225     {
226         std::stringstream samplerstrstr;
227         samplerstrstr << "uSampler" << count;
228         GLint samplerLocation = glGetUniformLocation(mProgram, samplerstrstr.str().c_str());
229         ASSERT_NE(-1, samplerLocation);
230 
231         glUniform1i(samplerLocation, count);
232     }
233 }
234 
destroyBenchmark()235 void TextureSamplingBenchmark::destroyBenchmark()
236 {
237     const auto &params = GetParam();
238 
239     glDeleteProgram(mProgram);
240     glDeleteBuffers(1, &mBuffer);
241     if (!mTextures.empty())
242     {
243         glDeleteTextures(params.numSamplers, mTextures.data());
244     }
245 }
246 
drawBenchmark()247 void TextureSamplingBenchmark::drawBenchmark()
248 {
249     glClear(GL_COLOR_BUFFER_BIT);
250 
251     const auto &params = GetParam();
252 
253     for (unsigned int it = 0; it < params.iterationsPerStep; ++it)
254     {
255         glDrawArrays(GL_TRIANGLES, 0, 6);
256     }
257 
258     ASSERT_GL_NO_ERROR();
259 }
260 
261 // Identical to TextureSamplingBenchmark, but enables and then disables
262 // EXT_texture_format_sRGB_override during initialization. This should force the internal texture
263 // representation to use VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, which is expected to carry a
264 // performance penalty. This penalty can be quantified by comparing the results of this test with
265 // the results from TextureSamplingBenchmark
266 class TextureSamplingMutableFormatBenchmark : public TextureSamplingBenchmark
267 {
268   public:
269     void initializeBenchmark() override;
270 
271   protected:
272     void initTextures();
273 };
274 
initializeBenchmark()275 void TextureSamplingMutableFormatBenchmark::initializeBenchmark()
276 {
277     if (IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"))
278     {
279         TextureSamplingBenchmark::initializeBenchmark();
280         initTextures();
281     }
282 }
283 
initTextures()284 void TextureSamplingMutableFormatBenchmark::initTextures()
285 {
286     TextureSamplingBenchmark::initTextures();
287 
288     for (unsigned int i = 0; i < mTextures.size(); ++i)
289     {
290         glActiveTexture(GL_TEXTURE0 + i);
291         glBindTexture(GL_TEXTURE_2D, mTextures[i]);
292         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_SRGB);
293     }
294 
295     // Force a state update
296     drawBenchmark();
297 
298     for (unsigned int i = 0; i < mTextures.size(); ++i)
299     {
300         glActiveTexture(GL_TEXTURE0 + i);
301         glBindTexture(GL_TEXTURE_2D, mTextures[i]);
302         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FORMAT_SRGB_OVERRIDE_EXT, GL_NONE);
303     }
304 }
305 
D3D11Params()306 TextureSamplingParams D3D11Params()
307 {
308     TextureSamplingParams params;
309     params.eglParameters = egl_platform::D3D11();
310     return params;
311 }
312 
OpenGLOrGLESParams()313 TextureSamplingParams OpenGLOrGLESParams()
314 {
315     TextureSamplingParams params;
316     params.eglParameters = egl_platform::OPENGL_OR_GLES();
317     return params;
318 }
319 
VulkanParams()320 TextureSamplingParams VulkanParams()
321 {
322     TextureSamplingParams params;
323     params.eglParameters = egl_platform::VULKAN();
324     return params;
325 }
326 
327 }  // anonymous namespace
328 
TEST_P(TextureSamplingBenchmark,Run)329 TEST_P(TextureSamplingBenchmark, Run)
330 {
331     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
332     run();
333 }
334 
TEST_P(TextureSamplingMutableFormatBenchmark,Run)335 TEST_P(TextureSamplingMutableFormatBenchmark, Run)
336 {
337     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_format_sRGB_override"));
338     run();
339 }
340 
341 ANGLE_INSTANTIATE_TEST(TextureSamplingBenchmark,
342                        D3D11Params(),
343                        OpenGLOrGLESParams(),
344                        VulkanParams());
345 
346 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TextureSamplingMutableFormatBenchmark);
347 ANGLE_INSTANTIATE_TEST(TextureSamplingMutableFormatBenchmark, VulkanParams());
348