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