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 shading tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fSampleShadingTests.hpp"
     25 #include "es31fMultisampleShaderRenderCase.hpp"
     26 #include "tcuRenderTarget.hpp"
     27 #include "tcuSurface.hpp"
     28 #include "glsStateQueryUtil.hpp"
     29 #include "gluCallLogWrapper.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "gluShaderProgram.hpp"
     32 #include "gluRenderContext.hpp"
     33 #include "gluPixelTransfer.hpp"
     34 #include "glwFunctions.hpp"
     35 #include "glwEnums.hpp"
     36 #include "deStringUtil.hpp"
     37 #include "deRandom.hpp"
     38 
     39 #include <map>
     40 
     41 namespace deqp
     42 {
     43 namespace gles31
     44 {
     45 namespace Functional
     46 {
     47 namespace
     48 {
     49 
     50 class SampleShadingStateCase : public TestCase
     51 {
     52 public:
     53 	enum VerifierType
     54 	{
     55 		TYPE_IS_ENABLED = 0,
     56 		TYPE_GET_BOOLEAN,
     57 		TYPE_GET_INTEGER,
     58 		TYPE_GET_FLOAT,
     59 		TYPE_GET_INTEGER64,
     60 		TYPE_LAST
     61 	};
     62 
     63 						SampleShadingStateCase	(Context& ctx, const char* name, const char* desc, VerifierType);
     64 
     65 	void				init					(void);
     66 	IterateResult		iterate					(void);
     67 
     68 private:
     69 	bool				verify					(bool v);
     70 
     71 	const VerifierType	m_verifier;
     72 };
     73 
     74 SampleShadingStateCase::SampleShadingStateCase (Context& ctx, const char* name, const char* desc, VerifierType type)
     75 	: TestCase		(ctx, name, desc)
     76 	, m_verifier	(type)
     77 {
     78 	DE_ASSERT(m_verifier < TYPE_LAST);
     79 }
     80 
     81 void SampleShadingStateCase::init (void)
     82 {
     83 	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
     84 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension");
     85 }
     86 
     87 SampleShadingStateCase::IterateResult SampleShadingStateCase::iterate (void)
     88 {
     89 	bool				allOk	= true;
     90 	glu::CallLogWrapper gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
     91 	gl.enableLogging(true);
     92 
     93 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
     94 
     95 	// initial
     96 	{
     97 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying initial value" << tcu::TestLog::EndMessage;
     98 		allOk &= verify(false);
     99 	}
    100 
    101 	// true and false too
    102 	{
    103 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying random values" << tcu::TestLog::EndMessage;
    104 
    105 		gl.glEnable(GL_SAMPLE_SHADING);
    106 		allOk &= verify(true);
    107 
    108 		gl.glDisable(GL_SAMPLE_SHADING);
    109 		allOk &= verify(false);
    110 	}
    111 
    112 	if (!allOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    113 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected value");
    114 
    115 	return STOP;
    116 }
    117 
    118 bool SampleShadingStateCase::verify (bool v)
    119 {
    120 	glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    121 	gl.enableLogging(true);
    122 
    123 	switch (m_verifier)
    124 	{
    125 		case TYPE_IS_ENABLED:
    126 		{
    127 			const glw::GLboolean retVal = gl.glIsEnabled(GL_SAMPLE_SHADING);
    128 
    129 			if ((v && retVal==GL_TRUE) || (!v && retVal==GL_FALSE))
    130 				return true;
    131 
    132 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v) ? ("GL_TRUE") : ("GL_FALSE")) << ", got " << ((retVal == GL_TRUE) ? ("GL_TRUE") : (retVal == GL_FALSE) ? ("GL_FALSE") : ("not-a-boolean")) << tcu::TestLog::EndMessage;
    133 			return false;
    134 		}
    135 
    136 		case TYPE_GET_BOOLEAN:
    137 		{
    138 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLboolean> state;
    139 			gl.glGetBooleanv(GL_SAMPLE_SHADING, &state);
    140 
    141 			if (!state.verifyValidity(m_testCtx))
    142 				return false;
    143 
    144 			if ((v && state==GL_TRUE) || (!v && state==GL_FALSE))
    145 				return true;
    146 
    147 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v) ? ("GL_TRUE") : ("GL_FALSE")) << ", got " << ((state == GL_TRUE) ? ("GL_TRUE") : (state == GL_FALSE) ? ("GL_FALSE") : ("not-a-boolean")) << tcu::TestLog::EndMessage;
    148 			return false;
    149 		}
    150 
    151 		case TYPE_GET_INTEGER:
    152 		{
    153 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> state;
    154 			gl.glGetIntegerv(GL_SAMPLE_SHADING, &state);
    155 
    156 			if (!state.verifyValidity(m_testCtx))
    157 				return false;
    158 
    159 			if ((v && state==1) || (!v && state==0))
    160 				return true;
    161 
    162 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v) ? ("1") : ("0")) << ", got " << state << tcu::TestLog::EndMessage;
    163 			return false;
    164 		}
    165 
    166 		case TYPE_GET_FLOAT:
    167 		{
    168 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLfloat> state;
    169 			gl.glGetFloatv(GL_SAMPLE_SHADING, &state);
    170 
    171 			if (!state.verifyValidity(m_testCtx))
    172 				return false;
    173 
    174 			if ((v && state==1.0f) || (!v && state==0.0f))
    175 				return true;
    176 
    177 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v) ? ("1.0") : ("0.0")) << ", got " << state << tcu::TestLog::EndMessage;
    178 			return false;
    179 		}
    180 
    181 		case TYPE_GET_INTEGER64:
    182 		{
    183 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint64> state;
    184 			gl.glGetInteger64v(GL_SAMPLE_SHADING, &state);
    185 
    186 			if (!state.verifyValidity(m_testCtx))
    187 				return false;
    188 
    189 			if ((v && state==1) || (!v && state==0))
    190 				return true;
    191 
    192 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v) ? ("1") : ("0")) << ", got " << state << tcu::TestLog::EndMessage;
    193 			return false;
    194 		}
    195 
    196 		default:
    197 		{
    198 			DE_ASSERT(false);
    199 			return false;
    200 		}
    201 	}
    202 }
    203 
    204 class MinSampleShadingValueCase : public TestCase
    205 {
    206 public:
    207 	enum VerifierType
    208 	{
    209 		TYPE_GET_BOOLEAN = 0,
    210 		TYPE_GET_INTEGER,
    211 		TYPE_GET_FLOAT,
    212 		TYPE_GET_INTEGER64,
    213 		TYPE_LAST
    214 	};
    215 
    216 						MinSampleShadingValueCase	(Context& ctx, const char* name, const char* desc, VerifierType);
    217 
    218 	void				init						(void);
    219 	IterateResult		iterate						(void);
    220 
    221 private:
    222 	bool				verify						(float v);
    223 
    224 	const VerifierType	m_verifier;
    225 };
    226 
    227 MinSampleShadingValueCase::MinSampleShadingValueCase (Context& ctx, const char* name, const char* desc, VerifierType type)
    228 	: TestCase		(ctx, name, desc)
    229 	, m_verifier	(type)
    230 {
    231 	DE_ASSERT(m_verifier < TYPE_LAST);
    232 }
    233 
    234 void MinSampleShadingValueCase::init (void)
    235 {
    236 	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
    237 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension");
    238 }
    239 
    240 MinSampleShadingValueCase::IterateResult MinSampleShadingValueCase::iterate (void)
    241 {
    242 	bool				allOk	= true;
    243 	glu::CallLogWrapper gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    244 	gl.enableLogging(true);
    245 
    246 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    247 
    248 	// initial
    249 	{
    250 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying initial value" << tcu::TestLog::EndMessage;
    251 		allOk &= verify(0.0);
    252 	}
    253 
    254 	// special values
    255 	{
    256 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying special values" << tcu::TestLog::EndMessage;
    257 
    258 		gl.glMinSampleShading(0.0f);
    259 		allOk &= verify(0.0);
    260 
    261 		gl.glMinSampleShading(1.0f);
    262 		allOk &= verify(1.0);
    263 
    264 		gl.glMinSampleShading(0.5f);
    265 		allOk &= verify(0.5);
    266 	}
    267 
    268 	// random values
    269 	{
    270 		const int	numRandomTests	= 10;
    271 		de::Random	rnd				(0xde123);
    272 
    273 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying random values" << tcu::TestLog::EndMessage;
    274 
    275 		for (int randNdx = 0; randNdx < numRandomTests; ++randNdx)
    276 		{
    277 			const float value = rnd.getFloat();
    278 
    279 			gl.glMinSampleShading(value);
    280 			allOk &= verify(value);
    281 		}
    282 	}
    283 
    284 	if (!allOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    285 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected value");
    286 
    287 	return STOP;
    288 }
    289 
    290 bool MinSampleShadingValueCase::verify (float v)
    291 {
    292 	glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    293 	gl.enableLogging(true);
    294 
    295 	switch (m_verifier)
    296 	{
    297 		case TYPE_GET_BOOLEAN:
    298 		{
    299 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLboolean> state;
    300 			gl.glGetBooleanv(GL_MIN_SAMPLE_SHADING_VALUE, &state);
    301 
    302 			if (!state.verifyValidity(m_testCtx))
    303 				return false;
    304 
    305 			if ((v!=0.0f && state==GL_TRUE) || (v==0.0f && state==GL_FALSE))
    306 				return true;
    307 
    308 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v!=0.0f) ? ("GL_TRUE") : ("GL_FALSE")) << ", got " << ((state == GL_TRUE) ? ("GL_TRUE") : (state == GL_FALSE) ? ("GL_FALSE") : ("not-a-boolean")) << tcu::TestLog::EndMessage;
    309 			return false;
    310 		}
    311 
    312 		case TYPE_GET_INTEGER:
    313 		{
    314 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> state;
    315 			gl.glGetIntegerv(GL_MIN_SAMPLE_SHADING_VALUE, &state);
    316 
    317 			if (!state.verifyValidity(m_testCtx))
    318 				return false;
    319 
    320 			if ((v>=0.5f && state==1) || (v<=0.5f && state==0))
    321 				return true;
    322 
    323 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v==0.5) ? ("0 or 1") : (v<0.5) ? ("0") : ("1")) << ", got " << state << tcu::TestLog::EndMessage;
    324 			return false;
    325 		}
    326 
    327 		case TYPE_GET_FLOAT:
    328 		{
    329 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLfloat> state;
    330 			gl.glGetFloatv(GL_MIN_SAMPLE_SHADING_VALUE, &state);
    331 
    332 			if (!state.verifyValidity(m_testCtx))
    333 				return false;
    334 
    335 			if (v == state)
    336 				return true;
    337 
    338 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << v << ", got " << state << tcu::TestLog::EndMessage;
    339 			return false;
    340 		}
    341 
    342 		case TYPE_GET_INTEGER64:
    343 		{
    344 			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint64> state;
    345 			gl.glGetInteger64v(GL_MIN_SAMPLE_SHADING_VALUE, &state);
    346 
    347 			if (!state.verifyValidity(m_testCtx))
    348 				return false;
    349 
    350 			if ((v>=0.5f && state==1) || (v<=0.5f && state==0))
    351 				return true;
    352 
    353 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << ((v==0.5) ? ("0 or 1") : (v<0.5) ? ("0") : ("1")) << ", got " << state << tcu::TestLog::EndMessage;
    354 			return false;
    355 		}
    356 
    357 		default:
    358 		{
    359 			DE_ASSERT(false);
    360 			return false;
    361 		}
    362 	}
    363 }
    364 
    365 class MinSampleShadingValueClampingCase : public TestCase
    366 {
    367 public:
    368 						MinSampleShadingValueClampingCase	(Context& ctx, const char* name, const char* desc);
    369 
    370 	void				init								(void);
    371 	IterateResult		iterate								(void);
    372 
    373 private:
    374 	bool				verify								(float v);
    375 };
    376 
    377 MinSampleShadingValueClampingCase::MinSampleShadingValueClampingCase (Context& ctx, const char* name, const char* desc)
    378 	: TestCase(ctx, name, desc)
    379 {
    380 }
    381 
    382 void MinSampleShadingValueClampingCase::init (void)
    383 {
    384 	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
    385 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension");
    386 }
    387 
    388 MinSampleShadingValueClampingCase::IterateResult MinSampleShadingValueClampingCase::iterate (void)
    389 {
    390 	bool				allOk	= true;
    391 	glu::CallLogWrapper gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    392 	gl.enableLogging(true);
    393 
    394 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    395 
    396 	// special values
    397 	{
    398 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying clamped values. Value is clamped when specified." << tcu::TestLog::EndMessage;
    399 
    400 		gl.glMinSampleShading(-0.5f);
    401 		allOk &= verify(0.0);
    402 
    403 		gl.glMinSampleShading(-1.0f);
    404 		allOk &= verify(0.0);
    405 
    406 		gl.glMinSampleShading(-1.5f);
    407 		allOk &= verify(0.0);
    408 
    409 		gl.glMinSampleShading(1.5f);
    410 		allOk &= verify(1.0);
    411 
    412 		gl.glMinSampleShading(2.0f);
    413 		allOk &= verify(1.0);
    414 
    415 		gl.glMinSampleShading(2.5f);
    416 		allOk &= verify(1.0);
    417 	}
    418 
    419 	if (!allOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    420 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected value");
    421 
    422 	return STOP;
    423 }
    424 
    425 bool MinSampleShadingValueClampingCase::verify (float v)
    426 {
    427 	glu::CallLogWrapper												gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
    428 	gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLfloat>	state;
    429 
    430 	gl.enableLogging(true);
    431 
    432 	gl.glGetFloatv(GL_MIN_SAMPLE_SHADING_VALUE, &state);
    433 
    434 	if (!state.verifyValidity(m_testCtx))
    435 		return false;
    436 
    437 	if (v == state)
    438 		return true;
    439 
    440 	m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << v << ", got " << state << tcu::TestLog::EndMessage;
    441 	return false;
    442 }
    443 
    444 class SampleShadingRenderingCase : public MultisampleShaderRenderUtil::MultisampleRenderCase
    445 {
    446 public:
    447 	enum TestType
    448 	{
    449 		TEST_DISCARD = 0,
    450 		TEST_COLOR,
    451 
    452 		TEST_LAST
    453 	};
    454 						SampleShadingRenderingCase	(Context& ctx, const char* name, const char* desc, RenderTarget target, int numSamples, TestType type);
    455 						~SampleShadingRenderingCase	(void);
    456 
    457 	void				init						(void);
    458 private:
    459 	void				setShadingValue				(int sampleCount);
    460 
    461 	void				preDraw						(void);
    462 	void				postDraw					(void);
    463 	std::string			getIterationDescription		(int iteration) const;
    464 
    465 	bool				verifyImage					(const tcu::Surface& resultImage);
    466 
    467 	std::string			genFragmentSource			(int numSamples) const;
    468 
    469 	enum
    470 	{
    471 		RENDER_SIZE = 128
    472 	};
    473 
    474 	const TestType		m_type;
    475 };
    476 
    477 SampleShadingRenderingCase::SampleShadingRenderingCase (Context& ctx, const char* name, const char* desc, RenderTarget target, int numSamples, TestType type)
    478 	: MultisampleShaderRenderUtil::MultisampleRenderCase	(ctx, name, desc, numSamples, target, RENDER_SIZE)
    479 	, m_type												(type)
    480 {
    481 	DE_ASSERT(type < TEST_LAST);
    482 }
    483 
    484 SampleShadingRenderingCase::~SampleShadingRenderingCase (void)
    485 {
    486 	deinit();
    487 }
    488 
    489 void SampleShadingRenderingCase::init (void)
    490 {
    491 	// requirements
    492 
    493 	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_shading"))
    494 		throw tcu::NotSupportedError("Test requires GL_OES_sample_shading extension");
    495 	if (m_renderTarget == TARGET_DEFAULT && m_context.getRenderTarget().getNumSamples() <= 1)
    496 		throw tcu::NotSupportedError("Multisampled default framebuffer required");
    497 
    498 	// test purpose and expectations
    499 	m_testCtx.getLog()
    500 		<< tcu::TestLog::Message
    501 		<< "Verifying that a varying is given at least N different values for different samples within a single pixel.\n"
    502 		<< "	Render high-frequency function, map result to black/white. Modify N with glMinSampleShading().\n"
    503 		<< "	=> Resulting image should contain N+1 shades of gray.\n"
    504 		<< tcu::TestLog::EndMessage;
    505 
    506 	// setup resources
    507 
    508 	MultisampleShaderRenderUtil::MultisampleRenderCase::init();
    509 
    510 	// set iterations
    511 
    512 	m_numIterations = m_numTargetSamples + 1;
    513 }
    514 
    515 void SampleShadingRenderingCase::setShadingValue (int sampleCount)
    516 {
    517 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    518 
    519 	if (sampleCount == 0)
    520 	{
    521 		gl.disable(GL_SAMPLE_SHADING);
    522 		gl.minSampleShading(1.0f);
    523 		GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
    524 	}
    525 	else
    526 	{
    527 		// Minimum number of samples is max(ceil(<mss> * <samples>),1). Decrease mss with epsilon to prevent
    528 		// ceiling to a too large sample count.
    529 		const float epsilon	= 0.25f / (float)m_numTargetSamples;
    530 		const float ratio	= (sampleCount / (float)m_numTargetSamples) - epsilon;
    531 
    532 		gl.enable(GL_SAMPLE_SHADING);
    533 		gl.minSampleShading(ratio);
    534 		GLU_EXPECT_NO_ERROR(gl.getError(), "set ratio");
    535 
    536 		m_testCtx.getLog()
    537 			<< tcu::TestLog::Message
    538 			<< "Setting MIN_SAMPLE_SHADING_VALUE = " << ratio << "\n"
    539 			<< "Requested sample count: shadingValue * numSamples = " << ratio << " * " << m_numTargetSamples << " = " << (ratio * m_numTargetSamples) << "\n"
    540 			<< "Minimum sample count: ceil(shadingValue * numSamples) = ceil(" << (ratio * m_numTargetSamples) << ") = " << sampleCount
    541 			<< tcu::TestLog::EndMessage;
    542 
    543 		// can't fail with reasonable values of numSamples
    544 		DE_ASSERT(deFloatCeil(ratio * m_numTargetSamples) == float(sampleCount));
    545 	}
    546 }
    547 
    548 void SampleShadingRenderingCase::preDraw (void)
    549 {
    550 	setShadingValue(m_iteration);
    551 }
    552 
    553 void SampleShadingRenderingCase::postDraw (void)
    554 {
    555 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    556 
    557 	gl.disable(GL_SAMPLE_SHADING);
    558 	gl.minSampleShading(1.0f);
    559 }
    560 
    561 std::string	SampleShadingRenderingCase::getIterationDescription (int iteration) const
    562 {
    563 	if (iteration == 0)
    564 		return "Disabled SAMPLE_SHADING";
    565 	else
    566 		return "Samples per pixel: " + de::toString(iteration);
    567 }
    568 
    569 bool SampleShadingRenderingCase::verifyImage (const tcu::Surface& resultImage)
    570 {
    571 	const int				numShadesRequired	= (m_iteration == 0) ? (2) : (m_iteration + 1);
    572 	const int				rareThreshold		= 100;
    573 	int						rareCount			= 0;
    574 	std::map<deUint32, int>	shadeFrequency;
    575 
    576 	// we should now have n+1 different shades of white, n = num samples
    577 
    578 	m_testCtx.getLog()
    579 		<< tcu::TestLog::Image("ResultImage", "Result Image", resultImage.getAccess())
    580 		<< tcu::TestLog::Message
    581 		<< "Verifying image has (at least) " << numShadesRequired << " different shades.\n"
    582 		<< "Excluding pixels with no full coverage (pixels on the shared edge of the triangle pair)."
    583 		<< tcu::TestLog::EndMessage;
    584 
    585 	for (int y = 0; y < RENDER_SIZE; ++y)
    586 	for (int x = 0; x < RENDER_SIZE; ++x)
    587 	{
    588 		const tcu::RGBA	color	= resultImage.getPixel(x, y);
    589 		const deUint32	packed	= ((deUint32)color.getRed()) + ((deUint32)color.getGreen() << 8) + ((deUint32)color.getGreen() << 16);
    590 
    591 		// on the triangle edge, skip
    592 		if (x == y)
    593 			continue;
    594 
    595 		if (shadeFrequency.find(packed) == shadeFrequency.end())
    596 			shadeFrequency[packed] = 1;
    597 		else
    598 			shadeFrequency[packed] = shadeFrequency[packed] + 1;
    599 	}
    600 
    601 	for (std::map<deUint32, int>::const_iterator it = shadeFrequency.begin(); it != shadeFrequency.end(); ++it)
    602 		if (it->second < rareThreshold)
    603 			rareCount++;
    604 
    605 	m_testCtx.getLog()
    606 		<< tcu::TestLog::Message
    607 		<< "Found " << (int)shadeFrequency.size() << " different shades.\n"
    608 		<< "\tRare (less than " << rareThreshold << " pixels): " << rareCount << "\n"
    609 		<< "\tCommon: " << (int)shadeFrequency.size() - rareCount << "\n"
    610 		<< tcu::TestLog::EndMessage;
    611 
    612 	if ((int)shadeFrequency.size() < numShadesRequired)
    613 	{
    614 		m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage;
    615 		return false;
    616 	}
    617 	return true;
    618 }
    619 
    620 std::string SampleShadingRenderingCase::genFragmentSource (int numSamples) const
    621 {
    622 	DE_UNREF(numSamples);
    623 
    624 	std::ostringstream buf;
    625 
    626 	buf <<	"#version 310 es\n"
    627 			"in highp vec4 v_position;\n"
    628 			"layout(location = 0) out mediump vec4 fragColor;\n"
    629 			"void main (void)\n"
    630 			"{\n"
    631 			"	highp float field = dot(v_position.xy, v_position.xy) + dot(21.0 * v_position.xx, sin(3.1 * v_position.xy));\n"
    632 			"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
    633 			"\n"
    634 			"	if (fract(field) > 0.5)\n";
    635 
    636 	if (m_type == TEST_DISCARD)
    637 		buf <<	"		discard;\n";
    638 	else if (m_type == TEST_COLOR)
    639 		buf <<	"		fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n";
    640 	else
    641 		DE_ASSERT(false);
    642 
    643 	buf <<	"}";
    644 
    645 	return buf.str();
    646 }
    647 
    648 } // anonymous
    649 
    650 SampleShadingTests::SampleShadingTests (Context& context)
    651 	: TestCaseGroup(context, "sample_shading", "Test sample shading")
    652 {
    653 }
    654 
    655 SampleShadingTests::~SampleShadingTests (void)
    656 {
    657 }
    658 
    659 void SampleShadingTests::init (void)
    660 {
    661 	tcu::TestCaseGroup* const stateQueryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "State query tests.");
    662 	tcu::TestCaseGroup* const minSamplesGroup = new tcu::TestCaseGroup(m_testCtx, "min_sample_shading", "Min sample shading tests.");
    663 
    664 	addChild(stateQueryGroup);
    665 	addChild(minSamplesGroup);
    666 
    667 	// .state query
    668 	{
    669 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_is_enabled",				"test SAMPLE_SHADING",						SampleShadingStateCase::TYPE_IS_ENABLED));
    670 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_boolean",				"test SAMPLE_SHADING",						SampleShadingStateCase::TYPE_GET_BOOLEAN));
    671 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_integer",				"test SAMPLE_SHADING",						SampleShadingStateCase::TYPE_GET_INTEGER));
    672 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_float",					"test SAMPLE_SHADING",						SampleShadingStateCase::TYPE_GET_FLOAT));
    673 		stateQueryGroup->addChild(new SampleShadingStateCase			(m_context, "sample_shading_get_integer64",				"test SAMPLE_SHADING",						SampleShadingStateCase::TYPE_GET_INTEGER64));
    674 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_boolean",		"test MIN_SAMPLE_SHADING_VALUE",			MinSampleShadingValueCase::TYPE_GET_BOOLEAN));
    675 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_integer",		"test MIN_SAMPLE_SHADING_VALUE",			MinSampleShadingValueCase::TYPE_GET_INTEGER));
    676 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_float",		"test MIN_SAMPLE_SHADING_VALUE",			MinSampleShadingValueCase::TYPE_GET_FLOAT));
    677 		stateQueryGroup->addChild(new MinSampleShadingValueCase			(m_context, "min_sample_shading_value_get_integer64",	"test MIN_SAMPLE_SHADING_VALUE",			MinSampleShadingValueCase::TYPE_GET_INTEGER64));
    678 		stateQueryGroup->addChild(new MinSampleShadingValueClampingCase	(m_context, "min_sample_shading_value_clamping",		"test MIN_SAMPLE_SHADING_VALUE clamping"));
    679 	}
    680 
    681 	// .min_sample_count
    682 	{
    683 		static const struct Target
    684 		{
    685 			SampleShadingRenderingCase::RenderTarget	target;
    686 			int											numSamples;
    687 			const char*									name;
    688 		} targets[] =
    689 		{
    690 			{ SampleShadingRenderingCase::TARGET_DEFAULT,			0,	"default_framebuffer"					},
    691 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			2,	"multisample_texture_samples_2"			},
    692 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			4,	"multisample_texture_samples_4"			},
    693 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			8,	"multisample_texture_samples_8"			},
    694 			{ SampleShadingRenderingCase::TARGET_TEXTURE,			16,	"multisample_texture_samples_16"		},
    695 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		2,	"multisample_renderbuffer_samples_2"	},
    696 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		4,	"multisample_renderbuffer_samples_4"	},
    697 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		8,	"multisample_renderbuffer_samples_8"	},
    698 			{ SampleShadingRenderingCase::TARGET_RENDERBUFFER,		16,	"multisample_renderbuffer_samples_16"	},
    699 		};
    700 
    701 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(targets); ++ndx)
    702 		{
    703 			minSamplesGroup->addChild(new SampleShadingRenderingCase(m_context, (std::string(targets[ndx].name) + "_color").c_str(),	"Test multiple samples per pixel with color",	targets[ndx].target, targets[ndx].numSamples, SampleShadingRenderingCase::TEST_COLOR));
    704 			minSamplesGroup->addChild(new SampleShadingRenderingCase(m_context, (std::string(targets[ndx].name) + "_discard").c_str(),	"Test multiple samples per pixel with",			targets[ndx].target, targets[ndx].numSamples, SampleShadingRenderingCase::TEST_DISCARD));
    705 		}
    706 	}
    707 }
    708 
    709 } // Functional
    710 } // gles31
    711 } // deqp
    712