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