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