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