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