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) / (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 
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 / (double)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) / (double)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