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 Sample variable tests
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fSampleVariableTests.hpp"
25#include "es31fMultisampleShaderRenderCase.hpp"
26#include "tcuSurface.hpp"
27#include "tcuTestLog.hpp"
28#include "tcuRenderTarget.hpp"
29#include "tcuTextureUtil.hpp"
30#include "tcuVectorUtil.hpp"
31#include "tcuFormatUtil.hpp"
32#include "gluContextInfo.hpp"
33#include "gluShaderProgram.hpp"
34#include "gluRenderContext.hpp"
35#include "glwFunctions.hpp"
36#include "glwEnums.hpp"
37#include "deStringUtil.hpp"
38
39namespace deqp
40{
41namespace gles31
42{
43namespace Functional
44{
45namespace
46{
47
48class Verifier
49{
50public:
51	virtual bool	verify	(const tcu::RGBA& testColor, const tcu::IVec2& position) const = 0;
52	virtual void	logInfo	(tcu::TestLog& log) const = 0;
53};
54
55class ColorVerifier : public Verifier
56{
57public:
58	ColorVerifier (const tcu::Vec3& _color, int _threshold = 8)
59		: m_color		(tcu::Vec4(_color.x(), _color.y(), _color.z(), 1.0f))
60		, m_threshold	(tcu::IVec3(_threshold))
61	{
62	}
63
64	ColorVerifier (const tcu::Vec3& _color, tcu::IVec3 _threshold)
65		: m_color		(tcu::Vec4(_color.x(), _color.y(), _color.z(), 1.0f))
66		, m_threshold	(_threshold)
67	{
68	}
69
70	bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
71	{
72		DE_UNREF(position);
73		return !tcu::boolAny(tcu::greaterThan(tcu::abs(m_color.toIVec().swizzle(0, 1, 2) - testColor.toIVec().swizzle(0, 1, 2)), tcu::IVec3(m_threshold)));
74	}
75
76	void logInfo (tcu::TestLog& log) const
77	{
78		// full threshold? print * for clarity
79		log	<< tcu::TestLog::Message
80			<< "Expecting unicolored image, color = RGB("
81			<< ((m_threshold[0] >= 255) ? ("*") : (de::toString(m_color.getRed()))) << ", "
82			<< ((m_threshold[1] >= 255) ? ("*") : (de::toString(m_color.getGreen()))) << ", "
83			<< ((m_threshold[2] >= 255) ? ("*") : (de::toString(m_color.getBlue()))) << ")"
84			<< tcu::TestLog::EndMessage;
85	}
86
87	const tcu::RGBA		m_color;
88	const tcu::IVec3	m_threshold;
89};
90
91class FullBlueSomeGreenVerifier : public Verifier
92{
93public:
94	FullBlueSomeGreenVerifier (void)
95	{
96	}
97
98	bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
99	{
100		DE_UNREF(position);
101
102		// Values from 0.0 and 1.0 are accurate
103
104		if (testColor.getRed() != 0)
105			return false;
106		if (testColor.getGreen() == 0)
107			return false;
108		if (testColor.getBlue() != 255)
109			return false;
110		return true;
111	}
112
113	void logInfo (tcu::TestLog& log) const
114	{
115		log << tcu::TestLog::Message << "Expecting color c = (0.0, x, 1.0), x > 0.0" << tcu::TestLog::EndMessage;
116	}
117};
118
119class NoRedVerifier : public Verifier
120{
121public:
122	NoRedVerifier (void)
123	{
124	}
125
126	bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
127	{
128		DE_UNREF(position);
129		return testColor.getRed() == 0;
130	}
131
132	void logInfo (tcu::TestLog& log) const
133	{
134		log << tcu::TestLog::Message << "Expecting zero-valued red channel." << tcu::TestLog::EndMessage;
135	}
136};
137
138class SampleAverageVerifier : public Verifier
139{
140public:
141				SampleAverageVerifier	(int _numSamples);
142
143	bool		verify					(const tcu::RGBA& testColor, const tcu::IVec2& position) const;
144	void		logInfo					(tcu::TestLog& log) const;
145
146	const int	m_numSamples;
147	const bool	m_isStatisticallySignificant;
148	float		m_distanceThreshold;
149};
150
151SampleAverageVerifier::SampleAverageVerifier (int _numSamples)
152	: m_numSamples					(_numSamples)
153	, m_isStatisticallySignificant	(_numSamples >= 4)
154	, m_distanceThreshold			(0.0f)
155{
156	// approximate Bates distribution as normal
157	const float variance			= (1.0f / (12.0f * m_numSamples));
158	const float standardDeviation	= deFloatSqrt(variance);
159
160	// 95% of means of sample positions are within 2 standard deviations if
161	// they were randomly assigned. Sample patterns are expected to be more
162	// uniform than a random pattern.
163	m_distanceThreshold = 2 * standardDeviation;
164}
165
166bool SampleAverageVerifier::verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
167{
168	DE_UNREF(position);
169	DE_ASSERT(m_isStatisticallySignificant);
170
171	const tcu::Vec2	avgPosition				(testColor.getGreen() / 255.0f, testColor.getBlue() / 255.0f);
172	const tcu::Vec2	distanceFromCenter		= tcu::abs(avgPosition - tcu::Vec2(0.5f, 0.5f));
173
174	return distanceFromCenter.x() < m_distanceThreshold && distanceFromCenter.y() < m_distanceThreshold;
175}
176
177void SampleAverageVerifier::logInfo (tcu::TestLog& log) const
178{
179	log << tcu::TestLog::Message << "Expecting average sample position to be near the pixel center. Maximum per-axis distance " << m_distanceThreshold << tcu::TestLog::EndMessage;
180}
181
182class PartialDiscardVerifier : public Verifier
183{
184public:
185	PartialDiscardVerifier (void)
186	{
187	}
188
189	bool verify (const tcu::RGBA& testColor, const tcu::IVec2& position) const
190	{
191		DE_UNREF(position);
192
193		return (testColor.getGreen() != 0) && (testColor.getGreen() != 255);
194	}
195
196	void logInfo (tcu::TestLog& log) const
197	{
198		log << tcu::TestLog::Message << "Expecting color non-zero and non-saturated green channel" << tcu::TestLog::EndMessage;
199	}
200};
201
202static bool verifyImageWithVerifier (const tcu::Surface& resultImage, tcu::TestLog& log, const Verifier& verifier, bool logOnSuccess = true)
203{
204	tcu::Surface	errorMask	(resultImage.getWidth(), resultImage.getHeight());
205	bool			error		= false;
206
207	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
208
209	if (logOnSuccess)
210	{
211		log << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
212		verifier.logInfo(log);
213	}
214
215	for (int y = 0; y < resultImage.getHeight(); ++y)
216	for (int x = 0; x < resultImage.getWidth(); ++x)
217	{
218		const tcu::RGBA color		= resultImage.getPixel(x, y);
219
220		// verify color value is valid for this pixel position
221		if (!verifier.verify(color, tcu::IVec2(x,y)))
222		{
223			error = true;
224			errorMask.setPixel(x, y, tcu::RGBA::red);
225		}
226	}
227
228	if (error)
229	{
230		// describe the verification logic if we haven't already
231		if (!logOnSuccess)
232			verifier.logInfo(log);
233
234		log	<< tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
235			<< tcu::TestLog::ImageSet("Verification", "Image Verification")
236			<< tcu::TestLog::Image("Result", "Result image", resultImage.getAccess())
237			<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
238			<< tcu::TestLog::EndImageSet;
239	}
240	else if (logOnSuccess)
241	{
242		log << tcu::TestLog::Message << "Image verification passed." << tcu::TestLog::EndMessage
243			<< tcu::TestLog::ImageSet("Verification", "Image Verification")
244			<< tcu::TestLog::Image("Result", "Result image", resultImage.getAccess())
245			<< tcu::TestLog::EndImageSet;
246	}
247
248	return !error;
249}
250
251class MultisampleRenderCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
252{
253public:
254						MultisampleRenderCase		(Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags = 0);
255	virtual				~MultisampleRenderCase		(void);
256
257	virtual void		init						(void);
258
259};
260
261MultisampleRenderCase::MultisampleRenderCase (Context& context, const char* name, const char* desc, int numSamples, RenderTarget target, int renderSize, int flags)
262	: MultisampleShaderRenderUtil::MultisampleRenderCase(context, name, desc, numSamples, target, renderSize, flags)
263{
264	DE_ASSERT(target < TARGET_LAST);
265}
266
267MultisampleRenderCase::~MultisampleRenderCase (void)
268{
269	MultisampleRenderCase::deinit();
270}
271
272void MultisampleRenderCase::init (void)
273{
274	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
275		throw tcu::NotSupportedError("Test requires GL_OES_sample_variables extension");
276
277	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
278}
279
280class NumSamplesCase : public MultisampleRenderCase
281{
282public:
283					NumSamplesCase				(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
284					~NumSamplesCase				(void);
285
286	std::string		genFragmentSource			(int numTargetSamples) const;
287	bool			verifyImage					(const tcu::Surface& resultImage);
288
289private:
290	enum
291	{
292		RENDER_SIZE = 64
293	};
294};
295
296NumSamplesCase::NumSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
297	: MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE)
298{
299}
300
301NumSamplesCase::~NumSamplesCase (void)
302{
303}
304
305std::string NumSamplesCase::genFragmentSource (int numTargetSamples) const
306{
307	std::ostringstream buf;
308
309	buf <<	"#version 310 es\n"
310			"#extension GL_OES_sample_variables : require\n"
311			"layout(location = 0) out mediump vec4 fragColor;\n"
312			"void main (void)\n"
313			"{\n"
314			"	fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
315			"	if (gl_NumSamples == " << numTargetSamples << ")\n"
316			"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
317			"}\n";
318
319	return buf.str();
320}
321
322bool NumSamplesCase::verifyImage (const tcu::Surface& resultImage)
323{
324	return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
325}
326
327class MaxSamplesCase : public MultisampleRenderCase
328{
329public:
330					MaxSamplesCase				(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
331					~MaxSamplesCase				(void);
332
333private:
334	void			preDraw						(void);
335	std::string		genFragmentSource			(int numTargetSamples) const;
336	bool			verifyImage					(const tcu::Surface& resultImage);
337
338	enum
339	{
340		RENDER_SIZE = 64
341	};
342};
343
344MaxSamplesCase::MaxSamplesCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
345	: MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE)
346{
347}
348
349MaxSamplesCase::~MaxSamplesCase (void)
350{
351}
352
353void MaxSamplesCase::preDraw (void)
354{
355	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
356	deInt32					maxSamples	= -1;
357
358	// query samples
359	{
360		gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
361		GLU_EXPECT_NO_ERROR(gl.getError(), "query GL_MAX_SAMPLES");
362
363		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
364	}
365
366	// set samples
367	{
368		const int maxSampleLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxSamples");
369		if (maxSampleLoc == -1)
370			throw tcu::TestError("Location of u_maxSamples was -1");
371
372		gl.uniform1i(maxSampleLoc, maxSamples);
373		GLU_EXPECT_NO_ERROR(gl.getError(), "set u_maxSamples uniform");
374
375		m_testCtx.getLog() << tcu::TestLog::Message << "Set u_maxSamples = " << maxSamples << tcu::TestLog::EndMessage;
376	}
377}
378
379std::string MaxSamplesCase::genFragmentSource (int numTargetSamples) const
380{
381	DE_UNREF(numTargetSamples);
382
383	std::ostringstream buf;
384
385	buf <<	"#version 310 es\n"
386			"#extension GL_OES_sample_variables : require\n"
387			"layout(location = 0) out mediump vec4 fragColor;\n"
388			"uniform mediump int u_maxSamples;\n"
389			"void main (void)\n"
390			"{\n"
391			"	fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
392			"	if (gl_MaxSamples == u_maxSamples)\n"
393			"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
394			"}\n";
395
396	return buf.str();
397}
398
399bool MaxSamplesCase::verifyImage (const tcu::Surface& resultImage)
400{
401	return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
402}
403
404class SampleIDCase : public MultisampleRenderCase
405{
406public:
407					SampleIDCase				(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
408					~SampleIDCase				(void);
409
410	void			init						(void);
411
412private:
413	std::string		genFragmentSource			(int numTargetSamples) const;
414	bool			verifyImage					(const tcu::Surface& resultImage);
415	bool			verifySampleBuffers			(const std::vector<tcu::Surface>& resultBuffers);
416
417	enum
418	{
419		RENDER_SIZE = 64
420	};
421	enum VerificationMode
422	{
423		VERIFY_USING_SAMPLES,
424		VERIFY_USING_SELECTION,
425	};
426
427	const VerificationMode	m_vericationMode;
428};
429
430SampleIDCase::SampleIDCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
431	: MultisampleRenderCase	(context, name, desc, sampleCount, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
432	, m_vericationMode		((target == TARGET_TEXTURE) ? (VERIFY_USING_SAMPLES) : (VERIFY_USING_SELECTION))
433{
434}
435
436SampleIDCase::~SampleIDCase (void)
437{
438}
439
440void SampleIDCase::init (void)
441{
442	// log the test method and expectations
443	if (m_vericationMode == VERIFY_USING_SAMPLES)
444		m_testCtx.getLog()
445			<< tcu::TestLog::Message
446			<< "Writing gl_SampleID to the green channel of the texture and verifying texture values, expecting:\n"
447			<< "	1) 0 with non-multisample targets.\n"
448			<< "	2) value N at sample index N of a multisample texture\n"
449			<< tcu::TestLog::EndMessage;
450	else if (m_vericationMode == VERIFY_USING_SELECTION)
451		m_testCtx.getLog()
452			<< tcu::TestLog::Message
453			<< "Selecting a single sample id for each pixel and writing color only if gl_SampleID == selected.\n"
454			<< "Expecting all output pixels to be partially (multisample) or fully (singlesample) colored.\n"
455			<< tcu::TestLog::EndMessage;
456	else
457		DE_ASSERT(false);
458
459	MultisampleRenderCase::init();
460}
461
462std::string SampleIDCase::genFragmentSource (int numTargetSamples) const
463{
464	DE_ASSERT(numTargetSamples != 0);
465
466	std::ostringstream buf;
467
468	if (m_vericationMode == VERIFY_USING_SAMPLES)
469	{
470		// encode the id to the output, and then verify it during sampling
471		buf <<	"#version 310 es\n"
472				"#extension GL_OES_sample_variables : require\n"
473				"layout(location = 0) out mediump vec4 fragColor;\n"
474				"void main (void)\n"
475				"{\n"
476				"	highp float normalizedSample = float(gl_SampleID) / float(" << numTargetSamples << ");\n"
477				"	fragColor = vec4(0.0, normalizedSample, 1.0, 1.0);\n"
478				"}\n";
479	}
480	else if (m_vericationMode == VERIFY_USING_SELECTION)
481	{
482		if (numTargetSamples == 1)
483		{
484			// single sample, just verify value is 0
485			buf <<	"#version 310 es\n"
486					"#extension GL_OES_sample_variables : require\n"
487					"layout(location = 0) out mediump vec4 fragColor;\n"
488					"void main (void)\n"
489					"{\n"
490					"	if (gl_SampleID == 0)\n"
491					"		fragColor = vec4(0.0, 1.0, 1.0, 1.0);\n"
492					"	else\n"
493					"		fragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
494					"}\n";
495		}
496		else
497		{
498			// select only one sample per PIXEL
499			buf <<	"#version 310 es\n"
500					"#extension GL_OES_sample_variables : require\n"
501					"in highp vec4 v_position;\n"
502					"layout(location = 0) out mediump vec4 fragColor;\n"
503					"void main (void)\n"
504					"{\n"
505					"	highp vec2 relPosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0;\n"
506					"	highp ivec2 pixelPos = ivec2(floor(relPosition * " << (int)RENDER_SIZE << ".0));\n"
507					"	highp int selectedID = abs(pixelPos.x + 17 * pixelPos.y) % " << numTargetSamples << ";\n"
508					"\n"
509					"	if (gl_SampleID == selectedID)\n"
510					"		fragColor = vec4(0.0, 1.0, 1.0, 1.0);\n"
511					"	else\n"
512					"		fragColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
513					"}\n";
514		}
515	}
516	else
517		DE_ASSERT(false);
518
519	return buf.str();
520}
521
522bool SampleIDCase::verifyImage (const tcu::Surface& resultImage)
523{
524	if (m_vericationMode == VERIFY_USING_SAMPLES)
525	{
526		// never happens
527		DE_ASSERT(false);
528		return false;
529	}
530	else if (m_vericationMode == VERIFY_USING_SELECTION)
531	{
532		// should result in full blue and some green everywhere
533		return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), FullBlueSomeGreenVerifier());
534	}
535	else
536	{
537		DE_ASSERT(false);
538		return false;
539	}
540}
541
542bool SampleIDCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
543{
544	// Verify all sample buffers
545	bool allOk = true;
546
547	// Log layers
548	{
549		m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
550		for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
551			m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
552		m_testCtx.getLog() << tcu::TestLog::EndImageSet;
553	}
554
555	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample buffers" << tcu::TestLog::EndMessage;
556	for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
557	{
558		// sample id should be sample index
559		const int threshold = 255 / 4 / m_numTargetSamples + 1;
560		const float sampleIdColor = sampleNdx / (float)m_numTargetSamples;
561
562		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
563		allOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, sampleIdColor, 1.0f), tcu::IVec3(1, threshold, 1)), false);
564	}
565
566	if (!allOk)
567		m_testCtx.getLog() << tcu::TestLog::Message << "Sample buffer verification failed" << tcu::TestLog::EndMessage;
568
569	return allOk;
570}
571
572class SamplePosDistributionCase : public MultisampleRenderCase
573{
574public:
575					SamplePosDistributionCase	(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
576					~SamplePosDistributionCase	(void);
577
578	void			init						(void);
579private:
580	enum
581	{
582		RENDER_SIZE = 64
583	};
584
585	std::string		genFragmentSource			(int numTargetSamples) const;
586	bool			verifyImage					(const tcu::Surface& resultImage);
587	bool			verifySampleBuffers			(const std::vector<tcu::Surface>& resultBuffers);
588};
589
590SamplePosDistributionCase::SamplePosDistributionCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
591	: MultisampleRenderCase(context, name, desc, sampleCount, target, RENDER_SIZE, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
592{
593}
594
595SamplePosDistributionCase::~SamplePosDistributionCase (void)
596{
597}
598
599void SamplePosDistributionCase::init (void)
600{
601	// log the test method and expectations
602	if (m_renderTarget == TARGET_TEXTURE)
603	{
604		m_testCtx.getLog()
605			<< tcu::TestLog::Message
606			<< "Verifying gl_SamplePosition value:\n"
607			<< "	1) With non-multisample targets: Expect the center of the pixel.\n"
608			<< "	2) With multisample targets:\n"
609			<< "		a) Expect legal sample position.\n"
610			<< "		b) Sample position is unique within the set of all sample positions of a pixel.\n"
611			<< "		c) Sample position distribution is uniform or almost uniform.\n"
612			<< tcu::TestLog::EndMessage;
613	}
614	else
615	{
616		m_testCtx.getLog()
617			<< tcu::TestLog::Message
618			<< "Verifying gl_SamplePosition value:\n"
619			<< "	1) With non-multisample targets: Expect the center of the pixel.\n"
620			<< "	2) With multisample targets:\n"
621			<< "		a) Expect legal sample position.\n"
622			<< "		b) Sample position distribution is uniform or almost uniform.\n"
623			<< tcu::TestLog::EndMessage;
624	}
625
626	MultisampleRenderCase::init();
627}
628
629std::string SamplePosDistributionCase::genFragmentSource (int numTargetSamples) const
630{
631	DE_ASSERT(numTargetSamples != 0);
632	DE_UNREF(numTargetSamples);
633
634	const bool			multisampleTarget = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
635	std::ostringstream	buf;
636
637	if (multisampleTarget)
638	{
639		// encode the position to the output, use red channel as error channel
640		buf <<	"#version 310 es\n"
641				"#extension GL_OES_sample_variables : require\n"
642				"layout(location = 0) out mediump vec4 fragColor;\n"
643				"void main (void)\n"
644				"{\n"
645				"	if (gl_SamplePosition.x < 0.0 || gl_SamplePosition.x > 1.0 || gl_SamplePosition.y < 0.0 || gl_SamplePosition.y > 1.0)\n"
646				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
647				"	else\n"
648				"		fragColor = vec4(0.0, gl_SamplePosition.x, gl_SamplePosition.y, 1.0);\n"
649				"}\n";
650	}
651	else
652	{
653		// verify value is ok
654		buf <<	"#version 310 es\n"
655				"#extension GL_OES_sample_variables : require\n"
656				"layout(location = 0) out mediump vec4 fragColor;\n"
657				"void main (void)\n"
658				"{\n"
659				"	if (gl_SamplePosition.x != 0.5 || gl_SamplePosition.y != 0.5)\n"
660				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
661				"	else\n"
662				"		fragColor = vec4(0.0, gl_SamplePosition.x, gl_SamplePosition.y, 1.0);\n"
663				"}\n";
664	}
665
666	return buf.str();
667}
668
669bool SamplePosDistributionCase::verifyImage (const tcu::Surface& resultImage)
670{
671	const int				sampleCount	= (m_renderTarget == TARGET_DEFAULT) ? (m_context.getRenderTarget().getNumSamples()) : (m_numRequestedSamples);
672	SampleAverageVerifier	verifier	(sampleCount);
673
674	// check there is nothing in the error channel
675	if (!verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier()))
676		return false;
677
678	// position average should be around 0.5, 0.5
679	if (verifier.m_isStatisticallySignificant && !verifyImageWithVerifier(resultImage, m_testCtx.getLog(), verifier))
680		throw MultisampleShaderRenderUtil::QualityWarning("Bias detected, sample positions are not uniformly distributed within the pixel");
681
682	return true;
683}
684
685bool SamplePosDistributionCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
686{
687	const int	width				= resultBuffers[0].getWidth();
688	const int	height				= resultBuffers[0].getHeight();
689	bool		allOk				= true;
690	bool		distibutionError	= false;
691
692	// Check sample range, uniqueness, and distribution, log layers
693	{
694		m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
695		for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
696			m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
697		m_testCtx.getLog() << tcu::TestLog::EndImageSet;
698	}
699
700	// verify range
701	{
702		bool rangeOk = true;
703
704		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position range" << tcu::TestLog::EndMessage;
705		for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
706		{
707			// shader does the check, just check the shader error output (red)
708			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
709			rangeOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), NoRedVerifier(), false);
710		}
711
712		if (!rangeOk)
713		{
714			allOk = false;
715
716			m_testCtx.getLog() << tcu::TestLog::Message << "Sample position verification failed." << tcu::TestLog::EndMessage;
717		}
718	}
719
720	// Verify uniqueness
721	{
722		bool					uniquenessOk	= true;
723		tcu::Surface			errorMask		(width, height);
724		std::vector<tcu::Vec2>	samplePositions	(resultBuffers.size());
725		int						printCount		= 0;
726		const int				printFloodLimit	= 5;
727
728		tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
729
730		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position uniqueness." << tcu::TestLog::EndMessage;
731
732		for (int y = 0; y < height; ++y)
733		for (int x = 0; x < width; ++x)
734		{
735			bool samplePosNotUnique = false;
736
737			for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
738			{
739				const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
740				samplePositions[sampleNdx] = tcu::Vec2(color.getGreen() / 255.0f, color.getBlue() / 255.0f);
741			}
742
743			// Just check there are no two samples with same positions
744			for (int sampleNdxA = 0;            sampleNdxA < (int)resultBuffers.size() && (!samplePosNotUnique || printCount < printFloodLimit); ++sampleNdxA)
745			for (int sampleNdxB = sampleNdxA+1; sampleNdxB < (int)resultBuffers.size() && (!samplePosNotUnique || printCount < printFloodLimit); ++sampleNdxB)
746			{
747				if (samplePositions[sampleNdxA] == samplePositions[sampleNdxB])
748				{
749					if (++printCount <= printFloodLimit)
750					{
751						m_testCtx.getLog()
752							<< tcu::TestLog::Message
753							<< "Pixel (" << x << ", " << y << "): Samples " << sampleNdxA << " and " << sampleNdxB << " have the same position."
754							<< tcu::TestLog::EndMessage;
755					}
756
757					samplePosNotUnique = true;
758					uniquenessOk = false;
759					errorMask.setPixel(x, y, tcu::RGBA::red);
760				}
761			}
762		}
763
764		// end result
765		if (!uniquenessOk)
766		{
767			if (printCount > printFloodLimit)
768				m_testCtx.getLog()
769					<< tcu::TestLog::Message
770					<< "...\n"
771					<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
772					<< tcu::TestLog::EndMessage;
773
774			m_testCtx.getLog()
775				<< tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
776				<< tcu::TestLog::ImageSet("Verification", "Image Verification")
777				<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
778				<< tcu::TestLog::EndImageSet;
779
780			allOk = false;
781		}
782	}
783
784	// check distribution
785	{
786		const SampleAverageVerifier verifier		(m_numTargetSamples);
787		tcu::Surface				errorMask		(width, height);
788		int							printCount		= 0;
789		const int					printFloodLimit	= 5;
790
791		tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
792
793		// don't bother with small sample counts
794		if (verifier.m_isStatisticallySignificant)
795		{
796			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample position distribution is (nearly) unbiased." << tcu::TestLog::EndMessage;
797			verifier.logInfo(m_testCtx.getLog());
798
799			for (int y = 0; y < height; ++y)
800			for (int x = 0; x < width; ++x)
801			{
802				tcu::IVec3 colorSum(0, 0, 0);
803
804				// color average
805
806				for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
807				{
808					const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
809					colorSum.x() += color.getRed();
810					colorSum.y() += color.getBlue();
811					colorSum.z() += color.getGreen();
812				}
813
814				colorSum.x() /= m_numTargetSamples;
815				colorSum.y() /= m_numTargetSamples;
816				colorSum.z() /= m_numTargetSamples;
817
818				// verify average sample position
819
820				if (!verifier.verify(tcu::RGBA(colorSum.x(), colorSum.y(), colorSum.z(), 0), tcu::IVec2(x, y)))
821				{
822					if (++printCount <= printFloodLimit)
823					{
824						m_testCtx.getLog()
825							<< tcu::TestLog::Message
826							<< "Pixel (" << x << ", " << y << "): Sample distribution is biased."
827							<< tcu::TestLog::EndMessage;
828					}
829
830					distibutionError = true;
831					errorMask.setPixel(x, y, tcu::RGBA::red);
832				}
833			}
834
835			// sub-verification result
836			if (distibutionError)
837			{
838				if (printCount > printFloodLimit)
839					m_testCtx.getLog()
840						<< tcu::TestLog::Message
841						<< "...\n"
842						<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
843						<< tcu::TestLog::EndMessage;
844
845				m_testCtx.getLog()
846					<< tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
847					<< tcu::TestLog::ImageSet("Verification", "Image Verification")
848					<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
849					<< tcu::TestLog::EndImageSet;
850			}
851		}
852	}
853
854	// results
855	if (!allOk)
856		return false;
857	else if (distibutionError)
858		throw MultisampleShaderRenderUtil::QualityWarning("Bias detected, sample positions are not uniformly distributed within the pixel");
859	else
860	{
861		m_testCtx.getLog() << tcu::TestLog::Message << "Verification ok." << tcu::TestLog::EndMessage;
862		return true;
863	}
864}
865
866class SamplePosCorrectnessCase : public MultisampleRenderCase
867{
868public:
869					SamplePosCorrectnessCase	(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
870					~SamplePosCorrectnessCase	(void);
871
872	void			init						(void);
873private:
874	enum
875	{
876		RENDER_SIZE = 32
877	};
878
879	void			preDraw						(void);
880	void			postDraw					(void);
881
882	std::string		genVertexSource				(int numTargetSamples) const;
883	std::string		genFragmentSource			(int numTargetSamples) const;
884	bool			verifyImage					(const tcu::Surface& resultImage);
885
886	bool			m_useSampleQualifier;
887};
888
889SamplePosCorrectnessCase::SamplePosCorrectnessCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
890	: MultisampleRenderCase	(context, name, desc, sampleCount, target, RENDER_SIZE)
891	, m_useSampleQualifier	(false)
892{
893}
894
895SamplePosCorrectnessCase::~SamplePosCorrectnessCase (void)
896{
897}
898
899void SamplePosCorrectnessCase::init (void)
900{
901	// requirements: per-invocation interpolation required
902	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation") &&
903		!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
904		throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation or GL_OES_sample_shading extension");
905
906	// prefer to use the sample qualifier path
907	m_useSampleQualifier = m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation");
908
909	// log the test method and expectations
910	m_testCtx.getLog()
911		<< tcu::TestLog::Message
912		<< "Verifying gl_SamplePosition correctness:\n"
913		<< "	1) Varying values should be sampled at the sample position.\n"
914		<< "		=> fract(screenSpacePosition) == gl_SamplePosition\n"
915		<< tcu::TestLog::EndMessage;
916
917	MultisampleRenderCase::init();
918}
919
920void SamplePosCorrectnessCase::preDraw (void)
921{
922	if (!m_useSampleQualifier)
923	{
924		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
925
926		// use GL_OES_sample_shading to set per fragment sample invocation interpolation
927		gl.enable(GL_SAMPLE_SHADING);
928		gl.minSampleShading(1.0f);
929		GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
930
931		m_testCtx.getLog() << tcu::TestLog::Message << "Enabling per-sample interpolation with GL_SAMPLE_SHADING." << tcu::TestLog::EndMessage;
932	}
933}
934
935void SamplePosCorrectnessCase::postDraw (void)
936{
937	if (!m_useSampleQualifier)
938	{
939		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
940
941		gl.disable(GL_SAMPLE_SHADING);
942		gl.minSampleShading(1.0f);
943		GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
944	}
945}
946
947std::string SamplePosCorrectnessCase::genVertexSource (int numTargetSamples) const
948{
949	DE_UNREF(numTargetSamples);
950
951	std::ostringstream buf;
952
953	buf <<	"#version 310 es\n"
954		<<	((m_useSampleQualifier) ? ("#extension GL_OES_shader_multisample_interpolation : require\n") : (""))
955		<<	"in highp vec4 a_position;\n"
956		<<	((m_useSampleQualifier) ? ("sample ") : ("")) << "out highp vec4 v_position;\n"
957			"void main (void)\n"
958			"{\n"
959			"	gl_Position = a_position;\n"
960			"	v_position = a_position;\n"
961			"}\n";
962
963	return buf.str();
964}
965
966std::string SamplePosCorrectnessCase::genFragmentSource (int numTargetSamples) const
967{
968	DE_UNREF(numTargetSamples);
969
970	std::ostringstream buf;
971
972	// encode the position to the output, use red channel as error channel
973	buf <<	"#version 310 es\n"
974			"#extension GL_OES_sample_variables : require\n"
975		<<	((m_useSampleQualifier) ? ("#extension GL_OES_shader_multisample_interpolation : require\n") : (""))
976		<<	((m_useSampleQualifier) ? ("sample ") : ("")) << "in highp vec4 v_position;\n"
977			"layout(location = 0) out mediump vec4 fragColor;\n"
978			"void main (void)\n"
979			"{\n"
980			"	const highp float maxDistance = 0.15625; // 4 subpixel bits. Assume 3 accurate bits + 0.03125 for other errors\n" // 0.03125 = mediump epsilon when value = 32 (RENDER_SIZE)
981			"\n"
982			"	highp vec2 screenSpacePosition = (v_position.xy + vec2(1.0, 1.0)) / 2.0 * " << (int)RENDER_SIZE << ".0;\n"
983			"	highp ivec2 nearbyPixel = ivec2(floor(screenSpacePosition));\n"
984			"	bool allOk = false;\n"
985			"\n"
986			"	// sample at edge + inaccuaries may cause us to round to any neighboring pixel\n"
987			"	// check all neighbors for any match\n"
988			"	for (highp int dy = -1; dy <= 1; ++dy)\n"
989			"	for (highp int dx = -1; dx <= 1; ++dx)\n"
990			"	{\n"
991			"		highp ivec2 currentPixel = nearbyPixel + ivec2(dx, dy);\n"
992			"		highp vec2 candidateSamplingPos = vec2(currentPixel) + gl_SamplePosition.xy;\n"
993			"		highp vec2 positionDiff = abs(candidateSamplingPos - screenSpacePosition);\n"
994			"		if (positionDiff.x < maxDistance && positionDiff.y < maxDistance)\n"
995			"			allOk = true;\n"
996			"	}\n"
997			"\n"
998			"	if (allOk)\n"
999			"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1000			"	else\n"
1001			"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1002			"}\n";
1003
1004	return buf.str();
1005}
1006
1007bool SamplePosCorrectnessCase::verifyImage (const tcu::Surface& resultImage)
1008{
1009	return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
1010}
1011
1012class SampleMaskBaseCase : public MultisampleRenderCase
1013{
1014public:
1015	enum ShaderRunMode
1016	{
1017		RUN_PER_PIXEL = 0,
1018		RUN_PER_SAMPLE,
1019		RUN_PER_TWO_SAMPLES,
1020
1021		RUN_LAST
1022	};
1023
1024						SampleMaskBaseCase			(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, int renderSize, ShaderRunMode runMode, int flags = 0);
1025	virtual				~SampleMaskBaseCase			(void);
1026
1027protected:
1028	virtual void		init						(void);
1029	virtual void		preDraw						(void);
1030	virtual void		postDraw					(void);
1031	virtual bool		verifyImage					(const tcu::Surface& resultImage);
1032
1033	const ShaderRunMode	m_runMode;
1034};
1035
1036SampleMaskBaseCase::SampleMaskBaseCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, int renderSize, ShaderRunMode runMode, int flags)
1037	: MultisampleRenderCase	(context, name, desc, sampleCount, target, renderSize, flags)
1038	, m_runMode				(runMode)
1039{
1040	DE_ASSERT(runMode < RUN_LAST);
1041}
1042
1043SampleMaskBaseCase::~SampleMaskBaseCase (void)
1044{
1045}
1046
1047void SampleMaskBaseCase::init (void)
1048{
1049	// required extra extension
1050	if (m_runMode == RUN_PER_TWO_SAMPLES && !m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
1051		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension");
1052
1053	MultisampleRenderCase::init();
1054}
1055
1056void SampleMaskBaseCase::preDraw (void)
1057{
1058	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1059
1060	if (m_runMode == RUN_PER_TWO_SAMPLES)
1061	{
1062		gl.enable(GL_SAMPLE_SHADING);
1063		gl.minSampleShading(0.5f);
1064		GLU_EXPECT_NO_ERROR(gl.getError(), "enable sample shading");
1065
1066		m_testCtx.getLog() << tcu::TestLog::Message << "Enabled GL_SAMPLE_SHADING, value = 0.5" << tcu::TestLog::EndMessage;
1067	}
1068}
1069
1070void SampleMaskBaseCase::postDraw (void)
1071{
1072	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1073
1074	if (m_runMode == RUN_PER_TWO_SAMPLES)
1075	{
1076		gl.disable(GL_SAMPLE_SHADING);
1077		gl.minSampleShading(1.0f);
1078		GLU_EXPECT_NO_ERROR(gl.getError(), "disable sample shading");
1079	}
1080}
1081
1082bool SampleMaskBaseCase::verifyImage (const tcu::Surface& resultImage)
1083{
1084	// shader does the verification
1085	return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), NoRedVerifier());
1086}
1087
1088class SampleMaskCase : public SampleMaskBaseCase
1089{
1090public:
1091						SampleMaskCase				(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target);
1092						~SampleMaskCase				(void);
1093
1094	void				init						(void);
1095	void				preDraw						(void);
1096	void				postDraw					(void);
1097
1098private:
1099	enum
1100	{
1101		RENDER_SIZE = 64
1102	};
1103
1104	std::string			genFragmentSource			(int numTargetSamples) const;
1105};
1106
1107SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target)
1108	: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, RUN_PER_PIXEL)
1109{
1110}
1111
1112SampleMaskCase::~SampleMaskCase (void)
1113{
1114}
1115
1116void SampleMaskCase::init (void)
1117{
1118	// log the test method and expectations
1119	m_testCtx.getLog()
1120		<< tcu::TestLog::Message
1121		<< "Verifying gl_SampleMaskIn value with SAMPLE_MASK state. gl_SampleMaskIn does not contain any bits set that are have been killed by SAMPLE_MASK state. Expecting:\n"
1122		<< "	1) With multisample targets: gl_SampleMaskIn AND ~(SAMPLE_MASK) should be zero.\n"
1123		<< "	2) With non-multisample targets: SAMPLE_MASK state is only ANDed as a multisample operation. gl_SampleMaskIn should only have its last bit set regardless of SAMPLE_MASK state.\n"
1124		<< tcu::TestLog::EndMessage;
1125
1126	SampleMaskBaseCase::init();
1127}
1128
1129void SampleMaskCase::preDraw (void)
1130{
1131	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
1132	const bool				multisampleTarget	= (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
1133	const deUint32			fullMask			= (deUint32)0xAAAAAAAAUL;
1134	const deUint32			maskMask			= (1U << m_numTargetSamples) - 1;
1135	const deUint32			effectiveMask		=  fullMask & maskMask;
1136
1137	// set test mask
1138	gl.enable(GL_SAMPLE_MASK);
1139	gl.sampleMaski(0, effectiveMask);
1140	GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
1141
1142	m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask " << tcu::Format::Hex<4>(effectiveMask) << tcu::TestLog::EndMessage;
1143
1144	// set multisample case uniforms
1145	if (multisampleTarget)
1146	{
1147		const int maskLoc = gl.getUniformLocation(m_program->getProgram(), "u_sampleMask");
1148		if (maskLoc == -1)
1149			throw tcu::TestError("Location of u_mask was -1");
1150
1151		gl.uniform1ui(maskLoc, effectiveMask);
1152		GLU_EXPECT_NO_ERROR(gl.getError(), "set mask uniform");
1153	}
1154
1155	// base class logic
1156	SampleMaskBaseCase::preDraw();
1157}
1158
1159void SampleMaskCase::postDraw (void)
1160{
1161	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1162	const deUint32			fullMask	= (1U << m_numTargetSamples) - 1;
1163
1164	gl.disable(GL_SAMPLE_MASK);
1165	gl.sampleMaski(0, fullMask);
1166	GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
1167
1168	// base class logic
1169	SampleMaskBaseCase::postDraw();
1170}
1171
1172std::string SampleMaskCase::genFragmentSource (int numTargetSamples) const
1173{
1174	DE_ASSERT(numTargetSamples != 0);
1175
1176	const bool			multisampleTarget = (m_numRequestedSamples > 0) || (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
1177	std::ostringstream	buf;
1178
1179	// test supports only one sample mask word
1180	if (numTargetSamples > 32)
1181		throw tcu::NotSupportedError("Sample count larger than 32 is not supported.");
1182
1183	if (multisampleTarget)
1184	{
1185		buf <<	"#version 310 es\n"
1186				"#extension GL_OES_sample_variables : require\n"
1187				"layout(location = 0) out mediump vec4 fragColor;\n"
1188				"uniform highp uint u_sampleMask;\n"
1189				"void main (void)\n"
1190				"{\n"
1191				"	if ((uint(gl_SampleMaskIn[0]) & (~u_sampleMask)) != 0u)\n"
1192				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1193				"	else\n"
1194				"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1195				"}\n";
1196	}
1197	else
1198	{
1199		// non-multisample targets don't get multisample operations like ANDing with mask
1200
1201		buf <<	"#version 310 es\n"
1202				"#extension GL_OES_sample_variables : require\n"
1203				"layout(location = 0) out mediump vec4 fragColor;\n"
1204				"uniform highp uint u_sampleMask;\n"
1205				"void main (void)\n"
1206				"{\n"
1207				"	if (gl_SampleMaskIn[0] != 1)\n"
1208				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1209				"	else\n"
1210				"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1211				"}\n";
1212	}
1213
1214	return buf.str();
1215}
1216
1217class SampleMaskCountCase : public SampleMaskBaseCase
1218{
1219public:
1220						SampleMaskCountCase			(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
1221						~SampleMaskCountCase		(void);
1222
1223	void				init						(void);
1224	void				preDraw						(void);
1225	void				postDraw					(void);
1226
1227private:
1228	enum
1229	{
1230		RENDER_SIZE = 64
1231	};
1232
1233	std::string			genFragmentSource			(int numTargetSamples) const;
1234};
1235
1236SampleMaskCountCase::SampleMaskCountCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
1237	: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode)
1238{
1239	DE_ASSERT(runMode < RUN_LAST);
1240}
1241
1242SampleMaskCountCase::~SampleMaskCountCase (void)
1243{
1244}
1245
1246void SampleMaskCountCase::init (void)
1247{
1248	// log the test method and expectations
1249	if (m_runMode == RUN_PER_PIXEL)
1250		m_testCtx.getLog()
1251			<< tcu::TestLog::Message
1252			<< "Verifying gl_SampleMaskIn.\n"
1253			<< "	Fragment shader may be invoked [1, numSamples] times.\n"
1254			<< "	=> gl_SampleMaskIn should have the number of bits set in range [1, numSamples]\n"
1255			<< tcu::TestLog::EndMessage;
1256	else if (m_runMode == RUN_PER_SAMPLE)
1257		m_testCtx.getLog()
1258			<< tcu::TestLog::Message
1259			<< "Verifying gl_SampleMaskIn.\n"
1260			<< "	Fragment will be invoked numSamples times.\n"
1261			<< "	=> gl_SampleMaskIn should have only one bit set.\n"
1262			<< tcu::TestLog::EndMessage;
1263	else if (m_runMode == RUN_PER_TWO_SAMPLES)
1264		m_testCtx.getLog()
1265			<< tcu::TestLog::Message
1266			<< "Verifying gl_SampleMaskIn.\n"
1267			<< "	Fragment shader may be invoked [ceil(numSamples/2), numSamples] times.\n"
1268			<< "	=> gl_SampleMaskIn should have the number of bits set in range [1, numSamples - ceil(numSamples/2) + 1]:\n"
1269			<< tcu::TestLog::EndMessage;
1270	else
1271		DE_ASSERT(false);
1272
1273	SampleMaskBaseCase::init();
1274}
1275
1276void SampleMaskCountCase::preDraw (void)
1277{
1278	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1279
1280	if (m_runMode == RUN_PER_PIXEL)
1281	{
1282		const int maxLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxBitCount");
1283		const int minLoc = gl.getUniformLocation(m_program->getProgram(), "u_minBitCount");
1284		const int minBitCount = 1;
1285		const int maxBitCount = m_numTargetSamples;
1286
1287		if (maxLoc == -1)
1288			throw tcu::TestError("Location of u_maxBitCount was -1");
1289		if (minLoc == -1)
1290			throw tcu::TestError("Location of u_minBitCount was -1");
1291
1292		gl.uniform1i(minLoc, minBitCount);
1293		gl.uniform1i(maxLoc, maxBitCount);
1294		GLU_EXPECT_NO_ERROR(gl.getError(), "set limits");
1295
1296		m_testCtx.getLog() << tcu::TestLog::Message << "Setting minBitCount = " << minBitCount << ", maxBitCount = " << maxBitCount << tcu::TestLog::EndMessage;
1297	}
1298	else if (m_runMode == RUN_PER_TWO_SAMPLES)
1299	{
1300		const int maxLoc = gl.getUniformLocation(m_program->getProgram(), "u_maxBitCount");
1301		const int minLoc = gl.getUniformLocation(m_program->getProgram(), "u_minBitCount");
1302
1303		// Worst case: all but one shader invocations get one sample, one shader invocation the rest of the samples
1304		const int minInvocationCount = ((m_numTargetSamples + 1) / 2);
1305		const int minBitCount = 1;
1306		const int maxBitCount = (m_numTargetSamples <= 2) ? (1) : (m_numTargetSamples - ((minInvocationCount-1) * minBitCount));
1307
1308		if (maxLoc == -1)
1309			throw tcu::TestError("Location of u_maxBitCount was -1");
1310		if (minLoc == -1)
1311			throw tcu::TestError("Location of u_minBitCount was -1");
1312
1313		gl.uniform1i(minLoc, minBitCount);
1314		gl.uniform1i(maxLoc, maxBitCount);
1315		GLU_EXPECT_NO_ERROR(gl.getError(), "set limits");
1316
1317		m_testCtx.getLog() << tcu::TestLog::Message << "Setting minBitCount = " << minBitCount << ", maxBitCount = " << maxBitCount << tcu::TestLog::EndMessage;
1318	}
1319
1320	SampleMaskBaseCase::preDraw();
1321}
1322
1323void SampleMaskCountCase::postDraw (void)
1324{
1325	SampleMaskBaseCase::postDraw();
1326}
1327
1328std::string SampleMaskCountCase::genFragmentSource (int numTargetSamples) const
1329{
1330	DE_ASSERT(numTargetSamples != 0);
1331
1332	std::ostringstream buf;
1333
1334	// test supports only one sample mask word
1335	if (numTargetSamples > 32)
1336		throw tcu::NotSupportedError("Sample count larger than 32 is not supported.");
1337
1338	// count the number of the bits in gl_SampleMask
1339
1340	buf <<	"#version 310 es\n"
1341			"#extension GL_OES_sample_variables : require\n"
1342			"layout(location = 0) out mediump vec4 fragColor;\n";
1343
1344	if (m_runMode != RUN_PER_SAMPLE)
1345		buf <<	"uniform highp int u_minBitCount;\n"
1346				"uniform highp int u_maxBitCount;\n";
1347
1348	buf <<	"void main (void)\n"
1349			"{\n"
1350			"	mediump int maskBitCount = 0;\n"
1351			"	for (int i = 0; i < 32; ++i)\n"
1352			"		if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
1353			"			++maskBitCount;\n"
1354			"\n";
1355
1356	if (m_runMode == RUN_PER_SAMPLE)
1357	{
1358		// check the validity here
1359		buf <<	"	// force per-sample shading\n"
1360				"	highp float blue = float(gl_SampleID);\n"
1361				"\n"
1362				"	if (maskBitCount != 1)\n"
1363				"		fragColor = vec4(1.0, 0.0, blue, 1.0);\n"
1364				"	else\n"
1365				"		fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
1366				"}\n";
1367	}
1368	else
1369	{
1370		// check the validity here
1371		buf <<	"	if (maskBitCount < u_minBitCount || maskBitCount > u_maxBitCount)\n"
1372				"		fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1373				"	else\n"
1374				"		fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1375				"}\n";
1376	}
1377
1378	return buf.str();
1379}
1380
1381class SampleMaskUniqueCase : public SampleMaskBaseCase
1382{
1383public:
1384						SampleMaskUniqueCase		(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
1385						~SampleMaskUniqueCase		(void);
1386
1387	void				init						(void);
1388
1389private:
1390	enum
1391	{
1392		RENDER_SIZE = 64
1393	};
1394
1395	std::string			genFragmentSource			(int numTargetSamples) const;
1396	bool				verifySampleBuffers			(const std::vector<tcu::Surface>& resultBuffers);
1397};
1398
1399SampleMaskUniqueCase::SampleMaskUniqueCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
1400	: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
1401{
1402	DE_ASSERT(runMode == RUN_PER_SAMPLE);
1403	DE_ASSERT(target == TARGET_TEXTURE);
1404}
1405
1406SampleMaskUniqueCase::~SampleMaskUniqueCase (void)
1407{
1408}
1409
1410void SampleMaskUniqueCase::init (void)
1411{
1412	// log the test method and expectations
1413	m_testCtx.getLog()
1414		<< tcu::TestLog::Message
1415		<< "Verifying gl_SampleMaskIn.\n"
1416		<< "	Fragment will be invoked numSamples times.\n"
1417		<< "	=> gl_SampleMaskIn should have only one bit set\n"
1418		<< "	=> and that bit index should be unique within other fragment shader invocations of that pixel.\n"
1419		<< "	Writing sampleMask bit index to green channel in render shader. Verifying uniqueness in sampler shader.\n"
1420		<< tcu::TestLog::EndMessage;
1421
1422	SampleMaskBaseCase::init();
1423}
1424
1425std::string SampleMaskUniqueCase::genFragmentSource (int numTargetSamples) const
1426{
1427	DE_ASSERT(numTargetSamples != 0);
1428
1429	std::ostringstream buf;
1430
1431	// test supports only one sample mask word
1432	if (numTargetSamples > 32)
1433		throw tcu::NotSupportedError("Sample count larger than 32 is not supported.");
1434
1435	// find our sampleID by searching for unique bit.
1436	buf <<	"#version 310 es\n"
1437			"#extension GL_OES_sample_variables : require\n"
1438			"layout(location = 0) out mediump vec4 fragColor;\n"
1439			"void main (void)\n"
1440			"{\n"
1441			"	mediump int firstIndex = -1;\n"
1442			"	for (int i = 0; i < 32; ++i)\n"
1443			"	{\n"
1444			"		if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
1445			"		{\n"
1446			"			firstIndex = i;\n"
1447			"			break;\n"
1448			"		}\n"
1449			"	}\n"
1450			"\n"
1451			"	bool notUniqueError = false;\n"
1452			"	for (int i = firstIndex + 1; i < 32; ++i)\n"
1453			"		if (((gl_SampleMaskIn[0] >> i) & 0x01) == 0x01)\n"
1454			"			notUniqueError = true;\n"
1455			"\n"
1456			"	highp float encodedSampleId = float(firstIndex) / " << numTargetSamples <<".0;\n"
1457			"\n"
1458			"	// force per-sample shading\n"
1459			"	highp float blue = float(gl_SampleID);\n"
1460			"\n"
1461			"	if (notUniqueError)\n"
1462			"		fragColor = vec4(1.0, 0.0, blue, 1.0);\n"
1463			"	else\n"
1464			"		fragColor = vec4(0.0, encodedSampleId, blue, 1.0);\n"
1465			"}\n";
1466
1467	return buf.str();
1468}
1469
1470bool SampleMaskUniqueCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
1471{
1472	const int	width				= resultBuffers[0].getWidth();
1473	const int	height				= resultBuffers[0].getHeight();
1474	bool		allOk				= true;
1475
1476	// Log samples
1477	{
1478		m_testCtx.getLog() << tcu::TestLog::ImageSet("SampleBuffers", "Image sample buffers");
1479		for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
1480			m_testCtx.getLog() << tcu::TestLog::Image("Buffer" + de::toString(sampleNdx), "Sample " + de::toString(sampleNdx), resultBuffers[sampleNdx].getAccess());
1481		m_testCtx.getLog() << tcu::TestLog::EndImageSet;
1482	}
1483
1484	// check for earlier errors (in fragment shader)
1485	{
1486		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying fragment shader invocation found only one set sample mask bit." << tcu::TestLog::EndMessage;
1487
1488		for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
1489		{
1490			// shader does the check, just check the shader error output (red)
1491			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample " << (sampleNdx+1) << "/" << (int)resultBuffers.size() << tcu::TestLog::EndMessage;
1492			allOk &= verifyImageWithVerifier(resultBuffers[sampleNdx], m_testCtx.getLog(), NoRedVerifier(), false);
1493		}
1494
1495		if (!allOk)
1496		{
1497			// can't check the uniqueness if the masks don't work at all
1498			m_testCtx.getLog() << tcu::TestLog::Message << "Could not get mask information from the rendered image, cannot continue verification." << tcu::TestLog::EndMessage;
1499			return false;
1500		}
1501	}
1502
1503	// verify index / index ranges
1504
1505	if (m_numRequestedSamples == 0)
1506	{
1507		// single sample target, expect index=0
1508
1509		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample mask bit index is 0." << tcu::TestLog::EndMessage;
1510
1511		// only check the mask index
1512		allOk &= verifyImageWithVerifier(resultBuffers[0], m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f), tcu::IVec3(255, 8, 255)), false);
1513	}
1514	else
1515	{
1516		// check uniqueness
1517
1518		tcu::Surface		errorMask		(width, height);
1519		bool				uniquenessOk	= true;
1520		int					printCount		= 0;
1521		const int			printFloodLimit	= 5;
1522		std::vector<int>	maskBitIndices	(resultBuffers.size());
1523
1524		tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1525
1526		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying per-invocation sample mask bit is unique." << tcu::TestLog::EndMessage;
1527
1528		for (int y = 0; y < height; ++y)
1529		for (int x = 0; x < width; ++x)
1530		{
1531			bool maskNdxNotUnique = false;
1532
1533			// decode index
1534			for (int sampleNdx = 0; sampleNdx < (int)resultBuffers.size(); ++sampleNdx)
1535			{
1536				const tcu::RGBA color = resultBuffers[sampleNdx].getPixel(x, y);
1537				maskBitIndices[sampleNdx] = (int)deFloatRound(color.getGreen() / 255.0f * m_numTargetSamples);
1538			}
1539
1540			// just check there are no two invocations with the same bit index
1541			for (int sampleNdxA = 0;            sampleNdxA < (int)resultBuffers.size() && (!maskNdxNotUnique || printCount < printFloodLimit); ++sampleNdxA)
1542			for (int sampleNdxB = sampleNdxA+1; sampleNdxB < (int)resultBuffers.size() && (!maskNdxNotUnique || printCount < printFloodLimit); ++sampleNdxB)
1543			{
1544				if (maskBitIndices[sampleNdxA] == maskBitIndices[sampleNdxB])
1545				{
1546					if (++printCount <= printFloodLimit)
1547					{
1548						m_testCtx.getLog()
1549							<< tcu::TestLog::Message
1550							<< "Pixel (" << x << ", " << y << "): Samples " << sampleNdxA << " and " << sampleNdxB << " have the same sample mask. (Single bit at index " << maskBitIndices[sampleNdxA] << ")"
1551							<< tcu::TestLog::EndMessage;
1552					}
1553
1554					maskNdxNotUnique = true;
1555					uniquenessOk = false;
1556					errorMask.setPixel(x, y, tcu::RGBA::red);
1557				}
1558			}
1559		}
1560
1561		// end result
1562		if (!uniquenessOk)
1563		{
1564			if (printCount > printFloodLimit)
1565				m_testCtx.getLog()
1566					<< tcu::TestLog::Message
1567					<< "...\n"
1568					<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1569					<< tcu::TestLog::EndMessage;
1570
1571			m_testCtx.getLog()
1572				<< tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage
1573				<< tcu::TestLog::ImageSet("Verification", "Image Verification")
1574				<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask.getAccess())
1575				<< tcu::TestLog::EndImageSet;
1576
1577			allOk = false;
1578		}
1579	}
1580
1581	return allOk;
1582}
1583
1584class SampleMaskUniqueSetCase : public SampleMaskBaseCase
1585{
1586public:
1587									SampleMaskUniqueSetCase		(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode);
1588									~SampleMaskUniqueSetCase	(void);
1589
1590	void							init						(void);
1591	void							deinit						(void);
1592
1593private:
1594	enum
1595	{
1596		RENDER_SIZE = 64
1597	};
1598
1599	void							preDraw						(void);
1600	void							postDraw					(void);
1601	std::string						genFragmentSource			(int numTargetSamples) const;
1602	bool							verifySampleBuffers			(const std::vector<tcu::Surface>& resultBuffers);
1603	std::string						getIterationDescription		(int iteration) const;
1604
1605	void							preTest						(void);
1606	void							postTest					(void);
1607
1608	std::vector<tcu::Surface>		m_iterationSampleBuffers;
1609};
1610
1611SampleMaskUniqueSetCase::SampleMaskUniqueSetCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode)
1612	: SampleMaskBaseCase(context, name, desc, sampleCount, target, RENDER_SIZE, runMode, MultisampleShaderRenderUtil::MultisampleRenderCase::FLAG_VERIFY_MSAA_TEXTURE_SAMPLE_BUFFERS)
1613{
1614	DE_ASSERT(runMode == RUN_PER_TWO_SAMPLES);
1615	DE_ASSERT(target == TARGET_TEXTURE);
1616
1617	// high and low bits
1618	m_numIterations = 2;
1619}
1620
1621SampleMaskUniqueSetCase::~SampleMaskUniqueSetCase (void)
1622{
1623}
1624
1625void SampleMaskUniqueSetCase::init (void)
1626{
1627	// log the test method and expectations
1628	m_testCtx.getLog()
1629		<< tcu::TestLog::Message
1630		<< "Verifying gl_SampleMaskIn.\n"
1631		<< "	Fragment shader may be invoked [ceil(numSamples/2), numSamples] times.\n"
1632		<< "	=> Each invocation should have unique bit set\n"
1633		<< "	Writing highest and lowest bit index to color channels in render shader. Verifying:\n"
1634		<< "		1) no other invocation contains these bits in sampler shader.\n"
1635		<< "		2) number of invocations is at least ceil(numSamples/2).\n"
1636		<< tcu::TestLog::EndMessage;
1637
1638	SampleMaskBaseCase::init();
1639}
1640
1641void SampleMaskUniqueSetCase::deinit (void)
1642{
1643	m_iterationSampleBuffers.clear();
1644}
1645
1646void SampleMaskUniqueSetCase::preDraw (void)
1647{
1648	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
1649	const int				selectorLoc	= gl.getUniformLocation(m_program->getProgram(), "u_bitSelector");
1650
1651	gl.uniform1ui(selectorLoc, (deUint32)m_iteration);
1652	GLU_EXPECT_NO_ERROR(gl.getError(), "set u_bitSelector");
1653
1654	m_testCtx.getLog() << tcu::TestLog::Message << "Setting u_bitSelector = " << m_iteration << tcu::TestLog::EndMessage;
1655
1656	SampleMaskBaseCase::preDraw();
1657}
1658
1659void SampleMaskUniqueSetCase::postDraw (void)
1660{
1661	SampleMaskBaseCase::postDraw();
1662}
1663
1664std::string SampleMaskUniqueSetCase::genFragmentSource (int numTargetSamples) const
1665{
1666	DE_ASSERT(numTargetSamples != 0);
1667
1668	std::ostringstream buf;
1669
1670	// test supports only one sample mask word
1671	if (numTargetSamples > 32)
1672		throw tcu::NotSupportedError("Sample count larger than 32 is not supported.");
1673
1674	// output min and max sample id
1675	buf <<	"#version 310 es\n"
1676			"#extension GL_OES_sample_variables : require\n"
1677			"uniform highp uint u_bitSelector;\n"
1678			"layout(location = 0) out mediump vec4 fragColor;\n"
1679			"void main (void)\n"
1680			"{\n"
1681			"	highp int selectedBits;\n"
1682			"	if (u_bitSelector == 0u)\n"
1683			"		selectedBits = (gl_SampleMaskIn[0] & 0xFFFF);\n"
1684			"	else\n"
1685			"		selectedBits = ((gl_SampleMaskIn[0] >> 16) & 0xFFFF);\n"
1686			"\n"
1687			"	// encode bits to color\n"
1688			"	highp int redBits = selectedBits & 31;\n"
1689			"	highp int greenBits = (selectedBits >> 5) & 63;\n"
1690			"	highp int blueBits = (selectedBits >> 11) & 31;\n"
1691			"\n"
1692			"	fragColor = vec4(float(redBits) / float(31), float(greenBits) / float(63), float(blueBits) / float(31), 1.0);\n"
1693			"}\n";
1694
1695	return buf.str();
1696}
1697
1698bool SampleMaskUniqueSetCase::verifySampleBuffers (const std::vector<tcu::Surface>& resultBuffers)
1699{
1700	// we need results from all passes to do verification. Store results and verify later (at postTest).
1701
1702	DE_ASSERT(m_numTargetSamples == (int)resultBuffers.size());
1703	for (int ndx = 0; ndx < m_numTargetSamples; ++ndx)
1704		m_iterationSampleBuffers[m_iteration * m_numTargetSamples + ndx] = resultBuffers[ndx];
1705
1706	return true;
1707}
1708
1709std::string SampleMaskUniqueSetCase::getIterationDescription (int iteration) const
1710{
1711	if (iteration == 0)
1712		return "Reading low bits";
1713	else if (iteration == 1)
1714		return "Reading high bits";
1715	else
1716		DE_ASSERT(false);
1717	return "";
1718}
1719
1720void SampleMaskUniqueSetCase::preTest (void)
1721{
1722	m_iterationSampleBuffers.resize(m_numTargetSamples * 2);
1723}
1724
1725void SampleMaskUniqueSetCase::postTest (void)
1726{
1727	DE_ASSERT((m_iterationSampleBuffers.size() % 2) == 0);
1728	DE_ASSERT((int)m_iterationSampleBuffers.size() / 2 == m_numTargetSamples);
1729
1730	const int						width			= m_iterationSampleBuffers[0].getWidth();
1731	const int						height			= m_iterationSampleBuffers[0].getHeight();
1732	bool							allOk			= true;
1733	std::vector<tcu::TextureLevel>	sampleCoverage	(m_numTargetSamples);
1734	const tcu::ScopedLogSection		section			(m_testCtx.getLog(), "Verify", "Verify masks");
1735
1736	// convert color layers to 32 bit coverage masks, 2 passes per coverage
1737
1738	for (int sampleNdx = 0; sampleNdx < (int)sampleCoverage.size(); ++sampleNdx)
1739	{
1740		sampleCoverage[sampleNdx].setStorage(tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::UNSIGNED_INT32), width, height);
1741
1742		for (int y = 0; y < height; ++y)
1743		for (int x = 0; x < width; ++x)
1744		{
1745			const tcu::RGBA		lowColor	= m_iterationSampleBuffers[sampleNdx].getPixel(x, y);
1746			const tcu::RGBA		highColor	= m_iterationSampleBuffers[sampleNdx + (int)sampleCoverage.size()].getPixel(x, y);
1747			deUint16			low;
1748			deUint16			high;
1749
1750			{
1751				int redBits		= (int)deFloatRound(lowColor.getRed() / 255.0f * 31);
1752				int greenBits	= (int)deFloatRound(lowColor.getGreen() / 255.0f * 63);
1753				int blueBits	= (int)deFloatRound(lowColor.getBlue() / 255.0f * 31);
1754
1755				low = (deUint16)(redBits | (greenBits << 5) | (blueBits << 11));
1756			}
1757			{
1758				int redBits		= (int)deFloatRound(highColor.getRed() / 255.0f * 31);
1759				int greenBits	= (int)deFloatRound(highColor.getGreen() / 255.0f * 63);
1760				int blueBits	= (int)deFloatRound(highColor.getBlue() / 255.0f * 31);
1761
1762				high = (deUint16)(redBits | (greenBits << 5) | (blueBits << 11));
1763			}
1764
1765			sampleCoverage[sampleNdx].getAccess().setPixel(tcu::UVec4((((deUint32)high) << 16) | low, 0, 0, 0), x, y);
1766		}
1767	}
1768
1769	// verify masks
1770
1771	if (m_numRequestedSamples == 0)
1772	{
1773		// single sample target, expect mask = 0x01
1774		const int	printFloodLimit	= 5;
1775		int			printCount		= 0;
1776
1777		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying sample mask is 0x00000001." << tcu::TestLog::EndMessage;
1778
1779		for (int y = 0; y < height; ++y)
1780		for (int x = 0; x < width; ++x)
1781		{
1782			deUint32 mask = sampleCoverage[0].getAccess().getPixelUint(x, y).x();
1783			if (mask != 0x01)
1784			{
1785				allOk = false;
1786
1787				if (++printCount <= printFloodLimit)
1788				{
1789					m_testCtx.getLog()
1790						<< tcu::TestLog::Message
1791						<< "Pixel (" << x << ", " << y << "): Invalid mask, got " << tcu::Format::Hex<8>(mask) << ", expected " << tcu::Format::Hex<8>(0x01) << "\n"
1792						<< tcu::TestLog::EndMessage;
1793				}
1794			}
1795		}
1796
1797		if (!allOk && printCount > printFloodLimit)
1798		{
1799			m_testCtx.getLog()
1800				<< tcu::TestLog::Message
1801				<< "...\n"
1802				<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1803				<< tcu::TestLog::EndMessage;
1804		}
1805	}
1806	else
1807	{
1808		// check uniqueness
1809		{
1810			bool		uniquenessOk	= true;
1811			int			printCount		= 0;
1812			const int	printFloodLimit	= 5;
1813
1814			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying invocation sample masks do not share bits." << tcu::TestLog::EndMessage;
1815
1816			for (int y = 0; y < height; ++y)
1817			for (int x = 0; x < width; ++x)
1818			{
1819				bool maskBitsNotUnique = false;
1820
1821				for (int sampleNdxA = 0;            sampleNdxA < m_numTargetSamples && (!maskBitsNotUnique || printCount < printFloodLimit); ++sampleNdxA)
1822				for (int sampleNdxB = sampleNdxA+1; sampleNdxB < m_numTargetSamples && (!maskBitsNotUnique || printCount < printFloodLimit); ++sampleNdxB)
1823				{
1824					const deUint32 maskA = sampleCoverage[sampleNdxA].getAccess().getPixelUint(x, y).x();
1825					const deUint32 maskB = sampleCoverage[sampleNdxB].getAccess().getPixelUint(x, y).x();
1826
1827					// equal mask == emitted by the same invocation
1828					if (maskA != maskB)
1829					{
1830						// shares samples?
1831						if (maskA & maskB)
1832						{
1833							maskBitsNotUnique = true;
1834							uniquenessOk = false;
1835
1836							if (++printCount <= printFloodLimit)
1837							{
1838								m_testCtx.getLog()
1839									<< tcu::TestLog::Message
1840									<< "Pixel (" << x << ", " << y << "):\n"
1841									<< "\tSamples " << sampleNdxA << " and " << sampleNdxB << " share mask bits\n"
1842									<< "\tMask" << sampleNdxA << " = " << tcu::Format::Hex<8>(maskA) << "\n"
1843									<< "\tMask" << sampleNdxB << " = " << tcu::Format::Hex<8>(maskB) << "\n"
1844									<< tcu::TestLog::EndMessage;
1845							}
1846						}
1847					}
1848				}
1849			}
1850
1851			if (!uniquenessOk)
1852			{
1853				allOk = false;
1854
1855				if (printCount > printFloodLimit)
1856					m_testCtx.getLog()
1857						<< tcu::TestLog::Message
1858						<< "...\n"
1859						<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1860						<< tcu::TestLog::EndMessage;
1861			}
1862		}
1863
1864		// check number of sample mask bit groups is valid ( == number of invocations )
1865		{
1866			const deUint32			minNumInvocations	= (deUint32)de::max(1, (m_numTargetSamples+1)/2);
1867			bool					countOk				= true;
1868			int						printCount			= 0;
1869			const int				printFloodLimit		= 5;
1870
1871			m_testCtx.getLog() << tcu::TestLog::Message << "Verifying cardinality of separate sample mask bit sets. Expecting equal to the number of invocations, (greater or equal to " << minNumInvocations << ")" << tcu::TestLog::EndMessage;
1872
1873			for (int y = 0; y < height; ++y)
1874			for (int x = 0; x < width; ++x)
1875			{
1876				std::set<deUint32> masks;
1877
1878				for (int maskNdx = 0; maskNdx < m_numTargetSamples; ++maskNdx)
1879				{
1880					const deUint32 mask = sampleCoverage[maskNdx].getAccess().getPixelUint(x, y).x();
1881					masks.insert(mask);
1882				}
1883
1884				if ((int)masks.size() < (int)minNumInvocations)
1885				{
1886					if (++printCount <= printFloodLimit)
1887					{
1888						m_testCtx.getLog()
1889							<< tcu::TestLog::Message
1890							<< "Pixel (" << x << ", " << y << "): Pixel invocations had only " << (int)masks.size() << " separate mask sets. Expected " << minNumInvocations << " or more. Found masks:"
1891							<< tcu::TestLog::EndMessage;
1892
1893						for (std::set<deUint32>::iterator it = masks.begin(); it != masks.end(); ++it)
1894							m_testCtx.getLog()
1895							<< tcu::TestLog::Message
1896							<< "\tMask: " << tcu::Format::Hex<8>(*it) << "\n"
1897							<< tcu::TestLog::EndMessage;
1898					}
1899
1900					countOk = false;
1901				}
1902			}
1903
1904			if (!countOk)
1905			{
1906				allOk = false;
1907
1908				if (printCount > printFloodLimit)
1909					m_testCtx.getLog()
1910						<< tcu::TestLog::Message
1911						<< "...\n"
1912						<< "Omitted " << (printCount-printFloodLimit) << " error descriptions."
1913						<< tcu::TestLog::EndMessage;
1914			}
1915		}
1916	}
1917
1918	if (!allOk)
1919		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1920}
1921
1922class SampleMaskWriteCase : public SampleMaskBaseCase
1923{
1924public:
1925	enum TestMode
1926	{
1927		TEST_DISCARD = 0,
1928		TEST_INVERSE,
1929
1930		TEST_LAST
1931	};
1932						SampleMaskWriteCase			(Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode, TestMode testMode);
1933						~SampleMaskWriteCase		(void);
1934
1935	void				init						(void);
1936	void				preDraw						(void);
1937	void				postDraw					(void);
1938
1939private:
1940	enum
1941	{
1942		RENDER_SIZE = 64
1943	};
1944
1945	std::string			genFragmentSource			(int numTargetSamples) const;
1946	bool				verifyImage					(const tcu::Surface& resultImage);
1947
1948	const TestMode		m_testMode;
1949};
1950
1951SampleMaskWriteCase::SampleMaskWriteCase (Context& context, const char* name, const char* desc, int sampleCount, RenderTarget target, ShaderRunMode runMode, TestMode testMode)
1952	: SampleMaskBaseCase	(context, name, desc, sampleCount, target, RENDER_SIZE, runMode)
1953	, m_testMode			(testMode)
1954{
1955	DE_ASSERT(testMode < TEST_LAST);
1956}
1957
1958SampleMaskWriteCase::~SampleMaskWriteCase (void)
1959{
1960}
1961
1962void SampleMaskWriteCase::init (void)
1963{
1964	// log the test method and expectations
1965	if (m_testMode == TEST_DISCARD)
1966		m_testCtx.getLog()
1967			<< tcu::TestLog::Message
1968			<< "Discarding half of the samples using gl_SampleMask, expecting:\n"
1969			<< "	1) half intensity on multisample targets (numSamples > 1)\n"
1970			<< "	2) full discard on multisample targets (numSamples == 1)\n"
1971			<< "	3) full intensity (no discard) on singlesample targets. (Mask is only applied as a multisample operation.)\n"
1972			<< tcu::TestLog::EndMessage;
1973	else if (m_testMode == TEST_INVERSE)
1974		m_testCtx.getLog()
1975			<< tcu::TestLog::Message
1976			<< "Discarding half of the samples using GL_SAMPLE_MASK, setting inverse mask in fragment shader using gl_SampleMask, expecting:\n"
1977			<< "	1) full discard on multisample targets (mask & modifiedCoverge == 0)\n"
1978			<< "	2) full intensity (no discard) on singlesample targets. (Mask and coverage is only applied as a multisample operation.)\n"
1979			<< tcu::TestLog::EndMessage;
1980	else
1981		DE_ASSERT(false);
1982
1983	SampleMaskBaseCase::init();
1984}
1985
1986void SampleMaskWriteCase::preDraw (void)
1987{
1988	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
1989
1990	if (m_testMode == TEST_INVERSE)
1991	{
1992		// set mask to 0xAAAA.., set inverse mask bit coverage in shader
1993
1994		const int		maskLoc	= gl.getUniformLocation(m_program->getProgram(), "u_mask");
1995		const deUint32	mask	= (deUint32)0xAAAAAAAAUL;
1996
1997		if (maskLoc == -1)
1998			throw tcu::TestError("Location of u_mask was -1");
1999
2000		gl.enable(GL_SAMPLE_MASK);
2001		gl.sampleMaski(0, mask);
2002		GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
2003
2004		gl.uniform1ui(maskLoc, mask);
2005		GLU_EXPECT_NO_ERROR(gl.getError(), "set mask uniform");
2006
2007		m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask " << tcu::Format::Hex<4>(mask) << tcu::TestLog::EndMessage;
2008	}
2009
2010	SampleMaskBaseCase::preDraw();
2011}
2012
2013void SampleMaskWriteCase::postDraw (void)
2014{
2015	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2016
2017	if (m_testMode == TEST_INVERSE)
2018	{
2019		const deUint32 fullMask	= (1U << m_numTargetSamples) - 1;
2020
2021		gl.disable(GL_SAMPLE_MASK);
2022		gl.sampleMaski(0, fullMask);
2023		GLU_EXPECT_NO_ERROR(gl.getError(), "set mask");
2024	}
2025
2026	SampleMaskBaseCase::postDraw();
2027}
2028
2029std::string SampleMaskWriteCase::genFragmentSource (int numTargetSamples) const
2030{
2031	DE_ASSERT(numTargetSamples != 0);
2032	DE_UNREF(numTargetSamples);
2033
2034	std::ostringstream	buf;
2035
2036	if (m_testMode == TEST_DISCARD)
2037	{
2038		// mask out every other coverage bit
2039
2040		buf <<	"#version 310 es\n"
2041				"#extension GL_OES_sample_variables : require\n"
2042				"layout(location = 0) out mediump vec4 fragColor;\n"
2043				"void main (void)\n"
2044				"{\n"
2045				"	for (int i = 0; i < gl_SampleMask.length(); ++i)\n"
2046				"		gl_SampleMask[i] = int(0xAAAAAAAA);\n"
2047				"\n";
2048
2049		if (m_runMode == RUN_PER_SAMPLE)
2050			buf <<	"	// force per-sample shading\n"
2051					"	highp float blue = float(gl_SampleID);\n"
2052					"\n"
2053					"	fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
2054					"}\n";
2055		else
2056			buf <<	"	fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
2057					"}\n";
2058	}
2059	else if (m_testMode == TEST_INVERSE)
2060	{
2061		// inverse every coverage bit
2062
2063		buf <<	"#version 310 es\n"
2064				"#extension GL_OES_sample_variables : require\n"
2065				"layout(location = 0) out mediump vec4 fragColor;\n"
2066				"uniform highp uint u_mask;\n"
2067				"void main (void)\n"
2068				"{\n"
2069				"	gl_SampleMask[0] = int(~u_mask);\n"
2070				"\n";
2071
2072		if (m_runMode == RUN_PER_SAMPLE)
2073			buf <<	"	// force per-sample shading\n"
2074					"	highp float blue = float(gl_SampleID);\n"
2075					"\n"
2076					"	fragColor = vec4(0.0, 1.0, blue, 1.0);\n"
2077					"}\n";
2078		else
2079			buf <<	"	fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
2080					"}\n";
2081	}
2082	else
2083		DE_ASSERT(false);
2084
2085	return buf.str();
2086}
2087
2088bool SampleMaskWriteCase::verifyImage (const tcu::Surface& resultImage)
2089{
2090	const bool singleSampleTarget = m_numRequestedSamples == 0 && !(m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() > 1);
2091
2092	if (m_testMode == TEST_DISCARD)
2093	{
2094		if (singleSampleTarget)
2095		{
2096			// single sample case => multisample operations are not effective => don't discard anything
2097			// expect green
2098			return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 1.0f, 0.0f)));
2099		}
2100		else if (m_numTargetSamples == 1)
2101		{
2102			// total discard, expect black
2103			return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f)));
2104		}
2105		else
2106		{
2107			// partial discard, expect something between black and green
2108			return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), PartialDiscardVerifier());
2109		}
2110	}
2111	else if (m_testMode == TEST_INVERSE)
2112	{
2113		if (singleSampleTarget)
2114		{
2115			// single sample case => multisample operations are not effective => don't discard anything
2116			// expect green
2117			return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 1.0f, 0.0f)));
2118		}
2119		else
2120		{
2121			// total discard, expect black
2122			return verifyImageWithVerifier(resultImage, m_testCtx.getLog(), ColorVerifier(tcu::Vec3(0.0f, 0.0f, 0.0f)));
2123		}
2124	}
2125	else
2126	{
2127		DE_ASSERT(false);
2128		return false;
2129	}
2130}
2131
2132} // anonymous
2133
2134SampleVariableTests::SampleVariableTests (Context& context)
2135	: TestCaseGroup(context, "sample_variables", "Test sample variables")
2136{
2137}
2138
2139SampleVariableTests::~SampleVariableTests (void)
2140{
2141}
2142
2143void SampleVariableTests::init (void)
2144{
2145	tcu::TestCaseGroup* const numSampleGroup	= new tcu::TestCaseGroup(m_testCtx,	"num_samples",		"Test NumSamples");
2146	tcu::TestCaseGroup* const maxSampleGroup	= new tcu::TestCaseGroup(m_testCtx,	"max_samples",		"Test MaxSamples");
2147	tcu::TestCaseGroup* const sampleIDGroup		= new tcu::TestCaseGroup(m_testCtx,	"sample_id",		"Test SampleID");
2148	tcu::TestCaseGroup* const samplePosGroup	= new tcu::TestCaseGroup(m_testCtx,	"sample_pos",		"Test SamplePosition");
2149	tcu::TestCaseGroup* const sampleMaskInGroup	= new tcu::TestCaseGroup(m_testCtx,	"sample_mask_in",	"Test SampleMaskIn");
2150	tcu::TestCaseGroup* const sampleMaskGroup	= new tcu::TestCaseGroup(m_testCtx,	"sample_mask",		"Test SampleMask");
2151
2152	addChild(numSampleGroup);
2153	addChild(maxSampleGroup);
2154	addChild(sampleIDGroup);
2155	addChild(samplePosGroup);
2156	addChild(sampleMaskInGroup);
2157	addChild(sampleMaskGroup);
2158
2159	static const struct RenderTarget
2160	{
2161		const char*							name;
2162		const char*							desc;
2163		int									numSamples;
2164		MultisampleRenderCase::RenderTarget	target;
2165	} targets[] =
2166	{
2167		{ "default_framebuffer",		"Test with default framebuffer",	0,	MultisampleRenderCase::TARGET_DEFAULT		},
2168		{ "singlesample_texture",		"Test with singlesample texture",	0,	MultisampleRenderCase::TARGET_TEXTURE		},
2169		{ "multisample_texture_1",		"Test with multisample texture",	1,	MultisampleRenderCase::TARGET_TEXTURE		},
2170		{ "multisample_texture_2",		"Test with multisample texture",	2,	MultisampleRenderCase::TARGET_TEXTURE		},
2171		{ "multisample_texture_4",		"Test with multisample texture",	4,	MultisampleRenderCase::TARGET_TEXTURE		},
2172		{ "multisample_texture_8",		"Test with multisample texture",	8,	MultisampleRenderCase::TARGET_TEXTURE		},
2173		{ "multisample_texture_16",		"Test with multisample texture",	16,	MultisampleRenderCase::TARGET_TEXTURE		},
2174		{ "singlesample_rbo",			"Test with singlesample rbo",		0,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
2175		{ "multisample_rbo_1",			"Test with multisample rbo",		1,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
2176		{ "multisample_rbo_2",			"Test with multisample rbo",		2,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
2177		{ "multisample_rbo_4",			"Test with multisample rbo",		4,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
2178		{ "multisample_rbo_8",			"Test with multisample rbo",		8,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
2179		{ "multisample_rbo_16",			"Test with multisample rbo",		16,	MultisampleRenderCase::TARGET_RENDERBUFFER	},
2180	};
2181
2182	// .num_samples
2183	{
2184		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2185			numSampleGroup->addChild(new NumSamplesCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2186	}
2187
2188	// .max_samples
2189	{
2190		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2191			maxSampleGroup->addChild(new MaxSamplesCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2192	}
2193
2194	// .sample_ID
2195	{
2196		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2197			sampleIDGroup->addChild(new SampleIDCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2198	}
2199
2200	// .sample_pos
2201	{
2202		{
2203			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"correctness", "Test SamplePos correctness");
2204			samplePosGroup->addChild(group);
2205
2206			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2207				group->addChild(new SamplePosCorrectnessCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2208		}
2209
2210		{
2211			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"distribution", "Test SamplePos distribution");
2212			samplePosGroup->addChild(group);
2213
2214			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2215				group->addChild(new SamplePosDistributionCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2216		}
2217	}
2218
2219	// .sample_mask_in
2220	{
2221		// .sample_mask
2222		{
2223			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"sample_mask", "Test with GL_SAMPLE_MASK");
2224			sampleMaskInGroup->addChild(group);
2225
2226			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2227				group->addChild(new SampleMaskCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target));
2228		}
2229		// .bit_count_per_pixel
2230		{
2231			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"bit_count_per_pixel", "Test number of coverage bits");
2232			sampleMaskInGroup->addChild(group);
2233
2234			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2235				group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_PIXEL));
2236		}
2237		// .bit_count_per_sample
2238		{
2239			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"bit_count_per_sample", "Test number of coverage bits");
2240			sampleMaskInGroup->addChild(group);
2241
2242			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2243				group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_SAMPLE));
2244		}
2245		// .bit_count_per_two_samples
2246		{
2247			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"bit_count_per_two_samples", "Test number of coverage bits");
2248			sampleMaskInGroup->addChild(group);
2249
2250			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2251				group->addChild(new SampleMaskCountCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskCountCase::RUN_PER_TWO_SAMPLES));
2252		}
2253		// .bits_unique_per_sample
2254		{
2255			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"bits_unique_per_sample", "Test coverage bits");
2256			sampleMaskInGroup->addChild(group);
2257
2258			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2259				if (targets[targetNdx].target == MultisampleRenderCase::TARGET_TEXTURE)
2260					group->addChild(new SampleMaskUniqueCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskUniqueCase::RUN_PER_SAMPLE));
2261		}
2262		// .bits_unique_per_two_samples
2263		{
2264			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"bits_unique_per_two_samples", "Test coverage bits");
2265			sampleMaskInGroup->addChild(group);
2266
2267			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2268				if (targets[targetNdx].target == MultisampleRenderCase::TARGET_TEXTURE)
2269					group->addChild(new SampleMaskUniqueSetCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskUniqueCase::RUN_PER_TWO_SAMPLES));
2270		}
2271	}
2272
2273	// .sample_mask
2274	{
2275		// .discard_half_per_pixel
2276		{
2277			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"discard_half_per_pixel", "Test coverage bits");
2278			sampleMaskGroup->addChild(group);
2279
2280			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2281				group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_PIXEL, SampleMaskWriteCase::TEST_DISCARD));
2282		}
2283		// .discard_half_per_sample
2284		{
2285			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"discard_half_per_sample", "Test coverage bits");
2286			sampleMaskGroup->addChild(group);
2287
2288			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2289				group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_SAMPLE, SampleMaskWriteCase::TEST_DISCARD));
2290		}
2291		// .discard_half_per_two_samples
2292		{
2293			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"discard_half_per_two_samples", "Test coverage bits");
2294			sampleMaskGroup->addChild(group);
2295
2296			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2297				group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_TWO_SAMPLES, SampleMaskWriteCase::TEST_DISCARD));
2298		}
2299
2300		// .discard_half_per_two_samples
2301		{
2302			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"inverse_per_pixel", "Test coverage bits");
2303			sampleMaskGroup->addChild(group);
2304
2305			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2306				group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_PIXEL, SampleMaskWriteCase::TEST_INVERSE));
2307		}
2308		// .inverse_per_sample
2309		{
2310			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"inverse_per_sample", "Test coverage bits");
2311			sampleMaskGroup->addChild(group);
2312
2313			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2314				group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_SAMPLE, SampleMaskWriteCase::TEST_INVERSE));
2315		}
2316		// .inverse_per_two_samples
2317		{
2318			tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx,	"inverse_per_two_samples", "Test coverage bits");
2319			sampleMaskGroup->addChild(group);
2320
2321			for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(targets); ++targetNdx)
2322				group->addChild(new SampleMaskWriteCase(m_context, targets[targetNdx].name, targets[targetNdx].desc, targets[targetNdx].numSamples, targets[targetNdx].target, SampleMaskWriteCase::RUN_PER_TWO_SAMPLES, SampleMaskWriteCase::TEST_INVERSE));
2323		}
2324	}
2325}
2326
2327} // Functional
2328} // gles31
2329} // deqp
2330