1 //
2 // Copyright 2014 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 // BufferSubDataBenchmark:
7 // Performance test for ANGLE buffer updates.
8 //
9
10 #include <sstream>
11
12 #include "ANGLEPerfTest.h"
13 #include "test_utils/draw_call_perf_utils.h"
14
15 using namespace angle;
16
17 namespace
18 {
19 constexpr unsigned int kIterationsPerStep = 4;
20
21 struct BufferSubDataParams final : public RenderTestParams
22 {
BufferSubDataParams__anon3ec7aeb30111::BufferSubDataParams23 BufferSubDataParams()
24 {
25 // Common default values
26 majorVersion = 2;
27 minorVersion = 0;
28 windowWidth = 512;
29 windowHeight = 512;
30 updateSize = 32000;
31 bufferSize = 40000;
32 iterationsPerStep = kIterationsPerStep;
33 updateRate = 1;
34 }
35
36 std::string story() const override;
37
38 GLboolean vertexNormalized;
39 GLenum vertexType;
40 GLint vertexComponentCount;
41 unsigned int updateRate;
42
43 // static parameters
44 GLsizeiptr updateSize;
45 GLsizeiptr bufferSize;
46 };
47
operator <<(std::ostream & os,const BufferSubDataParams & params)48 std::ostream &operator<<(std::ostream &os, const BufferSubDataParams ¶ms)
49 {
50 os << params.backendAndStory().substr(1);
51 return os;
52 }
53
54 class BufferSubDataBenchmark : public ANGLERenderTest,
55 public ::testing::WithParamInterface<BufferSubDataParams>
56 {
57 public:
58 BufferSubDataBenchmark();
59
60 void initializeBenchmark() override;
61 void destroyBenchmark() override;
62 void drawBenchmark() override;
63
64 private:
65 GLuint mProgram;
66 GLuint mBuffer;
67 uint8_t *mUpdateData;
68 int mNumTris;
69 };
70
GetFloatData(GLint componentCount)71 GLfloat *GetFloatData(GLint componentCount)
72 {
73 static GLfloat vertices2[] = {
74 1, 2, 0, 0, 2, 0,
75 };
76
77 static GLfloat vertices3[] = {
78 1, 2, 1, 0, 0, 1, 2, 0, 1,
79 };
80
81 static GLfloat vertices4[] = {
82 1, 2, 1, 3, 0, 0, 1, 3, 2, 0, 1, 3,
83 };
84
85 switch (componentCount)
86 {
87 case 2:
88 return vertices2;
89 case 3:
90 return vertices3;
91 case 4:
92 return vertices4;
93 default:
94 return nullptr;
95 }
96 }
97
98 template <class T>
GetNormalizedData(GLsizeiptr numElements,GLfloat * floatData,std::vector<uint8_t> * data)99 GLsizeiptr GetNormalizedData(GLsizeiptr numElements, GLfloat *floatData, std::vector<uint8_t> *data)
100 {
101 GLsizeiptr triDataSize = sizeof(T) * numElements;
102 data->resize(triDataSize);
103
104 T *destPtr = reinterpret_cast<T *>(data->data());
105
106 for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++)
107 {
108 GLfloat scaled = floatData[dataIndex] * 0.25f;
109 destPtr[dataIndex] =
110 static_cast<T>(scaled * static_cast<GLfloat>(std::numeric_limits<T>::max()));
111 }
112
113 return triDataSize;
114 }
115
116 template <class T>
GetIntData(GLsizeiptr numElements,GLfloat * floatData,std::vector<uint8_t> * data)117 GLsizeiptr GetIntData(GLsizeiptr numElements, GLfloat *floatData, std::vector<uint8_t> *data)
118 {
119 GLsizeiptr triDataSize = sizeof(T) * numElements;
120 data->resize(triDataSize);
121
122 T *destPtr = reinterpret_cast<T *>(data->data());
123
124 for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++)
125 {
126 destPtr[dataIndex] = static_cast<T>(floatData[dataIndex]);
127 }
128
129 return triDataSize;
130 }
131
GetVertexData(GLenum type,GLint componentCount,GLboolean normalized,std::vector<uint8_t> * data)132 GLsizeiptr GetVertexData(GLenum type,
133 GLint componentCount,
134 GLboolean normalized,
135 std::vector<uint8_t> *data)
136 {
137 GLsizeiptr triDataSize = 0;
138 GLfloat *floatData = GetFloatData(componentCount);
139
140 if (type == GL_FLOAT)
141 {
142 triDataSize = sizeof(GLfloat) * componentCount * 3;
143 data->resize(triDataSize);
144 memcpy(data->data(), floatData, triDataSize);
145 }
146 else if (normalized == GL_TRUE)
147 {
148 GLsizeiptr numElements = componentCount * 3;
149
150 switch (type)
151 {
152 case GL_BYTE:
153 triDataSize = GetNormalizedData<GLbyte>(numElements, floatData, data);
154 break;
155 case GL_SHORT:
156 triDataSize = GetNormalizedData<GLshort>(numElements, floatData, data);
157 break;
158 case GL_INT:
159 triDataSize = GetNormalizedData<GLint>(numElements, floatData, data);
160 break;
161 case GL_UNSIGNED_BYTE:
162 triDataSize = GetNormalizedData<GLubyte>(numElements, floatData, data);
163 break;
164 case GL_UNSIGNED_SHORT:
165 triDataSize = GetNormalizedData<GLushort>(numElements, floatData, data);
166 break;
167 case GL_UNSIGNED_INT:
168 triDataSize = GetNormalizedData<GLuint>(numElements, floatData, data);
169 break;
170 default:
171 assert(0);
172 }
173 }
174 else
175 {
176 GLsizeiptr numElements = componentCount * 3;
177
178 switch (type)
179 {
180 case GL_BYTE:
181 triDataSize = GetIntData<GLbyte>(numElements, floatData, data);
182 break;
183 case GL_SHORT:
184 triDataSize = GetIntData<GLshort>(numElements, floatData, data);
185 break;
186 case GL_INT:
187 triDataSize = GetIntData<GLint>(numElements, floatData, data);
188 break;
189 case GL_UNSIGNED_BYTE:
190 triDataSize = GetIntData<GLubyte>(numElements, floatData, data);
191 break;
192 case GL_UNSIGNED_SHORT:
193 triDataSize = GetIntData<GLushort>(numElements, floatData, data);
194 break;
195 case GL_UNSIGNED_INT:
196 triDataSize = GetIntData<GLuint>(numElements, floatData, data);
197 break;
198 default:
199 assert(0);
200 }
201 }
202
203 return triDataSize;
204 }
205
story() const206 std::string BufferSubDataParams::story() const
207 {
208 std::stringstream strstr;
209
210 strstr << RenderTestParams::story();
211
212 if (vertexNormalized)
213 {
214 strstr << "_norm";
215 }
216
217 switch (vertexType)
218 {
219 case GL_FLOAT:
220 strstr << "_float";
221 break;
222 case GL_INT:
223 strstr << "_int";
224 break;
225 case GL_BYTE:
226 strstr << "_byte";
227 break;
228 case GL_SHORT:
229 strstr << "_short";
230 break;
231 case GL_UNSIGNED_INT:
232 strstr << "_uint";
233 break;
234 case GL_UNSIGNED_BYTE:
235 strstr << "_ubyte";
236 break;
237 case GL_UNSIGNED_SHORT:
238 strstr << "_ushort";
239 break;
240 default:
241 strstr << "_vunk_" << vertexType << "_";
242 break;
243 }
244
245 strstr << vertexComponentCount;
246 strstr << "_every" << updateRate;
247
248 return strstr.str();
249 }
250
BufferSubDataBenchmark()251 BufferSubDataBenchmark::BufferSubDataBenchmark()
252 : ANGLERenderTest("BufferSubData", GetParam()),
253 mProgram(0),
254 mBuffer(0),
255 mUpdateData(nullptr),
256 mNumTris(0)
257 {}
258
initializeBenchmark()259 void BufferSubDataBenchmark::initializeBenchmark()
260 {
261 const auto ¶ms = GetParam();
262
263 ASSERT_LT(1, params.vertexComponentCount);
264
265 mProgram = SetupSimpleScaleAndOffsetProgram();
266 ASSERT_NE(0u, mProgram);
267
268 if (params.vertexNormalized == GL_TRUE)
269 {
270 GLfloat scale = 2.0f;
271 GLfloat offset = -0.5f;
272 glUniform1f(glGetUniformLocation(mProgram, "uScale"), scale);
273 glUniform1f(glGetUniformLocation(mProgram, "uOffset"), offset);
274 }
275
276 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
277
278 std::vector<uint8_t> zeroData(params.bufferSize);
279 memset(&zeroData[0], 0, zeroData.size());
280
281 glGenBuffers(1, &mBuffer);
282 glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
283 glBufferData(GL_ARRAY_BUFFER, params.bufferSize, &zeroData[0], GL_DYNAMIC_DRAW);
284
285 glVertexAttribPointer(0, params.vertexComponentCount, params.vertexType,
286 params.vertexNormalized, 0, 0);
287 glEnableVertexAttribArray(0);
288
289 if (params.updateSize > 0)
290 {
291 mUpdateData = new uint8_t[params.updateSize];
292 }
293
294 std::vector<uint8_t> data;
295 GLsizei triDataSize = static_cast<GLsizei>(GetVertexData(
296 params.vertexType, params.vertexComponentCount, params.vertexNormalized, &data));
297
298 mNumTris = static_cast<int>(params.updateSize / triDataSize);
299 for (int i = 0, offset = 0; i < mNumTris; ++i)
300 {
301 memcpy(mUpdateData + offset, &data[0], triDataSize);
302 offset += triDataSize;
303 }
304
305 if (params.updateSize == 0)
306 {
307 mNumTris = 1;
308 glBufferSubData(GL_ARRAY_BUFFER, 0, data.size(), &data[0]);
309 }
310
311 // Set the viewport
312 glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
313
314 ASSERT_GL_NO_ERROR();
315 }
316
destroyBenchmark()317 void BufferSubDataBenchmark::destroyBenchmark()
318 {
319 glDeleteProgram(mProgram);
320 glDeleteBuffers(1, &mBuffer);
321 SafeDeleteArray(mUpdateData);
322 }
323
drawBenchmark()324 void BufferSubDataBenchmark::drawBenchmark()
325 {
326 glClear(GL_COLOR_BUFFER_BIT);
327
328 const auto ¶ms = GetParam();
329
330 for (unsigned int it = 0; it < params.iterationsPerStep; it++)
331 {
332 if (params.updateSize > 0 && ((getNumStepsPerformed() % params.updateRate) == 0))
333 {
334 glBufferSubData(GL_ARRAY_BUFFER, 0, params.updateSize, mUpdateData);
335 }
336
337 glDrawArrays(GL_TRIANGLES, 0, 3 * mNumTris);
338 }
339
340 ASSERT_GL_NO_ERROR();
341 }
342
BufferUpdateD3D11Params()343 BufferSubDataParams BufferUpdateD3D11Params()
344 {
345 BufferSubDataParams params;
346 params.eglParameters = egl_platform::D3D11();
347 params.vertexType = GL_FLOAT;
348 params.vertexComponentCount = 4;
349 params.vertexNormalized = GL_FALSE;
350 return params;
351 }
352
BufferUpdateMetalParams()353 BufferSubDataParams BufferUpdateMetalParams()
354 {
355 BufferSubDataParams params;
356 params.eglParameters = egl_platform::METAL();
357 params.vertexType = GL_FLOAT;
358 params.vertexComponentCount = 4;
359 params.vertexNormalized = GL_FALSE;
360 return params;
361 }
362
BufferUpdateOpenGLOrGLESParams()363 BufferSubDataParams BufferUpdateOpenGLOrGLESParams()
364 {
365 BufferSubDataParams params;
366 params.eglParameters = egl_platform::OPENGL_OR_GLES();
367 params.vertexType = GL_FLOAT;
368 params.vertexComponentCount = 4;
369 params.vertexNormalized = GL_FALSE;
370 return params;
371 }
372
BufferUpdateVulkanParams()373 BufferSubDataParams BufferUpdateVulkanParams()
374 {
375 BufferSubDataParams params;
376 params.eglParameters = egl_platform::VULKAN();
377 params.vertexType = GL_FLOAT;
378 params.vertexComponentCount = 4;
379 params.vertexNormalized = GL_FALSE;
380 return params;
381 }
382
TEST_P(BufferSubDataBenchmark,Run)383 TEST_P(BufferSubDataBenchmark, Run)
384 {
385 run();
386 }
387
388 ANGLE_INSTANTIATE_TEST(BufferSubDataBenchmark,
389 BufferUpdateD3D11Params(),
390 BufferUpdateMetalParams(),
391 BufferUpdateOpenGLOrGLESParams(),
392 BufferUpdateVulkanParams());
393
394 } // namespace
395