es31fMultisampleTests.cpp revision 3c827367444ee418f129b2c238299f49d3264554
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
41using namespace glw;
42
43using tcu::TestLog;
44using tcu::Vec2;
45using tcu::Vec3;
46using tcu::Vec4;
47
48namespace deqp
49{
50namespace gles31
51{
52namespace Functional
53{
54namespace
55{
56
57static 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 *//*--------------------------------------------------------------------*/
83static 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 *//*--------------------------------------------------------------------*/
94static 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
108class SamplePosQueryCase : public TestCase
109{
110public:
111					SamplePosQueryCase (Context& context, const char* name, const char* desc);
112private:
113	void			init				(void);
114	IterateResult	iterate				(void);
115};
116
117SamplePosQueryCase::SamplePosQueryCase (Context& context, const char* name, const char* desc)
118	: TestCase(context, name, desc)
119{
120}
121
122void SamplePosQueryCase::init (void)
123{
124	if (m_context.getRenderTarget().getNumSamples() == 0)
125		throw tcu::NotSupportedError("No multisample buffers");
126}
127
128SamplePosQueryCase::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 *//*--------------------------------------------------------------------*/
162class DefaultFBOMultisampleCase : public TestCase
163{
164public:
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
171protected:
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
186private:
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
203DefaultFBOMultisampleCase::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
218DefaultFBOMultisampleCase::~DefaultFBOMultisampleCase (void)
219{
220	DefaultFBOMultisampleCase::deinit();
221}
222
223void 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
283void 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
293void 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
337void 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
342void 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
350void 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
355void 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
361void 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
366void 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
377void 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 *//*--------------------------------------------------------------------*/
393class MaskInvertCase : public DefaultFBOMultisampleCase
394{
395public:
396					MaskInvertCase				(Context& context, const char* name, const char* description);
397					~MaskInvertCase				(void) {}
398
399	void			init						(void);
400	IterateResult	iterate						(void);
401
402private:
403	void			drawPattern					(bool invert) const;
404};
405
406MaskInvertCase::MaskInvertCase (Context& context, const char* name, const char* description)
407	: DefaultFBOMultisampleCase	(context, name, description, 256)
408{
409}
410
411void 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
426MaskInvertCase::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
485void 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 *//*--------------------------------------------------------------------*/
530class MaskProportionalityCase : public DefaultFBOMultisampleCase
531{
532public:
533					MaskProportionalityCase				(Context& context, const char* name, const char* description);
534					~MaskProportionalityCase			(void) {}
535
536	void			init								(void);
537
538	IterateResult	iterate								(void);
539
540private:
541	int				m_numIterations;
542	int				m_currentIteration;
543
544	deInt32			m_previousIterationColorSum;
545};
546
547MaskProportionalityCase::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
555void 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
578MaskProportionalityCase::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 *//*--------------------------------------------------------------------*/
683class MaskConstancyCase : public DefaultFBOMultisampleCase
684{
685public:
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);
695					~MaskConstancyCase			(void) {}
696
697	void			init						(void);
698	IterateResult	iterate						(void);
699
700private:
701	const bool		m_isAlphaToCoverageCase;
702	const bool		m_isSampleCoverageCase;
703	const bool		m_isInvertedSampleCoverageCase;
704	const bool		m_isSampleMaskCase;
705};
706
707MaskConstancyCase::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
719void 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
736MaskConstancyCase::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 *//*--------------------------------------------------------------------*/
869class SampleMaskHighBitsCase : public DefaultFBOMultisampleCase
870{
871public:
872					SampleMaskHighBitsCase		(Context& context, const char* name, const char* description);
873					~SampleMaskHighBitsCase		(void) {}
874
875	void			init						(void);
876	IterateResult	iterate						(void);
877};
878
879SampleMaskHighBitsCase::SampleMaskHighBitsCase (Context& context, const char* name, const char* description)
880	: DefaultFBOMultisampleCase(context, name, description, 256)
881{
882}
883
884void 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
898SampleMaskHighBitsCase::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
990MultisampleTests::MultisampleTests (Context& context)
991	: TestCaseGroup(context, "multisample", "Multisample tests")
992{
993}
994
995MultisampleTests::~MultisampleTests (void)
996{
997}
998
999void 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