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