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 ¶ms)
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 ¶ms = 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 ¶ms = 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 ¶ms = 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 ¶ms = 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 ¶ms = 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