1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 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 gl_HelperInvocation tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fShaderHelperInvocationTests.hpp" 25 26 #include "gluObjectWrapper.hpp" 27 #include "gluShaderProgram.hpp" 28 #include "gluDrawUtil.hpp" 29 #include "gluPixelTransfer.hpp" 30 31 #include "glwFunctions.hpp" 32 #include "glwEnums.hpp" 33 34 #include "tcuTestLog.hpp" 35 #include "tcuVector.hpp" 36 #include "tcuSurface.hpp" 37 38 #include "deUniquePtr.hpp" 39 #include "deStringUtil.hpp" 40 #include "deRandom.hpp" 41 #include "deString.h" 42 43 namespace deqp 44 { 45 namespace gles31 46 { 47 namespace Functional 48 { 49 namespace 50 { 51 52 using glu::ShaderProgram; 53 using tcu::TestLog; 54 using tcu::Vec2; 55 using tcu::IVec2; 56 using de::MovePtr; 57 using std::string; 58 using std::vector; 59 60 enum PrimitiveType 61 { 62 PRIMITIVETYPE_TRIANGLE = 0, 63 PRIMITIVETYPE_LINE, 64 PRIMITIVETYPE_WIDE_LINE, 65 PRIMITIVETYPE_POINT, 66 PRIMITIVETYPE_WIDE_POINT, 67 68 PRIMITIVETYPE_LAST 69 }; 70 71 static int getNumVerticesPerPrimitive (PrimitiveType primType) 72 { 73 switch (primType) 74 { 75 case PRIMITIVETYPE_TRIANGLE: return 3; 76 case PRIMITIVETYPE_LINE: return 2; 77 case PRIMITIVETYPE_WIDE_LINE: return 2; 78 case PRIMITIVETYPE_POINT: return 1; 79 case PRIMITIVETYPE_WIDE_POINT: return 1; 80 default: 81 DE_ASSERT(false); 82 return 0; 83 } 84 } 85 86 static glu::PrimitiveType getGluPrimitiveType (PrimitiveType primType) 87 { 88 switch (primType) 89 { 90 case PRIMITIVETYPE_TRIANGLE: return glu::PRIMITIVETYPE_TRIANGLES; 91 case PRIMITIVETYPE_LINE: return glu::PRIMITIVETYPE_LINES; 92 case PRIMITIVETYPE_WIDE_LINE: return glu::PRIMITIVETYPE_LINES; 93 case PRIMITIVETYPE_POINT: return glu::PRIMITIVETYPE_POINTS; 94 case PRIMITIVETYPE_WIDE_POINT: return glu::PRIMITIVETYPE_POINTS; 95 default: 96 DE_ASSERT(false); 97 return glu::PRIMITIVETYPE_LAST; 98 } 99 } 100 101 static void genVertices (PrimitiveType primType, int numPrimitives, de::Random* rnd, vector<Vec2>* dst) 102 { 103 const bool isTri = primType == PRIMITIVETYPE_TRIANGLE; 104 const float minCoord = isTri ? -1.5f : -1.0f; 105 const float maxCoord = isTri ? +1.5f : +1.0f; 106 const int numVert = getNumVerticesPerPrimitive(primType)*numPrimitives; 107 108 dst->resize(numVert); 109 110 for (size_t ndx = 0; ndx < dst->size(); ndx++) 111 { 112 (*dst)[ndx][0] = rnd->getFloat(minCoord, maxCoord); 113 (*dst)[ndx][1] = rnd->getFloat(minCoord, maxCoord); 114 } 115 } 116 117 static int getInteger (const glw::Functions& gl, deUint32 pname) 118 { 119 int v = 0; 120 gl.getIntegerv(pname, &v); 121 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetIntegerv()"); 122 return v; 123 } 124 125 static Vec2 getRange (const glw::Functions& gl, deUint32 pname) 126 { 127 Vec2 v(0.0f); 128 gl.getFloatv(pname, v.getPtr()); 129 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetFloatv()"); 130 return v; 131 } 132 133 static void drawRandomPrimitives (const glu::RenderContext& renderCtx, deUint32 program, PrimitiveType primType, int numPrimitives, de::Random* rnd) 134 { 135 const glw::Functions& gl = renderCtx.getFunctions(); 136 const float minPointSize = 16.0f; 137 const float maxPointSize = 32.0f; 138 const float minLineWidth = 16.0f; 139 const float maxLineWidth = 32.0f; 140 vector<Vec2> vertices; 141 vector<glu::VertexArrayBinding> vertexArrays; 142 143 genVertices(primType, numPrimitives, rnd, &vertices); 144 145 vertexArrays.push_back(glu::va::Float("a_position", 2, (int)vertices.size(), 0, (const float*)&vertices[0])); 146 147 gl.useProgram(program); 148 149 // Special state for certain primitives 150 if (primType == PRIMITIVETYPE_POINT || primType == PRIMITIVETYPE_WIDE_POINT) 151 { 152 const Vec2 range = getRange(gl, GL_ALIASED_POINT_SIZE_RANGE); 153 const bool isWidePoint = primType == PRIMITIVETYPE_WIDE_POINT; 154 const float pointSize = isWidePoint ? de::min(rnd->getFloat(minPointSize, maxPointSize), range.y()) : 1.0f; 155 const int pointSizeLoc = gl.getUniformLocation(program, "u_pointSize"); 156 157 gl.uniform1f(pointSizeLoc, pointSize); 158 } 159 else if (primType == PRIMITIVETYPE_WIDE_LINE) 160 { 161 const Vec2 range = getRange(gl, GL_ALIASED_LINE_WIDTH_RANGE); 162 const float lineWidth = de::min(rnd->getFloat(minLineWidth, maxLineWidth), range.y()); 163 164 gl.lineWidth(lineWidth); 165 } 166 167 glu::draw(renderCtx, program, (int)vertexArrays.size(), &vertexArrays[0], 168 glu::PrimitiveList(getGluPrimitiveType(primType), (int)vertices.size())); 169 } 170 171 class FboHelper 172 { 173 public: 174 FboHelper (const glu::RenderContext& renderCtx, int width, int height, deUint32 format, int numSamples); 175 ~FboHelper (void); 176 177 void bindForRendering (void); 178 void readPixels (int x, int y, const tcu::PixelBufferAccess& dst); 179 180 private: 181 const glu::RenderContext& m_renderCtx; 182 const int m_numSamples; 183 184 glu::Renderbuffer m_colorbuffer; 185 glu::Framebuffer m_framebuffer; 186 glu::Renderbuffer m_resolveColorbuffer; 187 glu::Framebuffer m_resolveFramebuffer; 188 }; 189 190 FboHelper::FboHelper (const glu::RenderContext& renderCtx, int width, int height, deUint32 format, int numSamples) 191 : m_renderCtx (renderCtx) 192 , m_numSamples (numSamples) 193 , m_colorbuffer (renderCtx) 194 , m_framebuffer (renderCtx) 195 , m_resolveColorbuffer (renderCtx) 196 , m_resolveFramebuffer (renderCtx) 197 { 198 const glw::Functions& gl = m_renderCtx.getFunctions(); 199 const int maxSamples = getInteger(gl, GL_MAX_SAMPLES); 200 201 gl.bindRenderbuffer(GL_RENDERBUFFER, *m_colorbuffer); 202 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples, format, width, height); 203 gl.bindFramebuffer(GL_FRAMEBUFFER, *m_framebuffer); 204 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *m_colorbuffer); 205 206 if (m_numSamples > maxSamples && gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 207 throw tcu::NotSupportedError("Sample count exceeds GL_MAX_SAMPLES"); 208 209 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 210 211 if (m_numSamples != 0) 212 { 213 gl.bindRenderbuffer(GL_RENDERBUFFER, *m_resolveColorbuffer); 214 gl.renderbufferStorage(GL_RENDERBUFFER, format, width, height); 215 gl.bindFramebuffer(GL_FRAMEBUFFER, *m_resolveFramebuffer); 216 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *m_resolveColorbuffer); 217 TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); 218 } 219 220 GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create framebuffer"); 221 } 222 223 FboHelper::~FboHelper (void) 224 { 225 } 226 227 void FboHelper::bindForRendering (void) 228 { 229 const glw::Functions& gl = m_renderCtx.getFunctions(); 230 gl.bindFramebuffer(GL_FRAMEBUFFER, *m_framebuffer); 231 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindFramebuffer()"); 232 } 233 234 void FboHelper::readPixels (int x, int y, const tcu::PixelBufferAccess& dst) 235 { 236 const glw::Functions& gl = m_renderCtx.getFunctions(); 237 const int width = dst.getWidth(); 238 const int height = dst.getHeight(); 239 240 if (m_numSamples != 0) 241 { 242 gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, *m_resolveFramebuffer); 243 gl.blitFramebuffer(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); 244 gl.bindFramebuffer(GL_READ_FRAMEBUFFER, *m_resolveFramebuffer); 245 } 246 247 glu::readPixels(m_renderCtx, x, y, dst); 248 } 249 250 enum 251 { 252 FRAMEBUFFER_WIDTH = 256, 253 FRAMEBUFFER_HEIGHT = 256, 254 FRAMEBUFFER_FORMAT = GL_RGBA8, 255 NUM_SAMPLES_MAX = -1 256 }; 257 258 //! Verifies that gl_HelperInvocation is false in all rendered pixels. 259 class HelperInvocationValueCase : public TestCase 260 { 261 public: 262 HelperInvocationValueCase (Context& context, const char* name, const char* description, PrimitiveType primType, int numSamples); 263 ~HelperInvocationValueCase (void); 264 265 void init (void); 266 void deinit (void); 267 IterateResult iterate (void); 268 269 private: 270 const PrimitiveType m_primitiveType; 271 const int m_numSamples; 272 273 const int m_numIters; 274 const int m_numPrimitivesPerIter; 275 276 MovePtr<ShaderProgram> m_program; 277 MovePtr<FboHelper> m_fbo; 278 int m_iterNdx; 279 }; 280 281 HelperInvocationValueCase::HelperInvocationValueCase (Context& context, const char* name, const char* description, PrimitiveType primType, int numSamples) 282 : TestCase (context, name, description) 283 , m_primitiveType (primType) 284 , m_numSamples (numSamples) 285 , m_numIters (5) 286 , m_numPrimitivesPerIter (10) 287 , m_iterNdx (0) 288 { 289 } 290 291 HelperInvocationValueCase::~HelperInvocationValueCase (void) 292 { 293 deinit(); 294 } 295 296 void HelperInvocationValueCase::init (void) 297 { 298 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 299 const glw::Functions& gl = renderCtx.getFunctions(); 300 const int maxSamples = getInteger(gl, GL_MAX_SAMPLES); 301 const int actualSamples = m_numSamples == NUM_SAMPLES_MAX ? maxSamples : m_numSamples; 302 303 m_program = MovePtr<ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), 304 glu::ProgramSources() 305 << glu::VertexSource( 306 "#version 310 es\n" 307 "in highp vec2 a_position;\n" 308 "uniform highp float u_pointSize;\n" 309 "void main (void)\n" 310 "{\n" 311 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 312 " gl_PointSize = u_pointSize;\n" 313 "}\n") 314 << glu::FragmentSource( 315 "#version 310 es\n" 316 "out mediump vec4 o_color;\n" 317 "void main (void)\n" 318 "{\n" 319 " if (gl_HelperInvocation)\n" 320 " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n" 321 " else\n" 322 " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n" 323 "}\n"))); 324 325 m_testCtx.getLog() << *m_program; 326 327 if (!m_program->isOk()) 328 { 329 m_program.clear(); 330 TCU_FAIL("Compile failed"); 331 } 332 333 m_testCtx.getLog() << TestLog::Message << "Using GL_RGBA8 framebuffer with " 334 << actualSamples << " samples" << TestLog::EndMessage; 335 336 m_fbo = MovePtr<FboHelper>(new FboHelper(renderCtx, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, 337 FRAMEBUFFER_FORMAT, actualSamples)); 338 339 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 340 } 341 342 void HelperInvocationValueCase::deinit (void) 343 { 344 m_program.clear(); 345 m_fbo.clear(); 346 } 347 348 static bool verifyHelperInvocationValue (TestLog& log, const tcu::Surface& result, bool isMultiSample) 349 { 350 const tcu::RGBA bgRef (0, 0, 0, 255); 351 const tcu::RGBA fgRef (0, 255, 0, 255); 352 const tcu::RGBA threshold (1, isMultiSample ? 254 : 1, 1, 1); 353 int numInvalidPixels = 0; 354 355 for (int y = 0; y < result.getHeight(); ++y) 356 { 357 for (int x = 0; x < result.getWidth(); ++x) 358 { 359 const tcu::RGBA resPix = result.getPixel(x, y); 360 361 if (!tcu::compareThreshold(resPix, bgRef, threshold) && 362 !tcu::compareThreshold(resPix, fgRef, threshold)) 363 numInvalidPixels += 1; 364 } 365 } 366 367 if (numInvalidPixels > 0) 368 { 369 log << TestLog::Image("Result", "Result image", result); 370 log << TestLog::Message << "ERROR: Found " << numInvalidPixels << " invalid result pixels!" << TestLog::EndMessage; 371 } 372 else 373 log << TestLog::Message << "All result pixels are valid" << TestLog::EndMessage; 374 375 return numInvalidPixels == 0; 376 } 377 378 HelperInvocationValueCase::IterateResult HelperInvocationValueCase::iterate (void) 379 { 380 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 381 const glw::Functions& gl = renderCtx.getFunctions(); 382 const string sectionName = string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(m_numIters); 383 const tcu::ScopedLogSection section (m_testCtx.getLog(), (string("Iter") + de::toString(m_iterNdx)), sectionName); 384 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(m_iterNdx)); 385 tcu::Surface result (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT); 386 387 m_fbo->bindForRendering(); 388 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 389 gl.clear(GL_COLOR_BUFFER_BIT); 390 391 drawRandomPrimitives(renderCtx, m_program->getProgram(), m_primitiveType, m_numPrimitivesPerIter, &rnd); 392 393 m_fbo->readPixels(0, 0, result.getAccess()); 394 395 if (!verifyHelperInvocationValue(m_testCtx.getLog(), result, m_numSamples != 0)) 396 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid pixels found"); 397 398 m_iterNdx += 1; 399 return (m_iterNdx < m_numIters) ? CONTINUE : STOP; 400 } 401 402 //! Checks derivates when value depends on gl_HelperInvocation. 403 class HelperInvocationDerivateCase : public TestCase 404 { 405 public: 406 HelperInvocationDerivateCase (Context& context, const char* name, const char* description, PrimitiveType primType, int numSamples, const char* derivateFunc); 407 ~HelperInvocationDerivateCase (void); 408 409 void init (void); 410 void deinit (void); 411 IterateResult iterate (void); 412 413 private: 414 const PrimitiveType m_primitiveType; 415 const int m_numSamples; 416 const std::string m_derivateFunc; 417 418 const int m_numIters; 419 420 MovePtr<ShaderProgram> m_program; 421 MovePtr<FboHelper> m_fbo; 422 int m_iterNdx; 423 }; 424 425 HelperInvocationDerivateCase::HelperInvocationDerivateCase (Context& context, const char* name, const char* description, PrimitiveType primType, int numSamples, const char* derivateFunc) 426 : TestCase (context, name, description) 427 , m_primitiveType (primType) 428 , m_numSamples (numSamples) 429 , m_derivateFunc (derivateFunc) 430 , m_numIters (16) 431 , m_iterNdx (0) 432 { 433 } 434 435 HelperInvocationDerivateCase::~HelperInvocationDerivateCase (void) 436 { 437 deinit(); 438 } 439 440 void HelperInvocationDerivateCase::init (void) 441 { 442 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 443 const glw::Functions& gl = renderCtx.getFunctions(); 444 const int maxSamples = getInteger(gl, GL_MAX_SAMPLES); 445 const int actualSamples = m_numSamples == NUM_SAMPLES_MAX ? maxSamples : m_numSamples; 446 447 m_program = MovePtr<ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), 448 glu::ProgramSources() 449 << glu::VertexSource( 450 "#version 310 es\n" 451 "in highp vec2 a_position;\n" 452 "uniform highp float u_pointSize;\n" 453 "void main (void)\n" 454 "{\n" 455 " gl_Position = vec4(a_position, 0.0, 1.0);\n" 456 " gl_PointSize = u_pointSize;\n" 457 "}\n") 458 << glu::FragmentSource(string( 459 "#version 310 es\n" 460 "out mediump vec4 o_color;\n" 461 "void main (void)\n" 462 "{\n" 463 " highp float value = gl_HelperInvocation ? 1.0 : 0.0;\n" 464 " highp float derivate = ") + m_derivateFunc + "(value);\n" 465 " if (gl_HelperInvocation)\n" 466 " o_color = vec4(1.0, 0.0, derivate, 1.0);\n" 467 " else\n" 468 " o_color = vec4(0.0, 1.0, derivate, 1.0);\n" 469 "}\n"))); 470 471 m_testCtx.getLog() << *m_program; 472 473 if (!m_program->isOk()) 474 { 475 m_program.clear(); 476 TCU_FAIL("Compile failed"); 477 } 478 479 m_testCtx.getLog() << TestLog::Message << "Using GL_RGBA8 framebuffer with " 480 << actualSamples << " samples" << TestLog::EndMessage; 481 482 m_fbo = MovePtr<FboHelper>(new FboHelper(renderCtx, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, 483 FRAMEBUFFER_FORMAT, actualSamples)); 484 485 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 486 } 487 488 void HelperInvocationDerivateCase::deinit (void) 489 { 490 m_program.clear(); 491 m_fbo.clear(); 492 } 493 494 static bool hasNeighborWithColor (const tcu::Surface& surface, int x, int y, tcu::RGBA color, tcu::RGBA threshold) 495 { 496 static const IVec2 s_neighbors[] = 497 { 498 IVec2(-1, -1), 499 IVec2( 0, -1), 500 IVec2(+1, -1), 501 IVec2(-1, 0), 502 IVec2(+1, 0), 503 IVec2(-1, +1), 504 IVec2( 0, +1), 505 IVec2(+1, +1) 506 }; 507 508 const int w = surface.getWidth(); 509 const int h = surface.getHeight(); 510 511 for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(s_neighbors); sample++) 512 { 513 const IVec2 pos = IVec2(x, y) + s_neighbors[sample]; 514 515 if (de::inBounds(pos.x(), 0, w) && de::inBounds(pos.y(), 0, h)) 516 { 517 const tcu::RGBA neighborColor = surface.getPixel(pos.x(), pos.y()); 518 519 if (tcu::compareThreshold(color, neighborColor, threshold)) 520 return true; 521 } 522 else 523 return true; // Can't know for certain 524 } 525 526 return false; 527 } 528 529 static bool verifyHelperInvocationDerivate (TestLog& log, const tcu::Surface& result, bool isMultiSample) 530 { 531 const tcu::RGBA bgRef (0, 0, 0, 255); 532 const tcu::RGBA fgRef (0, 255, 0, 255); 533 const tcu::RGBA isBgThreshold (1, isMultiSample ? 254 : 1, 0, 1); 534 const tcu::RGBA isFgThreshold (1, isMultiSample ? 254 : 1, 255, 1); 535 int numInvalidPixels = 0; 536 int numNonZeroDeriv = 0; 537 538 for (int y = 0; y < result.getHeight(); ++y) 539 { 540 for (int x = 0; x < result.getWidth(); ++x) 541 { 542 const tcu::RGBA resPix = result.getPixel(x, y); 543 const bool isBg = tcu::compareThreshold(resPix, bgRef, isBgThreshold); 544 const bool isFg = tcu::compareThreshold(resPix, fgRef, isFgThreshold); 545 const bool nonZeroDeriv = resPix.getBlue() > 0; 546 const bool neighborBg = nonZeroDeriv ? hasNeighborWithColor(result, x, y, bgRef, isBgThreshold) : false; 547 548 if (nonZeroDeriv) 549 numNonZeroDeriv += 1; 550 551 if ((!isBg && !isFg) || // Neither of valid colors (ignoring blue channel that has derivate) 552 (nonZeroDeriv && !neighborBg)) // Has non-zero derivate, but sample not at primitive edge 553 numInvalidPixels += 1; 554 } 555 } 556 557 if (numInvalidPixels > 0) 558 { 559 log << TestLog::Image("Result", "Result image", result); 560 log << TestLog::Message << "ERROR: Found " << numInvalidPixels << " invalid result pixels!" << TestLog::EndMessage; 561 } 562 else 563 log << TestLog::Message << "All result pixels are valid" << TestLog::EndMessage; 564 565 log << TestLog::Message << "Found " << numNonZeroDeriv << " pixels with non-zero derivate (neighbor sample has gl_HelperInvocation = true)" << TestLog::EndMessage; 566 567 return numInvalidPixels == 0; 568 } 569 570 HelperInvocationDerivateCase::IterateResult HelperInvocationDerivateCase::iterate (void) 571 { 572 const glu::RenderContext& renderCtx = m_context.getRenderContext(); 573 const glw::Functions& gl = renderCtx.getFunctions(); 574 const string sectionName = string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(m_numIters); 575 const tcu::ScopedLogSection section (m_testCtx.getLog(), (string("Iter") + de::toString(m_iterNdx)), sectionName); 576 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(m_iterNdx)); 577 tcu::Surface result (FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT); 578 579 m_fbo->bindForRendering(); 580 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 581 gl.clear(GL_COLOR_BUFFER_BIT); 582 583 drawRandomPrimitives(renderCtx, m_program->getProgram(), m_primitiveType, 1, &rnd); 584 585 m_fbo->readPixels(0, 0, result.getAccess()); 586 587 if (!verifyHelperInvocationDerivate(m_testCtx.getLog(), result, m_numSamples != 0)) 588 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid pixels found"); 589 590 m_iterNdx += 1; 591 return (m_iterNdx < m_numIters) ? CONTINUE : STOP; 592 } 593 594 } // anonymous 595 596 ShaderHelperInvocationTests::ShaderHelperInvocationTests (Context& context) 597 : TestCaseGroup(context, "helper_invocation", "gl_HelperInvocation tests") 598 { 599 } 600 601 ShaderHelperInvocationTests::~ShaderHelperInvocationTests (void) 602 { 603 } 604 605 void ShaderHelperInvocationTests::init (void) 606 { 607 static const struct 608 { 609 const char* caseName; 610 PrimitiveType primType; 611 } s_primTypes[] = 612 { 613 { "triangles", PRIMITIVETYPE_TRIANGLE }, 614 { "lines", PRIMITIVETYPE_LINE }, 615 { "wide_lines", PRIMITIVETYPE_WIDE_LINE }, 616 { "points", PRIMITIVETYPE_POINT }, 617 { "wide_points", PRIMITIVETYPE_WIDE_POINT } 618 }; 619 620 static const struct 621 { 622 const char* suffix; 623 int numSamples; 624 } s_sampleCounts[] = 625 { 626 { "", 0 }, 627 { "_4_samples", 4 }, 628 { "_8_samples", 8 }, 629 { "_max_samples", NUM_SAMPLES_MAX } 630 }; 631 632 // value 633 { 634 tcu::TestCaseGroup* const valueGroup = new tcu::TestCaseGroup(m_testCtx, "value", "gl_HelperInvocation value in rendered pixels"); 635 addChild(valueGroup); 636 637 for (int sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(s_sampleCounts); sampleCountNdx++) 638 { 639 for (int primTypeNdx = 0; primTypeNdx < DE_LENGTH_OF_ARRAY(s_primTypes); primTypeNdx++) 640 { 641 const string name = string(s_primTypes[primTypeNdx].caseName) + s_sampleCounts[sampleCountNdx].suffix; 642 const PrimitiveType primType = s_primTypes[primTypeNdx].primType; 643 const int numSamples = s_sampleCounts[sampleCountNdx].numSamples; 644 645 valueGroup->addChild(new HelperInvocationValueCase(m_context, name.c_str(), "", primType, numSamples)); 646 } 647 } 648 } 649 650 // derivate 651 { 652 tcu::TestCaseGroup* const derivateGroup = new tcu::TestCaseGroup(m_testCtx, "derivate", "Derivate of gl_HelperInvocation-dependent value"); 653 addChild(derivateGroup); 654 655 for (int sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(s_sampleCounts); sampleCountNdx++) 656 { 657 for (int primTypeNdx = 0; primTypeNdx < DE_LENGTH_OF_ARRAY(s_primTypes); primTypeNdx++) 658 { 659 const string name = string(s_primTypes[primTypeNdx].caseName) + s_sampleCounts[sampleCountNdx].suffix; 660 const PrimitiveType primType = s_primTypes[primTypeNdx].primType; 661 const int numSamples = s_sampleCounts[sampleCountNdx].numSamples; 662 663 derivateGroup->addChild(new HelperInvocationDerivateCase(m_context, (name + "_dfdx").c_str(), "", primType, numSamples, "dFdx")); 664 derivateGroup->addChild(new HelperInvocationDerivateCase(m_context, (name + "_dfdy").c_str(), "", primType, numSamples, "dFdy")); 665 derivateGroup->addChild(new HelperInvocationDerivateCase(m_context, (name + "_fwidth").c_str(), "", primType, numSamples, "fwidth")); 666 } 667 } 668 } 669 } 670 671 } // Functional 672 } // gles31 673 } // deqp 674