xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fFlushFinishTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 2.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 "es2fFlushFinishTests.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 gles2
51 {
52 namespace Functional
53 {
54 
55 using deqp::gls::LineParameters;
56 using deqp::gls::theilSenLinearRegression;
57 using std::string;
58 using std::vector;
59 using tcu::TestLog;
60 using tcu::Vec2;
61 
62 namespace
63 {
64 
65 enum
66 {
67     MAX_VIEWPORT_SIZE      = 128,
68     MAX_SAMPLE_DURATION_US = 1000 * 1000,
69     WAIT_TIME_MS           = 1200,
70     NUM_SAMPLES            = 25,
71     MIN_DRAW_CALL_COUNT    = 10,
72     MAX_DRAW_CALL_COUNT    = 1 << 20,
73     NUM_ITERS_IN_SHADER    = 10
74 };
75 
76 const float NO_CORR_COEF_THRESHOLD    = 0.1f;
77 const float FLUSH_COEF_THRESHOLD      = 0.2f;
78 const float CORRELATED_COEF_THRESHOLD = 0.5f;
79 
busyWait(int milliseconds)80 static void busyWait(int milliseconds)
81 {
82     const uint64_t startTime = deGetMicroseconds();
83     float v                  = 2.0f;
84 
85     for (;;)
86     {
87         for (int i = 0; i < 10; i++)
88             v = deFloatSin(v);
89 
90         if (deGetMicroseconds() - startTime >= uint64_t(1000 * milliseconds))
91             break;
92     }
93 }
94 
95 class CalibrationFailedException : public std::runtime_error
96 {
97 public:
CalibrationFailedException(const std::string & reason)98     CalibrationFailedException(const std::string &reason) : std::runtime_error(reason)
99     {
100     }
101 };
102 
103 class FlushFinishCase : public TestCase
104 {
105 public:
106     enum ExpectedBehavior
107     {
108         EXPECT_COEF_LESS_THAN = 0,
109         EXPECT_COEF_GREATER_THAN,
110     };
111 
112     FlushFinishCase(Context &context, const char *name, const char *description, ExpectedBehavior waitBehavior,
113                     float waitThreshold, ExpectedBehavior readBehavior, float readThreshold);
114     ~FlushFinishCase(void);
115 
116     void init(void);
117     void deinit(void);
118     IterateResult iterate(void);
119 
120     struct Sample
121     {
122         int numDrawCalls;
123         uint64_t waitTime;
124         uint64_t readPixelsTime;
125     };
126 
127     struct CalibrationParams
128     {
129         int maxDrawCalls;
130     };
131 
132 protected:
133     virtual void waitForGL(void) = 0;
134 
135 private:
136     FlushFinishCase(const FlushFinishCase &);
137     FlushFinishCase &operator=(const FlushFinishCase &);
138 
139     CalibrationParams calibrate(void);
140     void analyzeResults(const std::vector<Sample> &samples, const CalibrationParams &calibrationParams);
141 
142     void setupRenderState(void);
143     void render(int numDrawCalls);
144     void readPixels(void);
145 
146     const ExpectedBehavior m_waitBehavior;
147     const float m_waitThreshold;
148     const ExpectedBehavior m_readBehavior;
149     const float m_readThreshold;
150 
151     glu::ShaderProgram *m_program;
152 };
153 
FlushFinishCase(Context & context,const char * name,const char * description,ExpectedBehavior waitBehavior,float waitThreshold,ExpectedBehavior readBehavior,float readThreshold)154 FlushFinishCase::FlushFinishCase(Context &context, const char *name, const char *description,
155                                  ExpectedBehavior waitBehavior, float waitThreshold, ExpectedBehavior readBehavior,
156                                  float readThreshold)
157     : TestCase(context, name, description)
158     , m_waitBehavior(waitBehavior)
159     , m_waitThreshold(waitThreshold)
160     , m_readBehavior(readBehavior)
161     , m_readThreshold(readThreshold)
162     , m_program(DE_NULL)
163 {
164 }
165 
~FlushFinishCase(void)166 FlushFinishCase::~FlushFinishCase(void)
167 {
168     FlushFinishCase::deinit();
169 }
170 
init(void)171 void FlushFinishCase::init(void)
172 {
173     DE_ASSERT(!m_program);
174 
175     m_program =
176         new glu::ShaderProgram(m_context.getRenderContext(),
177                                glu::ProgramSources() << glu::VertexSource("attribute highp vec4 a_position;\n"
178                                                                           "varying highp vec4 v_coord;\n"
179                                                                           "void main (void)\n"
180                                                                           "{\n"
181                                                                           "    gl_Position = a_position;\n"
182                                                                           "    v_coord = a_position;\n"
183                                                                           "}\n")
184                                                      << glu::FragmentSource("uniform mediump int u_numIters;\n"
185                                                                             "varying mediump vec4 v_coord;\n"
186                                                                             "void main (void)\n"
187                                                                             "{\n"
188                                                                             "    highp vec4 color = v_coord;\n"
189                                                                             "    for (int i = 0; i < " +
190                                                                             de::toString(int(NUM_ITERS_IN_SHADER)) +
191                                                                             "; i++)\n"
192                                                                             "        color = sin(color);\n"
193                                                                             "    gl_FragColor = color;\n"
194                                                                             "}\n"));
195 
196     if (!m_program->isOk())
197     {
198         m_testCtx.getLog() << *m_program;
199         delete m_program;
200         m_program = DE_NULL;
201         TCU_FAIL("Compile failed");
202     }
203 }
204 
deinit(void)205 void FlushFinishCase::deinit(void)
206 {
207     delete m_program;
208     m_program = DE_NULL;
209 }
210 
operator <<(tcu::TestLog & log,const FlushFinishCase::Sample & sample)211 tcu::TestLog &operator<<(tcu::TestLog &log, const FlushFinishCase::Sample &sample)
212 {
213     log << TestLog::Message << sample.numDrawCalls << " calls:\t" << sample.waitTime << " us wait,\t"
214         << sample.readPixelsTime << " us read" << TestLog::EndMessage;
215     return log;
216 }
217 
setupRenderState(void)218 void FlushFinishCase::setupRenderState(void)
219 {
220     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
221     const int posLoc         = gl.getAttribLocation(m_program->getProgram(), "a_position");
222     const int viewportW      = de::min<int>(m_context.getRenderTarget().getWidth(), MAX_VIEWPORT_SIZE);
223     const int viewportH      = de::min<int>(m_context.getRenderTarget().getHeight(), MAX_VIEWPORT_SIZE);
224 
225     static const float s_positions[] = {-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f};
226 
227     TCU_CHECK(posLoc >= 0);
228 
229     gl.viewport(0, 0, viewportW, viewportH);
230     gl.useProgram(m_program->getProgram());
231     gl.enableVertexAttribArray(posLoc);
232     gl.vertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, &s_positions[0]);
233     gl.enable(GL_BLEND);
234     gl.blendFunc(GL_ONE, GL_ONE);
235     gl.blendEquation(GL_FUNC_ADD);
236     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set up render state");
237 }
238 
render(int numDrawCalls)239 void FlushFinishCase::render(int numDrawCalls)
240 {
241     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
242 
243     const uint8_t indices[] = {0, 1, 2, 2, 1, 3};
244 
245     gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
246 
247     for (int ndx = 0; ndx < numDrawCalls; ndx++)
248         gl.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_BYTE, &indices[0]);
249 }
250 
readPixels(void)251 void FlushFinishCase::readPixels(void)
252 {
253     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
254     uint8_t tmp[4];
255 
256     gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &tmp);
257 }
258 
calibrate(void)259 FlushFinishCase::CalibrationParams FlushFinishCase::calibrate(void)
260 {
261     tcu::ScopedLogSection section(m_testCtx.getLog(), "CalibrationInfo", "Calibration info");
262     CalibrationParams params;
263 
264     // Find draw call count that results in desired maximum time.
265     {
266         uint64_t prevDuration = 0;
267         int prevDrawCount     = 1;
268         int curDrawCount      = 1;
269 
270         m_testCtx.getLog() << TestLog::Message
271                            << "Calibrating maximum draw call count, target duration = " << int(MAX_SAMPLE_DURATION_US)
272                            << " us" << TestLog::EndMessage;
273 
274         for (;;)
275         {
276             uint64_t curDuration;
277 
278             {
279                 const uint64_t startTime = deGetMicroseconds();
280                 render(curDrawCount);
281                 readPixels();
282                 curDuration = deGetMicroseconds() - startTime;
283             }
284 
285             m_testCtx.getLog() << TestLog::Message << "Duration with " << curDrawCount
286                                << " draw calls = " << curDuration << " us" << TestLog::EndMessage;
287 
288             if (curDuration > MAX_SAMPLE_DURATION_US)
289             {
290                 if (curDrawCount > 1)
291                 {
292                     // Compute final count by using linear estimation.
293                     const float a   = float(curDuration - prevDuration) / float(curDrawCount - prevDrawCount);
294                     const float b   = float(prevDuration) - a * float(prevDrawCount);
295                     const float est = (float(MAX_SAMPLE_DURATION_US) - b) / a;
296 
297                     curDrawCount = de::clamp(deFloorFloatToInt32(est), 1, int(MAX_DRAW_CALL_COUNT));
298                 }
299                 // else: Settle on 1.
300 
301                 break;
302             }
303             else if (curDrawCount >= MAX_DRAW_CALL_COUNT)
304                 break; // Settle on maximum.
305             else
306             {
307                 prevDrawCount = curDrawCount;
308                 prevDuration  = curDuration;
309                 curDrawCount  = curDrawCount * 2;
310             }
311         }
312 
313         params.maxDrawCalls = curDrawCount;
314 
315         m_testCtx.getLog() << TestLog::Integer("MaxDrawCalls", "Maximum number of draw calls", "", QP_KEY_TAG_NONE,
316                                                params.maxDrawCalls);
317     }
318 
319     // Quick check.
320     if (params.maxDrawCalls < MIN_DRAW_CALL_COUNT)
321         throw CalibrationFailedException("Calibration failed, maximum draw call count is too low");
322 
323     return params;
324 }
325 
326 struct CompareSampleDrawCount
327 {
operator ()deqp::gles2::Functional::__anonc425510d0111::CompareSampleDrawCount328     bool operator()(const FlushFinishCase::Sample &a, const FlushFinishCase::Sample &b) const
329     {
330         return a.numDrawCalls < b.numDrawCalls;
331     }
332 };
333 
getPointsFromSamples(const std::vector<FlushFinishCase::Sample> & samples,const uint64_t FlushFinishCase::Sample::* field)334 std::vector<Vec2> getPointsFromSamples(const std::vector<FlushFinishCase::Sample> &samples,
335                                        const uint64_t FlushFinishCase::Sample::*field)
336 {
337     vector<Vec2> points(samples.size());
338 
339     for (size_t ndx = 0; ndx < samples.size(); ndx++)
340         points[ndx] = Vec2(float(samples[ndx].numDrawCalls), float(samples[ndx].*field));
341 
342     return points;
343 }
344 
345 template <typename T>
getMaximumValue(const std::vector<FlushFinishCase::Sample> & samples,const T FlushFinishCase::Sample::* field)346 T getMaximumValue(const std::vector<FlushFinishCase::Sample> &samples, const T FlushFinishCase::Sample::*field)
347 {
348     DE_ASSERT(!samples.empty());
349 
350     T maxVal = samples[0].*field;
351 
352     for (size_t ndx = 1; ndx < samples.size(); ndx++)
353         maxVal = de::max(maxVal, samples[ndx].*field);
354 
355     return maxVal;
356 }
357 
analyzeResults(const std::vector<Sample> & samples,const CalibrationParams & calibrationParams)358 void FlushFinishCase::analyzeResults(const std::vector<Sample> &samples, const CalibrationParams &calibrationParams)
359 {
360     const vector<Vec2> waitTimes  = getPointsFromSamples(samples, &Sample::waitTime);
361     const vector<Vec2> readTimes  = getPointsFromSamples(samples, &Sample::readPixelsTime);
362     const LineParameters waitLine = theilSenLinearRegression(waitTimes);
363     const LineParameters readLine = theilSenLinearRegression(readTimes);
364     const float normWaitCoef =
365         waitLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
366     const float normReadCoef =
367         readLine.coefficient * float(calibrationParams.maxDrawCalls) / float(MAX_SAMPLE_DURATION_US);
368     bool allOk = true;
369 
370     {
371         tcu::ScopedLogSection section(m_testCtx.getLog(), "Samples", "Samples");
372         vector<Sample> sortedSamples(samples.begin(), samples.end());
373 
374         std::sort(sortedSamples.begin(), sortedSamples.end(), CompareSampleDrawCount());
375 
376         for (vector<Sample>::const_iterator iter = sortedSamples.begin(); iter != sortedSamples.end(); ++iter)
377             m_testCtx.getLog() << *iter;
378     }
379 
380     m_testCtx.getLog() << TestLog::Float("WaitCoefficient", "Wait coefficient", "", QP_KEY_TAG_NONE,
381                                          waitLine.coefficient)
382                        << TestLog::Float("ReadCoefficient", "Read coefficient", "", QP_KEY_TAG_NONE,
383                                          readLine.coefficient)
384                        << TestLog::Float("NormalizedWaitCoefficient", "Normalized wait coefficient", "",
385                                          QP_KEY_TAG_NONE, normWaitCoef)
386                        << TestLog::Float("NormalizedReadCoefficient", "Normalized read coefficient", "",
387                                          QP_KEY_TAG_NONE, normReadCoef);
388 
389     {
390         const bool waitCorrelated = normWaitCoef > CORRELATED_COEF_THRESHOLD;
391         const bool readCorrelated = normReadCoef > CORRELATED_COEF_THRESHOLD;
392         const bool waitNotCorr    = normWaitCoef < NO_CORR_COEF_THRESHOLD;
393         const bool readNotCorr    = normReadCoef < NO_CORR_COEF_THRESHOLD;
394 
395         if (waitCorrelated || waitNotCorr)
396             m_testCtx.getLog() << TestLog::Message << "Wait time is" << (waitCorrelated ? "" : " NOT")
397                                << " correlated to rendering workload size." << TestLog::EndMessage;
398         else
399             m_testCtx.getLog() << TestLog::Message
400                                << "Warning: Wait time correlation to rendering workload size is unclear."
401                                << TestLog::EndMessage;
402 
403         if (readCorrelated || readNotCorr)
404             m_testCtx.getLog() << TestLog::Message << "Read time is" << (readCorrelated ? "" : " NOT")
405                                << " correlated to rendering workload size." << TestLog::EndMessage;
406         else
407             m_testCtx.getLog() << TestLog::Message
408                                << "Warning: Read time correlation to rendering workload size is unclear."
409                                << TestLog::EndMessage;
410     }
411 
412     for (int ndx = 0; ndx < 2; ndx++)
413     {
414         const float coef                = ndx == 0 ? normWaitCoef : normReadCoef;
415         const char *name                = ndx == 0 ? "wait" : "read";
416         const ExpectedBehavior behavior = ndx == 0 ? m_waitBehavior : m_readBehavior;
417         const float threshold           = ndx == 0 ? m_waitThreshold : m_readThreshold;
418         const bool isOk                 = behavior == EXPECT_COEF_GREATER_THAN ? coef > threshold :
419                                           behavior == EXPECT_COEF_LESS_THAN    ? coef < threshold :
420                                                                                  false;
421         const char *cmpName             = behavior == EXPECT_COEF_GREATER_THAN ? "greater than" :
422                                           behavior == EXPECT_COEF_LESS_THAN    ? "less than" :
423                                                                                  DE_NULL;
424 
425         if (!isOk)
426         {
427             m_testCtx.getLog() << TestLog::Message << "ERROR: Expected " << name << " coefficient to be " << cmpName
428                                << " " << threshold << TestLog::EndMessage;
429             allOk = false;
430         }
431     }
432 
433     m_testCtx.setTestResult(allOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_COMPATIBILITY_WARNING,
434                             allOk ? "Pass" : "Suspicious performance behavior");
435 }
436 
iterate(void)437 FlushFinishCase::IterateResult FlushFinishCase::iterate(void)
438 {
439     vector<Sample> samples(NUM_SAMPLES);
440     CalibrationParams params;
441 
442     tcu::warmupCPU();
443 
444     setupRenderState();
445 
446     // Do one full render cycle.
447     {
448         render(1);
449         readPixels();
450     }
451 
452     // Calibrate.
453     try
454     {
455         params = calibrate();
456     }
457     catch (const CalibrationFailedException &e)
458     {
459         m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, e.what());
460         return STOP;
461     }
462 
463     // Do measurement.
464     {
465         de::Random rnd(123);
466 
467         for (size_t ndx = 0; ndx < samples.size(); ndx++)
468         {
469             const int drawCallCount = rnd.getInt(1, params.maxDrawCalls);
470             uint64_t waitStartTime;
471             uint64_t readStartTime;
472             uint64_t readFinishTime;
473 
474             render(drawCallCount);
475 
476             waitStartTime = deGetMicroseconds();
477             waitForGL();
478 
479             readStartTime = deGetMicroseconds();
480             readPixels();
481             readFinishTime = deGetMicroseconds();
482 
483             samples[ndx].numDrawCalls   = drawCallCount;
484             samples[ndx].waitTime       = readStartTime - waitStartTime;
485             samples[ndx].readPixelsTime = readFinishTime - readStartTime;
486 
487             if (m_testCtx.getWatchDog())
488                 qpWatchDog_touch(m_testCtx.getWatchDog());
489         }
490     }
491 
492     // Analyze - sets test case result.
493     analyzeResults(samples, params);
494 
495     return STOP;
496 }
497 
498 class WaitOnlyCase : public FlushFinishCase
499 {
500 public:
WaitOnlyCase(Context & context)501     WaitOnlyCase(Context &context)
502         : FlushFinishCase(context, "wait", "Wait only", EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD,
503                           EXPECT_COEF_GREATER_THAN, -1000.0f /* practically nothing is expected */)
504     {
505     }
506 
init(void)507     void init(void)
508     {
509         m_testCtx.getLog() << TestLog::Message << int(WAIT_TIME_MS) << " ms busy wait" << TestLog::EndMessage;
510         FlushFinishCase::init();
511     }
512 
513 protected:
waitForGL(void)514     void waitForGL(void)
515     {
516         busyWait(WAIT_TIME_MS);
517     }
518 };
519 
520 class FlushOnlyCase : public FlushFinishCase
521 {
522 public:
FlushOnlyCase(Context & context)523     FlushOnlyCase(Context &context)
524         : FlushFinishCase(context, "flush", "Flush only", EXPECT_COEF_LESS_THAN, FLUSH_COEF_THRESHOLD,
525                           EXPECT_COEF_GREATER_THAN, CORRELATED_COEF_THRESHOLD)
526     {
527     }
528 
init(void)529     void init(void)
530     {
531         m_testCtx.getLog() << TestLog::Message << "Single call to glFlush()" << TestLog::EndMessage;
532         FlushFinishCase::init();
533     }
534 
535 protected:
waitForGL(void)536     void waitForGL(void)
537     {
538         m_context.getRenderContext().getFunctions().flush();
539     }
540 };
541 
542 class FlushWaitCase : public FlushFinishCase
543 {
544 public:
FlushWaitCase(Context & context)545     FlushWaitCase(Context &context)
546         : FlushFinishCase(context, "flush_wait", "Wait after flushing", EXPECT_COEF_LESS_THAN, FLUSH_COEF_THRESHOLD,
547                           EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD)
548     {
549     }
550 
init(void)551     void init(void)
552     {
553         m_testCtx.getLog() << TestLog::Message << "glFlush() followed by " << int(WAIT_TIME_MS) << " ms busy wait"
554                            << TestLog::EndMessage;
555         FlushFinishCase::init();
556     }
557 
558 protected:
waitForGL(void)559     void waitForGL(void)
560     {
561         m_context.getRenderContext().getFunctions().flush();
562         busyWait(WAIT_TIME_MS);
563     }
564 };
565 
566 class FinishOnlyCase : public FlushFinishCase
567 {
568 public:
FinishOnlyCase(Context & context)569     FinishOnlyCase(Context &context)
570         : FlushFinishCase(context, "finish", "Finish only", EXPECT_COEF_GREATER_THAN, CORRELATED_COEF_THRESHOLD,
571                           EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD)
572     {
573     }
574 
init(void)575     void init(void)
576     {
577         m_testCtx.getLog() << TestLog::Message << "Single call to glFinish()" << TestLog::EndMessage;
578         FlushFinishCase::init();
579     }
580 
581 protected:
waitForGL(void)582     void waitForGL(void)
583     {
584         m_context.getRenderContext().getFunctions().finish();
585     }
586 };
587 
588 class FinishWaitCase : public FlushFinishCase
589 {
590 public:
FinishWaitCase(Context & context)591     FinishWaitCase(Context &context)
592         : FlushFinishCase(context, "finish_wait", "Finish and wait", EXPECT_COEF_GREATER_THAN,
593                           CORRELATED_COEF_THRESHOLD, EXPECT_COEF_LESS_THAN, NO_CORR_COEF_THRESHOLD)
594     {
595     }
596 
init(void)597     void init(void)
598     {
599         m_testCtx.getLog() << TestLog::Message << "glFinish() followed by " << int(WAIT_TIME_MS) << " ms busy wait"
600                            << TestLog::EndMessage;
601         FlushFinishCase::init();
602     }
603 
604 protected:
waitForGL(void)605     void waitForGL(void)
606     {
607         m_context.getRenderContext().getFunctions().finish();
608         busyWait(WAIT_TIME_MS);
609     }
610 };
611 
612 } // namespace
613 
FlushFinishTests(Context & context)614 FlushFinishTests::FlushFinishTests(Context &context) : TestCaseGroup(context, "flush_finish", "Flush and Finish tests")
615 {
616 }
617 
~FlushFinishTests(void)618 FlushFinishTests::~FlushFinishTests(void)
619 {
620 }
621 
init(void)622 void FlushFinishTests::init(void)
623 {
624     addChild(new WaitOnlyCase(m_context));
625     addChild(new FlushOnlyCase(m_context));
626     addChild(new FlushWaitCase(m_context));
627     addChild(new FinishOnlyCase(m_context));
628     addChild(new FinishWaitCase(m_context));
629 }
630 
631 } // namespace Functional
632 } // namespace gles2
633 } // namespace deqp
634