1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Multisample tests
22 *//*--------------------------------------------------------------------*/
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"
61 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits)
63 std::string result(numBits, '0');
65 // move from back to front and set chars to 1
66 for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx)
68 for (int bit = 0; bit < 32; ++bit)
70 const int targetCharNdx = numBits - (wordNdx*32+bit) - 1;
72 // beginning of the string reached
73 if (targetCharNdx < 0)
76 if ((bitfield[wordNdx] >> bit) & 0x01)
77 result[targetCharNdx] = '1';
84 /*--------------------------------------------------------------------*//*!
85 * \brief Returns the number of words needed to represent mask of given length
86 *//*--------------------------------------------------------------------*/
87 static int getEffectiveSampleMaskWordCount (int highestBitNdx)
89 const int wordSize = 32;
90 const int maskLen = highestBitNdx + 1;
92 return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len / wordSize)
95 /*--------------------------------------------------------------------*//*!
96 * \brief Creates sample mask with all less significant bits than nthBit set
97 *//*--------------------------------------------------------------------*/
98 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit)
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);
105 for (int ndx = 0; ndx < numWords - 1; ++ndx)
106 mask[ndx] = 0xFFFFFFFF;
108 mask[numWords - 1] = deBitMask32(0, (int)topWordBits);
112 class SamplePosQueryCase : public TestCase
115 SamplePosQueryCase (Context& context, const char* name, const char* desc);
118 IterateResult iterate (void);
121 SamplePosQueryCase::SamplePosQueryCase (Context& context, const char* name, const char* desc)
122 : TestCase(context, name, desc)
126 void SamplePosQueryCase::init (void)
128 if (m_context.getRenderTarget().getNumSamples() == 0)
129 throw tcu::NotSupportedError("No multisample buffers");
132 SamplePosQueryCase::IterateResult SamplePosQueryCase::iterate (void)
134 glu::CallLogWrapper gl (m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
137 gl.enableLogging(true);
139 for (int ndx = 0; ndx < m_context.getRenderTarget().getNumSamples(); ++ndx)
141 tcu::Vec2 samplePos = tcu::Vec2(-1, -1);
143 gl.glGetMultisamplefv(GL_SAMPLE_POSITION, ndx, samplePos.getPtr());
144 GLU_EXPECT_NO_ERROR(gl.glGetError(), "getMultisamplefv");
147 if (samplePos.x() < 0.0f || samplePos.x() > 1.0f ||
148 samplePos.y() < 0.0f || samplePos.y() > 1.0f)
150 m_testCtx.getLog() << tcu::TestLog::Message << "Sample " << ndx << " is not in valid range [0,1], got " << samplePos << tcu::TestLog::EndMessage;
156 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
158 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid sample pos");
163 /*--------------------------------------------------------------------*//*!
164 * \brief Abstract base class handling common stuff for default fbo multisample cases.
165 *//*--------------------------------------------------------------------*/
166 class DefaultFBOMultisampleCase : public TestCase
169 DefaultFBOMultisampleCase (Context& context, const char* name, const char* desc, int desiredViewportSize);
170 virtual ~DefaultFBOMultisampleCase (void);
172 virtual void init (void);
173 virtual void deinit (void);
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 Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const;
178 void renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const;
179 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;
180 void renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const;
182 void randomizeViewport (void);
183 void readImage (tcu::Surface& dst) const;
190 DefaultFBOMultisampleCase (const DefaultFBOMultisampleCase& other);
191 DefaultFBOMultisampleCase& operator= (const DefaultFBOMultisampleCase& other);
193 const int m_desiredViewportSize;
195 glu::ShaderProgram* m_program;
196 int m_attrPositionLoc;
206 DefaultFBOMultisampleCase::DefaultFBOMultisampleCase (Context& context, const char* name, const char* desc, int desiredViewportSize)
207 : TestCase (context, name, desc)
210 , m_desiredViewportSize (desiredViewportSize)
211 , m_program (DE_NULL)
212 , m_attrPositionLoc (-1)
213 , m_attrColorLoc (-1)
216 , m_rnd (deStringHash(name))
217 , m_initCalled (false)
221 DefaultFBOMultisampleCase::~DefaultFBOMultisampleCase (void)
223 DefaultFBOMultisampleCase::deinit();
226 void DefaultFBOMultisampleCase::init (void)
228 const bool supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
229 map<string, string> args;
230 args["GLSL_VERSION_DECL"] = supportsES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
232 static const char* vertShaderSource =
233 "${GLSL_VERSION_DECL}\n"
234 "in highp vec4 a_position;\n"
235 "in mediump vec4 a_color;\n"
236 "out mediump vec4 v_color;\n"
239 " gl_Position = a_position;\n"
240 " v_color = a_color;\n"
243 static const char* fragShaderSource =
244 "${GLSL_VERSION_DECL}\n"
245 "in mediump vec4 v_color;\n"
246 "layout(location = 0) out mediump vec4 o_color;\n"
249 " o_color = v_color;\n"
252 TestLog& log = m_testCtx.getLog();
253 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
255 if (m_context.getRenderTarget().getNumSamples() <= 1)
256 throw tcu::NotSupportedError("No multisample buffers");
260 // Query and log number of samples per pixel.
262 gl.getIntegerv(GL_SAMPLES, &m_numSamples);
263 GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_SAMPLES)");
264 log << TestLog::Message << "GL_SAMPLES = " << m_numSamples << TestLog::EndMessage;
268 DE_ASSERT(!m_program);
270 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
271 << glu::VertexSource(tcu::StringTemplate(vertShaderSource).specialize(args))
272 << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args)));
273 if (!m_program->isOk())
274 throw tcu::TestError("Failed to compile program", DE_NULL, __FILE__, __LINE__);
276 m_attrPositionLoc = gl.getAttribLocation(m_program->getProgram(), "a_position");
277 m_attrColorLoc = gl.getAttribLocation(m_program->getProgram(), "a_color");
278 GLU_EXPECT_NO_ERROR(gl.getError(), "getAttribLocation");
280 if (m_attrPositionLoc < 0 || m_attrColorLoc < 0)
283 throw tcu::TestError("Invalid attribute locations", DE_NULL, __FILE__, __LINE__);
286 // Get suitable viewport size.
288 m_viewportSize = de::min<int>(m_desiredViewportSize, de::min(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()));
292 void DefaultFBOMultisampleCase::deinit (void)
294 // Do not try to call GL functions during case list creation
302 void DefaultFBOMultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
304 const float vertexPositions[] =
306 p0.x(), p0.y(), p0.z(), 1.0f,
307 p1.x(), p1.y(), p1.z(), 1.0f,
308 p2.x(), p2.y(), p2.z(), 1.0f
310 const float vertexColors[] =
312 c0.x(), c0.y(), c0.z(), c0.w(),
313 c1.x(), c1.y(), c1.z(), c1.w(),
314 c2.x(), c2.y(), c2.z(), c2.w(),
317 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
318 glu::Buffer vtxBuf (m_context.getRenderContext());
319 glu::Buffer colBuf (m_context.getRenderContext());
320 glu::VertexArray vao (m_context.getRenderContext());
322 gl.bindVertexArray(*vao);
323 GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
325 gl.bindBuffer(GL_ARRAY_BUFFER, *vtxBuf);
326 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), &vertexPositions[0], GL_STATIC_DRAW);
327 GLU_EXPECT_NO_ERROR(gl.getError(), "vtx buf");
329 gl.enableVertexAttribArray(m_attrPositionLoc);
330 gl.vertexAttribPointer(m_attrPositionLoc, 4, GL_FLOAT, false, 0, DE_NULL);
331 GLU_EXPECT_NO_ERROR(gl.getError(), "vtx vertexAttribPointer");
333 gl.bindBuffer(GL_ARRAY_BUFFER, *colBuf);
334 gl.bufferData(GL_ARRAY_BUFFER, sizeof(vertexColors), &vertexColors[0], GL_STATIC_DRAW);
335 GLU_EXPECT_NO_ERROR(gl.getError(), "col buf");
337 gl.enableVertexAttribArray(m_attrColorLoc);
338 gl.vertexAttribPointer(m_attrColorLoc, 4, GL_FLOAT, false, 0, DE_NULL);
339 GLU_EXPECT_NO_ERROR(gl.getError(), "col vertexAttribPointer");
341 gl.useProgram(m_program->getProgram());
342 gl.drawArrays(GL_TRIANGLES, 0, 3);
343 GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
346 void DefaultFBOMultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
348 renderTriangle(Vec3(p0.x(), p0.y(), 0.0f),
349 Vec3(p1.x(), p1.y(), 0.0f),
350 Vec3(p2.x(), p2.y(), 0.0f),
354 void DefaultFBOMultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const
356 renderTriangle(p0, p1, p2, color, color, color);
359 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
361 renderTriangle(p0, p1, p2, c0, c1, c2);
362 renderTriangle(p2, p1, p3, c2, c1, c3);
365 void DefaultFBOMultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const
367 renderQuad(p0, p1, p2, p3, color, color, color, color);
370 void DefaultFBOMultisampleCase::randomizeViewport (void)
372 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
374 m_viewportX = m_rnd.getInt(0, m_context.getRenderTarget().getWidth() - m_viewportSize);
375 m_viewportY = m_rnd.getInt(0, m_context.getRenderTarget().getHeight() - m_viewportSize);
377 gl.viewport(m_viewportX, m_viewportY, m_viewportSize, m_viewportSize);
378 GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
381 void DefaultFBOMultisampleCase::readImage (tcu::Surface& dst) const
383 glu::readPixels(m_context.getRenderContext(), m_viewportX, m_viewportY, dst.getAccess());
386 /*--------------------------------------------------------------------*//*!
387 * \brief Tests coverage mask inversion validity.
389 * Tests that the coverage masks obtained by masks set with glSampleMaski(mask)
390 * and glSampleMaski(~mask) are indeed each others' inverses.
392 * This is done by drawing a pattern, with varying coverage values,
393 * overlapped by a pattern that has inverted masks and is otherwise
394 * identical. The resulting image is compared to one obtained by drawing
395 * the same pattern but with all-ones coverage masks.
396 *//*--------------------------------------------------------------------*/
397 class MaskInvertCase : public DefaultFBOMultisampleCase
400 MaskInvertCase (Context& context, const char* name, const char* description);
401 ~MaskInvertCase (void) {}
404 IterateResult iterate (void);
407 void drawPattern (bool invert) const;
410 MaskInvertCase::MaskInvertCase (Context& context, const char* name, const char* description)
411 : DefaultFBOMultisampleCase (context, name, description, 256)
415 void MaskInvertCase::init (void)
417 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
419 // check the test is even possible
421 GLint maxSampleMaskWords = 0;
422 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
423 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords)
424 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
427 DefaultFBOMultisampleCase::init();
430 MaskInvertCase::IterateResult MaskInvertCase::iterate (void)
432 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
433 TestLog& log = m_testCtx.getLog();
434 tcu::Surface renderedImgNoSampleCoverage (m_viewportSize, m_viewportSize);
435 tcu::Surface renderedImgSampleCoverage (m_viewportSize, m_viewportSize);
440 gl.blendEquation(GL_FUNC_ADD);
441 gl.blendFunc(GL_ONE, GL_ONE);
442 GLU_EXPECT_NO_ERROR(gl.getError(), "set blend");
443 log << TestLog::Message << "Additive blending enabled in order to detect (erroneously) overlapping samples" << TestLog::EndMessage;
445 log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage;
446 gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);
447 gl.clear(GL_COLOR_BUFFER_BIT);
448 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
450 log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK disabled" << TestLog::EndMessage;
452 readImage(renderedImgNoSampleCoverage);
454 log << TestLog::Image("RenderedImageNoSampleMask", "Rendered image with GL_SAMPLE_MASK disabled", renderedImgNoSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
456 log << TestLog::Message << "Clearing color to all-zeros" << TestLog::EndMessage;
457 gl.clear(GL_COLOR_BUFFER_BIT);
458 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
460 gl.enable(GL_SAMPLE_MASK);
461 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK)");
463 log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK enabled, using non-inverted sample masks" << TestLog::EndMessage;
465 log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK enabled, using inverted sample masks" << TestLog::EndMessage;
468 readImage(renderedImgSampleCoverage);
470 log << TestLog::Image("RenderedImageSampleMask", "Rendered image with GL_SAMPLE_MASK enabled", renderedImgSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
472 bool passed = tcu::pixelThresholdCompare(log,
473 "CoverageVsNoCoverage",
474 "Comparison of same pattern with GL_SAMPLE_MASK disabled and enabled",
475 renderedImgNoSampleCoverage,
476 renderedImgSampleCoverage,
478 tcu::COMPARE_LOG_ON_ERROR);
481 log << TestLog::Message << "Success: The two images rendered are identical" << TestLog::EndMessage;
483 m_context.getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
484 passed ? "Passed" : "Failed");
489 void MaskInvertCase::drawPattern (bool invert) const
491 const int numTriangles = 25;
492 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
494 for (int triNdx = 0; triNdx < numTriangles; triNdx++)
496 const float angle0 = 2.0f*DE_PI * (float)triNdx / (float)numTriangles;
497 const float angle1 = 2.0f*DE_PI * ((float)triNdx + 0.5f) / (float)numTriangles;
498 const Vec4 color = Vec4(0.4f + (float)triNdx/(float)numTriangles*0.6f,
499 0.5f + (float)triNdx/(float)numTriangles*0.3f,
500 0.6f - (float)triNdx/(float)numTriangles*0.5f,
501 0.7f - (float)triNdx/(float)numTriangles*0.7f);
504 const int wordCount = getEffectiveSampleMaskWordCount(m_numSamples - 1);
505 const GLbitfield finalWordBits = m_numSamples - 32 * ((m_numSamples-1) / 32);
506 const GLbitfield finalWordMask = (GLbitfield)deBitMask32(0, (int)finalWordBits);
508 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
510 const GLbitfield rawMask = (GLbitfield)deUint32Hash(wordNdx * 32 + triNdx);
511 const GLbitfield mask = (invert) ? (~rawMask) : (rawMask);
512 const bool isFinalWord = (wordNdx + 1) == wordCount;
513 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask prevents setting coverage bits higher than sample count
515 gl.sampleMaski(wordNdx, mask & maskMask);
517 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
519 renderTriangle(Vec2(0.0f, 0.0f),
520 Vec2(deFloatCos(angle0)*0.95f, deFloatSin(angle0)*0.95f),
521 Vec2(deFloatCos(angle1)*0.95f, deFloatSin(angle1)*0.95f),
526 /*--------------------------------------------------------------------*//*!
527 * \brief Tests coverage mask generation proportionality property.
529 * Tests that the number of coverage bits in a coverage mask set with
530 * glSampleMaski is, on average, proportional to the number of set bits.
531 * Draws multiple frames, each time increasing the number of mask bits set
532 * and checks that the average color is changing appropriately.
533 *//*--------------------------------------------------------------------*/
534 class MaskProportionalityCase : public DefaultFBOMultisampleCase
537 MaskProportionalityCase (Context& context, const char* name, const char* description);
538 ~MaskProportionalityCase (void) {}
542 IterateResult iterate (void);
546 int m_currentIteration;
548 deInt32 m_previousIterationColorSum;
551 MaskProportionalityCase::MaskProportionalityCase (Context& context, const char* name, const char* description)
552 : DefaultFBOMultisampleCase (context, name, description, 32)
553 , m_numIterations (-1)
554 , m_currentIteration (0)
555 , m_previousIterationColorSum (-1)
559 void MaskProportionalityCase::init (void)
561 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
562 TestLog& log = m_testCtx.getLog();
564 // check the test is even possible
565 GLint maxSampleMaskWords = 0;
566 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
567 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords)
568 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
570 DefaultFBOMultisampleCase::init();
573 gl.enable(GL_SAMPLE_MASK);
574 GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK)");
575 log << TestLog::Message << "GL_SAMPLE_MASK is enabled" << TestLog::EndMessage;
577 m_numIterations = m_numSamples + 1;
579 randomizeViewport(); // \note Using the same viewport for every iteration since coverage mask may depend on window-relative pixel coordinate.
582 MaskProportionalityCase::IterateResult MaskProportionalityCase::iterate (void)
584 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
585 TestLog& log = m_testCtx.getLog();
586 tcu::Surface renderedImg (m_viewportSize, m_viewportSize);
587 deInt32 numPixels = (deInt32)renderedImg.getWidth()*(deInt32)renderedImg.getHeight();
589 DE_ASSERT(m_numIterations >= 0);
591 log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage;
592 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
593 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
594 gl.clear(GL_COLOR_BUFFER_BIT);
595 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
600 const Vec2 pt0 (-1.0f, -1.0f);
601 const Vec2 pt1 ( 1.0f, -1.0f);
602 const Vec2 pt2 (-1.0f, 1.0f);
603 const Vec2 pt3 ( 1.0f, 1.0f);
604 Vec4 quadColor (1.0f, 0.0f, 0.0f, 1.0f);
605 const std::vector<deUint32> sampleMask = genAllSetToNthBitSampleMask(m_currentIteration);
607 DE_ASSERT(m_currentIteration <= m_numSamples + 1);
609 log << TestLog::Message << "Drawing a red quad using sample mask 0b" << sampleMaskToString(sampleMask, m_numSamples) << TestLog::EndMessage;
611 for (int wordNdx = 0; wordNdx < getEffectiveSampleMaskWordCount(m_numSamples - 1); ++wordNdx)
613 const GLbitfield mask = (wordNdx < (int)sampleMask.size()) ? ((GLbitfield)(sampleMask[wordNdx])) : (0);
615 gl.sampleMaski(wordNdx, mask);
616 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
619 renderQuad(pt0, pt1, pt2, pt3, quadColor);
622 // Read ang log image.
624 readImage(renderedImg);
626 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
628 // Compute average red component in rendered image.
632 for (int y = 0; y < renderedImg.getHeight(); y++)
633 for (int x = 0; x < renderedImg.getWidth(); x++)
634 sumRed += renderedImg.getPixel(x, y).getRed();
636 log << TestLog::Message << "Average red color component: " << de::floatToString((float)sumRed / 255.0f / (float)numPixels, 2) << TestLog::EndMessage;
638 // Check if average color has decreased from previous frame's color.
640 if (sumRed < m_previousIterationColorSum)
642 log << TestLog::Message << "Failure: Current average red color component is lower than previous" << TestLog::EndMessage;
643 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
647 // Check if coverage mask is not all-zeros if alpha or coverage value is 0 (or 1, if inverted).
649 if (m_currentIteration == 0 && sumRed != 0)
651 log << TestLog::Message << "Failure: Image should be completely black" << TestLog::EndMessage;
652 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
656 if (m_currentIteration == m_numIterations-1 && sumRed != 0xff*numPixels)
658 log << TestLog::Message << "Failure: Image should be completely red" << TestLog::EndMessage;
660 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
664 m_previousIterationColorSum = sumRed;
666 m_currentIteration++;
668 if (m_currentIteration >= m_numIterations)
670 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;
671 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
678 /*--------------------------------------------------------------------*//*!
679 * \brief Tests coverage mask generation constancy property.
681 * Tests that the coverage mask created by GL_SAMPLE_MASK is constant at
682 * given pixel coordinates. Draws two quads, with the second one fully
683 * overlapping the first one such that at any given pixel, both quads have
684 * the same coverage mask value. This way, if the constancy property is
685 * fulfilled, only the second quad should be visible.
686 *//*--------------------------------------------------------------------*/
687 class MaskConstancyCase : public DefaultFBOMultisampleCase
692 CASEBIT_ALPHA_TO_COVERAGE = 1, //!< Use alpha-to-coverage.
693 CASEBIT_SAMPLE_COVERAGE = 2, //!< Use sample coverage.
694 CASEBIT_SAMPLE_COVERAGE_INVERTED = 4, //!< Inverted sample coverage.
695 CASEBIT_SAMPLE_MASK = 8, //!< Use sample mask.
698 MaskConstancyCase (Context& context, const char* name, const char* description, deUint32 typeBits);
699 ~MaskConstancyCase (void) {}
702 IterateResult iterate (void);
705 const bool m_isAlphaToCoverageCase;
706 const bool m_isSampleCoverageCase;
707 const bool m_isInvertedSampleCoverageCase;
708 const bool m_isSampleMaskCase;
711 MaskConstancyCase::MaskConstancyCase (Context& context, const char* name, const char* description, deUint32 typeBits)
712 : DefaultFBOMultisampleCase (context, name, description, 256)
713 , m_isAlphaToCoverageCase (0 != (typeBits & CASEBIT_ALPHA_TO_COVERAGE))
714 , m_isSampleCoverageCase (0 != (typeBits & CASEBIT_SAMPLE_COVERAGE))
715 , m_isInvertedSampleCoverageCase (0 != (typeBits & CASEBIT_SAMPLE_COVERAGE_INVERTED))
716 , m_isSampleMaskCase (0 != (typeBits & CASEBIT_SAMPLE_MASK))
718 // CASEBIT_SAMPLE_COVERAGE_INVERT => CASEBIT_SAMPLE_COVERAGE
719 DE_ASSERT((typeBits & CASEBIT_SAMPLE_COVERAGE) || ~(typeBits & CASEBIT_SAMPLE_COVERAGE_INVERTED));
720 DE_ASSERT(m_isSampleMaskCase); // no point testing non-sample-mask cases, they are checked already in gles3
723 void MaskConstancyCase::init (void)
725 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
727 // check the test is even possible
728 if (m_isSampleMaskCase)
730 GLint maxSampleMaskWords = 0;
731 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
732 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords)
733 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
737 DefaultFBOMultisampleCase::init();
740 MaskConstancyCase::IterateResult MaskConstancyCase::iterate (void)
742 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
743 TestLog& log = m_testCtx.getLog();
744 tcu::Surface renderedImg (m_viewportSize, m_viewportSize);
748 log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage;
749 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
750 gl.clear(GL_COLOR_BUFFER_BIT);
751 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
753 if (m_isAlphaToCoverageCase)
755 gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
756 gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
757 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_ALPHA_TO_COVERAGE");
759 log << TestLog::Message << "GL_SAMPLE_ALPHA_TO_COVERAGE is enabled" << TestLog::EndMessage;
760 log << TestLog::Message << "Color mask is TRUE, TRUE, TRUE, FALSE" << TestLog::EndMessage;
763 if (m_isSampleCoverageCase)
765 gl.enable(GL_SAMPLE_COVERAGE);
766 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_COVERAGE");
768 log << TestLog::Message << "GL_SAMPLE_COVERAGE is enabled" << TestLog::EndMessage;
771 if (m_isSampleMaskCase)
773 gl.enable(GL_SAMPLE_MASK);
774 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_MASK");
776 log << TestLog::Message << "GL_SAMPLE_MASK is enabled" << TestLog::EndMessage;
779 log << TestLog::Message
780 << "Drawing several green quads, each fully overlapped by a red quad with the same "
781 << (m_isAlphaToCoverageCase ? "alpha" : "")
782 << (m_isAlphaToCoverageCase && (m_isSampleCoverageCase || m_isSampleMaskCase) ? " and " : "")
783 << (m_isInvertedSampleCoverageCase ? "inverted " : "")
784 << (m_isSampleCoverageCase ? "sample coverage" : "")
785 << (m_isSampleCoverageCase && m_isSampleMaskCase ? " and " : "")
786 << (m_isSampleMaskCase ? "sample mask" : "")
788 << TestLog::EndMessage;
790 const int numQuadRowsCols = m_numSamples*4;
792 for (int row = 0; row < numQuadRowsCols; row++)
794 for (int col = 0; col < numQuadRowsCols; col++)
796 float x0 = (float)(col+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
797 float x1 = (float)(col+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
798 float y0 = (float)(row+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
799 float y1 = (float)(row+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
800 const Vec4 baseGreen (0.0f, 1.0f, 0.0f, 0.0f);
801 const Vec4 baseRed (1.0f, 0.0f, 0.0f, 0.0f);
802 Vec4 alpha0 (0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)col / (float)(numQuadRowsCols-1) : 1.0f);
803 Vec4 alpha1 (0.0f, 0.0f, 0.0f, m_isAlphaToCoverageCase ? (float)row / (float)(numQuadRowsCols-1) : 1.0f);
805 if (m_isSampleCoverageCase)
807 float value = (float)(row*numQuadRowsCols + col) / (float)(numQuadRowsCols*numQuadRowsCols-1);
808 gl.sampleCoverage(m_isInvertedSampleCoverageCase ? 1.0f - value : value, m_isInvertedSampleCoverageCase ? GL_TRUE : GL_FALSE);
809 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleCoverage");
812 if (m_isSampleMaskCase)
814 const int wordCount = getEffectiveSampleMaskWordCount(m_numSamples - 1);
815 const GLbitfield finalWordBits = m_numSamples - 32 * ((m_numSamples-1) / 32);
816 const GLbitfield finalWordMask = (GLbitfield)deBitMask32(0, (int)finalWordBits);
818 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
820 const GLbitfield mask = (GLbitfield)deUint32Hash((col << (m_numSamples / 2)) ^ row);
821 const bool isFinalWord = (wordNdx + 1) == wordCount;
822 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask prevents setting coverage bits higher than sample count
824 gl.sampleMaski(wordNdx, mask & maskMask);
825 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
829 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseGreen + alpha0, baseGreen + alpha1, baseGreen + alpha0, baseGreen + alpha1);
830 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseRed + alpha0, baseRed + alpha1, baseRed + alpha0, baseRed + alpha1);
834 readImage(renderedImg);
836 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
838 for (int y = 0; y < renderedImg.getHeight(); y++)
839 for (int x = 0; x < renderedImg.getWidth(); x++)
841 if (renderedImg.getPixel(x, y).getGreen() > 0)
843 log << TestLog::Message << "Failure: Non-zero green color component detected - should have been completely overwritten by red quad" << TestLog::EndMessage;
844 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
849 log << TestLog::Message
850 << "Success: Coverage mask appears to be constant at a given pixel coordinate with a given "
851 << (m_isAlphaToCoverageCase ? "alpha" : "")
852 << (m_isAlphaToCoverageCase && m_isSampleCoverageCase ? " and " : "")
853 << (m_isSampleCoverageCase ? "coverage value" : "")
854 << TestLog::EndMessage;
856 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
861 /*--------------------------------------------------------------------*//*!
862 * \brief Tests that unused bits of a sample mask have no effect
864 * Tests that the bits in the sample mask with positions higher than
865 * the number of samples do not have effect. In multisample fragment
866 * operations the sample mask is ANDed with the fragment coverage value.
867 * The coverage value cannot have the corresponding bits set.
869 * This is done by drawing a quads with varying sample masks and then
870 * redrawing the quads with identical masks but with the mask's high bits
871 * having different values. Only the latter quad pattern should be visible.
872 *//*--------------------------------------------------------------------*/
873 class SampleMaskHighBitsCase : public DefaultFBOMultisampleCase
876 SampleMaskHighBitsCase (Context& context, const char* name, const char* description);
877 ~SampleMaskHighBitsCase (void) {}
880 IterateResult iterate (void);
883 SampleMaskHighBitsCase::SampleMaskHighBitsCase (Context& context, const char* name, const char* description)
884 : DefaultFBOMultisampleCase(context, name, description, 256)
888 void SampleMaskHighBitsCase::init (void)
890 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
891 GLint maxSampleMaskWords = 0;
893 // check the test is even possible
894 gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
895 if (getEffectiveSampleMaskWordCount(m_numSamples - 1) > maxSampleMaskWords)
896 throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
899 DefaultFBOMultisampleCase::init();
902 SampleMaskHighBitsCase::IterateResult SampleMaskHighBitsCase::iterate (void)
904 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
905 TestLog& log = m_testCtx.getLog();
906 tcu::Surface renderedImg (m_viewportSize, m_viewportSize);
907 de::Random rnd (12345);
909 if (m_numSamples % 32 == 0)
911 log << TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << TestLog::EndMessage;
912 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Skipped");
918 log << TestLog::Message << "Clearing color to black" << TestLog::EndMessage;
919 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
920 gl.clear(GL_COLOR_BUFFER_BIT);
921 GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
923 gl.enable(GL_SAMPLE_MASK);
924 GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_MASK");
925 log << TestLog::Message << "GL_SAMPLE_MASK is enabled" << TestLog::EndMessage;
926 log << TestLog::Message << "Drawing several green quads, each fully overlapped by a red quad with the same effective sample mask values" << TestLog::EndMessage;
928 const int numQuadRowsCols = m_numSamples*4;
930 for (int row = 0; row < numQuadRowsCols; row++)
932 for (int col = 0; col < numQuadRowsCols; col++)
934 float x0 = (float)(col+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
935 float x1 = (float)(col+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
936 float y0 = (float)(row+0) / (float)numQuadRowsCols * 2.0f - 1.0f;
937 float y1 = (float)(row+1) / (float)numQuadRowsCols * 2.0f - 1.0f;
938 const Vec4 baseGreen (0.0f, 1.0f, 0.0f, 1.0f);
939 const Vec4 baseRed (1.0f, 0.0f, 0.0f, 1.0f);
941 const int wordCount = getEffectiveSampleMaskWordCount(m_numSamples - 1);
942 const GLbitfield finalWordBits = m_numSamples - 32 * ((m_numSamples-1) / 32);
943 const GLbitfield finalWordMask = (GLbitfield)deBitMask32(0, (int)finalWordBits);
945 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
947 const GLbitfield mask = (GLbitfield)deUint32Hash((col << (m_numSamples / 2)) ^ row);
948 const bool isFinalWord = (wordNdx + 1) == wordCount;
949 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask is 1 on bits in lower positions than sample count
950 const GLbitfield highBits = rnd.getUint32();
952 gl.sampleMaski(wordNdx, (mask & maskMask) | (highBits & ~maskMask));
953 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
955 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseGreen, baseGreen, baseGreen, baseGreen);
957 for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
959 const GLbitfield mask = (GLbitfield)deUint32Hash((col << (m_numSamples / 2)) ^ row);
960 const bool isFinalWord = (wordNdx + 1) == wordCount;
961 const GLbitfield maskMask = (isFinalWord) ? (finalWordMask) : (0xFFFFFFFFUL); // maskMask is 1 on bits in lower positions than sample count
962 const GLbitfield highBits = rnd.getUint32();
964 gl.sampleMaski(wordNdx, (mask & maskMask) | (highBits & ~maskMask));
965 GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
967 renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseRed, baseRed, baseRed, baseRed);
971 readImage(renderedImg);
973 log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
975 for (int y = 0; y < renderedImg.getHeight(); y++)
976 for (int x = 0; x < renderedImg.getWidth(); x++)
978 if (renderedImg.getPixel(x, y).getGreen() > 0)
980 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;
981 m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits modified mask");
986 log << TestLog::Message << "Success: Coverage mask high bits appear to have no effect." << TestLog::EndMessage;
987 m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
994 MultisampleTests::MultisampleTests (Context& context)
995 : TestCaseGroup(context, "multisample", "Multisample tests")
999 MultisampleTests::~MultisampleTests (void)
1003 void MultisampleTests::init (void)
1005 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "default_framebuffer", "Test with default framebuffer");
1009 // .default_framebuffer
1012 group->addChild(new SamplePosQueryCase (m_context, "sample_position", "test SAMPLE_POSITION"));
1015 group->addChild(new MaskInvertCase (m_context, "sample_mask_sum_of_inverses", "Test that mask and its negation's sum equal the fully set mask"));
1016 group->addChild(new MaskProportionalityCase (m_context, "proportionality_sample_mask", "Test the proportionality property of GL_SAMPLE_MASK"));
1018 group->addChild(new MaskConstancyCase (m_context, "constancy_sample_mask",
1019 "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_MASK",
1020 MaskConstancyCase::CASEBIT_SAMPLE_MASK));
1021 group->addChild(new MaskConstancyCase (m_context, "constancy_alpha_to_coverage_sample_mask",
1022 "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",
1023 MaskConstancyCase::CASEBIT_ALPHA_TO_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_MASK));
1024 group->addChild(new MaskConstancyCase (m_context, "constancy_sample_coverage_sample_mask",
1025 "Test that coverage mask is constant at given coordinates with a given alpha or coverage value, using GL_SAMPLE_COVERAGE and GL_SAMPLE_MASK",
1026 MaskConstancyCase::CASEBIT_SAMPLE_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_MASK));
1027 group->addChild(new MaskConstancyCase (m_context, "constancy_alpha_to_coverage_sample_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, GL_SAMPLE_COVERAGE and GL_SAMPLE_MASK",
1029 MaskConstancyCase::CASEBIT_ALPHA_TO_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_COVERAGE | MaskConstancyCase::CASEBIT_SAMPLE_MASK));
1030 group->addChild(new SampleMaskHighBitsCase (m_context, "sample_mask_non_effective_bits",
1031 "Test that values of unused bits of a sample mask (bit index > sample count) have no effect"));