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