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