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