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