Lower correlation threshold in flush-finish tests again
[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
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.3f;
83 const float             CALIBRATION_VERIFICATION_THRESHOLD      = 0.10f;        // Rendering time needs to be within 10% of MAX_SAMPLE_DURATION_US
84
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:
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
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
179 FlushFinishCase::~FlushFinishCase (void)
180 {
181         FlushFinishCase::deinit();
182 }
183
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
224 void FlushFinishCase::deinit (void)
225 {
226         delete m_program;
227         m_program = DE_NULL;
228 }
229
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
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
263 void FlushFinishCase::setShaderIterCount (int numIters)
264 {
265         const glw::Functions&   gl      = m_context.getRenderContext().getFunctions();
266         gl.uniform1i(m_iterCountLoc, numIters);
267 }
268
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
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
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
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 {
439         bool operator() (const FlushFinishCase::Sample& a, const FlushFinishCase::Sample& b) const { return a.numDrawCalls < b.numDrawCalls; }
440 };
441
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>
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
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
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:
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
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:
626         void waitForGL (void)
627         {
628                 busyWait(WAIT_TIME_MS);
629         }
630 };
631
632 class FlushOnlyCase : public FlushFinishCase
633 {
634 public:
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
640         void init (void)
641         {
642                 m_testCtx.getLog() << TestLog::Message << "Single call to glFlush()" << TestLog::EndMessage;
643                 FlushFinishCase::init();
644         }
645
646 protected:
647         void waitForGL (void)
648         {
649                 m_context.getRenderContext().getFunctions().flush();
650         }
651 };
652
653 class FlushWaitCase : public FlushFinishCase
654 {
655 public:
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
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:
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:
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
683         void init (void)
684         {
685                 m_testCtx.getLog() << TestLog::Message << "Single call to glFinish()" << TestLog::EndMessage;
686                 FlushFinishCase::init();
687         }
688
689 protected:
690         void waitForGL (void)
691         {
692                 m_context.getRenderContext().getFunctions().finish();
693         }
694 };
695
696 class FinishWaitCase : public FlushFinishCase
697 {
698 public:
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
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:
711         void waitForGL (void)
712         {
713                 m_context.getRenderContext().getFunctions().finish();
714                 busyWait(WAIT_TIME_MS);
715         }
716 };
717
718 } // anonymous
719
720 FlushFinishTests::FlushFinishTests (Context& context)
721         : TestCaseGroup(context, "flush_finish", "Flush and Finish tests")
722 {
723 }
724
725 FlushFinishTests::~FlushFinishTests (void)
726 {
727 }
728
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