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
calculateStats(const vector<deUint64> & values)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) / 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 /= 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
genIndices(vector<GLushort> & indices,int triangleCount)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
genCoords(vector<GLfloat> & coords,int triangleCount)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
genTextureData(vector<deUint8> & data,int width,int height)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
calculateVariance(const vector<deUint64> & values,double avg)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 / values.size();
177 }
178
findMin(const vector<deUint64> & values)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
findMax(const vector<deUint64> & values)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
findMedian(const vector<deUint64> & v)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
StateChangePerformanceCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description,DrawType drawType,int drawCallCount,int triangleCount)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
~StateChangePerformanceCase(void)221 StateChangePerformanceCase::~StateChangePerformanceCase (void)
222 {
223 StateChangePerformanceCase::deinit();
224 }
225
init(void)226 void StateChangePerformanceCase::init (void)
227 {
228 if (m_drawType == DRAWTYPE_INDEXED_USER_PTR)
229 genIndices(m_indices, m_triangleCount);
230 }
231
requireIndexBuffers(int count)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
requireCoordBuffers(int count)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
requirePrograms(int count)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
requireTextures(int count)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
requireFramebuffers(int count)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
requireRenderbuffers(int count)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
requireSamplers(int count)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
requireVertexArrays(int count)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
deinit(void)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
logAndSetTestResult(void)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
iterate(void)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
callDraw(const glw::Functions & gl)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
StateChangeCallPerformanceCase(tcu::TestContext & testCtx,glu::RenderContext & renderCtx,const char * name,const char * description)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
~StateChangeCallPerformanceCase(void)650 StateChangeCallPerformanceCase::~StateChangeCallPerformanceCase (void)
651 {
652 }
653
executeTest(void)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
logTestCase(void)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
calculateAverage(const vector<deUint64> & values)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) / values.size();
685 }
686
logAndSetTestResult(void)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
iterate(void)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
730