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