xref: /aosp_15_r20/external/deqp/modules/glshared/glsStateChangePerfTestCases.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) 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 State change performance tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsStateChangePerfTestCases.hpp"
25 
26 #include "tcuTestLog.hpp"
27 
28 #include "gluDefs.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluShaderProgram.hpp"
31 
32 #include "glwFunctions.hpp"
33 #include "glwEnums.hpp"
34 
35 #include "deStringUtil.hpp"
36 
37 #include "deClock.h"
38 
39 #include <vector>
40 #include <algorithm>
41 
42 using std::string;
43 using std::vector;
44 using tcu::TestLog;
45 using namespace glw;
46 
47 namespace deqp
48 {
49 namespace gls
50 {
51 
52 namespace
53 {
54 
55 struct ResultStats
56 {
57     double median;
58     double mean;
59     double variance;
60 
61     uint64_t min;
62     uint64_t max;
63 };
64 
calculateStats(const vector<uint64_t> & values)65 ResultStats calculateStats(const vector<uint64_t> &values)
66 {
67     ResultStats result = {0.0, 0.0, 0.0, 0xFFFFFFFFFFFFFFFFu, 0};
68 
69     uint64_t sum = 0;
70 
71     for (int i = 0; i < (int)values.size(); i++)
72         sum += values[i];
73 
74     result.mean = ((double)sum) / (double)values.size();
75 
76     for (int i = 0; i < (int)values.size(); i++)
77     {
78         const double val = (double)values[i];
79         result.variance += (val - result.mean) * (val - result.mean);
80     }
81 
82     result.variance /= (double)values.size();
83 
84     {
85         const int n = (int)(values.size() / 2);
86 
87         vector<uint64_t> sortedValues = values;
88 
89         std::sort(sortedValues.begin(), sortedValues.end());
90 
91         result.median = (double)sortedValues[n];
92     }
93 
94     for (int i = 0; i < (int)values.size(); i++)
95     {
96         result.min = std::min(result.min, values[i]);
97         result.max = std::max(result.max, values[i]);
98     }
99 
100     return result;
101 }
102 
genIndices(vector<GLushort> & indices,int triangleCount)103 void genIndices(vector<GLushort> &indices, int triangleCount)
104 {
105     indices.reserve(triangleCount * 3);
106 
107     for (int triangleNdx = 0; triangleNdx < triangleCount; triangleNdx++)
108     {
109         indices.push_back((GLushort)(triangleNdx * 3));
110         indices.push_back((GLushort)(triangleNdx * 3 + 1));
111         indices.push_back((GLushort)(triangleNdx * 3 + 2));
112     }
113 }
114 
genCoords(vector<GLfloat> & coords,int triangleCount)115 void genCoords(vector<GLfloat> &coords, int triangleCount)
116 {
117     coords.reserve(triangleCount * 3 * 2);
118 
119     for (int triangleNdx = 0; triangleNdx < triangleCount; triangleNdx++)
120     {
121         if ((triangleNdx % 2) == 0)
122         {
123             // CW
124             coords.push_back(-1.0f);
125             coords.push_back(-1.0f);
126 
127             coords.push_back(1.0f);
128             coords.push_back(-1.0f);
129 
130             coords.push_back(1.0f);
131             coords.push_back(1.0f);
132         }
133         else
134         {
135             // CCW
136             coords.push_back(-1.0f);
137             coords.push_back(-1.0f);
138 
139             coords.push_back(-1.0f);
140             coords.push_back(1.0f);
141 
142             coords.push_back(1.0f);
143             coords.push_back(1.0f);
144         }
145     }
146 }
147 
genTextureData(vector<uint8_t> & data,int width,int height)148 void genTextureData(vector<uint8_t> &data, int width, int height)
149 {
150     data.clear();
151     data.reserve(width * height * 4);
152 
153     for (int x = 0; x < width; x++)
154     {
155         for (int y = 0; y < height; y++)
156         {
157             data.push_back((uint8_t)((255 * x) / width));
158             data.push_back((uint8_t)((255 * y) / width));
159             data.push_back((uint8_t)((255 * x * y) / (width * height)));
160             data.push_back(255);
161         }
162     }
163 }
164 
calculateVariance(const vector<uint64_t> & values,double avg)165 double calculateVariance(const vector<uint64_t> &values, double avg)
166 {
167     double sum = 0.0;
168 
169     for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
170     {
171         double value = (double)values[valueNdx];
172         sum += (value - avg) * (value - avg);
173     }
174 
175     return sum / (double)values.size();
176 }
177 
findMin(const vector<uint64_t> & values)178 uint64_t findMin(const vector<uint64_t> &values)
179 {
180     uint64_t min = ~0ull;
181 
182     for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
183         min = std::min(values[valueNdx], min);
184 
185     return min;
186 }
187 
findMax(const vector<uint64_t> & values)188 uint64_t findMax(const vector<uint64_t> &values)
189 {
190     uint64_t max = 0;
191 
192     for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
193         max = std::max(values[valueNdx], max);
194 
195     return max;
196 }
197 
findMedian(const vector<uint64_t> & v)198 uint64_t findMedian(const vector<uint64_t> &v)
199 {
200     vector<uint64_t> values = v;
201     size_t n                = values.size() / 2;
202 
203     std::nth_element(values.begin(), values.begin() + n, values.end());
204 
205     return values[n];
206 }
207 
208 } // namespace
209 
StateChangePerformanceCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,DrawType drawType,int drawCallCount,int triangleCount)210 StateChangePerformanceCase::StateChangePerformanceCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
211                                                        const char *name, const char *description, DrawType drawType,
212                                                        int drawCallCount, int triangleCount)
213     : tcu::TestCase(testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
214     , m_renderCtx(renderCtx)
215     , m_drawType(drawType)
216     , m_iterationCount(100)
217     , m_callCount(drawCallCount)
218     , m_triangleCount(triangleCount)
219 {
220 }
221 
~StateChangePerformanceCase(void)222 StateChangePerformanceCase::~StateChangePerformanceCase(void)
223 {
224     StateChangePerformanceCase::deinit();
225 }
226 
init(void)227 void StateChangePerformanceCase::init(void)
228 {
229     if (m_drawType == DRAWTYPE_INDEXED_USER_PTR)
230         genIndices(m_indices, m_triangleCount);
231 }
232 
requireIndexBuffers(int count)233 void StateChangePerformanceCase::requireIndexBuffers(int count)
234 {
235     const glw::Functions &gl = m_renderCtx.getFunctions();
236 
237     if ((int)m_indexBuffers.size() >= count)
238         return;
239 
240     m_indexBuffers.reserve(count);
241 
242     vector<GLushort> indices;
243     genIndices(indices, m_triangleCount);
244 
245     while ((int)m_indexBuffers.size() < count)
246     {
247         GLuint buffer;
248 
249         gl.genBuffers(1, &buffer);
250         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()");
251 
252         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
253         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
254         gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(indices.size() * sizeof(GLushort)), &(indices[0]),
255                       GL_STATIC_DRAW);
256         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData()");
257         gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
258         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
259 
260         m_indexBuffers.push_back(buffer);
261     }
262 }
263 
requireCoordBuffers(int count)264 void StateChangePerformanceCase::requireCoordBuffers(int count)
265 {
266     const glw::Functions &gl = m_renderCtx.getFunctions();
267 
268     if ((int)m_coordBuffers.size() >= count)
269         return;
270 
271     m_coordBuffers.reserve(count);
272 
273     vector<GLfloat> coords;
274     genCoords(coords, m_triangleCount);
275 
276     while ((int)m_coordBuffers.size() < count)
277     {
278         GLuint buffer;
279 
280         gl.genBuffers(1, &buffer);
281         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()");
282 
283         gl.bindBuffer(GL_ARRAY_BUFFER, buffer);
284         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
285         gl.bufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(coords.size() * sizeof(GLfloat)), &(coords[0]), GL_STATIC_DRAW);
286         GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData()");
287         gl.bindBuffer(GL_ARRAY_BUFFER, 0);
288         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer()");
289 
290         m_coordBuffers.push_back(buffer);
291     }
292 }
293 
requirePrograms(int count)294 void StateChangePerformanceCase::requirePrograms(int count)
295 {
296     if ((int)m_programs.size() >= count)
297         return;
298 
299     m_programs.reserve(count);
300 
301     while ((int)m_programs.size() < count)
302     {
303         string vertexShaderSource = "attribute mediump vec2 a_coord;\n"
304                                     "varying mediump vec2 v_texCoord;\n"
305                                     "void main (void)\n"
306                                     "{\n"
307                                     "\tv_texCoord = vec2(0.5) + 0.5" +
308                                     de::toString(m_programs.size()) +
309                                     " * a_coord.xy;\n"
310                                     "\tgl_Position = vec4(a_coord, 0.5, 1.0);\n"
311                                     "}";
312 
313         string fragmentShaderSource = "uniform sampler2D u_sampler;\n"
314                                       "varying mediump vec2 v_texCoord;\n"
315                                       "void main (void)\n"
316                                       "{\n"
317                                       "\tgl_FragColor = vec4(1.0" +
318                                       de::toString(m_programs.size()) +
319                                       " * texture2D(u_sampler, v_texCoord).xyz, 1.0);\n"
320                                       "}";
321 
322         glu::ShaderProgram *program =
323             new glu::ShaderProgram(m_renderCtx, glu::ProgramSources() << glu::VertexSource(vertexShaderSource)
324                                                                       << glu::FragmentSource(fragmentShaderSource));
325 
326         if (!program->isOk())
327         {
328             m_testCtx.getLog() << *program;
329             delete program;
330             TCU_FAIL("Compile failed");
331         }
332 
333         m_programs.push_back(program);
334     }
335 }
336 
requireTextures(int count)337 void StateChangePerformanceCase::requireTextures(int count)
338 {
339     const glw::Functions &gl = m_renderCtx.getFunctions();
340 
341     const int textureWidth  = 64;
342     const int textureHeight = 64;
343 
344     if ((int)m_textures.size() >= count)
345         return;
346 
347     m_textures.reserve(count);
348 
349     vector<uint8_t> textureData;
350     genTextureData(textureData, textureWidth, textureHeight);
351 
352     DE_ASSERT(textureData.size() == textureWidth * textureHeight * 4);
353 
354     while ((int)m_textures.size() < count)
355     {
356         GLuint texture;
357 
358         gl.genTextures(1, &texture);
359         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenTextures()");
360 
361         gl.bindTexture(GL_TEXTURE_2D, texture);
362         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture()");
363 
364         gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
365                       &(textureData[0]));
366         GLU_EXPECT_NO_ERROR(gl.getError(), "glTexImage2D()");
367 
368         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
369         GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
370         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
371         GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
372         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
373         GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
374         gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
375         GLU_EXPECT_NO_ERROR(gl.getError(), "glTexParameteri()");
376 
377         gl.bindTexture(GL_TEXTURE_2D, 0);
378         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture()");
379 
380         m_textures.push_back(texture);
381     }
382 }
383 
requireFramebuffers(int count)384 void StateChangePerformanceCase::requireFramebuffers(int count)
385 {
386     const glw::Functions &gl = m_renderCtx.getFunctions();
387 
388     if ((int)m_framebuffers.size() >= count)
389         return;
390 
391     m_framebuffers.reserve(count);
392 
393     requireRenderbuffers(count);
394 
395     while ((int)m_framebuffers.size() < count)
396     {
397         GLuint framebuffer;
398 
399         gl.genFramebuffers(1, &framebuffer);
400         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenFramebuffers()");
401 
402         gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
403         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer()");
404 
405         gl.bindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers[m_framebuffers.size()]);
406         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
407 
408         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
409                                    m_renderbuffers[m_framebuffers.size()]);
410         GLU_EXPECT_NO_ERROR(gl.getError(), "glFramebufferRenderbuffer()");
411 
412         gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
413         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
414 
415         gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
416         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer()");
417 
418         m_framebuffers.push_back(framebuffer);
419     }
420 }
421 
requireRenderbuffers(int count)422 void StateChangePerformanceCase::requireRenderbuffers(int count)
423 {
424     const glw::Functions &gl = m_renderCtx.getFunctions();
425 
426     if ((int)m_renderbuffers.size() >= count)
427         return;
428 
429     m_renderbuffers.reserve(count);
430 
431     while ((int)m_renderbuffers.size() < count)
432     {
433         GLuint renderbuffer;
434 
435         gl.genRenderbuffers(1, &renderbuffer);
436         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenRenderbuffers()");
437 
438         gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
439         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
440 
441         gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGB565, 24, 24);
442         GLU_EXPECT_NO_ERROR(gl.getError(), "glRenderbufferStorage()");
443 
444         gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
445         GLU_EXPECT_NO_ERROR(gl.getError(), "glBindRenderbuffer()");
446 
447         m_renderbuffers.push_back(renderbuffer);
448     }
449 }
450 
requireSamplers(int count)451 void StateChangePerformanceCase::requireSamplers(int count)
452 {
453     const glw::Functions &gl = m_renderCtx.getFunctions();
454 
455     if ((int)m_samplers.size() >= count)
456         return;
457 
458     m_samplers.reserve(count);
459 
460     while ((int)m_samplers.size() < count)
461     {
462         GLuint sampler;
463         gl.genSamplers(1, &sampler);
464         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenSamplers()");
465         m_samplers.push_back(sampler);
466     }
467 }
468 
requireVertexArrays(int count)469 void StateChangePerformanceCase::requireVertexArrays(int count)
470 {
471     const glw::Functions &gl = m_renderCtx.getFunctions();
472 
473     if ((int)m_vertexArrays.size() >= count)
474         return;
475 
476     m_vertexArrays.reserve(count);
477 
478     while ((int)m_vertexArrays.size() < count)
479     {
480         GLuint vertexArray;
481         gl.genVertexArrays(1, &vertexArray);
482         GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays()");
483         m_vertexArrays.push_back(vertexArray);
484     }
485 }
486 
deinit(void)487 void StateChangePerformanceCase::deinit(void)
488 {
489     m_indices.clear();
490     m_interleavedResults.clear();
491     m_batchedResults.clear();
492 
493     {
494         const glw::Functions &gl = m_renderCtx.getFunctions();
495 
496         if (!m_indexBuffers.empty())
497         {
498             gl.deleteBuffers((GLsizei)m_indexBuffers.size(), &(m_indexBuffers[0]));
499             m_indexBuffers.clear();
500         }
501 
502         if (!m_coordBuffers.empty())
503         {
504             gl.deleteBuffers((GLsizei)m_coordBuffers.size(), &(m_coordBuffers[0]));
505             m_coordBuffers.clear();
506         }
507 
508         if (!m_textures.empty())
509         {
510             gl.deleteTextures((GLsizei)m_textures.size(), &(m_textures[0]));
511             m_textures.clear();
512         }
513 
514         if (!m_framebuffers.empty())
515         {
516             gl.deleteFramebuffers((GLsizei)m_framebuffers.size(), &(m_framebuffers[0]));
517             m_framebuffers.clear();
518         }
519 
520         if (!m_renderbuffers.empty())
521         {
522             gl.deleteRenderbuffers((GLsizei)m_renderbuffers.size(), &(m_renderbuffers[0]));
523             m_renderbuffers.clear();
524         }
525 
526         if (!m_samplers.empty())
527         {
528             gl.deleteSamplers((GLsizei)m_samplers.size(), &m_samplers[0]);
529             m_samplers.clear();
530         }
531 
532         if (!m_vertexArrays.empty())
533         {
534             gl.deleteVertexArrays((GLsizei)m_vertexArrays.size(), &m_vertexArrays[0]);
535             m_vertexArrays.clear();
536         }
537 
538         for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
539         {
540             delete m_programs[programNdx];
541             m_programs[programNdx] = NULL;
542         }
543         m_programs.clear();
544     }
545 }
546 
logAndSetTestResult(void)547 void StateChangePerformanceCase::logAndSetTestResult(void)
548 {
549     TestLog &log = m_testCtx.getLog();
550 
551     ResultStats interleaved = calculateStats(m_interleavedResults);
552     ResultStats batched     = calculateStats(m_batchedResults);
553 
554     log << TestLog::Message << "Interleaved mean: " << interleaved.mean << TestLog::EndMessage;
555     log << TestLog::Message << "Interleaved median: " << interleaved.median << TestLog::EndMessage;
556     log << TestLog::Message << "Interleaved variance: " << interleaved.variance << TestLog::EndMessage;
557     log << TestLog::Message << "Interleaved min: " << interleaved.min << TestLog::EndMessage;
558     log << TestLog::Message << "Interleaved max: " << interleaved.max << TestLog::EndMessage;
559 
560     log << TestLog::Message << "Batched mean: " << batched.mean << TestLog::EndMessage;
561     log << TestLog::Message << "Batched median: " << batched.median << TestLog::EndMessage;
562     log << TestLog::Message << "Batched variance: " << batched.variance << TestLog::EndMessage;
563     log << TestLog::Message << "Batched min: " << batched.min << TestLog::EndMessage;
564     log << TestLog::Message << "Batched max: " << batched.max << TestLog::EndMessage;
565 
566     log << TestLog::Message << "Batched/Interleaved mean ratio: " << (interleaved.mean / batched.mean)
567         << TestLog::EndMessage;
568     log << TestLog::Message << "Batched/Interleaved median ratio: " << (interleaved.median / batched.median)
569         << TestLog::EndMessage;
570 
571     m_testCtx.setTestResult(QP_TEST_RESULT_PASS,
572                             de::floatToString((float)(((double)interleaved.median) / batched.median), 2).c_str());
573 }
574 
iterate(void)575 tcu::TestCase::IterateResult StateChangePerformanceCase::iterate(void)
576 {
577     if (m_interleavedResults.empty() && m_batchedResults.empty())
578     {
579         TestLog &log = m_testCtx.getLog();
580 
581         log << TestLog::Message << "Draw call count: " << m_callCount << TestLog::EndMessage;
582         log << TestLog::Message << "Per call triangle count: " << m_triangleCount << TestLog::EndMessage;
583     }
584 
585     // \note [mika] Interleave sampling to balance effects of powerstate etc.
586     if ((int)m_interleavedResults.size() < m_iterationCount && m_batchedResults.size() >= m_interleavedResults.size())
587     {
588         const glw::Functions &gl = m_renderCtx.getFunctions();
589         uint64_t resBeginUs      = 0;
590         uint64_t resEndUs        = 0;
591 
592         setupInitialState(gl);
593         gl.finish();
594         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
595 
596         // Render result
597         resBeginUs = deGetMicroseconds();
598 
599         renderTest(gl);
600 
601         gl.finish();
602         resEndUs = deGetMicroseconds();
603         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
604 
605         m_interleavedResults.push_back(resEndUs - resBeginUs);
606 
607         return CONTINUE;
608     }
609     else if ((int)m_batchedResults.size() < m_iterationCount)
610     {
611         const glw::Functions &gl = m_renderCtx.getFunctions();
612         uint64_t refBeginUs      = 0;
613         uint64_t refEndUs        = 0;
614 
615         setupInitialState(gl);
616         gl.finish();
617         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
618 
619         // Render reference
620         refBeginUs = deGetMicroseconds();
621 
622         renderReference(gl);
623 
624         gl.finish();
625         refEndUs = deGetMicroseconds();
626         GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish()");
627 
628         m_batchedResults.push_back(refEndUs - refBeginUs);
629 
630         return CONTINUE;
631     }
632     else
633     {
634         logAndSetTestResult();
635         return STOP;
636     }
637 }
638 
callDraw(const glw::Functions & gl)639 void StateChangePerformanceCase::callDraw(const glw::Functions &gl)
640 {
641     switch (m_drawType)
642     {
643     case DRAWTYPE_NOT_INDEXED:
644         gl.drawArrays(GL_TRIANGLES, 0, m_triangleCount * 3);
645         break;
646     case DRAWTYPE_INDEXED_USER_PTR:
647         gl.drawElements(GL_TRIANGLES, m_triangleCount * 3, GL_UNSIGNED_SHORT, &m_indices[0]);
648         break;
649     case DRAWTYPE_INDEXED_BUFFER:
650         gl.drawElements(GL_TRIANGLES, m_triangleCount * 3, GL_UNSIGNED_SHORT, NULL);
651         break;
652     default:
653         DE_ASSERT(false);
654     }
655 }
656 
657 // StateChangeCallPerformanceCase
658 
StateChangeCallPerformanceCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description)659 StateChangeCallPerformanceCase::StateChangeCallPerformanceCase(tcu::TestContext &testCtx, glu::RenderContext &renderCtx,
660                                                                const char *name, const char *description)
661     : tcu::TestCase(testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
662     , m_renderCtx(renderCtx)
663     , m_iterationCount(100)
664     , m_callCount(1000)
665 {
666 }
667 
~StateChangeCallPerformanceCase(void)668 StateChangeCallPerformanceCase::~StateChangeCallPerformanceCase(void)
669 {
670 }
671 
executeTest(void)672 void StateChangeCallPerformanceCase::executeTest(void)
673 {
674     const glw::Functions &gl = m_renderCtx.getFunctions();
675     uint64_t beginTimeUs     = 0;
676     uint64_t endTimeUs       = 0;
677 
678     beginTimeUs = deGetMicroseconds();
679 
680     execCalls(gl, (int)m_results.size(), m_callCount);
681 
682     endTimeUs = deGetMicroseconds();
683 
684     m_results.push_back(endTimeUs - beginTimeUs);
685 }
686 
logTestCase(void)687 void StateChangeCallPerformanceCase::logTestCase(void)
688 {
689     TestLog &log = m_testCtx.getLog();
690 
691     log << TestLog::Message << "Iteration count: " << m_iterationCount << TestLog::EndMessage;
692     log << TestLog::Message << "Per iteration call count: " << m_callCount << TestLog::EndMessage;
693 }
694 
calculateAverage(const vector<uint64_t> & values)695 double calculateAverage(const vector<uint64_t> &values)
696 {
697     uint64_t sum = 0;
698 
699     for (int valueNdx = 0; valueNdx < (int)values.size(); valueNdx++)
700         sum += values[valueNdx];
701 
702     return ((double)sum) / (double)values.size();
703 }
704 
logAndSetTestResult(void)705 void StateChangeCallPerformanceCase::logAndSetTestResult(void)
706 {
707     TestLog &log = m_testCtx.getLog();
708 
709     uint64_t minUs         = findMin(m_results);
710     uint64_t maxUs         = findMax(m_results);
711     uint64_t medianUs      = findMedian(m_results);
712     double avgIterationUs  = calculateAverage(m_results);
713     double avgCallUs       = avgIterationUs / m_callCount;
714     double varIteration    = calculateVariance(m_results, avgIterationUs);
715     double avgMedianCallUs = ((double)medianUs) / m_callCount;
716 
717     log << TestLog::Message << "Min iteration time: " << minUs << "us" << TestLog::EndMessage;
718     log << TestLog::Message << "Max iteration time: " << maxUs << "us" << TestLog::EndMessage;
719     log << TestLog::Message << "Average iteration time: " << avgIterationUs << "us" << TestLog::EndMessage;
720     log << TestLog::Message << "Iteration variance time: " << varIteration << TestLog::EndMessage;
721     log << TestLog::Message << "Median iteration time: " << medianUs << "us" << TestLog::EndMessage;
722     log << TestLog::Message << "Average call time: " << avgCallUs << "us" << TestLog::EndMessage;
723     log << TestLog::Message << "Average call time for median iteration: " << avgMedianCallUs << "us"
724         << TestLog::EndMessage;
725 
726     m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)avgMedianCallUs, 3).c_str());
727 }
728 
iterate(void)729 tcu::TestCase::IterateResult StateChangeCallPerformanceCase::iterate(void)
730 {
731     if (m_results.empty())
732         logTestCase();
733 
734     if ((int)m_results.size() < m_iterationCount)
735     {
736         executeTest();
737         GLU_EXPECT_NO_ERROR(m_renderCtx.getFunctions().getError(), "Unexpected error");
738         return CONTINUE;
739     }
740     else
741     {
742         logAndSetTestResult();
743         return STOP;
744     }
745 }
746 
747 } // namespace gls
748 } // namespace deqp
749