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 Multisample tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es31fMultisampleTests.hpp" 25 #include "tcuRenderTarget.hpp" 26 #include "tcuVector.hpp" 27 #include "tcuSurface.hpp" 28 #include "tcuImageCompare.hpp" 29 #include "tcuStringTemplate.hpp" 30 #include "gluPixelTransfer.hpp" 31 #include "gluRenderContext.hpp" 32 #include "gluCallLogWrapper.hpp" 33 #include "gluObjectWrapper.hpp" 34 #include "gluShaderProgram.hpp" 35 #include "glwFunctions.hpp" 36 #include "glwEnums.hpp" 37 #include "deRandom.hpp" 38 #include "deStringUtil.hpp" 39 #include "deString.h" 40 #include "deMath.h" 41 42 using namespace glw; 43 44 using tcu::TestLog; 45 using tcu::Vec2; 46 using tcu::Vec3; 47 using tcu::Vec4; 48 49 namespace deqp 50 { 51 namespace gles31 52 { 53 namespace Functional 54 { 55 namespace 56 { 57 58 using std::map; 59 using std::string; 60 61 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits) 62 { 63 std::string result(numBits, '0'); 64 65 // move from back to front and set chars to 1 66 for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx) 67 { 68 for (int bit = 0; bit < 32; ++bit) 69 { 70 const int targetCharNdx = numBits - (wordNdx*32+bit) - 1; 71 72 // beginning of the string reached 73 if (targetCharNdx < 0) 74 return result; 75 76 if ((bitfield[wordNdx] >> bit) & 0x01) 77 result[targetCharNdx] = '1'; 78 } 79 } 80 81 return result; 82 } 83 84 /*--------------------------------------------------------------------*//*! 85 * \brief Returns the number of words needed to represent mask of given length 86 *//*--------------------------------------------------------------------*/ 87 static int getEffectiveSampleMaskWordCount (int highestBitNdx) 88 { 89 const int wordSize = 32; 90 const int maskLen = highestBitNdx + 1; 91 92 return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len / wordSize) 93 } 94 95 /*--------------------------------------------------------------------*//*! 96 * \brief Creates sample mask with all less significant bits than nthBit set 97 *//*--------------------------------------------------------------------*/ 98 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit) 99 { 100 const int wordSize = 32; 101 const int numWords = getEffectiveSampleMaskWordCount(nthBit - 1); 102 const deUint32 topWordBits = (deUint32)(nthBit - (numWords - 1) * wordSize); 103 std::vector<deUint32> mask (numWords); 104 105 for (int ndx = 0; ndx < numWords - 1; ++ndx) 106 mask[ndx] = 0xFFFFFFFF; 107 108 mask[numWords - 1] = deBitMask32(0, (int)topWordBits); 109 return mask; 110 } 111 112 class SamplePosQueryCase : public TestCase 113 { 114 public: 115 SamplePosQueryCase (Context& context, const char* name, const char* desc); 116 private: 117 void init (void); 118 IterateResult iterate (void); 119 }; 120 121 SamplePosQueryCase::SamplePosQueryCase (Context& context, const char* name, const char* desc) 122 : TestCase(context, name, desc) 123 { 124 } 125 126 void SamplePosQueryCase::init (void) 127 { 128 if (m_context.getRenderTarget().getNumSamples() == 0) 129 throw tcu::NotSupportedError("No multisample buffers"); 130 } 131 132 SamplePosQueryCase::IterateResult SamplePosQueryCase::iterate (void) 133 { 134 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog()); 135 bool error = false; 136 137 gl.enableLogging(true); 138 139 for (int ndx = 0; ndx < m_context.getRenderTarget().getNumSamples(); ++ndx) 140 { 141 tcu::Vec2 samplePos = tcu::Vec2(-1, -1); 142 143 gl.glGetMultisamplefv(GL_SAMPLE_POSITION, ndx, samplePos.getPtr()); 144 GLU_EXPECT_NO_ERROR(gl.glGetError(), "getMultisamplefv"); 145 146 // check value range 147 if (samplePos.x() < 0.0f || samplePos.x() > 1.0f || 148 samplePos.y() < 0.0f || samplePos.y() > 1.0f) 149 { 150 m_testCtx.getLog() << tcu::TestLog::Message << "Sample " << ndx << " is not in valid range [0,1], got " << samplePos << tcu::TestLog::EndMessage; 151 error = true; 152 } 153 } 154 155 if (!error) 156 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 157 else 158 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid sample pos"); 159 160 return STOP; 161 } 162 163 /*--------------------------------------------------------------------*//*! 164 * \brief Abstract base class handling common stuff for default fbo multisample cases. 165 *//*--------------------------------------------------------------------*/ 166 class DefaultFBOMultisampleCase : public TestCase 167 { 168 public: 169 DefaultFBOMultisampleCase (Context& context, const char* name, const char* desc, int desiredViewportSize); 170 virtual ~DefaultFBOMultisampleCase (void); 171 172 virtual void init (void); 173 virtual void deinit (void); 174 175 protected: 176 void renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const; 177 void renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& color) const; 178 void renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const; 179 void renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const; 180 void renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& c0, const Vec4& c1, const Vec4& c2, const Vec4& c3) const; 181 void renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const; 182 183 void randomizeViewport (void); 184 void readImage (tcu::Surface& dst) const; 185 186 int m_numSamples; 187 188 int m_viewportSize; 189 190 private: 191 DefaultFBOMultisampleCase (const DefaultFBOMultisampleCase& other); 192 DefaultFBOMultisampleCase& operator= (const DefaultFBOMultisampleCase& other); 193 194 const int m_desiredViewportSize; 195 196 glu::ShaderProgram* m_program; 197 int m_attrPositionLoc; 198 int m_attrColorLoc; 199 200 int m_viewportX; 201 int m_viewportY; 202 de::Random m_rnd; 203 204 bool m_initCalled; 205 }; 206 207 DefaultFBOMultisampleCase::DefaultFBOMultisampleCase (Context& context, const char* name, const char* desc, int desiredViewportSize) 208 : TestCase (context, name, desc) 209 , m_numSamples (0) 210 , m_viewportSize (0) 211 , m_desiredViewportSize (desiredViewportSize) 212 , m_program (DE_NULL) 213 , m_attrPositionLoc (-1) 214 , m_attrColorLoc (-1) 215 , m_viewportX (0) 216 , m_viewportY (0) 217 , m_rnd (deStringHash(name)) 218 , m_initCalled (false) 219 { 220 } 221 222 DefaultFBOMultisampleCase::~DefaultFBOMultisampleCase (void) 223 { 224 DefaultFBOMultisampleCase::deinit(); 225 } 226 227 void DefaultFBOMultisampleCase::init (void) 228 { 229 const bool isES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)); 230 map<string, string> args; 231 args["GLSL_VERSION_DECL"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES); 232 233 static const char* vertShaderSource = 234 "${GLSL_VERSION_DECL}\n" 235 "in highp vec4 a_position;\n" 236 "in mediump vec4 a_color;\n" 237 "out mediump vec4 v_color;\n" 238 "void main()\n" 239 "{\n" 240 " gl_Position = a_position;\n" 241 " v_color = a_color;\n" 242 "}\n"; 243 244 static const char* fragShaderSource = 245 "${GLSL_VERSION_DECL}\n" 246 "in mediump vec4 v_color;\n" 247 "layout(location = 0) out mediump vec4 o_color;\n" 248 "void main()\n" 249 "{\n" 250 " o_color = v_color;\n" 251 "}\n"; 252 253 TestLog& log = m_testCtx.getLog(); 254 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 255 256 if (m_context.getRenderTarget().getNumSamples() <= 1) 257 throw tcu::NotSupportedError("No multisample buffers"); 258 259 m_initCalled = true; 260 261 // Query and log number of samples per pixel. 262 263 gl.getIntegerv(GL_SAMPLES, &m_numSamples); 264 GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_SAMPLES)"); 265 log << TestLog::Message << "GL_SAMPLES = " << m_numSamples << TestLog::EndMessage; 266 267 // Prepare program. 268 269 DE_ASSERT(!m_program); 270 271 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() 272 << glu::VertexSource(tcu::StringTemplate(vertShaderSource).specialize(args)) 273 << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args))); 274 if (!m_program->isOk()) 275 throw tcu::TestError("Failed to compile program", DE_NULL, __FILE__, __LINE__); 276 277 m_attrPositionLoc = gl.getAttribLocation(m_program->getProgram(), "a_position"); 278 m_attrColorLoc = gl.getAttribLocation(m_program->getProgram(), "a_color"); 279 GLU_EXPECT_NO_ERROR(gl.getError(), "getAttribLocation"); 280 281 if (m_attrPositionLoc < 0 || m_attrColorLoc < 0) 282 { 283 delete m_program; 284 throw tcu::TestError("Invalid attribute locations", DE_NULL, __FILE__, __LINE__); 285 } 286 287 // Get suitable viewport size. 288 289 m_viewportSize = de::min<int>(m_desiredViewportSize, de::min(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight())); 290 randomizeViewport(); 291 } 292 293 void DefaultFBOMultisampleCase::deinit (void) 294 { 295 // Do not try to call GL functions during case list creation 296 if (!m_initCalled) 297 return; 298 299 delete m_program; 300 m_program = DE_NULL; 301 } 302 303 void DefaultFBOMultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const 304 { 305 const float vertexPositions[] = 306 { 307 p0.x(), p0.y(), p0.z(), 1.0f, 308 p1.x(), p1.y(), p1.z(), 1.0f, 309 p2.x(), p2.y(), p2.z(), 1.0f 310 }; 311 const float vertexColors[] = 312 { 313 c0.x(), c0.y(), c0.z(), c0.w(), 314 c1.x(), c1.y(), c1.z(), c1.w(), 315 c2.x(), c2.y(), c2.z(), c2.w(), 316 }; 317 318 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 319 glu::Buffer vtxBuf (m_context.getRenderContext()); 320 glu::Buffer colBuf (m_context.getRenderContext()); 321 glu::VertexArray vao (m_context.getRenderContext()); 322 323 gl.bindVertexArray(*vao); 324 GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray"); 325 326 gl.bindBuffer(GL_ARRAY_BUFFER, *vtxBuf); 327 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), &vertexPositions[0], GL_STATIC_DRAW); 328 GLU_EXPECT_NO_ERROR(gl.getError(), "vtx buf"); 329 330 gl.enableVertexAttribArray(m_attrPositionLoc); 331 gl.vertexAttribPointer(m_attrPositionLoc, 4, GL_FLOAT, false, 0, DE_NULL); 332 GLU_EXPECT_NO_ERROR(gl.getError(), "vtx vertexAttribPointer"); 333 334 gl.bindBuffer(GL_ARRAY_BUFFER, *colBuf); 335 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexColors), &vertexColors[0], GL_STATIC_DRAW); 336 GLU_EXPECT_NO_ERROR(gl.getError(), "col buf"); 337 338 gl.enableVertexAttribArray(m_attrColorLoc); 339 gl.vertexAttribPointer(m_attrColorLoc, 4, GL_FLOAT, false, 0, DE_NULL); 340 GLU_EXPECT_NO_ERROR(gl.getError(), "col vertexAttribPointer"); 341 342 gl.useProgram(m_program->getProgram()); 343 gl.drawArrays(GL_TRIANGLES, 0, 3); 344 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays"); 345 } 346 347 void DefaultFBOMultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& color) const 348 { 349 renderTriangle(p0, p1, p2, color, color, color); 350 } 351 352 void DefaultFBOMultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const 353 { 354 renderTriangle(Vec3(p0.x(), p0.y(), 0.0f), 355 Vec3(p1.x(), p1.y(), 0.0f), 356 Vec3(p2.x(), p2.y(), 0.0f), 357 c0, c1, c2); 358 } 359 360 void DefaultFBOMultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const 361 { 362 renderTriangle(p0, p1, p2, color, color, color); 363 } 364 365 void DefaultFBOMultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& c0, const Vec4& c1, const Vec4& c2, const Vec4& c3) const 366 { 367 renderTriangle(p0, p1, p2, c0, c1, c2); 368 renderTriangle(p2, p1, p3, c2, c1, c3); 369 } 370 371 void DefaultFBOMultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const 372 { 373 renderQuad(p0, p1, p2, p3, color, color, color, color); 374 } 375 376 void DefaultFBOMultisampleCase::randomizeViewport (void) 377 { 378 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 379 380 m_viewportX = m_rnd.getInt(0, m_context.getRenderTarget().getWidth() - m_viewportSize); 381 m_viewportY = m_rnd.getInt(0, m_context.getRenderTarget().getHeight() - m_viewportSize); 382 383 gl.viewport(m_viewportX, m_viewportY, m_viewportSize, m_viewportSize); 384 GLU_EXPECT_NO_ERROR(gl.getError(), "viewport"); 385 } 386 387 void DefaultFBOMultisampleCase::readImage (tcu::Surface& dst) const 388 { 389 glu::readPixels(m_context.getRenderContext(), m_viewportX, m_viewportY, dst.getAccess()); 390 } 391 392 /*--------------------------------------------------------------------*//*! 393 * \brief Tests coverage mask inversion validity. 394 * 395 * Tests that the coverage masks obtained by masks set with glSampleMaski(mask) 396 * and glSampleMaski(~mask) are indeed each others' inverses. 397 * 398 * This is done by drawing a pattern, with varying coverage values, 399 * overlapped by a pattern that has inverted masks and is otherwise 400 * identical. The resulting image is compared to one obtained by drawing 401 * the same pattern but with all-ones coverage masks. 402 *//*--------------------------------------------------------------------*/ 403 class MaskInvertCase : public DefaultFBOMultisampleCase 404 { 405 public: 406 MaskInvertCase (Context& context, const char* name, const char* description); 407 ~MaskInvertCase (void) {} 408 409 void init (void); 410 IterateResult iterate (void); 411 412 private: 413 void drawPattern (bool invert) const; 414 }; 415 416 MaskInvertCase::MaskInvertCase (Context& context, const char* name, const char* description) 417 : DefaultFBOMultisampleCase (context, name, description, 256) 418 { 419 } 420 421 void MaskInvertCase::init (void) 422 { 423 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 424 425 // check the test is even possible 426 427 GLint maxSampleMaskWords = 0; 428 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords); 429 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords) 430 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS"); 431 432 // normal init 433 DefaultFBOMultisampleCase::init(); 434 } 435 436 MaskInvertCase::IterateResult MaskInvertCase::iterate (void) 437 { 438 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 439 TestLog& log = m_testCtx.getLog(); 440 tcu::Surface renderedImgNoSampleCoverage (m_viewportSize, m_viewportSize); 441 tcu::Surface renderedImgSampleCoverage (m_viewportSize, m_viewportSize); 442 443 randomizeViewport(); 444 445 gl.enable(GL_BLEND); 446 gl.blendEquation(GL_FUNC_ADD); 447 gl.blendFunc(GL_ONE, GL_ONE); 448 GLU_EXPECT_NO_ERROR(gl.getError(), "set blend"); 449 log << TestLog::Message << "Additive blending enabled in order to detect (erroneously) overlapping samples" << TestLog::EndMessage; 450 451 log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage; 452 gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f); 453 gl.clear(GL_COLOR_BUFFER_BIT); 454 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 455 456 log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK disabled" << TestLog::EndMessage; 457 drawPattern(false); 458 readImage(renderedImgNoSampleCoverage); 459 460 log << TestLog::Image("RenderedImageNoSampleMask", "Rendered image with GL_SAMPLE_MASK disabled", renderedImgNoSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG); 461 462 log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage; 463 gl.clear(GL_COLOR_BUFFER_BIT); 464 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 465 466 gl.enable(GL_SAMPLE_MASK); 467 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK)"); 468 469 log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK enabled, using non-inverted sample masks" << TestLog::EndMessage; 470 drawPattern(false); 471 log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK enabled, using inverted sample masks" << TestLog::EndMessage; 472 drawPattern(true); 473 474 readImage(renderedImgSampleCoverage); 475 476 log << TestLog::Image("RenderedImageSampleMask", "Rendered image with GL_SAMPLE_MASK enabled", renderedImgSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG); 477 478 bool passed = tcu::pixelThresholdCompare(log, 479 "CoverageVsNoCoverage", 480 "Comparison of same pattern with GL_SAMPLE_MASK disabled and enabled", 481 renderedImgNoSampleCoverage, 482 renderedImgSampleCoverage, 483 tcu::RGBA(0), 484 tcu::COMPARE_LOG_ON_ERROR); 485 486 if (passed) 487 log << TestLog::Message << "Success: The two images rendered are identical" << TestLog::EndMessage; 488 489 m_context.getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 490 passed ? "Passed" : "Failed"); 491 492 return STOP; 493 } 494 495 void MaskInvertCase::drawPattern (bool invert) const 496 { 497 const int numTriangles = 25; 498 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 499 500 for (int triNdx = 0; triNdx < numTriangles; triNdx++) 501 { 502 const float angle0 = 2.0f*DE_PI * (float)triNdx / (float)numTriangles; 503 const float angle1 = 2.0f*DE_PI * ((float)triNdx + 0.5f) / (float)numTriangles; 504 const Vec4 color = Vec4(0.4f + (float)triNdx/(float)numTriangles*0.6f, 505 0.5f + (float)triNdx/(float)numTriangles*0.3f, 506 0.6f - (float)triNdx/(float)numTriangles*0.5f, 507 0.7f - (float)triNdx/(float)numTriangles*0.7f); 508 509 510 const int wordCount = getEffectiveSampleMaskWordCount(m_numSamples - 1); 511 const GLbitfield finalWordBits = m_numSamples - 32 * ((m_numSamples-1) / 32); 512 const GLbitfield finalWordMask = (GLbitfield)deBitMask32(0, (int)finalWordBits); 513 514 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx) 515 { 516 const GLbitfield rawMask = (GLbitfield)deUint32Hash(wordNdx * 32 + triNdx); 517 const GLbitfield mask = (invert) ? (~rawMask) : (rawMask); 518 const bool isFinalWord = (wordNdx + 1) == wordCount; 519 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask prevents setting coverage bits higher than sample count 520 521 gl.sampleMaski(wordNdx, mask & maskMask); 522 } 523 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski"); 524 525 renderTriangle(Vec2(0.0f, 0.0f), 526 Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f), 527 Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f), 528 color); 529 } 530 } 531 532 /*--------------------------------------------------------------------*//*! 533 * \brief Tests coverage mask generation proportionality property. 534 * 535 * Tests that the number of coverage bits in a coverage mask set with 536 * glSampleMaski is, on average, proportional to the number of set bits. 537 * Draws multiple frames, each time increasing the number of mask bits set 538 * and checks that the average color is changing appropriately. 539 *//*--------------------------------------------------------------------*/ 540 class MaskProportionalityCase : public DefaultFBOMultisampleCase 541 { 542 public: 543 MaskProportionalityCase (Context& context, const char* name, const char* description); 544 ~MaskProportionalityCase (void) {} 545 546 void init (void); 547 548 IterateResult iterate (void); 549 550 private: 551 int m_numIterations; 552 int m_currentIteration; 553 554 deInt32 m_previousIterationColorSum; 555 }; 556 557 MaskProportionalityCase::MaskProportionalityCase (Context& context, const char* name, const char* description) 558 : DefaultFBOMultisampleCase (context, name, description, 32) 559 , m_numIterations (-1) 560 , m_currentIteration (0) 561 , m_previousIterationColorSum (-1) 562 { 563 } 564 565 void MaskProportionalityCase::init (void) 566 { 567 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 568 TestLog& log = m_testCtx.getLog(); 569 570 // check the test is even possible 571 GLint maxSampleMaskWords = 0; 572 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords); 573 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords) 574 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS"); 575 576 DefaultFBOMultisampleCase::init(); 577 578 // set state 579 gl.enable(GL_SAMPLE_MASK); 580 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK)"); 581 log << TestLog::Message << "GL_SAMPLE_MASK is enabled" << TestLog::EndMessage; 582 583 m_numIterations = m_numSamples + 1; 584 585 randomizeViewport(); // \note Using the same viewport for every iteration since coverage mask may depend on window-relative pixel coordinate. 586 } 587 588 MaskProportionalityCase::IterateResult MaskProportionalityCase::iterate (void) 589 { 590 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 591 TestLog& log = m_testCtx.getLog(); 592 tcu::Surface renderedImg (m_viewportSize, m_viewportSize); 593 deInt32 numPixels = (deInt32)renderedImg.getWidth()*(deInt32)renderedImg.getHeight(); 594 595 DE_ASSERT(m_numIterations >= 0); 596 597 log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage; 598 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 599 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 600 gl.clear(GL_COLOR_BUFFER_BIT); 601 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 602 603 // Draw quad. 604 605 { 606 const Vec2 pt0 (-1.0f, -1.0f); 607 const Vec2 pt1 ( 1.0f, -1.0f); 608 const Vec2 pt2 (-1.0f, 1.0f); 609 const Vec2 pt3 ( 1.0f, 1.0f); 610 Vec4 quadColor (1.0f, 0.0f, 0.0f, 1.0f); 611 const std::vector<deUint32> sampleMask = genAllSetToNthBitSampleMask(m_currentIteration); 612 613 DE_ASSERT(m_currentIteration <= m_numSamples + 1); 614 615 log << TestLog::Message << "Drawing a red quad using sample mask 0b" << sampleMaskToString(sampleMask, m_numSamples) << TestLog::EndMessage; 616 617 for (int wordNdx = 0; wordNdx < getEffectiveSampleMaskWordCount(m_numSamples - 1); ++wordNdx) 618 { 619 const GLbitfield mask = (wordNdx < (int)sampleMask.size()) ? ((GLbitfield)(sampleMask[wordNdx])) : (0); 620 621 gl.sampleMaski(wordNdx, mask); 622 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski"); 623 } 624 625 renderQuad(pt0, pt1, pt2, pt3, quadColor); 626 } 627 628 // Read ang log image. 629 630 readImage(renderedImg); 631 632 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG); 633 634 // Compute average red component in rendered image. 635 636 deInt32 sumRed = 0; 637 638 for (int y = 0; y < renderedImg.getHeight(); y++) 639 for (int x = 0; x < renderedImg.getWidth(); x++) 640 sumRed += renderedImg.getPixel(x, y).getRed(); 641 642 log << TestLog::Message << "Average red color component: " << de::floatToString((float)sumRed / 255.0f / (float)numPixels, 2) << TestLog::EndMessage; 643 644 // Check if average color has decreased from previous frame's color. 645 646 if (sumRed < m_previousIterationColorSum) 647 { 648 log << TestLog::Message << "Failure: Current average red color component is lower than previous" << TestLog::EndMessage; 649 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed"); 650 return STOP; 651 } 652 653 // Check if coverage mask is not all-zeros if alpha or coverage value is 0 (or 1, if inverted). 654 655 if (m_currentIteration == 0 && sumRed != 0) 656 { 657 log << TestLog::Message << "Failure: Image should be completely black" << TestLog::EndMessage; 658 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed"); 659 return STOP; 660 } 661 662 if (m_currentIteration == m_numIterations-1 && sumRed != 0xff*numPixels) 663 { 664 log << TestLog::Message << "Failure: Image should be completely red" << TestLog::EndMessage; 665 666 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed"); 667 return STOP; 668 } 669 670 m_previousIterationColorSum = sumRed; 671 672 m_currentIteration++; 673 674 if (m_currentIteration >= m_numIterations) 675 { 676 log << TestLog::Message << "Success: Number of coverage mask bits set appears to be, on average, proportional to the number of set sample mask bits" << TestLog::EndMessage; 677 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed"); 678 return STOP; 679 } 680 else 681 return CONTINUE; 682 } 683 684 /*--------------------------------------------------------------------*//*! 685 * \brief Tests coverage mask generation constancy property. 686 * 687 * Tests that the coverage mask created by GL_SAMPLE_MASK is constant at 688 * given pixel coordinates. Draws two quads, with the second one fully 689 * overlapping the first one such that at any given pixel, both quads have 690 * the same coverage mask value. This way, if the constancy property is 691 * fulfilled, only the second quad should be visible. 692 *//*--------------------------------------------------------------------*/ 693 class MaskConstancyCase : public DefaultFBOMultisampleCase 694 { 695 public: 696 enum CaseBits 697 { 698 CASEBIT_ALPHA_TO_COVERAGE = 1, //!< Use alpha-to-coverage. 699 CASEBIT_SAMPLE_COVERAGE = 2, //!< Use sample coverage. 700 CASEBIT_SAMPLE_COVERAGE_INVERTED = 4, //!< Inverted sample coverage. 701 CASEBIT_SAMPLE_MASK = 8, //!< Use sample mask. 702 }; 703 704 MaskConstancyCase (Context& context, const char* name, const char* description, deUint32 typeBits); 705 ~MaskConstancyCase (void) {} 706 707 void init (void); 708 IterateResult iterate (void); 709 710 private: 711 const bool m_isAlphaToCoverageCase; 712 const bool m_isSampleCoverageCase; 713 const bool m_isInvertedSampleCoverageCase; 714 const bool m_isSampleMaskCase; 715 }; 716 717 MaskConstancyCase::MaskConstancyCase (Context& context, const char* name, const char* description, deUint32 typeBits) 718 : DefaultFBOMultisampleCase (context, name, description, 256) 719 , m_isAlphaToCoverageCase (0 != (typeBits & CASEBIT_ALPHA_TO_COVERAGE)) 720 , m_isSampleCoverageCase (0 != (typeBits & CASEBIT_SAMPLE_COVERAGE)) 721 , m_isInvertedSampleCoverageCase (0 != (typeBits & CASEBIT_SAMPLE_COVERAGE_INVERTED)) 722 , m_isSampleMaskCase (0 != (typeBits & CASEBIT_SAMPLE_MASK)) 723 { 724 // CASEBIT_SAMPLE_COVERAGE_INVERT => CASEBIT_SAMPLE_COVERAGE 725 DE_ASSERT((typeBits & CASEBIT_SAMPLE_COVERAGE) || ~(typeBits & CASEBIT_SAMPLE_COVERAGE_INVERTED)); 726 DE_ASSERT(m_isSampleMaskCase); // no point testing non-sample-mask cases, they are checked already in gles3 727 } 728 729 void MaskConstancyCase::init (void) 730 { 731 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 732 733 // check the test is even possible 734 if (m_isSampleMaskCase) 735 { 736 GLint maxSampleMaskWords = 0; 737 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords); 738 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords) 739 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS"); 740 } 741 742 // normal init 743 DefaultFBOMultisampleCase::init(); 744 } 745 746 MaskConstancyCase::IterateResult MaskConstancyCase::iterate (void) 747 { 748 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 749 TestLog& log = m_testCtx.getLog(); 750 tcu::Surface renderedImg (m_viewportSize, m_viewportSize); 751 752 randomizeViewport(); 753 754 log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage; 755 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 756 gl.clear(GL_COLOR_BUFFER_BIT); 757 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 758 759 if (m_isAlphaToCoverageCase) 760 { 761 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE); 762 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); 763 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_ALPHA_TO_COVERAGE"); 764 765 log << TestLog::Message << "GL_SAMPLE_ALPHA_TO_COVERAGE is enabled" << TestLog::EndMessage; 766 log << TestLog::Message << "Color mask is TRUE, TRUE, TRUE, FALSE" << TestLog::EndMessage; 767 } 768 769 if (m_isSampleCoverageCase) 770 { 771 gl.enable(GL_SAMPLE_COVERAGE); 772 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_COVERAGE"); 773 774 log << TestLog::Message << "GL_SAMPLE_COVERAGE is enabled" << TestLog::EndMessage; 775 } 776 777 if (m_isSampleMaskCase) 778 { 779 gl.enable(GL_SAMPLE_MASK); 780 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_MASK"); 781 782 log << TestLog::Message << "GL_SAMPLE_MASK is enabled" << TestLog::EndMessage; 783 } 784 785 log << TestLog::Message 786 << "Drawing several green quads, each fully overlapped by a red quad with the same " 787 << (m_isAlphaToCoverageCase ? "alpha" : "") 788 << (m_isAlphaToCoverageCase && (m_isSampleCoverageCase || m_isSampleMaskCase) ? " and " : "") 789 << (m_isInvertedSampleCoverageCase ? "inverted " : "") 790 << (m_isSampleCoverageCase ? "sample coverage" : "") 791 << (m_isSampleCoverageCase && m_isSampleMaskCase ? " and " : "") 792 << (m_isSampleMaskCase ? "sample mask" : "") 793 << " values" 794 << TestLog::EndMessage; 795 796 const int numQuadRowsCols = m_numSamples*4; 797 798 for (int row = 0; row < numQuadRowsCols; row++) 799 { 800 for (int col = 0; col < numQuadRowsCols; col++) 801 { 802 float x0 = (float)(col+0) / (float)numQuadRowsCols * 2.0f - 1.0f; 803 float x1 = (float)(col+1) / (float)numQuadRowsCols * 2.0f - 1.0f; 804 float y0 = (float)(row+0) / (float)numQuadRowsCols * 2.0f - 1.0f; 805 float y1 = (float)(row+1) / (float)numQuadRowsCols * 2.0f - 1.0f; 806 const Vec4 baseGreen (0.0f, 1.0f, 0.0f, 0.0f); 807 const Vec4 baseRed (1.0f, 0.0f, 0.0f, 0.0f); 808 Vec4 alpha0 (0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)col / (float)(numQuadRowsCols-1) : 1.0f); 809 Vec4 alpha1 (0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)row / (float)(numQuadRowsCols-1) : 1.0f); 810 811 if (m_isSampleCoverageCase) 812 { 813 float value = (float)(row*numQuadRowsCols + col) / (float)(numQuadRowsCols*numQuadRowsCols-1); 814 gl.sampleCoverage(m_isInvertedSampleCoverageCase ? 1.0f - value : value, m_isInvertedSampleCoverageCase ? GL_TRUE : GL_FALSE); 815 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleCoverage"); 816 } 817 818 if (m_isSampleMaskCase) 819 { 820 const int wordCount = getEffectiveSampleMaskWordCount(m_numSamples - 1); 821 const GLbitfield finalWordBits = m_numSamples - 32 * ((m_numSamples-1) / 32); 822 const GLbitfield finalWordMask = (GLbitfield)deBitMask32(0, (int)finalWordBits); 823 824 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx) 825 { 826 const GLbitfield mask = (GLbitfield)deUint32Hash((col << (m_numSamples / 2)) ^ row); 827 const bool isFinalWord = (wordNdx + 1) == wordCount; 828 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask prevents setting coverage bits higher than sample count 829 830 gl.sampleMaski(wordNdx, mask & maskMask); 831 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski"); 832 } 833 } 834 835 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseGreen + alpha0, baseGreen + alpha1, baseGreen + alpha0, baseGreen + alpha1); 836 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseRed + alpha0, baseRed + alpha1, baseRed + alpha0, baseRed + alpha1); 837 } 838 } 839 840 readImage(renderedImg); 841 842 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG); 843 844 for (int y = 0; y < renderedImg.getHeight(); y++) 845 for (int x = 0; x < renderedImg.getWidth(); x++) 846 { 847 if (renderedImg.getPixel(x, y).getGreen() > 0) 848 { 849 log << TestLog::Message << "Failure: Non-zero green color component detected - should have been completely overwritten by red quad" << TestLog::EndMessage; 850 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed"); 851 return STOP; 852 } 853 } 854 855 log << TestLog::Message 856 << "Success: Coverage mask appears to be constant at a given pixel coordinate with a given " 857 << (m_isAlphaToCoverageCase ? "alpha" : "") 858 << (m_isAlphaToCoverageCase && m_isSampleCoverageCase ? " and " : "") 859 << (m_isSampleCoverageCase ? "coverage value" : "") 860 << TestLog::EndMessage; 861 862 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed"); 863 864 return STOP; 865 } 866 867 /*--------------------------------------------------------------------*//*! 868 * \brief Tests that unused bits of a sample mask have no effect 869 * 870 * Tests that the bits in the sample mask with positions higher than 871 * the number of samples do not have effect. In multisample fragment 872 * operations the sample mask is ANDed with the fragment coverage value. 873 * The coverage value cannot have the corresponding bits set. 874 * 875 * This is done by drawing a quads with varying sample masks and then 876 * redrawing the quads with identical masks but with the mask's high bits 877 * having different values. Only the latter quad pattern should be visible. 878 *//*--------------------------------------------------------------------*/ 879 class SampleMaskHighBitsCase : public DefaultFBOMultisampleCase 880 { 881 public: 882 SampleMaskHighBitsCase (Context& context, const char* name, const char* description); 883 ~SampleMaskHighBitsCase (void) {} 884 885 void init (void); 886 IterateResult iterate (void); 887 }; 888 889 SampleMaskHighBitsCase::SampleMaskHighBitsCase (Context& context, const char* name, const char* description) 890 : DefaultFBOMultisampleCase(context, name, description, 256) 891 { 892 } 893 894 void SampleMaskHighBitsCase::init (void) 895 { 896 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 897 GLint maxSampleMaskWords = 0; 898 899 // check the test is even possible 900 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords); 901 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords) 902 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS"); 903 904 // normal init 905 DefaultFBOMultisampleCase::init(); 906 } 907 908 SampleMaskHighBitsCase::IterateResult SampleMaskHighBitsCase::iterate (void) 909 { 910 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 911 TestLog& log = m_testCtx.getLog(); 912 tcu::Surface renderedImg (m_viewportSize, m_viewportSize); 913 de::Random rnd (12345); 914 915 if (m_numSamples % 32 == 0) 916 { 917 log << TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << TestLog::EndMessage; 918 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Skipped"); 919 return STOP; 920 } 921 922 randomizeViewport(); 923 924 log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage; 925 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); 926 gl.clear(GL_COLOR_BUFFER_BIT); 927 GLU_EXPECT_NO_ERROR(gl.getError(), "clear"); 928 929 gl.enable(GL_SAMPLE_MASK); 930 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_MASK"); 931 log << TestLog::Message << "GL_SAMPLE_MASK is enabled" << TestLog::EndMessage; 932 log << TestLog::Message << "Drawing several green quads, each fully overlapped by a red quad with the same effective sample mask values" << TestLog::EndMessage; 933 934 const int numQuadRowsCols = m_numSamples*4; 935 936 for (int row = 0; row < numQuadRowsCols; row++) 937 { 938 for (int col = 0; col < numQuadRowsCols; col++) 939 { 940 float x0 = (float)(col+0) / (float)numQuadRowsCols * 2.0f - 1.0f; 941 float x1 = (float)(col+1) / (float)numQuadRowsCols * 2.0f - 1.0f; 942 float y0 = (float)(row+0) / (float)numQuadRowsCols * 2.0f - 1.0f; 943 float y1 = (float)(row+1) / (float)numQuadRowsCols * 2.0f - 1.0f; 944 const Vec4 baseGreen (0.0f, 1.0f, 0.0f, 1.0f); 945 const Vec4 baseRed (1.0f, 0.0f, 0.0f, 1.0f); 946 947 const int wordCount = getEffectiveSampleMaskWordCount(m_numSamples - 1); 948 const GLbitfield finalWordBits = m_numSamples - 32 * ((m_numSamples-1) / 32); 949 const GLbitfield finalWordMask = (GLbitfield)deBitMask32(0, (int)finalWordBits); 950 951 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx) 952 { 953 const GLbitfield mask = (GLbitfield)deUint32Hash((col << (m_numSamples / 2)) ^ row); 954 const bool isFinalWord = (wordNdx + 1) == wordCount; 955 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask is 1 on bits in lower positions than sample count 956 const GLbitfield highBits = rnd.getUint32(); 957 958 gl.sampleMaski(wordNdx, (mask & maskMask) | (highBits & ~maskMask)); 959 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski"); 960 } 961 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseGreen, baseGreen, baseGreen, baseGreen); 962 963 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx) 964 { 965 const GLbitfield mask = (GLbitfield)deUint32Hash((col << (m_numSamples / 2)) ^ row); 966 const bool isFinalWord = (wordNdx + 1) == wordCount; 967 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask is 1 on bits in lower positions than sample count 968 const GLbitfield highBits = rnd.getUint32(); 969 970 gl.sampleMaski(wordNdx, (mask & maskMask) | (highBits & ~maskMask)); 971 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski"); 972 } 973 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseRed, baseRed, baseRed, baseRed); 974 } 975 } 976 977 readImage(renderedImg); 978 979 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG); 980 981 for (int y = 0; y < renderedImg.getHeight(); y++) 982 for (int x = 0; x < renderedImg.getWidth(); x++) 983 { 984 if (renderedImg.getPixel(x, y).getGreen() > 0) 985 { 986 log << TestLog::Message << "Failure: Non-zero green color component detected - should have been completely overwritten by red quad. Mask unused bits have effect." << TestLog::EndMessage; 987 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits modified mask"); 988 return STOP; 989 } 990 } 991 992 log << TestLog::Message << "Success: Coverage mask high bits appear to have no effect." << TestLog::EndMessage; 993 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed"); 994 995 return STOP; 996 } 997 998 } // anonymous 999 1000 MultisampleTests::MultisampleTests (Context& context) 1001 : TestCaseGroup(context, "multisample", "Multisample tests") 1002 { 1003 } 1004 1005 MultisampleTests::~MultisampleTests (void) 1006 { 1007 } 1008 1009 void MultisampleTests::init (void) 1010 { 1011 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "default_framebuffer", "Test with default framebuffer"); 1012 1013 addChild(group); 1014 1015 // .default_framebuffer 1016 { 1017 // sample positions 1018 group->addChild(new SamplePosQueryCase (m_context, "sample_position", "test SAMPLE_POSITION")); 1019 1020 // sample mask 1021 group->addChild(new MaskInvertCase (m_context, "sample_mask_sum_of_inverses", "Test that mask and its negation's sum equal the fully set mask")); 1022 group->addChild(new MaskProportionalityCase (m_context, "proportionality_sample_mask", "Test the proportionality property of GL_SAMPLE_MASK")); 1023 1024 group->addChild(new MaskConstancyCase (m_context, "constancy_sample_mask", 1025 "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_MASK", 1026 MaskConstancyCase::CASEBIT_SAMPLE_MASK)); 1027 group->addChild(new MaskConstancyCase (m_context, "constancy_alpha_to_coverage_sample_mask", 1028 "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE and GL_SAMPLE_MASK", 1029 MaskConstancyCase::CASEBIT_ALPHA_TO_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_MASK)); 1030 group->addChild(new MaskConstancyCase (m_context, "constancy_sample_coverage_sample_mask", 1031 "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_COVERAGE and GL_SAMPLE_MASK", 1032 MaskConstancyCase::CASEBIT_SAMPLE_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_MASK)); 1033 group->addChild(new MaskConstancyCase (m_context, "constancy_alpha_to_coverage_sample_coverage_sample_mask", 1034 "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_ALPHA_TO_COVERAGE, GL_SAMPLE_COVERAGE and GL_SAMPLE_MASK", 1035 MaskConstancyCase::CASEBIT_ALPHA_TO_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_MASK)); 1036 group->addChild(new SampleMaskHighBitsCase (m_context, "sample_mask_non_effective_bits", 1037 "Test that values of unused bits of a sample mask (bit index > sample count) have no effect")); 1038 } 1039 } 1040 1041 } // Functional 1042 } // gles31 1043 } // deqp 1044