Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.1 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Multisample tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fMultisampleTests.hpp"
     25 #include "tcuRenderTarget.hpp"
     26 #include "tcuVector.hpp"
     27 #include "tcuSurface.hpp"
     28 #include "tcuImageCompare.hpp"
     29 #include "tcuStringTemplate.hpp"
     30 #include "gluPixelTransfer.hpp"
     31 #include "gluRenderContext.hpp"
     32 #include "gluCallLogWrapper.hpp"
     33 #include "gluObjectWrapper.hpp"
     34 #include "gluShaderProgram.hpp"
     35 #include "glwFunctions.hpp"
     36 #include "glwEnums.hpp"
     37 #include "deRandom.hpp"
     38 #include "deStringUtil.hpp"
     39 #include "deString.h"
     40 #include "deMath.h"
     41 
     42 using namespace glw;
     43 
     44 using tcu::TestLog;
     45 using tcu::Vec2;
     46 using tcu::Vec3;
     47 using tcu::Vec4;
     48 
     49 namespace deqp
     50 {
     51 namespace gles31
     52 {
     53 namespace Functional
     54 {
     55 namespace
     56 {
     57 
     58 using std::map;
     59 using std::string;
     60 
     61 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits)
     62 {
     63 	std::string result(numBits, '0');
     64 
     65 	// move from back to front and set chars to 1
     66 	for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx)
     67 	{
     68 		for (int bit = 0; bit < 32; ++bit)
     69 		{
     70 			const int targetCharNdx = numBits - (wordNdx*32+bit) - 1;
     71 
     72 			// beginning of the string reached
     73 			if (targetCharNdx < 0)
     74 				return result;
     75 
     76 			if ((bitfield[wordNdx] >> bit) & 0x01)
     77 				result[targetCharNdx] = '1';
     78 		}
     79 	}
     80 
     81 	return result;
     82 }
     83 
     84 /*--------------------------------------------------------------------*//*!
     85  * \brief Returns the number of words needed to represent mask of given length
     86  *//*--------------------------------------------------------------------*/
     87 static int getEffectiveSampleMaskWordCount (int highestBitNdx)
     88 {
     89 	const int wordSize	= 32;
     90 	const int maskLen	= highestBitNdx + 1;
     91 
     92 	return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len /  wordSize)
     93 }
     94 
     95 /*--------------------------------------------------------------------*//*!
     96  * \brief Creates sample mask with all less significant bits than nthBit set
     97  *//*--------------------------------------------------------------------*/
     98 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit)
     99 {
    100 	const int				wordSize	= 32;
    101 	const int				numWords	= getEffectiveSampleMaskWordCount(nthBit - 1);
    102 	const deUint32			topWordBits	= (deUint32)(nthBit - (numWords - 1) * wordSize);
    103 	std::vector<deUint32>	mask		(numWords);
    104 
    105 	for (int ndx = 0; ndx < numWords - 1; ++ndx)
    106 		mask[ndx] = 0xFFFFFFFF;
    107 
    108 	mask[numWords - 1] = deBitMask32(0, (int)topWordBits);
    109 	return mask;
    110 }
    111 
    112 class SamplePosQueryCase : public TestCase
    113 {
    114 public:
    115 					SamplePosQueryCase (Context& context, const char* name, const char* desc);
    116 private:
    117 	void			init				(void);
    118 	IterateResult	iterate				(void);
    119 };
    120 
    121 SamplePosQueryCase::SamplePosQueryCase (Context& context, const char* name, const char* desc)
    122 	: TestCase(context, name, desc)
    123 {
    124 }
    125 
    126 void SamplePosQueryCase::init (void)
    127 {
    128 	if (m_context.getRenderTarget().getNumSamples() == 0)
    129 		throw tcu::NotSupportedError("No multisample buffers");
    130 }
    131 
    132 SamplePosQueryCase::IterateResult SamplePosQueryCase::iterate (void)
    133 {
    134 	glu::CallLogWrapper gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    135 	bool				error	= false;
    136 
    137 	gl.enableLogging(true);
    138 
    139 	for (int ndx = 0; ndx < m_context.getRenderTarget().getNumSamples(); ++ndx)
    140 	{
    141 		tcu::Vec2 samplePos = tcu::Vec2(-1, -1);
    142 
    143 		gl.glGetMultisamplefv(GL_SAMPLE_POSITION, ndx, samplePos.getPtr());
    144 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "getMultisamplefv");
    145 
    146 		// check value range
    147 		if (samplePos.x() < 0.0f || samplePos.x() > 1.0f ||
    148 			samplePos.y() < 0.0f || samplePos.y() > 1.0f)
    149 		{
    150 			m_testCtx.getLog() << tcu::TestLog::Message << "Sample " << ndx << " is not in valid range [0,1], got " << samplePos << tcu::TestLog::EndMessage;
    151 			error = true;
    152 		}
    153 	}
    154 
    155 	if (!error)
    156 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    157 	else
    158 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid sample pos");
    159 
    160 	return STOP;
    161 }
    162 
    163 /*--------------------------------------------------------------------*//*!
    164  * \brief Abstract base class handling common stuff for default fbo multisample cases.
    165  *//*--------------------------------------------------------------------*/
    166 class DefaultFBOMultisampleCase : public TestCase
    167 {
    168 public:
    169 								DefaultFBOMultisampleCase	(Context& context, const char* name, const char* desc, int desiredViewportSize);
    170 	virtual						~DefaultFBOMultisampleCase	(void);
    171 
    172 	virtual void				init						(void);
    173 	virtual void				deinit						(void);
    174 
    175 protected:
    176 	void						renderTriangle				(const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const;
    177 	void						renderTriangle				(const 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;
    181 
    182 	void						randomizeViewport			(void);
    183 	void						readImage					(tcu::Surface& dst) const;
    184 
    185 	int							m_numSamples;
    186 
    187 	int							m_viewportSize;
    188 
    189 private:
    190 								DefaultFBOMultisampleCase	(const DefaultFBOMultisampleCase& other);
    191 	DefaultFBOMultisampleCase&	operator=					(const DefaultFBOMultisampleCase& other);
    192 
    193 	const int					m_desiredViewportSize;
    194 
    195 	glu::ShaderProgram*			m_program;
    196 	int							m_attrPositionLoc;
    197 	int							m_attrColorLoc;
    198 
    199 	int							m_viewportX;
    200 	int							m_viewportY;
    201 	de::Random					m_rnd;
    202 
    203 	bool						m_initCalled;
    204 };
    205 
    206 DefaultFBOMultisampleCase::DefaultFBOMultisampleCase (Context& context, const char* name, const char* desc, int desiredViewportSize)
    207 	: TestCase				(context, name, desc)
    208 	, m_numSamples			(0)
    209 	, m_viewportSize		(0)
    210 	, m_desiredViewportSize	(desiredViewportSize)
    211 	, m_program				(DE_NULL)
    212 	, m_attrPositionLoc		(-1)
    213 	, m_attrColorLoc		(-1)
    214 	, m_viewportX			(0)
    215 	, m_viewportY			(0)
    216 	, m_rnd					(deStringHash(name))
    217 	, m_initCalled			(false)
    218 {
    219 }
    220 
    221 DefaultFBOMultisampleCase::~DefaultFBOMultisampleCase (void)
    222 {
    223 	DefaultFBOMultisampleCase::deinit();
    224 }
    225 
    226 void DefaultFBOMultisampleCase::init (void)
    227 {
    228 	const bool					isES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
    229 	map<string, string>			args;
    230 	args["GLSL_VERSION_DECL"] = isES32 ? getGLSLVersionDeclaration(glu::GLSL_VERSION_320_ES) : getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES);
    231 
    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"
    237 		"void main()\n"
    238 		"{\n"
    239 		"	gl_Position = a_position;\n"
    240 		"	v_color = a_color;\n"
    241 		"}\n";
    242 
    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"
    247 		"void main()\n"
    248 		"{\n"
    249 		"	o_color = v_color;\n"
    250 		"}\n";
    251 
    252 	TestLog&				log	= m_testCtx.getLog();
    253 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
    254 
    255 	if (m_context.getRenderTarget().getNumSamples() <= 1)
    256 		throw tcu::NotSupportedError("No multisample buffers");
    257 
    258 	m_initCalled = true;
    259 
    260 	// Query and log number of samples per pixel.
    261 
    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;
    265 
    266 	// Prepare program.
    267 
    268 	DE_ASSERT(!m_program);
    269 
    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__);
    275 
    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");
    279 
    280 	if (m_attrPositionLoc < 0 || m_attrColorLoc < 0)
    281 	{
    282 		delete m_program;
    283 		throw tcu::TestError("Invalid attribute locations", DE_NULL, __FILE__, __LINE__);
    284 	}
    285 
    286 	// Get suitable viewport size.
    287 
    288 	m_viewportSize = de::min<int>(m_desiredViewportSize, de::min(m_context.getRenderTarget().getWidth(), m_context.getRenderTarget().getHeight()));
    289 	randomizeViewport();
    290 }
    291 
    292 void DefaultFBOMultisampleCase::deinit (void)
    293 {
    294 	// Do not try to call GL functions during case list creation
    295 	if (!m_initCalled)
    296 		return;
    297 
    298 	delete m_program;
    299 	m_program = DE_NULL;
    300 }
    301 
    302 void DefaultFBOMultisampleCase::renderTriangle (const Vec3& p0, const Vec3& p1, const Vec3& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
    303 {
    304 	const float vertexPositions[] =
    305 	{
    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
    309 	};
    310 	const float vertexColors[] =
    311 	{
    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(),
    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 
    346 void DefaultFBOMultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& c0, const Vec4& c1, const Vec4& c2) const
    347 {
    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),
    351 				   c0, c1, c2);
    352 }
    353 
    354 void DefaultFBOMultisampleCase::renderTriangle (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec4& color) const
    355 {
    356 	renderTriangle(p0, p1, p2, color, color, color);
    357 }
    358 
    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
    360 {
    361 	renderTriangle(p0, p1, p2, c0, c1, c2);
    362 	renderTriangle(p2, p1, p3, c2, c1, c3);
    363 }
    364 
    365 void DefaultFBOMultisampleCase::renderQuad (const Vec2& p0, const Vec2& p1, const Vec2& p2, const Vec2& p3, const Vec4& color) const
    366 {
    367 	renderQuad(p0, p1, p2, p3, color, color, color, color);
    368 }
    369 
    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 
    381 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);
    401 					~MaskInvertCase				(void) {}
    402 
    403 	void			init						(void);
    404 	IterateResult	iterate						(void);
    405 
    406 private:
    407 	void			drawPattern					(bool invert) const;
    408 };
    409 
    410 MaskInvertCase::MaskInvertCase (Context& context, const char* name, const char* description)
    411 	: DefaultFBOMultisampleCase	(context, name, description, 256)
    412 {
    413 }
    414 
    415 void MaskInvertCase::init (void)
    416 {
    417 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    418 
    419 	// check the test is even possible
    420 
    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");
    425 
    426 	// normal init
    427 	DefaultFBOMultisampleCase::init();
    428 }
    429 
    430 MaskInvertCase::IterateResult MaskInvertCase::iterate (void)
    431 {
    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);
    436 
    437 	randomizeViewport();
    438 
    439 	gl.enable(GL_BLEND);
    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;
    444 
    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");
    449 
    450 	log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK disabled" << TestLog::EndMessage;
    451 	drawPattern(false);
    452 	readImage(renderedImgNoSampleCoverage);
    453 
    454 	log << TestLog::Image("RenderedImageNoSampleMask", "Rendered image with GL_SAMPLE_MASK disabled", renderedImgNoSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
    455 
    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");
    459 
    460 	gl.enable(GL_SAMPLE_MASK);
    461 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEnable(GL_SAMPLE_MASK)");
    462 
    463 	log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK enabled, using non-inverted sample masks" << TestLog::EndMessage;
    464 	drawPattern(false);
    465 	log << TestLog::Message << "Drawing the pattern with GL_SAMPLE_MASK enabled, using inverted sample masks" << TestLog::EndMessage;
    466 	drawPattern(true);
    467 
    468 	readImage(renderedImgSampleCoverage);
    469 
    470 	log << TestLog::Image("RenderedImageSampleMask", "Rendered image with GL_SAMPLE_MASK enabled", renderedImgSampleCoverage, QP_IMAGE_COMPRESSION_MODE_PNG);
    471 
    472 	bool passed = tcu::pixelThresholdCompare(log,
    473 											 "CoverageVsNoCoverage",
    474 											 "Comparison of same pattern with GL_SAMPLE_MASK disabled and enabled",
    475 											 renderedImgNoSampleCoverage,
    476 											 renderedImgSampleCoverage,
    477 											 tcu::RGBA(0),
    478 											 tcu::COMPARE_LOG_ON_ERROR);
    479 
    480 	if (passed)
    481 		log << TestLog::Message << "Success: The two images rendered are identical" << TestLog::EndMessage;
    482 
    483 	m_context.getTestContext().setTestResult(passed ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    484 											 passed ? "Passed"				: "Failed");
    485 
    486 	return STOP;
    487 }
    488 
    489 void MaskInvertCase::drawPattern (bool invert) const
    490 {
    491 	const int				numTriangles	= 25;
    492 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
    493 
    494 	for (int triNdx = 0; triNdx < numTriangles; triNdx++)
    495 	{
    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);
    502 
    503 
    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);
    507 
    508 		for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
    509 		{
    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
    514 
    515 			gl.sampleMaski(wordNdx, mask & maskMask);
    516 		}
    517 		GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
    518 
    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),
    522 					   color);
    523 	}
    524 }
    525 
    526 /*--------------------------------------------------------------------*//*!
    527  * \brief Tests coverage mask generation proportionality property.
    528  *
    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
    535 {
    536 public:
    537 					MaskProportionalityCase				(Context& context, const char* name, const char* description);
    538 					~MaskProportionalityCase			(void) {}
    539 
    540 	void			init								(void);
    541 
    542 	IterateResult	iterate								(void);
    543 
    544 private:
    545 	int				m_numIterations;
    546 	int				m_currentIteration;
    547 
    548 	deInt32			m_previousIterationColorSum;
    549 };
    550 
    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)
    556 {
    557 }
    558 
    559 void MaskProportionalityCase::init (void)
    560 {
    561 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
    562 	TestLog&				log	= m_testCtx.getLog();
    563 
    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");
    569 
    570 	DefaultFBOMultisampleCase::init();
    571 
    572 	// set state
    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;
    576 
    577 	m_numIterations = m_numSamples + 1;
    578 
    579 	randomizeViewport(); // \note Using the same viewport for every iteration since coverage mask may depend on window-relative pixel coordinate.
    580 }
    581 
    582 MaskProportionalityCase::IterateResult MaskProportionalityCase::iterate (void)
    583 {
    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();
    588 
    589 	DE_ASSERT(m_numIterations >= 0);
    590 
    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");
    596 
    597 	// Draw quad.
    598 
    599 	{
    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);
    606 
    607 		DE_ASSERT(m_currentIteration <= m_numSamples + 1);
    608 
    609 		log << TestLog::Message << "Drawing a red quad using sample mask 0b" << sampleMaskToString(sampleMask, m_numSamples) << TestLog::EndMessage;
    610 
    611 		for (int wordNdx = 0; wordNdx < getEffectiveSampleMaskWordCount(m_numSamples - 1); ++wordNdx)
    612 		{
    613 			const GLbitfield mask = (wordNdx < (int)sampleMask.size()) ? ((GLbitfield)(sampleMask[wordNdx])) : (0);
    614 
    615 			gl.sampleMaski(wordNdx, mask);
    616 			GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
    617 		}
    618 
    619 		renderQuad(pt0, pt1, pt2, pt3, quadColor);
    620 	}
    621 
    622 	// Read ang log image.
    623 
    624 	readImage(renderedImg);
    625 
    626 	log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
    627 
    628 	// Compute average red component in rendered image.
    629 
    630 	deInt32 sumRed = 0;
    631 
    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();
    635 
    636 	log << TestLog::Message << "Average red color component: " << de::floatToString((float)sumRed / 255.0f / (float)numPixels, 2) << TestLog::EndMessage;
    637 
    638 	// Check if average color has decreased from previous frame's color.
    639 
    640 	if (sumRed < m_previousIterationColorSum)
    641 	{
    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");
    644 		return STOP;
    645 	}
    646 
    647 	// Check if coverage mask is not all-zeros if alpha or coverage value is 0 (or 1, if inverted).
    648 
    649 	if (m_currentIteration == 0 && sumRed != 0)
    650 	{
    651 		log << TestLog::Message << "Failure: Image should be completely black" << TestLog::EndMessage;
    652 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
    653 		return STOP;
    654 	}
    655 
    656 	if (m_currentIteration == m_numIterations-1 && sumRed != 0xff*numPixels)
    657 	{
    658 		log << TestLog::Message << "Failure: Image should be completely red" << TestLog::EndMessage;
    659 
    660 		m_context.getTestContext().setTestResult(QP_TEST_RESULT_FAIL, "Failed");
    661 		return STOP;
    662 	}
    663 
    664 	m_previousIterationColorSum = sumRed;
    665 
    666 	m_currentIteration++;
    667 
    668 	if (m_currentIteration >= m_numIterations)
    669 	{
    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");
    672 		return STOP;
    673 	}
    674 	else
    675 		return CONTINUE;
    676 }
    677 
    678 /*--------------------------------------------------------------------*//*!
    679  * \brief Tests coverage mask generation constancy property.
    680  *
    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
    688 {
    689 public:
    690 	enum CaseBits
    691 	{
    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.
    696 	};
    697 
    698 					MaskConstancyCase			(Context& context, const char* name, const char* description, deUint32 typeBits);
    699 					~MaskConstancyCase			(void) {}
    700 
    701 	void			init						(void);
    702 	IterateResult	iterate						(void);
    703 
    704 private:
    705 	const bool		m_isAlphaToCoverageCase;
    706 	const bool		m_isSampleCoverageCase;
    707 	const bool		m_isInvertedSampleCoverageCase;
    708 	const bool		m_isSampleMaskCase;
    709 };
    710 
    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))
    717 {
    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
    721 }
    722 
    723 void MaskConstancyCase::init (void)
    724 {
    725 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    726 
    727 	// check the test is even possible
    728 	if (m_isSampleMaskCase)
    729 	{
    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");
    734 	}
    735 
    736 	// normal init
    737 	DefaultFBOMultisampleCase::init();
    738 }
    739 
    740 MaskConstancyCase::IterateResult MaskConstancyCase::iterate (void)
    741 {
    742 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
    743 	TestLog&				log				= m_testCtx.getLog();
    744 	tcu::Surface			renderedImg		(m_viewportSize, m_viewportSize);
    745 
    746 	randomizeViewport();
    747 
    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");
    752 
    753 	if (m_isAlphaToCoverageCase)
    754 	{
    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");
    758 
    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;
    761 	}
    762 
    763 	if (m_isSampleCoverageCase)
    764 	{
    765 		gl.enable(GL_SAMPLE_COVERAGE);
    766 		GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_COVERAGE");
    767 
    768 		log << TestLog::Message << "GL_SAMPLE_COVERAGE is enabled" << TestLog::EndMessage;
    769 	}
    770 
    771 	if (m_isSampleMaskCase)
    772 	{
    773 		gl.enable(GL_SAMPLE_MASK);
    774 		GLU_EXPECT_NO_ERROR(gl.getError(), "enable GL_SAMPLE_MASK");
    775 
    776 		log << TestLog::Message << "GL_SAMPLE_MASK is enabled" << TestLog::EndMessage;
    777 	}
    778 
    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" : "")
    787 		<< " values"
    788 		<< TestLog::EndMessage;
    789 
    790 	const int numQuadRowsCols = m_numSamples*4;
    791 
    792 	for (int row = 0; row < numQuadRowsCols; row++)
    793 	{
    794 		for (int col = 0; col < numQuadRowsCols; col++)
    795 		{
    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);
    804 
    805 			if (m_isSampleCoverageCase)
    806 			{
    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");
    810 			}
    811 
    812 			if (m_isSampleMaskCase)
    813 			{
    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);
    817 
    818 				for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
    819 				{
    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
    823 
    824 					gl.sampleMaski(wordNdx, mask & maskMask);
    825 					GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
    826 				}
    827 			}
    828 
    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);
    831 		}
    832 	}
    833 
    834 	readImage(renderedImg);
    835 
    836 	log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
    837 
    838 	for (int y = 0; y < renderedImg.getHeight(); y++)
    839 	for (int x = 0; x < renderedImg.getWidth(); x++)
    840 	{
    841 		if (renderedImg.getPixel(x, y).getGreen() > 0)
    842 		{
    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");
    845 			return STOP;
    846 		}
    847 	}
    848 
    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;
    855 
    856 	m_context.getTestContext().setTestResult(QP_TEST_RESULT_PASS, "Passed");
    857 
    858 	return STOP;
    859 }
    860 
    861 /*--------------------------------------------------------------------*//*!
    862  * \brief Tests that unused bits of a sample mask have no effect
    863  *
    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.
    868  *
    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
    874 {
    875 public:
    876 					SampleMaskHighBitsCase		(Context& context, const char* name, const char* description);
    877 					~SampleMaskHighBitsCase		(void) {}
    878 
    879 	void			init						(void);
    880 	IterateResult	iterate						(void);
    881 };
    882 
    883 SampleMaskHighBitsCase::SampleMaskHighBitsCase (Context& context, const char* name, const char* description)
    884 	: DefaultFBOMultisampleCase(context, name, description, 256)
    885 {
    886 }
    887 
    888 void SampleMaskHighBitsCase::init (void)
    889 {
    890 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
    891 	GLint					 maxSampleMaskWords	= 0;
    892 
    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");
    897 
    898 	// normal init
    899 	DefaultFBOMultisampleCase::init();
    900 }
    901 
    902 SampleMaskHighBitsCase::IterateResult SampleMaskHighBitsCase::iterate (void)
    903 {
    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);
    908 
    909 	if (m_numSamples % 32 == 0)
    910 	{
    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");
    913 		return STOP;
    914 	}
    915 
    916 	randomizeViewport();
    917 
    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");
    922 
    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;
    927 
    928 	const int numQuadRowsCols = m_numSamples*4;
    929 
    930 	for (int row = 0; row < numQuadRowsCols; row++)
    931 	{
    932 		for (int col = 0; col < numQuadRowsCols; col++)
    933 		{
    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);
    940 
    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);
    944 
    945 			for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
    946 			{
    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();
    951 
    952 				gl.sampleMaski(wordNdx, (mask & maskMask) | (highBits & ~maskMask));
    953 				GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
    954 			}
    955 			renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseGreen, baseGreen, baseGreen, baseGreen);
    956 
    957 			for (int wordNdx = 0; wordNdx < wordCount; ++wordNdx)
    958 			{
    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();
    963 
    964 				gl.sampleMaski(wordNdx, (mask & maskMask) | (highBits & ~maskMask));
    965 				GLU_EXPECT_NO_ERROR(gl.getError(), "glSampleMaski");
    966 			}
    967 			renderQuad(Vec2(x0, y0), Vec2(x1, y0), Vec2(x0, y1), Vec2(x1, y1), baseRed, baseRed, baseRed, baseRed);
    968 		}
    969 	}
    970 
    971 	readImage(renderedImg);
    972 
    973 	log << TestLog::Image("RenderedImage", "Rendered image", renderedImg, QP_IMAGE_COMPRESSION_MODE_PNG);
    974 
    975 	for (int y = 0; y < renderedImg.getHeight(); y++)
    976 	for (int x = 0; x < renderedImg.getWidth(); x++)
    977 	{
    978 		if (renderedImg.getPixel(x, y).getGreen() > 0)
    979 		{
    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");
    982 			return STOP;
    983 		}
    984 	}
    985 
    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");
    988 
    989 	return STOP;
    990 }
    991 
    992 } // anonymous
    993 
    994 MultisampleTests::MultisampleTests (Context& context)
    995 	: TestCaseGroup(context, "multisample", "Multisample tests")
    996 {
    997 }
    998 
    999 MultisampleTests::~MultisampleTests (void)
   1000 {
   1001 }
   1002 
   1003 void MultisampleTests::init (void)
   1004 {
   1005 	tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "default_framebuffer", "Test with default framebuffer");
   1006 
   1007 	addChild(group);
   1008 
   1009 	// .default_framebuffer
   1010 	{
   1011 		// sample positions
   1012 		group->addChild(new SamplePosQueryCase			(m_context, "sample_position", "test SAMPLE_POSITION"));
   1013 
   1014 		// sample mask
   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"));
   1017 
   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"));
   1032 	}
   1033 }
   1034 
   1035 } // Functional
   1036 } // gles31
   1037 } // deqp
   1038