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