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