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