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