xref: /aosp_15_r20/external/angle/src/tests/perf_tests/MapBufferRange.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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__anon88e5e65a0111::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 
BufferUpdateMetalParams()365 MapBufferRangeParams BufferUpdateMetalParams()
366 {
367     MapBufferRangeParams params;
368     params.eglParameters        = egl_platform::METAL();
369     params.vertexType           = GL_FLOAT;
370     params.vertexComponentCount = 4;
371     params.vertexNormalized     = GL_FALSE;
372     return params;
373 }
374 
BufferUpdateMetalParamsLargeUpdate()375 MapBufferRangeParams BufferUpdateMetalParamsLargeUpdate()
376 {
377     MapBufferRangeParams params;
378     params.eglParameters        = egl_platform::METAL();
379     params.vertexType           = GL_FLOAT;
380     params.vertexComponentCount = 4;
381     params.vertexNormalized     = GL_FALSE;
382     params.updateSize           = 524288;
383     return params;
384 }
385 
BufferUpdateOpenGLOrGLESParams()386 MapBufferRangeParams BufferUpdateOpenGLOrGLESParams()
387 {
388     MapBufferRangeParams params;
389     params.eglParameters        = egl_platform::OPENGL_OR_GLES();
390     params.vertexType           = GL_FLOAT;
391     params.vertexComponentCount = 4;
392     params.vertexNormalized     = GL_FALSE;
393     return params;
394 }
395 
BufferUpdateVulkanParams()396 MapBufferRangeParams BufferUpdateVulkanParams()
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     return params;
404 }
405 
BufferUpdateVulkanParamsMidBuffer()406 MapBufferRangeParams BufferUpdateVulkanParamsMidBuffer()
407 {
408     MapBufferRangeParams params;
409     params.eglParameters        = egl_platform::VULKAN();
410     params.vertexType           = GL_FLOAT;
411     params.vertexComponentCount = 4;
412     params.vertexNormalized     = GL_FALSE;
413     params.updateOffset         = 524288;
414     return params;
415 }
416 
BufferUpdateVulkanParamsLargeUpdate()417 MapBufferRangeParams BufferUpdateVulkanParamsLargeUpdate()
418 {
419     MapBufferRangeParams params;
420     params.eglParameters        = egl_platform::VULKAN();
421     params.vertexType           = GL_FLOAT;
422     params.vertexComponentCount = 4;
423     params.vertexNormalized     = GL_FALSE;
424     params.updateSize           = 524288;
425     return params;
426 }
427 
BufferUpdateVulkanParamsFullBuffer()428 MapBufferRangeParams BufferUpdateVulkanParamsFullBuffer()
429 {
430     MapBufferRangeParams params;
431     params.eglParameters        = egl_platform::VULKAN();
432     params.vertexType           = GL_FLOAT;
433     params.vertexComponentCount = 4;
434     params.vertexNormalized     = GL_FALSE;
435     params.updateSize           = 1048576;
436     return params;
437 }
438 
BufferUpdateVulkanParamsTinyUpdate()439 MapBufferRangeParams BufferUpdateVulkanParamsTinyUpdate()
440 {
441     MapBufferRangeParams params;
442     params.eglParameters        = egl_platform::VULKAN();
443     params.vertexType           = GL_FLOAT;
444     params.vertexComponentCount = 4;
445     params.vertexNormalized     = GL_FALSE;
446     params.updateSize           = 128;
447     return params;
448 }
449 
BufferUpdateVulkanParamsNonPowerOf2()450 MapBufferRangeParams BufferUpdateVulkanParamsNonPowerOf2()
451 {
452     MapBufferRangeParams params;
453     params.eglParameters        = egl_platform::VULKAN();
454     params.vertexType           = GL_FLOAT;
455     params.vertexComponentCount = 4;
456     params.vertexNormalized     = GL_FALSE;
457     params.updateSize           = 32000;
458     params.bufferSize           = 800000;
459     return params;
460 }
461 
BufferUpdateVulkanParamsUnsynchronized()462 MapBufferRangeParams BufferUpdateVulkanParamsUnsynchronized()
463 {
464     MapBufferRangeParams params;
465     params.eglParameters        = egl_platform::VULKAN();
466     params.vertexType           = GL_FLOAT;
467     params.vertexComponentCount = 4;
468     params.vertexNormalized     = GL_FALSE;
469     params.access               = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
470     return params;
471 }
472 
BufferUpdateVulkanParamsLargeUpdateUnsynchronized()473 MapBufferRangeParams BufferUpdateVulkanParamsLargeUpdateUnsynchronized()
474 {
475     MapBufferRangeParams params;
476     params.eglParameters        = egl_platform::VULKAN();
477     params.vertexType           = GL_FLOAT;
478     params.vertexComponentCount = 4;
479     params.vertexNormalized     = GL_FALSE;
480     params.updateSize           = 524288;
481     params.access               = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
482     return params;
483 }
484 
TEST_P(MapBufferRangeBenchmark,Run)485 TEST_P(MapBufferRangeBenchmark, Run)
486 {
487     run();
488 }
489 
490 ANGLE_INSTANTIATE_TEST(MapBufferRangeBenchmark,
491                        BufferUpdateD3D11Params(),
492                        BufferUpdateMetalParams(),
493                        BufferUpdateMetalParamsLargeUpdate(),
494                        BufferUpdateOpenGLOrGLESParams(),
495                        BufferUpdateVulkanParams(),
496                        BufferUpdateVulkanParamsMidBuffer(),
497                        BufferUpdateVulkanParamsLargeUpdate(),
498                        BufferUpdateVulkanParamsFullBuffer(),
499                        BufferUpdateVulkanParamsTinyUpdate(),
500                        BufferUpdateVulkanParamsNonPowerOf2(),
501                        BufferUpdateVulkanParamsUnsynchronized(),
502                        BufferUpdateVulkanParamsLargeUpdateUnsynchronized());
503 
504 }  // namespace
505