xref: /aosp_15_r20/external/deqp/modules/gles2/performance/es2pDrawCallBatchingTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Draw call batching performance tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es2pDrawCallBatchingTests.hpp"
25 
26 #include "gluShaderProgram.hpp"
27 #include "gluRenderContext.hpp"
28 
29 #include "glwDefs.hpp"
30 #include "glwFunctions.hpp"
31 #include "glwEnums.hpp"
32 
33 #include "tcuTestLog.hpp"
34 
35 #include "deRandom.hpp"
36 #include "deStringUtil.hpp"
37 
38 #include "deFile.h"
39 #include "deString.h"
40 #include "deClock.h"
41 #include "deThread.h"
42 
43 #include <cmath>
44 #include <vector>
45 #include <string>
46 #include <sstream>
47 
48 using tcu::TestLog;
49 
50 using namespace glw;
51 
52 using std::string;
53 using std::vector;
54 
55 namespace deqp
56 {
57 namespace gles2
58 {
59 namespace Performance
60 {
61 
62 namespace
63 {
64 const int CALIBRATION_SAMPLE_COUNT = 34;
65 
66 class DrawCallBatchingTest : public tcu::TestCase
67 {
68 public:
69     struct TestSpec
70     {
71         bool useStaticBuffer;
72         int staticAttributeCount;
73 
74         bool useDynamicBuffer;
75         int dynamicAttributeCount;
76 
77         int triangleCount;
78         int drawCallCount;
79 
80         bool useDrawElements;
81         bool useIndexBuffer;
82         bool dynamicIndices;
83     };
84 
85     DrawCallBatchingTest(Context &context, const char *name, const char *description, const TestSpec &spec);
86     ~DrawCallBatchingTest(void);
87 
88     void init(void);
89     void deinit(void);
90     IterateResult iterate(void);
91 
92 private:
93     enum State
94     {
95         STATE_LOG_INFO = 0,
96         STATE_WARMUP_BATCHED,
97         STATE_WARMUP_UNBATCHED,
98         STATE_CALC_CALIBRATION,
99         STATE_SAMPLE
100     };
101 
102     State m_state;
103 
104     glu::RenderContext &m_renderCtx;
105     de::Random m_rnd;
106     int m_sampleIteration;
107 
108     int m_unbatchedSampleCount;
109     int m_batchedSampleCount;
110 
111     TestSpec m_spec;
112 
113     glu::ShaderProgram *m_program;
114 
115     vector<uint8_t> m_dynamicIndexData;
116     vector<uint8_t> m_staticIndexData;
117 
118     vector<GLuint> m_unbatchedDynamicIndexBuffers;
119     GLuint m_batchedDynamicIndexBuffer;
120 
121     GLuint m_unbatchedStaticIndexBuffer;
122     GLuint m_batchedStaticIndexBuffer;
123 
124     vector<vector<int8_t>> m_staticAttributeDatas;
125     vector<vector<int8_t>> m_dynamicAttributeDatas;
126 
127     vector<GLuint> m_batchedStaticBuffers;
128     vector<GLuint> m_unbatchedStaticBuffers;
129 
130     vector<GLuint> m_batchedDynamicBuffers;
131     vector<vector<GLuint>> m_unbatchedDynamicBuffers;
132 
133     vector<uint64_t> m_unbatchedSamplesUs;
134     vector<uint64_t> m_batchedSamplesUs;
135 
136     void logTestInfo(void);
137 
138     uint64_t renderUnbatched(void);
139     uint64_t renderBatched(void);
140 
141     void createIndexData(void);
142     void createIndexBuffer(void);
143 
144     void createShader(void);
145     void createAttributeDatas(void);
146     void createArrayBuffers(void);
147 };
148 
DrawCallBatchingTest(Context & context,const char * name,const char * description,const TestSpec & spec)149 DrawCallBatchingTest::DrawCallBatchingTest(Context &context, const char *name, const char *description,
150                                            const TestSpec &spec)
151     : tcu::TestCase(context.getTestContext(), tcu::NODETYPE_PERFORMANCE, name, description)
152     , m_state(STATE_LOG_INFO)
153     , m_renderCtx(context.getRenderContext())
154     , m_rnd(deStringHash(name))
155     , m_sampleIteration(0)
156     , m_unbatchedSampleCount(CALIBRATION_SAMPLE_COUNT)
157     , m_batchedSampleCount(CALIBRATION_SAMPLE_COUNT)
158     , m_spec(spec)
159     , m_program(NULL)
160     , m_batchedDynamicIndexBuffer(0)
161     , m_unbatchedStaticIndexBuffer(0)
162     , m_batchedStaticIndexBuffer(0)
163 {
164 }
165 
~DrawCallBatchingTest(void)166 DrawCallBatchingTest::~DrawCallBatchingTest(void)
167 {
168     deinit();
169 }
170 
createIndexData(void)171 void DrawCallBatchingTest::createIndexData(void)
172 {
173     if (m_spec.dynamicIndices)
174     {
175         for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
176         {
177             for (int triangleNdx = 0; triangleNdx < m_spec.triangleCount; triangleNdx++)
178             {
179                 m_dynamicIndexData.push_back(uint8_t(triangleNdx * 3));
180                 m_dynamicIndexData.push_back(uint8_t(triangleNdx * 3 + 1));
181                 m_dynamicIndexData.push_back(uint8_t(triangleNdx * 3 + 2));
182             }
183         }
184     }
185     else
186     {
187         for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
188         {
189             for (int triangleNdx = 0; triangleNdx < m_spec.triangleCount; triangleNdx++)
190             {
191                 m_staticIndexData.push_back(uint8_t(triangleNdx * 3));
192                 m_staticIndexData.push_back(uint8_t(triangleNdx * 3 + 1));
193                 m_staticIndexData.push_back(uint8_t(triangleNdx * 3 + 2));
194             }
195         }
196     }
197 }
198 
createShader(void)199 void DrawCallBatchingTest::createShader(void)
200 {
201     std::ostringstream vertexShader;
202     std::ostringstream fragmentShader;
203 
204     for (int attributeNdx = 0; attributeNdx < m_spec.staticAttributeCount; attributeNdx++)
205         vertexShader << "attribute mediump vec4 a_static" << attributeNdx << ";\n";
206 
207     if (m_spec.staticAttributeCount > 0 && m_spec.dynamicAttributeCount > 0)
208         vertexShader << "\n";
209 
210     for (int attributeNdx = 0; attributeNdx < m_spec.dynamicAttributeCount; attributeNdx++)
211         vertexShader << "attribute mediump vec4 a_dyn" << attributeNdx << ";\n";
212 
213     vertexShader << "\n"
214                  << "varying mediump vec4 v_color;\n"
215                  << "\n"
216                  << "void main (void)\n"
217                  << "{\n";
218 
219     vertexShader << "\tv_color = ";
220 
221     bool first = true;
222 
223     for (int attributeNdx = 0; attributeNdx < m_spec.staticAttributeCount; attributeNdx++)
224     {
225         if (!first)
226             vertexShader << " + ";
227         first = false;
228 
229         vertexShader << "a_static" << attributeNdx;
230     }
231 
232     for (int attributeNdx = 0; attributeNdx < m_spec.dynamicAttributeCount; attributeNdx++)
233     {
234         if (!first)
235             vertexShader << " + ";
236         first = false;
237 
238         vertexShader << "a_dyn" << attributeNdx;
239     }
240 
241     vertexShader << ";\n";
242 
243     if (m_spec.dynamicAttributeCount > 0)
244         vertexShader << "\tgl_Position = a_dyn0;\n";
245     else
246         vertexShader << "\tgl_Position = a_static0;\n";
247 
248     vertexShader << "}";
249 
250     fragmentShader << "varying mediump vec4 v_color;\n"
251                    << "\n"
252                    << "void main(void)\n"
253                    << "{\n"
254                    << "\tgl_FragColor = v_color;\n"
255                    << "}\n";
256 
257     m_program = new glu::ShaderProgram(m_renderCtx, glu::ProgramSources() << glu::VertexSource(vertexShader.str())
258                                                                           << glu::FragmentSource(fragmentShader.str()));
259 
260     m_testCtx.getLog() << (*m_program);
261     TCU_CHECK(m_program->isOk());
262 }
263 
createAttributeDatas(void)264 void DrawCallBatchingTest::createAttributeDatas(void)
265 {
266     // Generate data for static attributes
267     for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
268     {
269         vector<int8_t> data;
270 
271         if (m_spec.dynamicAttributeCount == 0 && attribute == 0)
272         {
273             data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
274 
275             for (int i = 0; i < m_spec.triangleCount * m_spec.drawCallCount; i++)
276             {
277                 int sign = (m_spec.triangleCount % 2 == 1 || i % 2 == 0 ? 1 : -1);
278 
279                 data.push_back(int8_t(-127 * sign));
280                 data.push_back(int8_t(-127 * sign));
281                 data.push_back(0);
282                 data.push_back(127);
283 
284                 data.push_back(int8_t(127 * sign));
285                 data.push_back(int8_t(-127 * sign));
286                 data.push_back(0);
287                 data.push_back(127);
288 
289                 data.push_back(int8_t(127 * sign));
290                 data.push_back(int8_t(127 * sign));
291                 data.push_back(0);
292                 data.push_back(127);
293             }
294         }
295         else
296         {
297             data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
298 
299             for (int i = 0; i < 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount; i++)
300                 data.push_back((int8_t)m_rnd.getUint32());
301         }
302 
303         m_staticAttributeDatas.push_back(data);
304     }
305 
306     // Generate data for dynamic attributes
307     for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
308     {
309         vector<int8_t> data;
310 
311         if (attribute == 0)
312         {
313             data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
314 
315             for (int i = 0; i < m_spec.triangleCount * m_spec.drawCallCount; i++)
316             {
317                 int sign = (i % 2 == 0 ? 1 : -1);
318 
319                 data.push_back(int8_t(-127 * sign));
320                 data.push_back(int8_t(-127 * sign));
321                 data.push_back(0);
322                 data.push_back(127);
323 
324                 data.push_back(int8_t(127 * sign));
325                 data.push_back(int8_t(-127 * sign));
326                 data.push_back(0);
327                 data.push_back(127);
328 
329                 data.push_back(int8_t(127 * sign));
330                 data.push_back(int8_t(127 * sign));
331                 data.push_back(0);
332                 data.push_back(127);
333             }
334         }
335         else
336         {
337             data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
338 
339             for (int i = 0; i < 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount; i++)
340                 data.push_back((int8_t)m_rnd.getUint32());
341         }
342 
343         m_dynamicAttributeDatas.push_back(data);
344     }
345 }
346 
createArrayBuffers(void)347 void DrawCallBatchingTest::createArrayBuffers(void)
348 {
349     const glw::Functions &gl = m_renderCtx.getFunctions();
350 
351     if (m_spec.useStaticBuffer)
352     {
353         // Upload static attributes for batched
354         for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
355         {
356             GLuint buffer;
357 
358             gl.genBuffers(1, &buffer);
359             gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
360             gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount,
361                           &(m_staticAttributeDatas[attribute][0]), GL_STATIC_DRAW);
362             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
363             GLU_EXPECT_NO_ERROR(gl.getError(), "Creating static buffer failed");
364 
365             m_batchedStaticBuffers.push_back(buffer);
366         }
367 
368         // Upload static attributes for unbatched
369         for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
370         {
371             GLuint buffer;
372 
373             gl.genBuffers(1, &buffer);
374             gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
375             gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount, &(m_staticAttributeDatas[attribute][0]),
376                           GL_STATIC_DRAW);
377             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
378             GLU_EXPECT_NO_ERROR(gl.getError(), "Creating static buffer failed");
379 
380             m_unbatchedStaticBuffers.push_back(buffer);
381         }
382     }
383 
384     if (m_spec.useDynamicBuffer)
385     {
386         // Upload dynamic attributes for batched
387         for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
388         {
389             GLuint buffer;
390 
391             gl.genBuffers(1, &buffer);
392             gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
393             gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount,
394                           &(m_dynamicAttributeDatas[attribute][0]), GL_STATIC_DRAW);
395             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
396             GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic buffer failed");
397 
398             m_batchedDynamicBuffers.push_back(buffer);
399         }
400 
401         // Upload dynamic attributes for unbatched
402         for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
403         {
404             vector<GLuint> buffers;
405 
406             for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
407             {
408                 GLuint buffer;
409 
410                 gl.genBuffers(1, &buffer);
411                 gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
412                 gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount,
413                               &(m_dynamicAttributeDatas[attribute][0]), GL_STATIC_DRAW);
414                 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
415                 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic buffer failed");
416 
417                 buffers.push_back(buffer);
418             }
419 
420             m_unbatchedDynamicBuffers.push_back(buffers);
421         }
422     }
423 }
424 
createIndexBuffer(void)425 void DrawCallBatchingTest::createIndexBuffer(void)
426 {
427     const glw::Functions &gl = m_renderCtx.getFunctions();
428 
429     if (m_spec.dynamicIndices)
430     {
431         for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
432         {
433             GLuint buffer;
434 
435             gl.genBuffers(1, &buffer);
436             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
437             gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount,
438                           &(m_dynamicIndexData[drawNdx * m_spec.triangleCount * 3]), GL_STATIC_DRAW);
439             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
440             GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
441 
442             m_unbatchedDynamicIndexBuffers.push_back(buffer);
443         }
444 
445         {
446             GLuint buffer;
447 
448             gl.genBuffers(1, &buffer);
449             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
450             gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount * m_spec.drawCallCount,
451                           &(m_dynamicIndexData[0]), GL_STATIC_DRAW);
452             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
453             GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
454 
455             m_batchedDynamicIndexBuffer = buffer;
456         }
457     }
458     else
459     {
460         {
461             GLuint buffer;
462 
463             gl.genBuffers(1, &buffer);
464             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
465             gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount * m_spec.drawCallCount,
466                           &(m_staticIndexData[0]), GL_STATIC_DRAW);
467             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
468             GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
469 
470             m_batchedStaticIndexBuffer = buffer;
471         }
472 
473         {
474             GLuint buffer;
475 
476             gl.genBuffers(1, &buffer);
477             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
478             gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount, &(m_staticIndexData[0]), GL_STATIC_DRAW);
479             gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
480             GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
481 
482             m_unbatchedStaticIndexBuffer = buffer;
483         }
484     }
485 }
486 
init(void)487 void DrawCallBatchingTest::init(void)
488 {
489     createShader();
490     createAttributeDatas();
491     createArrayBuffers();
492 
493     if (m_spec.useDrawElements)
494     {
495         createIndexData();
496 
497         if (m_spec.useIndexBuffer)
498             createIndexBuffer();
499     }
500 }
501 
deinit(void)502 void DrawCallBatchingTest::deinit(void)
503 {
504     const glw::Functions &gl = m_renderCtx.getFunctions();
505 
506     delete m_program;
507     m_program = NULL;
508 
509     m_dynamicIndexData = vector<uint8_t>();
510     m_staticIndexData  = vector<uint8_t>();
511 
512     if (!m_unbatchedDynamicIndexBuffers.empty())
513     {
514         gl.deleteBuffers((GLsizei)m_unbatchedDynamicIndexBuffers.size(), &(m_unbatchedDynamicIndexBuffers[0]));
515         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
516 
517         m_unbatchedDynamicIndexBuffers = vector<GLuint>();
518     }
519 
520     if (m_batchedDynamicIndexBuffer)
521     {
522         gl.deleteBuffers((GLsizei)1, &m_batchedDynamicIndexBuffer);
523         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
524 
525         m_batchedDynamicIndexBuffer = 0;
526     }
527 
528     if (m_unbatchedStaticIndexBuffer)
529     {
530         gl.deleteBuffers((GLsizei)1, &m_unbatchedStaticIndexBuffer);
531         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
532 
533         m_unbatchedStaticIndexBuffer = 0;
534     }
535 
536     if (m_batchedStaticIndexBuffer)
537     {
538         gl.deleteBuffers((GLsizei)1, &m_batchedStaticIndexBuffer);
539         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
540 
541         m_batchedStaticIndexBuffer = 0;
542     }
543 
544     m_staticAttributeDatas  = vector<vector<int8_t>>();
545     m_dynamicAttributeDatas = vector<vector<int8_t>>();
546 
547     if (!m_batchedStaticBuffers.empty())
548     {
549         gl.deleteBuffers((GLsizei)m_batchedStaticBuffers.size(), &(m_batchedStaticBuffers[0]));
550         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
551 
552         m_batchedStaticBuffers = vector<GLuint>();
553     }
554 
555     if (!m_unbatchedStaticBuffers.empty())
556     {
557         gl.deleteBuffers((GLsizei)m_unbatchedStaticBuffers.size(), &(m_unbatchedStaticBuffers[0]));
558         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
559 
560         m_unbatchedStaticBuffers = vector<GLuint>();
561     }
562 
563     if (!m_batchedDynamicBuffers.empty())
564     {
565         gl.deleteBuffers((GLsizei)m_batchedDynamicBuffers.size(), &(m_batchedDynamicBuffers[0]));
566         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
567 
568         m_batchedDynamicBuffers = vector<GLuint>();
569     }
570 
571     for (int i = 0; i < (int)m_unbatchedDynamicBuffers.size(); i++)
572     {
573         gl.deleteBuffers((GLsizei)m_unbatchedDynamicBuffers[i].size(), &(m_unbatchedDynamicBuffers[i][0]));
574         GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
575     }
576 
577     m_unbatchedDynamicBuffers = vector<vector<GLuint>>();
578 
579     m_unbatchedSamplesUs = vector<uint64_t>();
580     m_batchedSamplesUs   = vector<uint64_t>();
581 }
582 
renderUnbatched(void)583 uint64_t DrawCallBatchingTest::renderUnbatched(void)
584 {
585     const glw::Functions &gl = m_renderCtx.getFunctions();
586     uint64_t beginUs         = 0;
587     uint64_t endUs           = 0;
588     vector<GLint> dynamicAttributeLocations;
589 
590     gl.viewport(0, 0, 32, 32);
591     gl.useProgram(m_program->getProgram());
592 
593     // Setup static buffers
594     for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
595     {
596         GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
597 
598         gl.enableVertexAttribArray(location);
599 
600         if (m_spec.useStaticBuffer)
601         {
602             gl.bindBuffer(GL_ARRAY_BUFFER, m_unbatchedStaticBuffers[attribNdx]);
603             gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, NULL);
604             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
605         }
606         else
607             gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, &(m_staticAttributeDatas[attribNdx][0]));
608     }
609 
610     // Get locations of dynamic attributes
611     for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
612     {
613         GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_dyn" + de::toString(attribNdx)).c_str());
614 
615         gl.enableVertexAttribArray(location);
616         dynamicAttributeLocations.push_back(location);
617     }
618 
619     if (m_spec.useDrawElements && m_spec.useIndexBuffer && !m_spec.dynamicIndices)
620         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_unbatchedStaticIndexBuffer);
621 
622     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup initial state for rendering.");
623 
624     gl.finish();
625 
626     beginUs = deGetMicroseconds();
627 
628     for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
629     {
630         for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
631         {
632             if (m_spec.useDynamicBuffer)
633             {
634                 gl.bindBuffer(GL_ARRAY_BUFFER, m_unbatchedDynamicBuffers[attribNdx][drawNdx]);
635                 gl.vertexAttribPointer(dynamicAttributeLocations[attribNdx], 4, GL_BYTE, GL_TRUE, 0, NULL);
636                 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
637             }
638             else
639                 gl.vertexAttribPointer(dynamicAttributeLocations[attribNdx], 4, GL_BYTE, GL_TRUE, 0,
640                                        &(m_dynamicAttributeDatas[attribNdx][m_spec.triangleCount * 3 * drawNdx * 4]));
641         }
642 
643         if (m_spec.useDrawElements)
644         {
645             if (m_spec.useIndexBuffer)
646             {
647                 if (m_spec.dynamicIndices)
648                 {
649                     gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_unbatchedDynamicIndexBuffers[drawNdx]);
650                     gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, NULL);
651                     gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
652                 }
653                 else
654                     gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, NULL);
655             }
656             else
657             {
658                 if (m_spec.dynamicIndices)
659                     gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE,
660                                     &(m_dynamicIndexData[drawNdx * m_spec.triangleCount * 3]));
661                 else
662                     gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, &(m_staticIndexData[0]));
663             }
664         }
665         else
666             gl.drawArrays(GL_TRIANGLES, 0, 3 * m_spec.triangleCount);
667     }
668 
669     gl.finish();
670 
671     endUs = deGetMicroseconds();
672 
673     GLU_EXPECT_NO_ERROR(gl.getError(), "Unbatched rendering failed");
674 
675     gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
676 
677     for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
678     {
679         GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
680         gl.disableVertexAttribArray(location);
681     }
682 
683     for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
684         gl.disableVertexAttribArray(dynamicAttributeLocations[attribNdx]);
685 
686     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to reset state after unbatched rendering");
687 
688     return endUs - beginUs;
689 }
690 
renderBatched(void)691 uint64_t DrawCallBatchingTest::renderBatched(void)
692 {
693     const glw::Functions &gl = m_renderCtx.getFunctions();
694     uint64_t beginUs         = 0;
695     uint64_t endUs           = 0;
696     vector<GLint> dynamicAttributeLocations;
697 
698     gl.viewport(0, 0, 32, 32);
699     gl.useProgram(m_program->getProgram());
700 
701     // Setup static buffers
702     for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
703     {
704         GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
705 
706         gl.enableVertexAttribArray(location);
707 
708         if (m_spec.useStaticBuffer)
709         {
710             gl.bindBuffer(GL_ARRAY_BUFFER, m_batchedStaticBuffers[attribNdx]);
711             gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, NULL);
712             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
713         }
714         else
715             gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, &(m_staticAttributeDatas[attribNdx][0]));
716     }
717 
718     // Get locations of dynamic attributes
719     for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
720     {
721         GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_dyn" + de::toString(attribNdx)).c_str());
722 
723         gl.enableVertexAttribArray(location);
724         dynamicAttributeLocations.push_back(location);
725     }
726 
727     if (m_spec.useDrawElements && m_spec.useIndexBuffer && !m_spec.dynamicIndices)
728         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_batchedStaticIndexBuffer);
729 
730     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup initial state for rendering.");
731 
732     gl.finish();
733 
734     beginUs = deGetMicroseconds();
735 
736     for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
737     {
738         if (m_spec.useDynamicBuffer)
739         {
740             gl.bindBuffer(GL_ARRAY_BUFFER, m_batchedDynamicBuffers[attribute]);
741             gl.vertexAttribPointer(dynamicAttributeLocations[attribute], 4, GL_BYTE, GL_TRUE, 0, NULL);
742             gl.bindBuffer(GL_ARRAY_BUFFER, 0);
743         }
744         else
745             gl.vertexAttribPointer(dynamicAttributeLocations[attribute], 4, GL_BYTE, GL_TRUE, 0,
746                                    &(m_dynamicAttributeDatas[attribute][0]));
747     }
748 
749     if (m_spec.useDrawElements)
750     {
751         if (m_spec.useIndexBuffer)
752         {
753             if (m_spec.dynamicIndices)
754             {
755                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_batchedDynamicIndexBuffer);
756                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, NULL);
757                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
758             }
759             else
760                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, NULL);
761         }
762         else
763         {
764             if (m_spec.dynamicIndices)
765                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE,
766                                 &(m_dynamicIndexData[0]));
767             else
768                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE,
769                                 &(m_staticIndexData[0]));
770         }
771     }
772     else
773         gl.drawArrays(GL_TRIANGLES, 0, 3 * m_spec.triangleCount * m_spec.drawCallCount);
774 
775     gl.finish();
776 
777     endUs = deGetMicroseconds();
778 
779     GLU_EXPECT_NO_ERROR(gl.getError(), "Batched rendering failed");
780 
781     gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
782 
783     for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
784     {
785         GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
786         gl.disableVertexAttribArray(location);
787     }
788 
789     for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
790         gl.disableVertexAttribArray(dynamicAttributeLocations[attribNdx]);
791 
792     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to reset state after batched rendering");
793 
794     return endUs - beginUs;
795 }
796 
797 struct Statistics
798 {
799     double mean;
800     double standardDeviation;
801     double standardErrorOfMean;
802 };
803 
calculateStats(const vector<uint64_t> & samples)804 Statistics calculateStats(const vector<uint64_t> &samples)
805 {
806     double mean = 0.0;
807 
808     for (int i = 0; i < (int)samples.size(); i++)
809         mean += (double)samples[i];
810 
811     mean /= (double)samples.size();
812 
813     double standardDeviation = 0.0;
814 
815     for (int i = 0; i < (int)samples.size(); i++)
816     {
817         double x = (double)samples[i];
818         standardDeviation += (x - mean) * (x - mean);
819     }
820 
821     standardDeviation /= (double)samples.size();
822     standardDeviation = std::sqrt(standardDeviation);
823 
824     double standardErrorOfMean = standardDeviation / std::sqrt((double)samples.size());
825 
826     Statistics stats;
827 
828     stats.mean                = mean;
829     stats.standardDeviation   = standardDeviation;
830     stats.standardErrorOfMean = standardErrorOfMean;
831 
832     return stats;
833 }
834 
logTestInfo(void)835 void DrawCallBatchingTest::logTestInfo(void)
836 {
837     TestLog &log = m_testCtx.getLog();
838     tcu::ScopedLogSection section(log, "Test info", "Test info");
839 
840     log << TestLog::Message << "Rendering using " << (m_spec.useDrawElements ? "glDrawElements()" : "glDrawArrays()")
841         << "." << TestLog::EndMessage;
842 
843     if (m_spec.useDrawElements)
844         log << TestLog::Message << "Using " << (m_spec.dynamicIndices ? "dynamic " : "") << "indices from "
845             << (m_spec.useIndexBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
846 
847     if (m_spec.staticAttributeCount > 0)
848         log << TestLog::Message << "Using " << m_spec.staticAttributeCount << " static attribute"
849             << (m_spec.staticAttributeCount > 1 ? "s" : "") << " from "
850             << (m_spec.useStaticBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
851 
852     if (m_spec.dynamicAttributeCount > 0)
853         log << TestLog::Message << "Using " << m_spec.dynamicAttributeCount << " dynamic attribute"
854             << (m_spec.dynamicAttributeCount > 1 ? "s" : "") << " from "
855             << (m_spec.useDynamicBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
856 
857     log << TestLog::Message << "Rendering " << m_spec.drawCallCount << " draw calls with " << m_spec.triangleCount
858         << " triangles per call." << TestLog::EndMessage;
859 }
860 
iterate(void)861 tcu::TestCase::IterateResult DrawCallBatchingTest::iterate(void)
862 {
863     if (m_state == STATE_LOG_INFO)
864     {
865         logTestInfo();
866         m_state = STATE_WARMUP_BATCHED;
867     }
868     else if (m_state == STATE_WARMUP_BATCHED)
869     {
870         renderBatched();
871         m_state = STATE_WARMUP_UNBATCHED;
872     }
873     else if (m_state == STATE_WARMUP_UNBATCHED)
874     {
875         renderUnbatched();
876         m_state = STATE_SAMPLE;
877     }
878     else if (m_state == STATE_SAMPLE)
879     {
880         if ((int)m_unbatchedSamplesUs.size() < m_unbatchedSampleCount &&
881             ((double)m_unbatchedSamplesUs.size() / ((double)m_unbatchedSampleCount) <
882                  (double)m_batchedSamplesUs.size() / ((double)m_batchedSampleCount) ||
883              (int)m_batchedSamplesUs.size() >= m_batchedSampleCount))
884             m_unbatchedSamplesUs.push_back(renderUnbatched());
885         else if ((int)m_batchedSamplesUs.size() < m_batchedSampleCount)
886             m_batchedSamplesUs.push_back(renderBatched());
887         else
888             m_state = STATE_CALC_CALIBRATION;
889     }
890     else if (m_state == STATE_CALC_CALIBRATION)
891     {
892         TestLog &log = m_testCtx.getLog();
893 
894         tcu::ScopedLogSection section(log, ("Sampling iteration " + de::toString(m_sampleIteration)).c_str(),
895                                       ("Sampling iteration " + de::toString(m_sampleIteration)).c_str());
896         const double targetSEM = 0.02;
897         const double limitSEM  = 0.025;
898 
899         Statistics unbatchedStats = calculateStats(m_unbatchedSamplesUs);
900         Statistics batchedStats   = calculateStats(m_batchedSamplesUs);
901 
902         log << TestLog::Message << "Batched samples; Count: " << m_batchedSamplesUs.size()
903             << ", Mean: " << batchedStats.mean << "us, Standard deviation: " << batchedStats.standardDeviation
904             << "us, Standard error of mean: " << batchedStats.standardErrorOfMean << "us("
905             << (batchedStats.standardErrorOfMean / batchedStats.mean) << ")" << TestLog::EndMessage;
906         log << TestLog::Message << "Unbatched samples; Count: " << m_unbatchedSamplesUs.size()
907             << ", Mean: " << unbatchedStats.mean << "us, Standard deviation: " << unbatchedStats.standardDeviation
908             << "us, Standard error of mean: " << unbatchedStats.standardErrorOfMean << "us("
909             << (unbatchedStats.standardErrorOfMean / unbatchedStats.mean) << ")" << TestLog::EndMessage;
910 
911         if (m_sampleIteration > 2 ||
912             (m_sampleIteration > 0 && (unbatchedStats.standardErrorOfMean / unbatchedStats.mean) +
913                                               (batchedStats.standardErrorOfMean / batchedStats.mean) <=
914                                           2.0 * limitSEM))
915         {
916             if (m_sampleIteration > 2)
917                 log << TestLog::Message << "Maximum iteration count reached." << TestLog::EndMessage;
918 
919             log << TestLog::Message << "Standard errors in target range." << TestLog::EndMessage;
920             log << TestLog::Message << "Batched/Unbatched ratio: " << (batchedStats.mean / unbatchedStats.mean)
921                 << TestLog::EndMessage;
922 
923             m_testCtx.setTestResult(QP_TEST_RESULT_PASS,
924                                     de::floatToString((float)(batchedStats.mean / unbatchedStats.mean), 1).c_str());
925             return STOP;
926         }
927         else
928         {
929             if ((unbatchedStats.standardErrorOfMean / unbatchedStats.mean) > targetSEM)
930                 log << TestLog::Message << "Unbatched standard error of mean outside of range." << TestLog::EndMessage;
931 
932             if ((batchedStats.standardErrorOfMean / batchedStats.mean) > targetSEM)
933                 log << TestLog::Message << "Batched standard error of mean outside of range." << TestLog::EndMessage;
934 
935             if (unbatchedStats.standardDeviation > 0.0)
936             {
937                 double x               = (unbatchedStats.standardDeviation / unbatchedStats.mean) / targetSEM;
938                 m_unbatchedSampleCount = std::max((int)m_unbatchedSamplesUs.size(), (int)(x * x));
939             }
940             else
941                 m_unbatchedSampleCount = (int)m_unbatchedSamplesUs.size();
942 
943             if (batchedStats.standardDeviation > 0.0)
944             {
945                 double x             = (batchedStats.standardDeviation / batchedStats.mean) / targetSEM;
946                 m_batchedSampleCount = std::max((int)m_batchedSamplesUs.size(), (int)(x * x));
947             }
948             else
949                 m_batchedSampleCount = (int)m_batchedSamplesUs.size();
950 
951             m_batchedSamplesUs.clear();
952             m_unbatchedSamplesUs.clear();
953 
954             m_sampleIteration++;
955             m_state = STATE_SAMPLE;
956         }
957     }
958     else
959         DE_ASSERT(false);
960 
961     return CONTINUE;
962 }
963 
specToName(const DrawCallBatchingTest::TestSpec & spec)964 string specToName(const DrawCallBatchingTest::TestSpec &spec)
965 {
966     std::ostringstream stream;
967 
968     DE_ASSERT(!spec.useStaticBuffer || spec.staticAttributeCount > 0);
969     DE_ASSERT(!spec.useDynamicBuffer || spec.dynamicAttributeCount > 0);
970 
971     if (spec.staticAttributeCount > 0)
972         stream << spec.staticAttributeCount << "_static_";
973 
974     if (spec.useStaticBuffer)
975         stream << (spec.staticAttributeCount == 1 ? "buffer_" : "buffers_");
976 
977     if (spec.dynamicAttributeCount > 0)
978         stream << spec.dynamicAttributeCount << "_dynamic_";
979 
980     if (spec.useDynamicBuffer)
981         stream << (spec.dynamicAttributeCount == 1 ? "buffer_" : "buffers_");
982 
983     stream << spec.triangleCount << "_triangles";
984 
985     return stream.str();
986 }
987 
specToDescrpition(const DrawCallBatchingTest::TestSpec & spec)988 string specToDescrpition(const DrawCallBatchingTest::TestSpec &spec)
989 {
990     DE_UNREF(spec);
991     return "Test performance of batched rendering against non-batched rendering.";
992 }
993 
994 } // namespace
995 
DrawCallBatchingTests(Context & context)996 DrawCallBatchingTests::DrawCallBatchingTests(Context &context)
997     : TestCaseGroup(context, "draw_call_batching", "Draw call batching performance tests.")
998 {
999 }
1000 
~DrawCallBatchingTests(void)1001 DrawCallBatchingTests::~DrawCallBatchingTests(void)
1002 {
1003 }
1004 
init(void)1005 void DrawCallBatchingTests::init(void)
1006 {
1007     int drawCallCounts[] = {10, 100};
1008 
1009     int triangleCounts[] = {2, 10};
1010 
1011     int staticAttributeCounts[] = {1, 0, 4, 8, 0};
1012 
1013     int dynamicAttributeCounts[] = {0, 1, 4, 0, 8};
1014 
1015     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(staticAttributeCounts) == DE_LENGTH_OF_ARRAY(dynamicAttributeCounts));
1016 
1017     for (int drawType = 0; drawType < 2; drawType++)
1018     {
1019         bool drawElements = (drawType == 1);
1020 
1021         for (int indexBufferNdx = 0; indexBufferNdx < 2; indexBufferNdx++)
1022         {
1023             bool useIndexBuffer = (indexBufferNdx == 1);
1024 
1025             if (useIndexBuffer && !drawElements)
1026                 continue;
1027 
1028             for (int dynamicIndexNdx = 0; dynamicIndexNdx < 2; dynamicIndexNdx++)
1029             {
1030                 bool dynamicIndices = (dynamicIndexNdx == 1);
1031 
1032                 if (dynamicIndices && !drawElements)
1033                     continue;
1034 
1035                 if (dynamicIndices && !useIndexBuffer)
1036                     continue;
1037 
1038                 TestCaseGroup *drawTypeGroup = new TestCaseGroup(
1039                     m_context,
1040                     (string(dynamicIndices ? "dynamic_" : "") + (useIndexBuffer ? "buffer_" : "") +
1041                      (drawElements ? "draw_elements" : "draw_arrays"))
1042                         .c_str(),
1043                     (string("Test batched rendering with ") + (drawElements ? "draw_elements" : "draw_arrays"))
1044                         .c_str());
1045 
1046                 addChild(drawTypeGroup);
1047 
1048                 for (int drawCallCountNdx = 0; drawCallCountNdx < DE_LENGTH_OF_ARRAY(drawCallCounts);
1049                      drawCallCountNdx++)
1050                 {
1051                     int drawCallCount = drawCallCounts[drawCallCountNdx];
1052 
1053                     TestCaseGroup *callCountGroup = new TestCaseGroup(
1054                         m_context, (de::toString(drawCallCount) + (drawCallCount == 1 ? "_draw" : "_draws")).c_str(),
1055                         ("Test batched rendering performance with " + de::toString(drawCallCount) + " draw calls.")
1056                             .c_str());
1057                     TestCaseGroup *attributeCount1Group =
1058                         new TestCaseGroup(m_context, "1_attribute", "Test draw call batching with 1 attribute.");
1059                     TestCaseGroup *attributeCount8Group =
1060                         new TestCaseGroup(m_context, "8_attributes", "Test draw call batching with 8 attributes.");
1061 
1062                     callCountGroup->addChild(attributeCount1Group);
1063                     callCountGroup->addChild(attributeCount8Group);
1064 
1065                     drawTypeGroup->addChild(callCountGroup);
1066 
1067                     for (int attributeCountNdx = 0; attributeCountNdx < DE_LENGTH_OF_ARRAY(dynamicAttributeCounts);
1068                          attributeCountNdx++)
1069                     {
1070                         TestCaseGroup *attributeCountGroup = NULL;
1071 
1072                         int staticAttributeCount  = staticAttributeCounts[attributeCountNdx];
1073                         int dynamicAttributeCount = dynamicAttributeCounts[attributeCountNdx];
1074 
1075                         if (staticAttributeCount + dynamicAttributeCount == 1)
1076                             attributeCountGroup = attributeCount1Group;
1077                         else if (staticAttributeCount + dynamicAttributeCount == 8)
1078                             attributeCountGroup = attributeCount8Group;
1079                         else
1080                             DE_ASSERT(false);
1081 
1082                         for (int triangleCountNdx = 0; triangleCountNdx < DE_LENGTH_OF_ARRAY(triangleCounts);
1083                              triangleCountNdx++)
1084                         {
1085                             int triangleCount = triangleCounts[triangleCountNdx];
1086 
1087                             for (int dynamicBufferNdx = 0; dynamicBufferNdx < 2; dynamicBufferNdx++)
1088                             {
1089                                 bool useDynamicBuffer = (dynamicBufferNdx != 0);
1090 
1091                                 for (int staticBufferNdx = 0; staticBufferNdx < 2; staticBufferNdx++)
1092                                 {
1093                                     bool useStaticBuffer = (staticBufferNdx != 0);
1094 
1095                                     DrawCallBatchingTest::TestSpec spec;
1096 
1097                                     spec.useStaticBuffer      = useStaticBuffer;
1098                                     spec.staticAttributeCount = staticAttributeCount;
1099 
1100                                     spec.useDynamicBuffer      = useDynamicBuffer;
1101                                     spec.dynamicAttributeCount = dynamicAttributeCount;
1102 
1103                                     spec.drawCallCount = drawCallCount;
1104                                     spec.triangleCount = triangleCount;
1105 
1106                                     spec.useDrawElements = drawElements;
1107                                     spec.useIndexBuffer  = useIndexBuffer;
1108                                     spec.dynamicIndices  = dynamicIndices;
1109 
1110                                     if (spec.useStaticBuffer && spec.staticAttributeCount == 0)
1111                                         continue;
1112 
1113                                     if (spec.useDynamicBuffer && spec.dynamicAttributeCount == 0)
1114                                         continue;
1115 
1116                                     attributeCountGroup->addChild(new DrawCallBatchingTest(
1117                                         m_context, specToName(spec).c_str(), specToDescrpition(spec).c_str(), spec));
1118                                 }
1119                             }
1120                         }
1121                     }
1122                 }
1123             }
1124         }
1125     }
1126 }
1127 
1128 } // namespace Performance
1129 } // namespace gles2
1130 } // namespace deqp
1131