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