Cherry-pick SPIR-V ClipDistance validation fixes
[platform/upstream/VK-GL-CTS.git] / modules / gles2 / performance / es2pDrawCallBatchingTests.cpp
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::vector;
53 using std::string;
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<deUint8>                         m_dynamicIndexData;
116         vector<deUint8>                         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<deInt8> >         m_staticAttributeDatas;
125         vector<vector<deInt8> >         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<deUint64>                        m_unbatchedSamplesUs;
134         vector<deUint64>                        m_batchedSamplesUs;
135
136         void                                            logTestInfo                             (void);
137
138         deUint64                                        renderUnbatched                 (void);
139         deUint64                                        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
149 DrawCallBatchingTest::DrawCallBatchingTest (Context& context, const char* name, const char* description, const TestSpec& spec)
150         : tcu::TestCase                                 (context.getTestContext(), tcu::NODETYPE_PERFORMANCE, name, description)
151         , m_state                                               (STATE_LOG_INFO)
152         , m_renderCtx                                   (context.getRenderContext())
153         , m_rnd                                                 (deStringHash(name))
154         , m_sampleIteration                             (0)
155         , m_unbatchedSampleCount                (CALIBRATION_SAMPLE_COUNT)
156         , m_batchedSampleCount                  (CALIBRATION_SAMPLE_COUNT)
157         , m_spec                                                (spec)
158         , m_program                                             (NULL)
159         , m_batchedDynamicIndexBuffer   (0)
160         , m_unbatchedStaticIndexBuffer  (0)
161         , m_batchedStaticIndexBuffer    (0)
162 {
163 }
164
165 DrawCallBatchingTest::~DrawCallBatchingTest (void)
166 {
167         deinit();
168 }
169
170 void DrawCallBatchingTest::createIndexData (void)
171 {
172         if (m_spec.dynamicIndices)
173         {
174                 for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
175                 {
176                         for (int triangleNdx = 0; triangleNdx < m_spec.triangleCount; triangleNdx++)
177                         {
178                                 m_dynamicIndexData.push_back(deUint8(triangleNdx * 3));
179                                 m_dynamicIndexData.push_back(deUint8(triangleNdx * 3 + 1));
180                                 m_dynamicIndexData.push_back(deUint8(triangleNdx * 3 + 2));
181                         }
182                 }
183         }
184         else
185         {
186                 for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
187                 {
188                         for (int triangleNdx = 0; triangleNdx < m_spec.triangleCount; triangleNdx++)
189                         {
190                                 m_staticIndexData.push_back(deUint8(triangleNdx * 3));
191                                 m_staticIndexData.push_back(deUint8(triangleNdx * 3 + 1));
192                                 m_staticIndexData.push_back(deUint8(triangleNdx * 3 + 2));
193                         }
194                 }
195         }
196 }
197
198 void DrawCallBatchingTest::createShader (void)
199 {
200         std::ostringstream              vertexShader;
201         std::ostringstream              fragmentShader;
202
203         for (int attributeNdx = 0; attributeNdx < m_spec.staticAttributeCount; attributeNdx++)
204                 vertexShader << "attribute mediump vec4 a_static" << attributeNdx << ";\n";
205
206         if (m_spec.staticAttributeCount > 0 && m_spec.dynamicAttributeCount > 0)
207                 vertexShader << "\n";
208
209         for (int attributeNdx = 0; attributeNdx < m_spec.dynamicAttributeCount; attributeNdx++)
210                 vertexShader << "attribute mediump vec4 a_dyn" << attributeNdx << ";\n";
211
212         vertexShader
213         << "\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
251         fragmentShader
252         << "varying mediump vec4 v_color;\n"
253         << "\n"
254         << "void main(void)\n"
255         << "{\n"
256         << "\tgl_FragColor = v_color;\n"
257         << "}\n";
258
259         m_program = new glu::ShaderProgram(m_renderCtx, glu::ProgramSources() << glu::VertexSource(vertexShader.str()) << glu::FragmentSource(fragmentShader.str()));
260
261         m_testCtx.getLog() << (*m_program);
262         TCU_CHECK(m_program->isOk());
263 }
264
265 void DrawCallBatchingTest::createAttributeDatas (void)
266 {
267         // Generate data for static attributes
268         for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
269         {
270                 vector<deInt8> data;
271
272                 if (m_spec.dynamicAttributeCount == 0 && attribute == 0)
273                 {
274                         data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
275
276                         for (int i = 0; i < m_spec.triangleCount * m_spec.drawCallCount; i++)
277                         {
278                                 int sign = (m_spec.triangleCount % 2 == 1 || i % 2 == 0 ? 1 : -1);
279
280                                 data.push_back(deInt8(-127 * sign));
281                                 data.push_back(deInt8(-127 * sign));
282                                 data.push_back(0);
283                                 data.push_back(127);
284
285                                 data.push_back(deInt8(127 * sign));
286                                 data.push_back(deInt8(-127 * sign));
287                                 data.push_back(0);
288                                 data.push_back(127);
289
290                                 data.push_back(deInt8(127 * sign));
291                                 data.push_back(deInt8(127 * sign));
292                                 data.push_back(0);
293                                 data.push_back(127);
294                         }
295                 }
296                 else
297                 {
298                         data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
299
300                         for (int i = 0; i < 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount; i++)
301                                 data.push_back((deInt8)m_rnd.getUint32());
302                 }
303
304                 m_staticAttributeDatas.push_back(data);
305         }
306
307         // Generate data for dynamic attributes
308         for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
309         {
310                 vector<deInt8> data;
311
312                 if (attribute == 0)
313                 {
314                         data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
315
316                         for (int i = 0; i < m_spec.triangleCount * m_spec.drawCallCount; i++)
317                         {
318                                 int sign = (i % 2 == 0 ? 1 : -1);
319
320                                 data.push_back(deInt8(-127 * sign));
321                                 data.push_back(deInt8(-127 * sign));
322                                 data.push_back(0);
323                                 data.push_back(127);
324
325                                 data.push_back(deInt8(127 * sign));
326                                 data.push_back(deInt8(-127 * sign));
327                                 data.push_back(0);
328                                 data.push_back(127);
329
330                                 data.push_back(deInt8(127 * sign));
331                                 data.push_back(deInt8(127 * sign));
332                                 data.push_back(0);
333                                 data.push_back(127);
334                         }
335                 }
336                 else
337                 {
338                         data.reserve(4 * 3 * m_spec.triangleCount * m_spec.drawCallCount);
339
340                         for (int i = 0; i < 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount; i++)
341                                 data.push_back((deInt8)m_rnd.getUint32());
342                 }
343
344                 m_dynamicAttributeDatas.push_back(data);
345         }
346 }
347
348 void DrawCallBatchingTest::createArrayBuffers (void)
349 {
350         const glw::Functions& gl = m_renderCtx.getFunctions();
351
352         if (m_spec.useStaticBuffer)
353         {
354                 // Upload static attributes for batched
355                 for (int attribute = 0; attribute < m_spec.staticAttributeCount; attribute++)
356                 {
357                         GLuint buffer;
358
359                         gl.genBuffers(1, &buffer);
360                         gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
361                         gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount, &(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]), GL_STATIC_DRAW);
376                         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
377                         GLU_EXPECT_NO_ERROR(gl.getError(), "Creating static buffer failed");
378
379                         m_unbatchedStaticBuffers.push_back(buffer);
380                 }
381         }
382
383         if (m_spec.useDynamicBuffer)
384         {
385                 // Upload dynamic attributes for batched
386                 for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
387                 {
388                         GLuint buffer;
389
390                         gl.genBuffers(1, &buffer);
391                         gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
392                         gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_dynamicAttributeDatas[attribute][0]), GL_STATIC_DRAW);
393                         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
394                         GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic buffer failed");
395
396                         m_batchedDynamicBuffers.push_back(buffer);
397                 }
398
399                 // Upload dynamic attributes for unbatched
400                 for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
401                 {
402                         vector<GLuint> buffers;
403
404                         for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
405                         {
406                                 GLuint buffer;
407
408                                 gl.genBuffers(1, &buffer);
409                                 gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
410                                 gl.bufferData(GL_ARRAY_BUFFER, 4 * 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_dynamicAttributeDatas[attribute][0]), GL_STATIC_DRAW);
411                                 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
412                                 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic buffer failed");
413
414                                 buffers.push_back(buffer);
415                         }
416
417                         m_unbatchedDynamicBuffers.push_back(buffers);
418                 }
419         }
420 }
421
422 void DrawCallBatchingTest::createIndexBuffer (void)
423 {
424         const glw::Functions& gl = m_renderCtx.getFunctions();
425
426         if (m_spec.dynamicIndices)
427         {
428                 for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
429                 {
430                         GLuint buffer;
431
432                         gl.genBuffers(1, &buffer);
433                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
434                         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount, &(m_dynamicIndexData[drawNdx * m_spec.triangleCount * 3]), GL_STATIC_DRAW);
435                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
436                         GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
437
438                         m_unbatchedDynamicIndexBuffers.push_back(buffer);
439                 }
440
441                 {
442                         GLuint buffer;
443
444                         gl.genBuffers(1, &buffer);
445                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
446                         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_dynamicIndexData[0]), GL_STATIC_DRAW);
447                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
448                         GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
449
450                         m_batchedDynamicIndexBuffer = buffer;
451                 }
452         }
453         else
454         {
455                 {
456                         GLuint buffer;
457
458                         gl.genBuffers(1, &buffer);
459                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
460                         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount * m_spec.drawCallCount, &(m_staticIndexData[0]), GL_STATIC_DRAW);
461                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
462                         GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
463
464                         m_batchedStaticIndexBuffer = buffer;
465                 }
466
467                 {
468                         GLuint buffer;
469
470                         gl.genBuffers(1, &buffer);
471                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
472                         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * m_spec.triangleCount, &(m_staticIndexData[0]), GL_STATIC_DRAW);
473                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
474                         GLU_EXPECT_NO_ERROR(gl.getError(), "Creating dynamic index buffer failed");
475
476                         m_unbatchedStaticIndexBuffer = buffer;
477                 }
478         }
479 }
480
481 void DrawCallBatchingTest::init (void)
482 {
483         createShader();
484         createAttributeDatas();
485         createArrayBuffers();
486
487         if (m_spec.useDrawElements)
488         {
489                 createIndexData();
490
491                 if (m_spec.useIndexBuffer)
492                         createIndexBuffer();
493         }
494 }
495
496 void DrawCallBatchingTest::deinit (void)
497 {
498         const glw::Functions& gl = m_renderCtx.getFunctions();
499
500         delete m_program;
501         m_program = NULL;
502
503         m_dynamicIndexData      = vector<deUint8>();
504         m_staticIndexData       = vector<deUint8>();
505
506         if (!m_unbatchedDynamicIndexBuffers.empty())
507         {
508                 gl.deleteBuffers((GLsizei)m_unbatchedDynamicIndexBuffers.size(), &(m_unbatchedDynamicIndexBuffers[0]));
509                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
510
511                 m_unbatchedDynamicIndexBuffers = vector<GLuint>();
512         }
513
514         if (m_batchedDynamicIndexBuffer)
515         {
516                 gl.deleteBuffers((GLsizei)1, &m_batchedDynamicIndexBuffer);
517                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
518
519                 m_batchedDynamicIndexBuffer = 0;
520         }
521
522         if (m_unbatchedStaticIndexBuffer)
523         {
524                 gl.deleteBuffers((GLsizei)1, &m_unbatchedStaticIndexBuffer);
525                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
526
527                 m_unbatchedStaticIndexBuffer = 0;
528         }
529
530         if (m_batchedStaticIndexBuffer)
531         {
532                 gl.deleteBuffers((GLsizei)1, &m_batchedStaticIndexBuffer);
533                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
534
535                 m_batchedStaticIndexBuffer = 0;
536         }
537
538         m_staticAttributeDatas  = vector<vector<deInt8> >();
539         m_dynamicAttributeDatas = vector<vector<deInt8> >();
540
541         if (!m_batchedStaticBuffers.empty())
542         {
543                 gl.deleteBuffers((GLsizei)m_batchedStaticBuffers.size(), &(m_batchedStaticBuffers[0]));
544                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
545
546                 m_batchedStaticBuffers = vector<GLuint>();
547         }
548
549         if (!m_unbatchedStaticBuffers.empty())
550         {
551                 gl.deleteBuffers((GLsizei)m_unbatchedStaticBuffers.size(), &(m_unbatchedStaticBuffers[0]));
552                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
553
554                 m_unbatchedStaticBuffers = vector<GLuint>();
555         }
556
557         if (!m_batchedDynamicBuffers.empty())
558         {
559                 gl.deleteBuffers((GLsizei)m_batchedDynamicBuffers.size(), &(m_batchedDynamicBuffers[0]));
560                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
561
562                 m_batchedDynamicBuffers = vector<GLuint>();
563         }
564
565         for (int i = 0; i < (int)m_unbatchedDynamicBuffers.size(); i++)
566         {
567                 gl.deleteBuffers((GLsizei)m_unbatchedDynamicBuffers[i].size(), &(m_unbatchedDynamicBuffers[i][0]));
568                 GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers()");
569         }
570
571         m_unbatchedDynamicBuffers = vector<vector<GLuint> >();
572
573         m_unbatchedSamplesUs    = vector<deUint64>();
574         m_batchedSamplesUs              = vector<deUint64>();
575 }
576
577 deUint64 DrawCallBatchingTest::renderUnbatched (void)
578 {
579         const glw::Functions&   gl              = m_renderCtx.getFunctions();
580         deUint64                                beginUs = 0;
581         deUint64                                endUs   = 0;
582         vector<GLint>                   dynamicAttributeLocations;
583
584         gl.viewport(0, 0, 32, 32);
585         gl.useProgram(m_program->getProgram());
586
587         // Setup static buffers
588         for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
589         {
590                 GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
591
592                 gl.enableVertexAttribArray(location);
593
594                 if (m_spec.useStaticBuffer)
595                 {
596                         gl.bindBuffer(GL_ARRAY_BUFFER, m_unbatchedStaticBuffers[attribNdx]);
597                         gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, NULL);
598                         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
599                 }
600                 else
601                         gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, &(m_staticAttributeDatas[attribNdx][0]));
602         }
603
604         // Get locations of dynamic attributes
605         for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
606         {
607                 GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_dyn" + de::toString(attribNdx)).c_str());
608
609                 gl.enableVertexAttribArray(location);
610                 dynamicAttributeLocations.push_back(location);
611         }
612
613         if (m_spec.useDrawElements && m_spec.useIndexBuffer && !m_spec.dynamicIndices)
614                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_unbatchedStaticIndexBuffer);
615
616         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup initial state for rendering.");
617
618         gl.finish();
619
620         beginUs = deGetMicroseconds();
621
622         for (int drawNdx = 0; drawNdx < m_spec.drawCallCount; drawNdx++)
623         {
624                 for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
625                 {
626                         if (m_spec.useDynamicBuffer)
627                         {
628                                 gl.bindBuffer(GL_ARRAY_BUFFER, m_unbatchedDynamicBuffers[attribNdx][drawNdx]);
629                                 gl.vertexAttribPointer(dynamicAttributeLocations[attribNdx], 4, GL_BYTE, GL_TRUE, 0, NULL);
630                                 gl.bindBuffer(GL_ARRAY_BUFFER, 0);
631                         }
632                         else
633                                 gl.vertexAttribPointer(dynamicAttributeLocations[attribNdx], 4, GL_BYTE, GL_TRUE, 0, &(m_dynamicAttributeDatas[attribNdx][m_spec.triangleCount * 3 * drawNdx * 4]));
634                 }
635
636                 if (m_spec.useDrawElements)
637                 {
638                         if (m_spec.useIndexBuffer)
639                         {
640                                 if (m_spec.dynamicIndices)
641                                 {
642                                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_unbatchedDynamicIndexBuffers[drawNdx]);
643                                         gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, NULL);
644                                         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
645                                 }
646                                 else
647                                         gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, NULL);
648                         }
649                         else
650                         {
651                                 if (m_spec.dynamicIndices)
652                                         gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, &(m_dynamicIndexData[drawNdx * m_spec.triangleCount * 3]));
653                                 else
654                                         gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3, GL_UNSIGNED_BYTE, &(m_staticIndexData[0]));
655                         }
656                 }
657                 else
658                         gl.drawArrays(GL_TRIANGLES, 0, 3 * m_spec.triangleCount);
659         }
660
661         gl.finish();
662
663         endUs = deGetMicroseconds();
664
665         GLU_EXPECT_NO_ERROR(gl.getError(), "Unbatched rendering failed");
666
667         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
668
669         for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
670         {
671                 GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
672                 gl.disableVertexAttribArray(location);
673         }
674
675         for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
676                 gl.disableVertexAttribArray(dynamicAttributeLocations[attribNdx]);
677
678         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to reset state after unbatched rendering");
679
680         return endUs - beginUs;
681 }
682
683 deUint64 DrawCallBatchingTest::renderBatched (void)
684 {
685         const glw::Functions&   gl              = m_renderCtx.getFunctions();
686         deUint64                                beginUs = 0;
687         deUint64                                endUs   = 0;
688         vector<GLint>                   dynamicAttributeLocations;
689
690         gl.viewport(0, 0, 32, 32);
691         gl.useProgram(m_program->getProgram());
692
693         // Setup static buffers
694         for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
695         {
696                 GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
697
698                 gl.enableVertexAttribArray(location);
699
700                 if (m_spec.useStaticBuffer)
701                 {
702                         gl.bindBuffer(GL_ARRAY_BUFFER, m_batchedStaticBuffers[attribNdx]);
703                         gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, NULL);
704                         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
705                 }
706                 else
707                         gl.vertexAttribPointer(location, 4, GL_BYTE, GL_TRUE, 0, &(m_staticAttributeDatas[attribNdx][0]));
708         }
709
710         // Get locations of dynamic attributes
711         for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
712         {
713                 GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_dyn" + de::toString(attribNdx)).c_str());
714
715                 gl.enableVertexAttribArray(location);
716                 dynamicAttributeLocations.push_back(location);
717         }
718
719         if (m_spec.useDrawElements && m_spec.useIndexBuffer && !m_spec.dynamicIndices)
720                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_batchedStaticIndexBuffer);
721
722         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup initial state for rendering.");
723
724         gl.finish();
725
726         beginUs = deGetMicroseconds();
727
728         for (int attribute = 0; attribute < m_spec.dynamicAttributeCount; attribute++)
729         {
730                 if (m_spec.useDynamicBuffer)
731                 {
732                         gl.bindBuffer(GL_ARRAY_BUFFER, m_batchedDynamicBuffers[attribute]);
733                         gl.vertexAttribPointer(dynamicAttributeLocations[attribute], 4, GL_BYTE, GL_TRUE, 0, NULL);
734                         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
735                 }
736                 else
737                         gl.vertexAttribPointer(dynamicAttributeLocations[attribute], 4, GL_BYTE, GL_TRUE, 0, &(m_dynamicAttributeDatas[attribute][0]));
738         }
739
740         if (m_spec.useDrawElements)
741         {
742                 if (m_spec.useIndexBuffer)
743                 {
744                         if (m_spec.dynamicIndices)
745                         {
746                                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_batchedDynamicIndexBuffer);
747                                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, NULL);
748                                 gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
749                         }
750                         else
751                                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, NULL);
752                 }
753                 else
754                 {
755                         if (m_spec.dynamicIndices)
756                                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, &(m_dynamicIndexData[0]));
757                         else
758                                 gl.drawElements(GL_TRIANGLES, m_spec.triangleCount * 3 * m_spec.drawCallCount, GL_UNSIGNED_BYTE, &(m_staticIndexData[0]));
759                 }
760         }
761         else
762                 gl.drawArrays(GL_TRIANGLES, 0, 3 * m_spec.triangleCount * m_spec.drawCallCount);
763
764         gl.finish();
765
766         endUs = deGetMicroseconds();
767
768         GLU_EXPECT_NO_ERROR(gl.getError(), "Batched rendering failed");
769
770         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
771
772         for (int attribNdx = 0; attribNdx < m_spec.staticAttributeCount; attribNdx++)
773         {
774                 GLint location = gl.getAttribLocation(m_program->getProgram(), ("a_static" + de::toString(attribNdx)).c_str());
775                 gl.disableVertexAttribArray(location);
776         }
777
778         for (int attribNdx = 0; attribNdx < m_spec.dynamicAttributeCount; attribNdx++)
779                 gl.disableVertexAttribArray(dynamicAttributeLocations[attribNdx]);
780
781         GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to reset state after batched rendering");
782
783         return endUs - beginUs;
784 }
785
786 struct Statistics
787 {
788         double mean;
789         double standardDeviation;
790         double standardErrorOfMean;
791 };
792
793 Statistics calculateStats (const vector<deUint64>& samples)
794 {
795         double mean = 0.0;
796
797         for (int i = 0; i < (int)samples.size(); i++)
798                 mean += (double)samples[i];
799
800         mean /= (double)samples.size();
801
802         double standardDeviation = 0.0;
803
804         for (int i = 0; i < (int)samples.size(); i++)
805         {
806                 double x = (double)samples[i];
807                 standardDeviation += (x - mean) * (x - mean);
808         }
809
810         standardDeviation /= (double)samples.size();
811         standardDeviation = std::sqrt(standardDeviation);
812
813         double standardErrorOfMean = standardDeviation / std::sqrt((double)samples.size());
814
815         Statistics stats;
816
817         stats.mean                                      = mean;
818         stats.standardDeviation         = standardDeviation;
819         stats.standardErrorOfMean       = standardErrorOfMean;
820
821         return stats;
822 }
823
824 void DrawCallBatchingTest::logTestInfo (void)
825 {
826         TestLog&                                log             = m_testCtx.getLog();
827         tcu::ScopedLogSection   section (log, "Test info", "Test info");
828
829         log << TestLog::Message << "Rendering using " << (m_spec.useDrawElements ? "glDrawElements()" : "glDrawArrays()") << "." << TestLog::EndMessage;
830
831         if (m_spec.useDrawElements)
832                 log << TestLog::Message << "Using " << (m_spec.dynamicIndices ? "dynamic " : "") << "indices from " << (m_spec.useIndexBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
833
834         if (m_spec.staticAttributeCount > 0)
835                 log << TestLog::Message << "Using " << m_spec.staticAttributeCount << " static attribute" << (m_spec.staticAttributeCount > 1 ? "s" : "") << " from " << (m_spec.useStaticBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
836
837         if (m_spec.dynamicAttributeCount > 0)
838                 log << TestLog::Message << "Using " << m_spec.dynamicAttributeCount << " dynamic attribute" << (m_spec.dynamicAttributeCount > 1 ? "s" : "") << " from " << (m_spec.useDynamicBuffer ? "buffer" : "pointer") << "." << TestLog::EndMessage;
839
840         log << TestLog::Message << "Rendering " << m_spec.drawCallCount << " draw calls with " << m_spec.triangleCount << " triangles per call." << TestLog::EndMessage;
841 }
842
843 tcu::TestCase::IterateResult DrawCallBatchingTest::iterate (void)
844 {
845         if (m_state == STATE_LOG_INFO)
846         {
847                 logTestInfo();
848                 m_state = STATE_WARMUP_BATCHED;
849         }
850         else if (m_state == STATE_WARMUP_BATCHED)
851         {
852                 renderBatched();
853                 m_state = STATE_WARMUP_UNBATCHED;
854         }
855         else if (m_state == STATE_WARMUP_UNBATCHED)
856         {
857                 renderUnbatched();
858                 m_state = STATE_SAMPLE;
859         }
860         else if (m_state == STATE_SAMPLE)
861         {
862                 if ((int)m_unbatchedSamplesUs.size() < m_unbatchedSampleCount && ((double)m_unbatchedSamplesUs.size() / ((double)m_unbatchedSampleCount) < (double)m_batchedSamplesUs.size() / ((double)m_batchedSampleCount) || (int)m_batchedSamplesUs.size() >= m_batchedSampleCount))
863                         m_unbatchedSamplesUs.push_back(renderUnbatched());
864                 else if ((int)m_batchedSamplesUs.size() < m_batchedSampleCount)
865                         m_batchedSamplesUs.push_back(renderBatched());
866                 else
867                         m_state = STATE_CALC_CALIBRATION;
868         }
869         else if (m_state == STATE_CALC_CALIBRATION)
870         {
871                 TestLog& log = m_testCtx.getLog();
872
873                 tcu::ScopedLogSection   section(log, ("Sampling iteration " + de::toString(m_sampleIteration)).c_str(), ("Sampling iteration " + de::toString(m_sampleIteration)).c_str());
874                 const double targetSEM  = 0.02;
875                 const double limitSEM   = 0.025;
876
877                 Statistics unbatchedStats       = calculateStats(m_unbatchedSamplesUs);
878                 Statistics batchedStats         = calculateStats(m_batchedSamplesUs);
879
880                 log << TestLog::Message << "Batched samples; Count: " << m_batchedSamplesUs.size() << ", Mean: " << batchedStats.mean << "us, Standard deviation: " << batchedStats.standardDeviation << "us, Standard error of mean: " << batchedStats.standardErrorOfMean << "us(" << (batchedStats.standardErrorOfMean/batchedStats.mean) << ")" << TestLog::EndMessage;
881                 log << TestLog::Message << "Unbatched samples; Count: " << m_unbatchedSamplesUs.size() << ", Mean: " << unbatchedStats.mean << "us, Standard deviation: " << unbatchedStats.standardDeviation << "us, Standard error of mean: " << unbatchedStats.standardErrorOfMean << "us(" << (unbatchedStats.standardErrorOfMean/unbatchedStats.mean) << ")" << TestLog::EndMessage;
882
883                 if (m_sampleIteration > 2 || (m_sampleIteration > 0 && (unbatchedStats.standardErrorOfMean/unbatchedStats.mean) + (batchedStats.standardErrorOfMean/batchedStats.mean) <= 2.0 * limitSEM))
884                 {
885                         if (m_sampleIteration > 2)
886                                 log << TestLog::Message << "Maximum iteration count reached." << TestLog::EndMessage;
887
888                         log << TestLog::Message << "Standard errors in target range." << TestLog::EndMessage;
889                         log << TestLog::Message << "Batched/Unbatched ratio: " << (batchedStats.mean / unbatchedStats.mean) << TestLog::EndMessage;
890
891                         m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)(batchedStats.mean/unbatchedStats.mean), 1).c_str());
892                         return STOP;
893                 }
894                 else
895                 {
896                         if ((unbatchedStats.standardErrorOfMean/unbatchedStats.mean) > targetSEM)
897                                 log << TestLog::Message << "Unbatched standard error of mean outside of range." << TestLog::EndMessage;
898
899                         if ((batchedStats.standardErrorOfMean/batchedStats.mean) > targetSEM)
900                                 log << TestLog::Message << "Batched standard error of mean outside of range." << TestLog::EndMessage;
901
902                         if (unbatchedStats.standardDeviation > 0.0)
903                         {
904                                 double x = (unbatchedStats.standardDeviation / unbatchedStats.mean) / targetSEM;
905                                 m_unbatchedSampleCount = std::max((int)m_unbatchedSamplesUs.size(), (int)(x * x));
906                         }
907                         else
908                                 m_unbatchedSampleCount = (int)m_unbatchedSamplesUs.size();
909
910                         if (batchedStats.standardDeviation > 0.0)
911                         {
912                                 double x = (batchedStats.standardDeviation / batchedStats.mean) / targetSEM;
913                                 m_batchedSampleCount = std::max((int)m_batchedSamplesUs.size(), (int)(x * x));
914                         }
915                         else
916                                 m_batchedSampleCount = (int)m_batchedSamplesUs.size();
917
918                         m_batchedSamplesUs.clear();
919                         m_unbatchedSamplesUs.clear();
920
921                         m_sampleIteration++;
922                         m_state = STATE_SAMPLE;
923                 }
924         }
925         else
926                 DE_ASSERT(false);
927
928         return CONTINUE;
929 }
930
931 string specToName (const DrawCallBatchingTest::TestSpec& spec)
932 {
933         std::ostringstream stream;
934
935         DE_ASSERT(!spec.useStaticBuffer || spec.staticAttributeCount > 0);
936         DE_ASSERT(!spec.useDynamicBuffer|| spec.dynamicAttributeCount > 0);
937
938         if (spec.staticAttributeCount > 0)
939                 stream << spec.staticAttributeCount << "_static_";
940
941         if (spec.useStaticBuffer)
942                 stream << (spec.staticAttributeCount == 1 ? "buffer_" : "buffers_");
943
944         if (spec.dynamicAttributeCount > 0)
945                 stream << spec.dynamicAttributeCount << "_dynamic_";
946
947         if (spec.useDynamicBuffer)
948                 stream << (spec.dynamicAttributeCount == 1 ? "buffer_" : "buffers_");
949
950         stream << spec.triangleCount << "_triangles";
951
952         return stream.str();
953 }
954
955 string specToDescrpition (const DrawCallBatchingTest::TestSpec& spec)
956 {
957         DE_UNREF(spec);
958         return "Test performance of batched rendering against non-batched rendering.";
959 }
960
961 } // anonymous
962
963 DrawCallBatchingTests::DrawCallBatchingTests (Context& context)
964         : TestCaseGroup(context, "draw_call_batching", "Draw call batching performance tests.")
965 {
966 }
967
968 DrawCallBatchingTests::~DrawCallBatchingTests (void)
969 {
970 }
971
972 void DrawCallBatchingTests::init (void)
973 {
974         int drawCallCounts[] = {
975                 10, 100
976         };
977
978         int triangleCounts[] = {
979                 2, 10
980         };
981
982         int staticAttributeCounts[] = {
983                 1, 0, 4, 8, 0
984         };
985
986         int dynamicAttributeCounts[] = {
987                 0, 1, 4, 0, 8
988         };
989
990         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(staticAttributeCounts) == DE_LENGTH_OF_ARRAY(dynamicAttributeCounts));
991
992         for (int drawType = 0; drawType < 2; drawType++)
993         {
994                 bool drawElements = (drawType == 1);
995
996                 for (int indexBufferNdx = 0; indexBufferNdx < 2; indexBufferNdx++)
997                 {
998                         bool useIndexBuffer = (indexBufferNdx == 1);
999
1000                         if (useIndexBuffer && !drawElements)
1001                                 continue;
1002
1003                         for (int dynamicIndexNdx = 0; dynamicIndexNdx < 2; dynamicIndexNdx++)
1004                         {
1005                                 bool dynamicIndices = (dynamicIndexNdx == 1);
1006
1007                                 if (dynamicIndices && !drawElements)
1008                                         continue;
1009
1010                                 if (dynamicIndices && !useIndexBuffer)
1011                                         continue;
1012
1013                                 TestCaseGroup* drawTypeGroup = new TestCaseGroup(m_context, (string(dynamicIndices ? "dynamic_" : "") + (useIndexBuffer ? "buffer_" : "" ) + (drawElements ? "draw_elements" : "draw_arrays")).c_str(), (string("Test batched rendering with ") + (drawElements ? "draw_elements" : "draw_arrays")).c_str());
1014
1015                                 addChild(drawTypeGroup);
1016
1017                                 for (int drawCallCountNdx = 0; drawCallCountNdx < DE_LENGTH_OF_ARRAY(drawCallCounts); drawCallCountNdx++)
1018                                 {
1019                                         int drawCallCount = drawCallCounts[drawCallCountNdx];
1020
1021                                         TestCaseGroup*  callCountGroup                  = new TestCaseGroup(m_context, (de::toString(drawCallCount) + (drawCallCount == 1 ? "_draw" : "_draws")).c_str(), ("Test batched rendering performance with " + de::toString(drawCallCount) + " draw calls.").c_str());
1022                                         TestCaseGroup*  attributeCount1Group    = new TestCaseGroup(m_context, "1_attribute", "Test draw call batching with 1 attribute.");
1023                                         TestCaseGroup*  attributeCount8Group    = new TestCaseGroup(m_context, "8_attributes", "Test draw call batching with 8 attributes.");
1024
1025                                         callCountGroup->addChild(attributeCount1Group);
1026                                         callCountGroup->addChild(attributeCount8Group);
1027
1028                                         drawTypeGroup->addChild(callCountGroup);
1029
1030                                         for (int attributeCountNdx = 0; attributeCountNdx < DE_LENGTH_OF_ARRAY(dynamicAttributeCounts); attributeCountNdx++)
1031                                         {
1032                                                 TestCaseGroup*  attributeCountGroup             = NULL;
1033
1034                                                 int                             staticAttributeCount    = staticAttributeCounts[attributeCountNdx];
1035                                                 int                             dynamicAttributeCount   = dynamicAttributeCounts[attributeCountNdx];
1036
1037                                                 if (staticAttributeCount + dynamicAttributeCount == 1)
1038                                                         attributeCountGroup = attributeCount1Group;
1039                                                 else if (staticAttributeCount + dynamicAttributeCount == 8)
1040                                                         attributeCountGroup = attributeCount8Group;
1041                                                 else
1042                                                         DE_ASSERT(false);
1043
1044                                                 for (int triangleCountNdx = 0; triangleCountNdx < DE_LENGTH_OF_ARRAY(triangleCounts); triangleCountNdx++)
1045                                                 {
1046                                                         int triangleCount = triangleCounts[triangleCountNdx];
1047
1048                                                         for (int dynamicBufferNdx = 0; dynamicBufferNdx < 2; dynamicBufferNdx++)
1049                                                         {
1050                                                                 bool useDynamicBuffer = (dynamicBufferNdx != 0);
1051
1052                                                                 for (int staticBufferNdx = 0; staticBufferNdx < 2; staticBufferNdx++)
1053                                                                 {
1054                                                                         bool useStaticBuffer = (staticBufferNdx != 0);
1055
1056                                                                         DrawCallBatchingTest::TestSpec spec;
1057
1058                                                                         spec.useStaticBuffer            = useStaticBuffer;
1059                                                                         spec.staticAttributeCount       = staticAttributeCount;
1060
1061                                                                         spec.useDynamicBuffer           = useDynamicBuffer;
1062                                                                         spec.dynamicAttributeCount      = dynamicAttributeCount;
1063
1064                                                                         spec.drawCallCount                      = drawCallCount;
1065                                                                         spec.triangleCount                      = triangleCount;
1066
1067                                                                         spec.useDrawElements            = drawElements;
1068                                                                         spec.useIndexBuffer                     = useIndexBuffer;
1069                                                                         spec.dynamicIndices                     = dynamicIndices;
1070
1071                                                                         if (spec.useStaticBuffer && spec.staticAttributeCount == 0)
1072                                                                                 continue;
1073
1074                                                                         if (spec.useDynamicBuffer && spec.dynamicAttributeCount == 0)
1075                                                                                 continue;
1076
1077                                                                         attributeCountGroup->addChild(new DrawCallBatchingTest(m_context, specToName(spec).c_str(), specToDescrpition(spec).c_str(), spec));
1078                                                                 }
1079                                                         }
1080                                                 }
1081                                         }
1082                                 }
1083                         }
1084                 }
1085         }
1086 }
1087
1088 } // Performance
1089 } // gles2
1090 } // deqp