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