Home | History | Annotate | Download | only in functional
      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 
     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:
     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 
    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 
    169 FlushFinishCase::~FlushFinishCase (void)
    170 {
    171 	FlushFinishCase::deinit();
    172 }
    173 
    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 
    214 void FlushFinishCase::deinit (void)
    215 {
    216 	delete m_program;
    217 	m_program = DE_NULL;
    218 }
    219 
    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 
    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 
    253 void FlushFinishCase::setShaderIterCount (int numIters)
    254 {
    255 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
    256 	gl.uniform1i(m_iterCountLoc, numIters);
    257 }
    258 
    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 
    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 
    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 {
    400 	bool operator() (const FlushFinishCase::Sample& a, const FlushFinishCase::Sample& b) const { return a.numDrawCalls < b.numDrawCalls; }
    401 };
    402 
    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>
    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 
    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 
    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:
    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 
    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:
    570 	void waitForGL (void)
    571 	{
    572 		busyWait(WAIT_TIME_MS);
    573 	}
    574 };
    575 
    576 class FlushOnlyCase : public FlushFinishCase
    577 {
    578 public:
    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 
    584 	void init (void)
    585 	{
    586 		m_testCtx.getLog() << TestLog::Message << "Single call to glFlush()" << TestLog::EndMessage;
    587 		FlushFinishCase::init();
    588 	}
    589 
    590 protected:
    591 	void waitForGL (void)
    592 	{
    593 		m_context.getRenderContext().getFunctions().flush();
    594 	}
    595 };
    596 
    597 class FlushWaitCase : public FlushFinishCase
    598 {
    599 public:
    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 
    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:
    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:
    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 
    627 	void init (void)
    628 	{
    629 		m_testCtx.getLog() << TestLog::Message << "Single call to glFinish()" << TestLog::EndMessage;
    630 		FlushFinishCase::init();
    631 	}
    632 
    633 protected:
    634 	void waitForGL (void)
    635 	{
    636 		m_context.getRenderContext().getFunctions().finish();
    637 	}
    638 };
    639 
    640 class FinishWaitCase : public FlushFinishCase
    641 {
    642 public:
    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 
    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:
    655 	void waitForGL (void)
    656 	{
    657 		m_context.getRenderContext().getFunctions().finish();
    658 		busyWait(WAIT_TIME_MS);
    659 	}
    660 };
    661 
    662 } // anonymous
    663 
    664 FlushFinishTests::FlushFinishTests (Context& context)
    665 	: TestCaseGroup(context, "flush_finish", "Flush and Finish tests")
    666 {
    667 }
    668 
    669 FlushFinishTests::~FlushFinishTests (void)
    670 {
    671 }
    672 
    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