xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fFlushFinishTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 &params);
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 &params)
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