• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Flush and finish tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es3fFlushFinishTests.hpp"
25 
26 #include "gluRenderContext.hpp"
27 #include "gluObjectWrapper.hpp"
28 #include "gluShaderProgram.hpp"
29 #include "gluDrawUtil.hpp"
30 
31 #include "glsCalibration.hpp"
32 
33 #include "tcuTestLog.hpp"
34 #include "tcuRenderTarget.hpp"
35 #include "tcuCPUWarmup.hpp"
36 #include "tcuApp.hpp"
37 
38 #include "glwEnums.hpp"
39 #include "glwFunctions.hpp"
40 
41 #include "deRandom.hpp"
42 #include "deStringUtil.hpp"
43 #include "deClock.h"
44 #include "deThread.h"
45 #include "deMath.h"
46 
47 #include <algorithm>
48 
49 namespace deqp
50 {
51 namespace gles3
52 {
53 namespace Functional
54 {
55 
56 using std::vector;
57 using std::string;
58 using tcu::TestLog;
59 using tcu::Vec2;
60 using deqp::gls::theilSenLinearRegression;
61 using deqp::gls::LineParameters;
62 
63 namespace
64 {
65 
66 enum
67 {
68 	MAX_VIEWPORT_SIZE			= 256,
69 	MAX_SAMPLE_DURATION_US		= 150*1000,
70 	MAX_CALIBRATE_DURATION_US	= tcu::WATCHDOG_INTERVAL_TIME_LIMIT_SECS/3*1000*1000,	// Abort when the watch dog gets nervous
71 	WAIT_TIME_MS				= 200,
72 	MIN_DRAW_CALL_COUNT			= 10,
73 	MAX_DRAW_CALL_COUNT			= 1<<20,
74 	MAX_SHADER_ITER_COUNT		= 1<<10,
75 	NUM_SAMPLES					= 50,
76 	NUM_VERIFICATION_SAMPLES	= 3,
77 	MAX_CALIBRATION_ATTEMPTS	= 5
78 };
79 
80 DE_STATIC_ASSERT(MAX_SAMPLE_DURATION_US < 1000*WAIT_TIME_MS);
81 
82 const float		NO_CORR_COEF_THRESHOLD				= 0.1f;
83 const float		FLUSH_COEF_THRESHOLD				= 0.2f;
84 const float		CORRELATED_COEF_THRESHOLD			= 0.3f;
85 const float		CALIBRATION_VERIFICATION_THRESHOLD	= 0.10f;	// Rendering time needs to be within 10% of MAX_SAMPLE_DURATION_US
86 
busyWait(int milliseconds)87 static void busyWait (int milliseconds)
88 {
89 	const deUint64	startTime	= deGetMicroseconds();
90 	float			v			= 2.0f;
91 
92 	for (;;)
93 	{
94 		for (int i = 0; i < 10; i++)
95 			v = deFloatSin(v);
96 
97 		if (deGetMicroseconds()-startTime >= deUint64(1000*milliseconds))
98 			break;
99 	}
100 }
101 
102 class CalibrationFailedException : public std::runtime_error
103 {
104 public:
CalibrationFailedException(const std::string & reason)105 	CalibrationFailedException (const std::string& reason) : std::runtime_error(reason) {}
106 };
107 
108 class FlushFinishCase : public TestCase
109 {
110 public:
111 	enum ExpectedBehavior
112 	{
113 		EXPECT_COEF_LESS_THAN = 0,
114 		EXPECT_COEF_GREATER_THAN,
115 	};
116 
117 							FlushFinishCase		(Context&			context,
118 												 const char*		name,
119 												 const char*		description,
120 												 ExpectedBehavior	waitBehavior,
121 												 float				waitThreshold,
122 												 ExpectedBehavior	readBehavior,
123 												 float				readThreshold);
124 							~FlushFinishCase	(void);
125 
126 	void					init				(void);
127 	void					deinit				(void);
128 	IterateResult			iterate				(void);
129 
130 	struct Sample
131 	{
132 		int			numDrawCalls;
133 		deUint64	submitTime;
134 		deUint64	waitTime;
135 		deUint64	readPixelsTime;
136 	};
137 
138 	struct CalibrationParams
139 	{
140 		int			numItersInShader;
141 		int			maxDrawCalls;
142 	};
143 
144 protected:
145 	virtual void			waitForGL			(void) = 0;
146 
147 private:
148 							FlushFinishCase		(const FlushFinishCase&);
149 	FlushFinishCase&		operator=			(const FlushFinishCase&);
150 
151 	CalibrationParams		calibrate			(void);
152 	void					verifyCalibration	(const CalibrationParams& params);
153 
154 	void					analyzeResults		(const std::vector<Sample>& samples, const CalibrationParams& calibrationParams);
155 
156 	void					setupRenderState	(void);
157 	void					setShaderIterCount	(int numIters);
158 	void					render				(int numDrawCalls);
159 	void					readPixels			(void);
160 
161 	const ExpectedBehavior	m_waitBehavior;
162 	const float				m_waitThreshold;
163 	const ExpectedBehavior	m_readBehavior;
164 	const float				m_readThreshold;
165 
166 	glu::ShaderProgram*		m_program;
167 	int						m_iterCountLoc;
168 };
169 
FlushFinishCase(Context & context,const char * name,const char * description,ExpectedBehavior waitBehavior,float waitThreshold,ExpectedBehavior readBehavior,float readThreshold)170 FlushFinishCase::FlushFinishCase (Context& context, const char* name, const char* description, ExpectedBehavior waitBehavior, float waitThreshold, ExpectedBehavior readBehavior, float readThreshold)
171 	: TestCase			(context, name, description)
172 	, m_waitBehavior	(waitBehavior)
173 	, m_waitThreshold	(waitThreshold)
174 	, m_readBehavior	(readBehavior)
175 	, m_readThreshold	(readThreshold)
176 	, m_program			(DE_NULL)
177 	, m_iterCountLoc	(0)
178 {
179 }
180 
~FlushFinishCase(void)181 FlushFinishCase::~FlushFinishCase (void)
182 {
183 	FlushFinishCase::deinit();
184 }
185 
init(void)186 void FlushFinishCase::init (void)
187 {
188 	DE_ASSERT(!m_program);
189 
190 	m_program = new glu::ShaderProgram(m_context.getRenderContext(),
191 		glu::ProgramSources()
192 			<< glu::VertexSource(
193 				"#version 300 es\n"
194 				"in highp vec4 a_position;\n"
195 				"out highp vec4 v_coord;\n"
196 				"void main (void)\n"
197 				"{\n"
198 				"	gl_Position = a_position;\n"
199 				"	v_coord = a_position;\n"
200 				"}\n")
201 			<< glu::FragmentSource(
202 				"#version 300 es\n"
203 				"uniform highp int u_numIters;\n"
204 				"in highp vec4 v_coord;\n"
205 				"out mediump vec4 o_color;\n"
206 				"void main (void)\n"
207 				"{\n"
208 				"	highp vec4 color = v_coord;\n"
209 				"	for (int i = 0; i < u_numIters; i++)\n"
210 				"		color = sin(color);\n"
211 				"	o_color = color;\n"
212 				"}\n"));
213 
214 	if (!m_program->isOk())
215 	{
216 		m_testCtx.getLog() << *m_program;
217 		delete m_program;
218 		m_program = DE_NULL;
219 		TCU_FAIL("Compile failed");
220 	}
221 
222 	m_iterCountLoc = m_context.getRenderContext().getFunctions().getUniformLocation(m_program->getProgram(), "u_numIters");
223 	TCU_CHECK(m_iterCountLoc >= 0);
224 }
225 
deinit(void)226 void FlushFinishCase::deinit (void)
227 {
228 	delete m_program;
229 	m_program = DE_NULL;
230 }
231 
operator <<(tcu::TestLog & log,const FlushFinishCase::Sample & sample)232 tcu::TestLog& operator<< (tcu::TestLog& log, const FlushFinishCase::Sample& sample)
233 {
234 	log << TestLog::Message << sample.numDrawCalls << " calls:\t" << sample.submitTime << " us submit,\t" << sample.waitTime << " us wait,\t" << sample.readPixelsTime << " us read" << TestLog::EndMessage;
235 	return log;
236 }
237 
setupRenderState(void)238 void FlushFinishCase::setupRenderState (void)
239 {
240 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
241 	const int				posLoc			= gl.getAttribLocation(m_program->getProgram(), "a_position");
242 	const int				viewportW		= de::min<int>(m_context.getRenderTarget().getWidth(), MAX_VIEWPORT_SIZE);
243 	const int				viewportH		= de::min<int>(m_context.getRenderTarget().getHeight(), MAX_VIEWPORT_SIZE);
244 
245 	static const float s_positions[] =
246 	{
247 		-1.0f, -1.0f,
248 		+1.0f, -1.0f,
249 		-1.0f, +1.0f,
250 		+1.0f, +1.0f
251 	};
252 
253 	TCU_CHECK(posLoc >= 0);
254 
255 	gl.viewport(0, 0, viewportW, viewportH);
256 	gl.useProgram(m_program->getProgram());
257 	gl.enableVertexAttribArray(posLoc);
258 	gl.vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, &s_positions[0]);
259 	gl.enable(GL_BLEND);
260 	gl.blendFunc(GL_ONE, GL_ONE);
261 	gl.blendEquation(GL_FUNC_ADD);
262 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set up render state");
263 }
264 
setShaderIterCount(int numIters)265 void FlushFinishCase::setShaderIterCount (int numIters)
266 {
267 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
268 	gl.uniform1i(m_iterCountLoc, numIters);
269 }
270 
render(int numDrawCalls)271 void FlushFinishCase::render (int numDrawCalls)
272 {
273 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
274 
275 	const deUint8 indices[] = { 0, 1, 2, 2, 1, 3 };
276 
277 	gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
278 
279 	for (int ndx = 0; ndx < numDrawCalls; ndx++)
280 		gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
281 }
282 
readPixels(void)283 void FlushFinishCase::readPixels (void)
284 {
285 	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
286 	deUint8					tmp[4];
287 
288 	gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &tmp);
289 }
290 
calibrate(void)291 FlushFinishCase::CalibrationParams FlushFinishCase::calibrate (void)
292 {
293 	tcu::ScopedLogSection		section				(m_testCtx.getLog(), "CalibrationInfo", "Calibration info");
294 	CalibrationParams			params;
295 
296 	const deUint64 calibrateStartTime = deGetMicroseconds();
297 
298 	// Step 1: find iteration count that results in rougly 1/10th of target maximum sample duration.
299 	{
300 		const deUint64		targetDurationUs		= MAX_SAMPLE_DURATION_US/100;
301 		deUint64			prevDuration			= 0;
302 		int					prevIterCount			= 1;
303 		int					curIterCount			= 1;
304 
305 		m_testCtx.getLog() << TestLog::Message << "Calibrating shader iteration count, target duration = " << targetDurationUs << " us" << TestLog::EndMessage;
306 
307 		for (;;)
308 		{
309 			deUint64 endTime;
310 			deUint64 curDuration;
311 
312 			setShaderIterCount(curIterCount);
313 			render(1); // \note Submit time is ignored
314 
315 			{
316 				const deUint64 startTime = deGetMicroseconds();
317 				readPixels();
318 				endTime = deGetMicroseconds();
319 				curDuration = endTime-startTime;
320 			}
321 
322 			m_testCtx.getLog() << TestLog::Message << "Duration with " << curIterCount << " iterations = " << curDuration << " us" << TestLog::EndMessage;
323 
324 			if (curDuration > targetDurationUs)
325 			{
326 				if (curIterCount > 1)
327 				{
328 					// Compute final count by using linear estimation.
329 					const float		a		= float(curDuration - prevDuration) / float(curIterCount - prevIterCount);
330 					const float		b		= float(prevDuration) - a*float(prevIterCount);
331 					const float		est		= (float(targetDurationUs) - b) / a;
332 
333 					curIterCount = de::clamp(deFloorFloatToInt32(est), 1, int(MAX_SHADER_ITER_COUNT));
334 				}
335 				// else: Settle on 1.
336 
337 				break;
338 			}
339 			else if (curIterCount >= MAX_SHADER_ITER_COUNT)
340 				break; // Settle on maximum.
341 			else if (endTime - calibrateStartTime > MAX_CALIBRATE_DURATION_US)
342 			{
343 				// Calibration is taking longer than expected. This can be due to eager draw call execution.
344 				throw CalibrationFailedException("Calibration failed, target duration not reached within expected time");
345 			}
346 			else
347 			{
348 				prevIterCount	= curIterCount;
349 				prevDuration	= curDuration;
350 				curIterCount	= curIterCount*2;
351 			}
352 		}
353 
354 		params.numItersInShader = curIterCount;
355 
356 		m_testCtx.getLog() << TestLog::Integer("ShaderIterCount", "Shader iteration count", "", QP_KEY_TAG_NONE, params.numItersInShader);
357 	}
358 
359 	// Step 2: Find draw call count that results in desired maximum time.
360 	{
361 		deUint64			prevDuration			= 0;
362 		int					prevDrawCount			= 1;
363 		int					curDrawCount			= 1;
364 
365 		m_testCtx.getLog() << TestLog::Message << "Calibrating maximum draw call count, target duration = " << int(MAX_SAMPLE_DURATION_US) << " us" << TestLog::EndMessage;
366 
367 		setShaderIterCount(params.numItersInShader);
368 
369 		for (;;)
370 		{
371 			deUint64 endTime;
372 			deUint64 curDuration;
373 
374 			render(curDrawCount); // \note Submit time is ignored
375 
376 			{
377 				const deUint64 startTime = deGetMicroseconds();
378 				readPixels();
379 				endTime = deGetMicroseconds();
380 				curDuration = endTime-startTime;
381 			}
382 
383 			m_testCtx.getLog() << TestLog::Message << "Duration with " << curDrawCount << " draw calls = " << curDuration << " us" << TestLog::EndMessage;
384 
385 			if (curDuration > MAX_SAMPLE_DURATION_US)
386 			{
387 				if (curDrawCount > 1)
388 				{
389 					// Compute final count by using linear estimation.
390 					const float		a		= float(curDuration - prevDuration) / float(curDrawCount - prevDrawCount);
391 					const float		b		= float(prevDuration) - a*float(prevDrawCount);
392 					const float		est		= (float(MAX_SAMPLE_DURATION_US) - b) / a;
393 
394 					curDrawCount = de::clamp(deFloorFloatToInt32(est), 1, int(MAX_DRAW_CALL_COUNT));
395 				}
396 				// else: Settle on 1.
397 
398 				break;
399 			}
400 			else if (curDrawCount >= MAX_DRAW_CALL_COUNT)
401 				break; // Settle on maximum.
402 			else if (endTime - calibrateStartTime > MAX_CALIBRATE_DURATION_US)
403 			{
404 				// Calibration is taking longer than expected. This can be due to eager draw call execution.
405 				throw CalibrationFailedException("Calibration failed, target duration not reached within expected time");
406 			}
407 			else
408 			{
409 				prevDrawCount	= curDrawCount;
410 				prevDuration	= curDuration;
411 				curDrawCount	= curDrawCount*2;
412 			}
413 		}
414 
415 		params.maxDrawCalls = curDrawCount;
416 
417 		m_testCtx.getLog() << TestLog::Integer("MaxDrawCalls", "Maximum number of draw calls", "", QP_KEY_TAG_NONE, params.maxDrawCalls);
418 	}
419 
420 	// Sanity check.
421 	if (params.maxDrawCalls < MIN_DRAW_CALL_COUNT)
422 		throw CalibrationFailedException("Calibration failed, maximum draw call count is too low");
423 
424 	return params;
425 }
426 
verifyCalibration(const CalibrationParams & params)427 void FlushFinishCase::verifyCalibration (const CalibrationParams& params)
428 {
429 	setShaderIterCount(params.numItersInShader);
430 
431 	for (int sampleNdx = 0; sampleNdx < NUM_VERIFICATION_SAMPLES; sampleNdx++)
432 	{
433 		deUint64 readStartTime;
434 
435 		render(params.maxDrawCalls);
436 
437 		readStartTime = deGetMicroseconds();
438 		readPixels();
439 
440 		{
441 			const deUint64	renderDuration	= deGetMicroseconds()-readStartTime;
442 			const float		relativeDelta	= float(double(renderDuration) / double(MAX_SAMPLE_DURATION_US)) - 1.0f;
443 
444 			if (!de::inBounds(relativeDelta, -CALIBRATION_VERIFICATION_THRESHOLD, CALIBRATION_VERIFICATION_THRESHOLD))
445 			{
446 				std::ostringstream msg;
447 				msg << "ERROR: Unstable performance, got " << renderDuration << " us read time, "
448 					<< de::floatToString(relativeDelta*100.0f, 1) << "% diff to estimated " << (int)MAX_SAMPLE_DURATION_US << " us";
449 				throw CalibrationFailedException(msg.str());
450 			}
451 		}
452 	}
453 }
454 
455 struct CompareSampleDrawCount
456 {
operator ()deqp::gles3::Functional::__anonf9388eda0111::CompareSampleDrawCount457 	bool operator() (const FlushFinishCase::Sample& a, const FlushFinishCase::Sample& b) const { return a.numDrawCalls < b.numDrawCalls; }
458 };
459 
getPointsFromSamples(const std::vector<FlushFinishCase::Sample> & samples,const deUint64 FlushFinishCase::Sample::* field)460 std::vector<Vec2> getPointsFromSamples (const std::vector<FlushFinishCase::Sample>& samples, const deUint64 FlushFinishCase::Sample::*field)
461 {
462 	vector<Vec2> points(samples.size());
463 
464 	for (size_t ndx = 0; ndx < samples.size(); ndx++)
465 		points[ndx] = Vec2(float(samples[ndx].numDrawCalls), float(samples[ndx].*field));
466 
467 	return points;
468 }
469 
470 template<typename T>
getMaximumValue(const std::vector<FlushFinishCase::Sample> & samples,const T FlushFinishCase::Sample::* field)471 T getMaximumValue (const std::vector<FlushFinishCase::Sample>& samples, const T FlushFinishCase::Sample::*field)
472 {
473 	DE_ASSERT(!samples.empty());
474 
475 	T maxVal = samples[0].*field;
476 
477 	for (size_t ndx = 1; ndx < samples.size(); ndx++)
478 		maxVal = de::max(maxVal, samples[ndx].*field);
479 
480 	return maxVal;
481 }
482 
analyzeResults(const std::vector<Sample> & samples,const CalibrationParams & calibrationParams)483 void FlushFinishCase::analyzeResults (const std::vector<Sample>& samples, const CalibrationParams& calibrationParams)
484 {
485 	const vector<Vec2>		waitTimes		= getPointsFromSamples(samples, &Sample::waitTime);
486 	const vector<Vec2>		readTimes		= getPointsFromSamples(samples, &Sample::readPixelsTime);
487 	const LineParameters	waitLine		= theilSenLinearRegression(waitTimes);
488 	const LineParameters	readLine		= theilSenLinearRegression(readTimes);
489 	const float				normWaitCoef	= waitLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
490 	const float				normReadCoef	= readLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
491 	bool					allOk			= true;
492 
493 	{
494 		tcu::ScopedLogSection	section			(m_testCtx.getLog(), "Samples", "Samples");
495 		vector<Sample>			sortedSamples	(samples.begin(), samples.end());
496 
497 		std::sort(sortedSamples.begin(), sortedSamples.end(), CompareSampleDrawCount());
498 
499 		for (vector<Sample>::const_iterator iter = sortedSamples.begin(); iter != sortedSamples.end(); ++iter)
500 			m_testCtx.getLog() << *iter;
501 	}
502 
503 	m_testCtx.getLog() << TestLog::Float("WaitCoefficient",				"Wait coefficient", "", QP_KEY_TAG_NONE, waitLine.coefficient)
504 					   << TestLog::Float("ReadCoefficient",				"Read coefficient", "", QP_KEY_TAG_NONE, readLine.coefficient)
505 					   << TestLog::Float("NormalizedWaitCoefficient",	"Normalized wait coefficient", "", QP_KEY_TAG_NONE, normWaitCoef)
506 					   << TestLog::Float("NormalizedReadCoefficient",	"Normalized read coefficient", "", QP_KEY_TAG_NONE, normReadCoef);
507 
508 	{
509 		const bool		waitCorrelated		= normWaitCoef > CORRELATED_COEF_THRESHOLD;
510 		const bool		readCorrelated		= normReadCoef > CORRELATED_COEF_THRESHOLD;
511 		const bool		waitNotCorr			= normWaitCoef < NO_CORR_COEF_THRESHOLD;
512 		const bool		readNotCorr			= normReadCoef < NO_CORR_COEF_THRESHOLD;
513 
514 		if (waitCorrelated || waitNotCorr)
515 			m_testCtx.getLog() << TestLog::Message << "Wait time is" << (waitCorrelated ? "" : " NOT") << " correlated to rendering workload size." << TestLog::EndMessage;
516 		else
517 			m_testCtx.getLog() << TestLog::Message << "Warning: Wait time correlation to rendering workload size is unclear." << TestLog::EndMessage;
518 
519 		if (readCorrelated || readNotCorr)
520 			m_testCtx.getLog() << TestLog::Message << "Read time is" << (readCorrelated ? "" : " NOT") << " correlated to rendering workload size." << TestLog::EndMessage;
521 		else
522 			m_testCtx.getLog() << TestLog::Message << "Warning: Read time correlation to rendering workload size is unclear." << TestLog::EndMessage;
523 	}
524 
525 	for (int ndx = 0; ndx < 2; ndx++)
526 	{
527 		const float				coef		= ndx == 0 ? normWaitCoef : normReadCoef;
528 		const char*				name		= ndx == 0 ? "wait" : "read";
529 		const ExpectedBehavior	behavior	= ndx == 0 ? m_waitBehavior : m_readBehavior;
530 		const float				threshold	= ndx == 0 ? m_waitThreshold : m_readThreshold;
531 		const bool				isOk		= behavior == EXPECT_COEF_GREATER_THAN	? coef > threshold :
532 											  behavior == EXPECT_COEF_LESS_THAN		? coef < threshold : false;
533 		const char*				cmpName		= behavior == EXPECT_COEF_GREATER_THAN	? "greater than" :
534 											  behavior == EXPECT_COEF_LESS_THAN		? "less than" : DE_NULL;
535 
536 		if (!isOk)
537 		{
538 			m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << name << " coefficient to be " << cmpName << " " << threshold << TestLog::EndMessage;
539 			allOk = false;
540 		}
541 	}
542 
543 	m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_COMPATIBILITY_WARNING,
544 							allOk ? "Pass"				: "Suspicious performance behavior");
545 }
546 
iterate(void)547 FlushFinishCase::IterateResult FlushFinishCase::iterate (void)
548 {
549 	vector<Sample>		samples		(NUM_SAMPLES);
550 	CalibrationParams	params;
551 
552 	tcu::warmupCPU();
553 
554 	setupRenderState();
555 
556 	// Do one full render cycle.
557 	{
558 		setShaderIterCount(1);
559 		render(1);
560 		readPixels();
561 	}
562 
563 	// Calibrate.
564 	for (int calibrationRoundNdx = 0; /* until done */; calibrationRoundNdx++)
565 	{
566 		try
567 		{
568 			m_testCtx.touchWatchdog();
569 			params = calibrate();
570 			verifyCalibration(params);
571 			break;
572 		}
573 		catch (const CalibrationFailedException& e)
574 		{
575 			m_testCtx.getLog() << e;
576 
577 			if (calibrationRoundNdx < MAX_CALIBRATION_ATTEMPTS)
578 			{
579 				m_testCtx.getLog() << TestLog::Message
580 								   << "Retrying calibration (" << (calibrationRoundNdx+1) << " / " << (int)MAX_CALIBRATION_ATTEMPTS << ")"
581 								   << TestLog::EndMessage;
582 			}
583 			else
584 			{
585 				m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, e.what());
586 				return STOP;
587 			}
588 		}
589 	}
590 
591 	// Do measurement.
592 	{
593 		de::Random	rnd		(123);
594 
595 		setShaderIterCount(params.numItersInShader);
596 
597 		for (size_t ndx = 0; ndx < samples.size(); ndx++)
598 		{
599 			const int		drawCallCount	= rnd.getInt(1, params.maxDrawCalls);
600 			const deUint64	submitStartTime	= deGetMicroseconds();
601 			deUint64		waitStartTime;
602 			deUint64		readStartTime;
603 			deUint64		readFinishTime;
604 
605 			render(drawCallCount);
606 
607 			waitStartTime = deGetMicroseconds();
608 			waitForGL();
609 
610 			readStartTime = deGetMicroseconds();
611 			readPixels();
612 			readFinishTime = deGetMicroseconds();
613 
614 			samples[ndx].numDrawCalls	= drawCallCount;
615 			samples[ndx].submitTime		= waitStartTime-submitStartTime;
616 			samples[ndx].waitTime		= readStartTime-waitStartTime;
617 			samples[ndx].readPixelsTime	= readFinishTime-readStartTime;
618 
619 			m_testCtx.touchWatchdog();
620 		}
621 	}
622 
623 	// Analyze - sets test case result.
624 	analyzeResults(samples, params);
625 
626 	return STOP;
627 }
628 
629 class WaitOnlyCase : public FlushFinishCase
630 {
631 public:
WaitOnlyCase(Context & context)632 	WaitOnlyCase (Context& context)
633 		: FlushFinishCase(context, "wait", "Wait only", EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD, EXPECT_COEF_GREATER_THAN, -1000.0f /* practically nothing is expected */)
634 	{
635 	}
636 
init(void)637 	void init (void)
638 	{
639 		m_testCtx.getLog() << TestLog::Message << int(WAIT_TIME_MS) << " ms busy wait" << TestLog::EndMessage;
640 		FlushFinishCase::init();
641 	}
642 
643 protected:
waitForGL(void)644 	void waitForGL (void)
645 	{
646 		busyWait(WAIT_TIME_MS);
647 	}
648 };
649 
650 class FlushOnlyCase : public FlushFinishCase
651 {
652 public:
FlushOnlyCase(Context & context)653 	FlushOnlyCase (Context& context)
654 		: FlushFinishCase(context, "flush", "Flush only", EXPECT_COEF_LESS_THAN, FLUSH_COEF_THRESHOLD, EXPECT_COEF_GREATER_THAN, CORRELATED_COEF_THRESHOLD)
655 	{
656 	}
657 
init(void)658 	void init (void)
659 	{
660 		m_testCtx.getLog() << TestLog::Message << "Single call to glFlush()" << TestLog::EndMessage;
661 		FlushFinishCase::init();
662 	}
663 
664 protected:
waitForGL(void)665 	void waitForGL (void)
666 	{
667 		m_context.getRenderContext().getFunctions().flush();
668 	}
669 };
670 
671 class FlushWaitCase : public FlushFinishCase
672 {
673 public:
FlushWaitCase(Context & context)674 	FlushWaitCase (Context& context)
675 		: FlushFinishCase(context, "flush_wait", "Wait after flushing", EXPECT_COEF_LESS_THAN, FLUSH_COEF_THRESHOLD, EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD)
676 	{
677 	}
678 
init(void)679 	void init (void)
680 	{
681 		m_testCtx.getLog() << TestLog::Message << "glFlush() followed by " << int(WAIT_TIME_MS) << " ms busy wait" << TestLog::EndMessage;
682 		FlushFinishCase::init();
683 	}
684 
685 protected:
waitForGL(void)686 	void waitForGL (void)
687 	{
688 		m_context.getRenderContext().getFunctions().flush();
689 		busyWait(WAIT_TIME_MS);
690 	}
691 };
692 
693 class FinishOnlyCase : public FlushFinishCase
694 {
695 public:
FinishOnlyCase(Context & context)696 	FinishOnlyCase (Context& context)
697 		: FlushFinishCase(context, "finish", "Finish only", EXPECT_COEF_GREATER_THAN, CORRELATED_COEF_THRESHOLD, EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD)
698 	{
699 	}
700 
init(void)701 	void init (void)
702 	{
703 		m_testCtx.getLog() << TestLog::Message << "Single call to glFinish()" << TestLog::EndMessage;
704 		FlushFinishCase::init();
705 	}
706 
707 protected:
waitForGL(void)708 	void waitForGL (void)
709 	{
710 		m_context.getRenderContext().getFunctions().finish();
711 	}
712 };
713 
714 class FinishWaitCase : public FlushFinishCase
715 {
716 public:
FinishWaitCase(Context & context)717 	FinishWaitCase (Context& context)
718 		: FlushFinishCase(context, "finish_wait", "Finish and wait", EXPECT_COEF_GREATER_THAN, CORRELATED_COEF_THRESHOLD, EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD)
719 	{
720 	}
721 
init(void)722 	void init (void)
723 	{
724 		m_testCtx.getLog() << TestLog::Message << "glFinish() followed by " << int(WAIT_TIME_MS) << " ms busy wait" << TestLog::EndMessage;
725 		FlushFinishCase::init();
726 	}
727 
728 protected:
waitForGL(void)729 	void waitForGL (void)
730 	{
731 		m_context.getRenderContext().getFunctions().finish();
732 		busyWait(WAIT_TIME_MS);
733 	}
734 };
735 
736 } // anonymous
737 
FlushFinishTests(Context & context)738 FlushFinishTests::FlushFinishTests (Context& context)
739 	: TestCaseGroup(context, "flush_finish", "Flush and Finish tests")
740 {
741 }
742 
~FlushFinishTests(void)743 FlushFinishTests::~FlushFinishTests (void)
744 {
745 }
746 
init(void)747 void FlushFinishTests::init (void)
748 {
749 	addChild(new WaitOnlyCase	(m_context));
750 	addChild(new FlushOnlyCase	(m_context));
751 	addChild(new FlushWaitCase	(m_context));
752 	addChild(new FinishOnlyCase	(m_context));
753 	addChild(new FinishWaitCase	(m_context));
754 }
755 
756 } // Functional
757 } // gles3
758 } // deqp
759