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