• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 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 // MapBufferRangeBenchmark::
7 //   Performance test for ANGLE GLES mapped buffers.
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include <sstream>
13 #include <vector>
14 
15 #include "common/debug.h"
16 #include "test_utils/draw_call_perf_utils.h"
17 
18 using namespace angle;
19 
20 namespace
21 {
22 constexpr unsigned int kIterationsPerStep = 10;
23 
24 struct MapBufferRangeParams final : public RenderTestParams
25 {
MapBufferRangeParams__anon7a62b7090111::MapBufferRangeParams26     MapBufferRangeParams()
27     {
28         // Common default values
29         majorVersion = 3;
30         minorVersion = 0;
31         windowWidth  = 512;
32         windowHeight = 512;
33         // Test intentionally small update versus buffer size to begin with.
34         updateSize        = 32768;
35         updateOffset      = 0;
36         bufferSize        = 1048576;
37         iterationsPerStep = kIterationsPerStep;
38         access            = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
39     }
40 
41     std::string story() const override;
42 
43     GLboolean vertexNormalized;
44     GLenum vertexType;
45     GLint vertexComponentCount;
46 
47     // static parameters
48     GLsizeiptr updateSize;
49     GLsizeiptr updateOffset;
50     GLsizeiptr bufferSize;
51     GLbitfield access;
52 };
53 
operator <<(std::ostream & os,const MapBufferRangeParams & params)54 std::ostream &operator<<(std::ostream &os, const MapBufferRangeParams &params)
55 {
56     os << params.backendAndStory().substr(1);
57     return os;
58 }
59 
60 class MapBufferRangeBenchmark : public ANGLERenderTest,
61                                 public ::testing::WithParamInterface<MapBufferRangeParams>
62 {
63   public:
64     MapBufferRangeBenchmark();
65 
66     void initializeBenchmark() override;
67     void destroyBenchmark() override;
68     void drawBenchmark() override;
69 
70   private:
71     GLuint mProgram;
72     GLuint mBuffer;
73     std::vector<uint8_t> mVertexData;
74     int mTriSize;
75     int mNumUpdateTris;
76 };
77 
GetFloatData(GLint componentCount)78 const GLfloat *GetFloatData(GLint componentCount)
79 {
80     static GLfloat vertices2[] = {
81         1, 2, 0, 0, 2, 0,
82     };
83 
84     static GLfloat vertices3[] = {
85         1, 2, 1, 0, 0, 1, 2, 0, 1,
86     };
87 
88     static GLfloat vertices4[] = {
89         1, 2, 1, 3, 0, 0, 1, 3, 2, 0, 1, 3,
90     };
91 
92     switch (componentCount)
93     {
94         case 2:
95             return vertices2;
96         case 3:
97             return vertices3;
98         case 4:
99             return vertices4;
100         default:
101             UNREACHABLE();
102     }
103 
104     return 0;
105 }
106 
107 template <class T>
GetNormalizedData(GLsizeiptr numElements,const GLfloat * floatData,std::vector<uint8_t> * data)108 GLsizei GetNormalizedData(GLsizeiptr numElements,
109                           const GLfloat *floatData,
110                           std::vector<uint8_t> *data)
111 {
112     GLsizei triDataSize = sizeof(T) * numElements;
113     data->resize(triDataSize);
114 
115     T *destPtr = reinterpret_cast<T *>(data->data());
116 
117     for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++)
118     {
119         GLfloat scaled = floatData[dataIndex] * 0.25f;
120         destPtr[dataIndex] =
121             static_cast<T>(scaled * static_cast<GLfloat>(std::numeric_limits<T>::max()));
122     }
123 
124     return triDataSize;
125 }
126 
127 template <class T>
GetIntData(GLsizeiptr numElements,const GLfloat * floatData,std::vector<uint8_t> * data)128 GLsizei GetIntData(GLsizeiptr numElements, const GLfloat *floatData, std::vector<uint8_t> *data)
129 {
130     GLsizei triDataSize = sizeof(T) * numElements;
131     data->resize(triDataSize);
132 
133     T *destPtr = reinterpret_cast<T *>(data->data());
134 
135     for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++)
136     {
137         destPtr[dataIndex] = static_cast<T>(floatData[dataIndex]);
138     }
139 
140     return triDataSize;
141 }
142 
GetVertexData(GLenum type,GLint componentCount,GLboolean normalized,std::vector<uint8_t> * data)143 GLsizei GetVertexData(GLenum type,
144                       GLint componentCount,
145                       GLboolean normalized,
146                       std::vector<uint8_t> *data)
147 {
148     GLsizei triDataSize      = 0;
149     const GLfloat *floatData = GetFloatData(componentCount);
150 
151     if (type == GL_FLOAT)
152     {
153         triDataSize = sizeof(GLfloat) * componentCount * 3;
154         data->resize(triDataSize);
155         memcpy(data->data(), floatData, triDataSize);
156     }
157     else if (normalized == GL_TRUE)
158     {
159         GLsizeiptr numElements = componentCount * 3;
160 
161         switch (type)
162         {
163             case GL_BYTE:
164                 triDataSize = GetNormalizedData<GLbyte>(numElements, floatData, data);
165                 break;
166             case GL_SHORT:
167                 triDataSize = GetNormalizedData<GLshort>(numElements, floatData, data);
168                 break;
169             case GL_INT:
170                 triDataSize = GetNormalizedData<GLint>(numElements, floatData, data);
171                 break;
172             case GL_UNSIGNED_BYTE:
173                 triDataSize = GetNormalizedData<GLubyte>(numElements, floatData, data);
174                 break;
175             case GL_UNSIGNED_SHORT:
176                 triDataSize = GetNormalizedData<GLushort>(numElements, floatData, data);
177                 break;
178             case GL_UNSIGNED_INT:
179                 triDataSize = GetNormalizedData<GLuint>(numElements, floatData, data);
180                 break;
181             default:
182                 UNREACHABLE();
183         }
184     }
185     else
186     {
187         GLsizeiptr numElements = componentCount * 3;
188 
189         switch (type)
190         {
191             case GL_BYTE:
192                 triDataSize = GetIntData<GLbyte>(numElements, floatData, data);
193                 break;
194             case GL_SHORT:
195                 triDataSize = GetIntData<GLshort>(numElements, floatData, data);
196                 break;
197             case GL_INT:
198                 triDataSize = GetIntData<GLint>(numElements, floatData, data);
199                 break;
200             case GL_UNSIGNED_BYTE:
201                 triDataSize = GetIntData<GLubyte>(numElements, floatData, data);
202                 break;
203             case GL_UNSIGNED_SHORT:
204                 triDataSize = GetIntData<GLushort>(numElements, floatData, data);
205                 break;
206             case GL_UNSIGNED_INT:
207                 triDataSize = GetIntData<GLuint>(numElements, floatData, data);
208                 break;
209             default:
210                 assert(0);
211         }
212     }
213 
214     return triDataSize;
215 }
216 
story() const217 std::string MapBufferRangeParams::story() const
218 {
219     std::stringstream strstr;
220 
221     strstr << RenderTestParams::story();
222 
223     if (vertexNormalized)
224     {
225         strstr << "_norm";
226     }
227 
228     switch (vertexType)
229     {
230         case GL_FLOAT:
231             strstr << "_float";
232             break;
233         case GL_INT:
234             strstr << "_int";
235             break;
236         case GL_BYTE:
237             strstr << "_byte";
238             break;
239         case GL_SHORT:
240             strstr << "_short";
241             break;
242         case GL_UNSIGNED_INT:
243             strstr << "_uint";
244             break;
245         case GL_UNSIGNED_BYTE:
246             strstr << "_ubyte";
247             break;
248         case GL_UNSIGNED_SHORT:
249             strstr << "_ushort";
250             break;
251         default:
252             UNREACHABLE();
253     }
254 
255     strstr << vertexComponentCount;
256     strstr << "_updateOffset" << updateOffset;
257     strstr << "_updateSize" << updateSize;
258     strstr << "_bufferSize" << bufferSize;
259     strstr << "_access0x" << std::hex << access;
260 
261     return strstr.str();
262 }
263 
MapBufferRangeBenchmark()264 MapBufferRangeBenchmark::MapBufferRangeBenchmark()
265     : ANGLERenderTest("MapBufferRange", GetParam()),
266       mProgram(0),
267       mBuffer(0),
268       mTriSize(0),
269       mNumUpdateTris(0)
270 {}
271 
initializeBenchmark()272 void MapBufferRangeBenchmark::initializeBenchmark()
273 {
274     const auto &params = GetParam();
275 
276     ASSERT_LT(1, params.vertexComponentCount);
277     ASSERT_LE(params.updateSize, params.bufferSize);
278     ASSERT_LT(params.updateOffset, params.bufferSize);
279     ASSERT_LE(params.updateOffset + params.updateSize, params.bufferSize);
280 
281     mProgram = SetupSimpleScaleAndOffsetProgram();
282     ASSERT_NE(0u, mProgram);
283 
284     if (params.vertexNormalized == GL_TRUE)
285     {
286         GLfloat scale  = 2.0f;
287         GLfloat offset = -0.5f;
288         glUniform1f(glGetUniformLocation(mProgram, "uScale"), scale);
289         glUniform1f(glGetUniformLocation(mProgram, "uOffset"), offset);
290     }
291 
292     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
293 
294     glGenBuffers(1, &mBuffer);
295     glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
296     glBufferData(GL_ARRAY_BUFFER, params.bufferSize, nullptr, GL_DYNAMIC_DRAW);
297 
298     glVertexAttribPointer(0, params.vertexComponentCount, params.vertexType,
299                           params.vertexNormalized, 0, 0);
300     glEnableVertexAttribArray(0);
301 
302     mTriSize = GetVertexData(params.vertexType, params.vertexComponentCount,
303                              params.vertexNormalized, &mVertexData);
304 
305     mNumUpdateTris = static_cast<int>(params.updateSize / mTriSize);
306     int totalTris  = static_cast<int>(params.updateSize / mTriSize);
307 
308     mVertexData.resize(params.bufferSize);
309 
310     for (int i = 1; i < totalTris; ++i)
311     {
312         memcpy(mVertexData.data() + i * mTriSize, mVertexData.data(), mTriSize);
313     }
314 
315     if (params.updateSize == 0)
316     {
317         mNumUpdateTris = 1;
318         glBufferSubData(GL_ARRAY_BUFFER, 0, mVertexData.size(), mVertexData.data());
319     }
320 
321     // Set the viewport
322     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
323 
324     ASSERT_GL_NO_ERROR();
325 }
326 
destroyBenchmark()327 void MapBufferRangeBenchmark::destroyBenchmark()
328 {
329     glDeleteProgram(mProgram);
330     glDeleteBuffers(1, &mBuffer);
331 }
332 
drawBenchmark()333 void MapBufferRangeBenchmark::drawBenchmark()
334 {
335     glClear(GL_COLOR_BUFFER_BIT);
336 
337     const auto &params = GetParam();
338 
339     for (unsigned int it = 0; it < params.iterationsPerStep; it++)
340     {
341         if (params.updateSize > 0)
342         {
343             void *mapPtr = glMapBufferRange(GL_ARRAY_BUFFER, params.updateOffset, params.updateSize,
344                                             params.access);
345             memcpy(mapPtr, mVertexData.data() + params.updateOffset, params.updateSize);
346             glUnmapBuffer(GL_ARRAY_BUFFER);
347         }
348 
349         glDrawArrays(GL_TRIANGLES, params.updateOffset / mTriSize, 3 * mNumUpdateTris);
350     }
351 
352     ASSERT_GL_NO_ERROR();
353 }
354 
BufferUpdateD3D11Params()355 MapBufferRangeParams BufferUpdateD3D11Params()
356 {
357     MapBufferRangeParams params;
358     params.eglParameters        = egl_platform::D3D11();
359     params.vertexType           = GL_FLOAT;
360     params.vertexComponentCount = 4;
361     params.vertexNormalized     = GL_FALSE;
362     return params;
363 }
364 
BufferUpdateOpenGLOrGLESParams()365 MapBufferRangeParams BufferUpdateOpenGLOrGLESParams()
366 {
367     MapBufferRangeParams params;
368     params.eglParameters        = egl_platform::OPENGL_OR_GLES();
369     params.vertexType           = GL_FLOAT;
370     params.vertexComponentCount = 4;
371     params.vertexNormalized     = GL_FALSE;
372     return params;
373 }
374 
BufferUpdateVulkanParams()375 MapBufferRangeParams BufferUpdateVulkanParams()
376 {
377     MapBufferRangeParams params;
378     params.eglParameters        = egl_platform::VULKAN();
379     params.vertexType           = GL_FLOAT;
380     params.vertexComponentCount = 4;
381     params.vertexNormalized     = GL_FALSE;
382     return params;
383 }
384 
BufferUpdateVulkanParamsMidBuffer()385 MapBufferRangeParams BufferUpdateVulkanParamsMidBuffer()
386 {
387     MapBufferRangeParams params;
388     params.eglParameters        = egl_platform::VULKAN();
389     params.vertexType           = GL_FLOAT;
390     params.vertexComponentCount = 4;
391     params.vertexNormalized     = GL_FALSE;
392     params.updateOffset         = 524288;
393     return params;
394 }
395 
BufferUpdateVulkanParamsLargeUpdate()396 MapBufferRangeParams BufferUpdateVulkanParamsLargeUpdate()
397 {
398     MapBufferRangeParams params;
399     params.eglParameters        = egl_platform::VULKAN();
400     params.vertexType           = GL_FLOAT;
401     params.vertexComponentCount = 4;
402     params.vertexNormalized     = GL_FALSE;
403     params.updateSize           = 524288;
404     return params;
405 }
406 
BufferUpdateVulkanParamsFullBuffer()407 MapBufferRangeParams BufferUpdateVulkanParamsFullBuffer()
408 {
409     MapBufferRangeParams params;
410     params.eglParameters        = egl_platform::VULKAN();
411     params.vertexType           = GL_FLOAT;
412     params.vertexComponentCount = 4;
413     params.vertexNormalized     = GL_FALSE;
414     params.updateSize           = 1048576;
415     return params;
416 }
417 
BufferUpdateVulkanParamsTinyUpdate()418 MapBufferRangeParams BufferUpdateVulkanParamsTinyUpdate()
419 {
420     MapBufferRangeParams params;
421     params.eglParameters        = egl_platform::VULKAN();
422     params.vertexType           = GL_FLOAT;
423     params.vertexComponentCount = 4;
424     params.vertexNormalized     = GL_FALSE;
425     params.updateSize           = 128;
426     return params;
427 }
428 
BufferUpdateVulkanParamsNonPowerOf2()429 MapBufferRangeParams BufferUpdateVulkanParamsNonPowerOf2()
430 {
431     MapBufferRangeParams params;
432     params.eglParameters        = egl_platform::VULKAN();
433     params.vertexType           = GL_FLOAT;
434     params.vertexComponentCount = 4;
435     params.vertexNormalized     = GL_FALSE;
436     params.updateSize           = 32000;
437     params.bufferSize           = 800000;
438     return params;
439 }
440 
BufferUpdateVulkanParamsUnsynchronized()441 MapBufferRangeParams BufferUpdateVulkanParamsUnsynchronized()
442 {
443     MapBufferRangeParams params;
444     params.eglParameters        = egl_platform::VULKAN();
445     params.vertexType           = GL_FLOAT;
446     params.vertexComponentCount = 4;
447     params.vertexNormalized     = GL_FALSE;
448     params.access               = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
449     return params;
450 }
451 
BufferUpdateVulkanParamsLargeUpdateUnsynchronized()452 MapBufferRangeParams BufferUpdateVulkanParamsLargeUpdateUnsynchronized()
453 {
454     MapBufferRangeParams params;
455     params.eglParameters        = egl_platform::VULKAN();
456     params.vertexType           = GL_FLOAT;
457     params.vertexComponentCount = 4;
458     params.vertexNormalized     = GL_FALSE;
459     params.updateSize           = 524288;
460     params.access               = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
461     return params;
462 }
463 
TEST_P(MapBufferRangeBenchmark,Run)464 TEST_P(MapBufferRangeBenchmark, Run)
465 {
466     run();
467 }
468 
469 ANGLE_INSTANTIATE_TEST(MapBufferRangeBenchmark,
470                        BufferUpdateD3D11Params(),
471                        BufferUpdateOpenGLOrGLESParams(),
472                        BufferUpdateVulkanParams(),
473                        BufferUpdateVulkanParamsMidBuffer(),
474                        BufferUpdateVulkanParamsLargeUpdate(),
475                        BufferUpdateVulkanParamsFullBuffer(),
476                        BufferUpdateVulkanParamsTinyUpdate(),
477                        BufferUpdateVulkanParamsNonPowerOf2(),
478                        BufferUpdateVulkanParamsUnsynchronized(),
479                        BufferUpdateVulkanParamsLargeUpdateUnsynchronized());
480 
481 }  // namespace
482