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