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