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 Multisample texture test
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fTextureMultisampleTests.hpp"
     25 #include "tcuTestLog.hpp"
     26 #include "tcuRenderTarget.hpp"
     27 #include "tcuSurface.hpp"
     28 #include "tcuStringTemplate.hpp"
     29 #include "tcuTextureUtil.hpp"
     30 #include "glsStateQueryUtil.hpp"
     31 #include "tcuRasterizationVerifier.hpp"
     32 #include "gluRenderContext.hpp"
     33 #include "gluCallLogWrapper.hpp"
     34 #include "gluObjectWrapper.hpp"
     35 #include "gluShaderProgram.hpp"
     36 #include "gluPixelTransfer.hpp"
     37 #include "gluStrUtil.hpp"
     38 #include "gluContextInfo.hpp"
     39 #include "glwEnums.hpp"
     40 #include "glwFunctions.hpp"
     41 #include "deStringUtil.hpp"
     42 #include "deRandom.hpp"
     43 
     44 using namespace glw;
     45 
     46 namespace deqp
     47 {
     48 namespace gles31
     49 {
     50 namespace Functional
     51 {
     52 namespace
     53 {
     54 
     55 using tcu::RasterizationArguments;
     56 using tcu::TriangleSceneSpec;
     57 
     58 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits)
     59 {
     60 	std::string result(numBits, '0');
     61 
     62 	// move from back to front and set chars to 1
     63 	for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx)
     64 	{
     65 		for (int bit = 0; bit < 32; ++bit)
     66 		{
     67 			const int targetCharNdx = numBits - (wordNdx*32+bit) - 1;
     68 
     69 			// beginning of the string reached
     70 			if (targetCharNdx < 0)
     71 				return result;
     72 
     73 			if ((bitfield[wordNdx] >> bit) & 0x01)
     74 				result[targetCharNdx] = '1';
     75 		}
     76 	}
     77 
     78 	return result;
     79 }
     80 
     81 /*--------------------------------------------------------------------*//*!
     82  * \brief Returns the number of words needed to represent mask of given length
     83  *//*--------------------------------------------------------------------*/
     84 static int getEffectiveSampleMaskWordCount (int highestBitNdx)
     85 {
     86 	const int wordSize	= 32;
     87 	const int maskLen	= highestBitNdx + 1;
     88 
     89 	return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len /  wordSize)
     90 }
     91 
     92 /*--------------------------------------------------------------------*//*!
     93  * \brief Creates sample mask with all less significant bits than nthBit set
     94  *//*--------------------------------------------------------------------*/
     95 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit)
     96 {
     97 	const int				wordSize	= 32;
     98 	const int				numWords	= getEffectiveSampleMaskWordCount(nthBit - 1);
     99 	const deUint32			topWordBits	= (deUint32)(nthBit - (numWords - 1) * wordSize);
    100 	std::vector<deUint32>	mask		(numWords);
    101 
    102 	for (int ndx = 0; ndx < numWords - 1; ++ndx)
    103 		mask[ndx] = 0xFFFFFFFF;
    104 
    105 	mask[numWords - 1] = (deUint32)((1ULL << topWordBits) - (deUint32)1);
    106 	return mask;
    107 }
    108 
    109 /*--------------------------------------------------------------------*//*!
    110  * \brief Creates sample mask with nthBit set
    111  *//*--------------------------------------------------------------------*/
    112 static std::vector<deUint32> genSetNthBitSampleMask (int nthBit)
    113 {
    114 	const int				wordSize	= 32;
    115 	const int				numWords	= getEffectiveSampleMaskWordCount(nthBit);
    116 	const deUint32			topWordBits	= (deUint32)(nthBit - (numWords - 1) * wordSize);
    117 	std::vector<deUint32>	mask		(numWords);
    118 
    119 	for (int ndx = 0; ndx < numWords - 1; ++ndx)
    120 		mask[ndx] = 0;
    121 
    122 	mask[numWords - 1] = (deUint32)(1ULL << topWordBits);
    123 	return mask;
    124 }
    125 
    126 std::string specializeShader (Context& context, const char* code)
    127 {
    128 	const glu::ContextType				contextType		= context.getRenderContext().getType();
    129 	const glu::GLSLVersion				glslVersion		= glu::getContextTypeGLSLVersion(contextType);
    130 	std::map<std::string, std::string> specializationMap;
    131 
    132 	specializationMap["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
    133 
    134 	return tcu::StringTemplate(code).specialize(specializationMap);
    135 }
    136 
    137 class SamplePosRasterizationTest : public TestCase
    138 {
    139 public:
    140 								SamplePosRasterizationTest	(Context& context, const char* name, const char* desc, int samples);
    141 								~SamplePosRasterizationTest	(void);
    142 
    143 private:
    144 	void						init						(void);
    145 	void						deinit						(void);
    146 	IterateResult				iterate						(void);
    147 	void						genMultisampleTexture		(void);
    148 	void						genSamplerProgram			(void);
    149 	bool						testMultisampleTexture		(int sampleNdx);
    150 	void						drawSample					(tcu::Surface& dst, int sampleNdx);
    151 	void						convertToSceneSpec			(TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const;
    152 
    153 	struct Triangle
    154 	{
    155 		tcu::Vec4 p1;
    156 		tcu::Vec4 p2;
    157 		tcu::Vec4 p3;
    158 	};
    159 
    160 	const int					m_samples;
    161 	const int					m_canvasSize;
    162 	std::vector<Triangle>		m_testTriangles;
    163 
    164 	int							m_iteration;
    165 	bool						m_allIterationsOk;
    166 
    167 	GLuint						m_texID;
    168 	GLuint						m_vaoID;
    169 	GLuint						m_vboID;
    170 	std::vector<tcu::Vec2>		m_samplePositions;
    171 	int							m_subpixelBits;
    172 
    173 	const glu::ShaderProgram*	m_samplerProgram;
    174 	GLint						m_samplerProgramPosLoc;
    175 	GLint						m_samplerProgramSamplerLoc;
    176 	GLint						m_samplerProgramSampleNdxLoc;
    177 };
    178 
    179 SamplePosRasterizationTest::SamplePosRasterizationTest (Context& context, const char* name, const char* desc, int samples)
    180 	: TestCase						(context, name, desc)
    181 	, m_samples						(samples)
    182 	, m_canvasSize					(256)
    183 	, m_iteration					(0)
    184 	, m_allIterationsOk				(true)
    185 	, m_texID						(0)
    186 	, m_vaoID						(0)
    187 	, m_vboID						(0)
    188 	, m_subpixelBits				(0)
    189 	, m_samplerProgram				(DE_NULL)
    190 	, m_samplerProgramPosLoc		(-1)
    191 	, m_samplerProgramSamplerLoc	(-1)
    192 	, m_samplerProgramSampleNdxLoc	(-1)
    193 {
    194 }
    195 
    196 SamplePosRasterizationTest::~SamplePosRasterizationTest (void)
    197 {
    198 	deinit();
    199 }
    200 
    201 void SamplePosRasterizationTest::init (void)
    202 {
    203 	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    204 	GLint					maxSamples	= 0;
    205 
    206 	// requirements
    207 
    208 	if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
    209 		throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
    210 
    211 	gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
    212 	if (m_samples > maxSamples)
    213 		throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES");
    214 
    215 	m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
    216 
    217 	gl.getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits);
    218 	m_testCtx.getLog() << tcu::TestLog::Message << "GL_SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
    219 
    220 	// generate textures & other gl stuff
    221 
    222 	m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture" << tcu::TestLog::EndMessage;
    223 
    224 	gl.genTextures				(1, &m_texID);
    225 	gl.bindTexture				(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
    226 	gl.texStorage2DMultisample	(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_TRUE);
    227 	GLU_EXPECT_NO_ERROR			(gl.getError(), "texStorage2DMultisample");
    228 
    229 	gl.genVertexArrays		(1, &m_vaoID);
    230 	gl.bindVertexArray		(m_vaoID);
    231 	GLU_EXPECT_NO_ERROR		(gl.getError(), "bindVertexArray");
    232 
    233 	gl.genBuffers			(1, &m_vboID);
    234 	gl.bindBuffer			(GL_ARRAY_BUFFER, m_vboID);
    235 	GLU_EXPECT_NO_ERROR		(gl.getError(), "bindBuffer");
    236 
    237 	// generate test scene
    238 	for (int i = 0; i < 20; ++i)
    239 	{
    240 		// vertical spikes
    241 		Triangle tri;
    242 		tri.p1 = tcu::Vec4(((float)i        + 1.0f / (float)(i + 1)) / 20.0f,	 0.0f,	0.0f,	1.0f);
    243 		tri.p2 = tcu::Vec4(((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f,	 0.0f,	0.0f,	1.0f);
    244 		tri.p3 = tcu::Vec4(((float)i        + 1.0f / (float)(i + 1)) / 20.0f,	-1.0f,	0.0f,	1.0f);
    245 		m_testTriangles.push_back(tri);
    246 	}
    247 	for (int i = 0; i < 20; ++i)
    248 	{
    249 		// horisontal spikes
    250 		Triangle tri;
    251 		tri.p1 = tcu::Vec4(-1.0f,	((float)i        + 1.0f / (float)(i + 1)) / 20.0f,	0.0f,	1.0f);
    252 		tri.p2 = tcu::Vec4(-1.0f,	((float)i + 0.3f + 1.0f / (float)(i + 1)) / 20.0f,	0.0f,	1.0f);
    253 		tri.p3 = tcu::Vec4( 0.0f,	((float)i        + 1.0f / (float)(i + 1)) / 20.0f,	0.0f,	1.0f);
    254 		m_testTriangles.push_back(tri);
    255 	}
    256 
    257 	for (int i = 0; i < 20; ++i)
    258 	{
    259 		// fan
    260 		const tcu::Vec2 p = tcu::Vec2(deFloatCos(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f, deFloatSin(((float)i)/20.0f*DE_PI*2) * 0.5f + 0.5f);
    261 		const tcu::Vec2 d = tcu::Vec2(0.1f, 0.02f);
    262 
    263 		Triangle tri;
    264 		tri.p1 = tcu::Vec4(0.4f,			0.4f,			0.0f,	1.0f);
    265 		tri.p2 = tcu::Vec4(p.x(),			p.y(),			0.0f,	1.0f);
    266 		tri.p3 = tcu::Vec4(p.x() + d.x(),	p.y() + d.y(),	0.0f,	1.0f);
    267 		m_testTriangles.push_back(tri);
    268 	}
    269 	{
    270 		Triangle tri;
    271 		tri.p1 = tcu::Vec4(-0.202f, -0.202f, 0.0f, 1.0f);
    272 		tri.p2 = tcu::Vec4(-0.802f, -0.202f, 0.0f, 1.0f);
    273 		tri.p3 = tcu::Vec4(-0.802f, -0.802f, 0.0f, 1.0f);
    274 		m_testTriangles.push_back(tri);
    275 	}
    276 
    277 	// generate multisample texture (and query the sample positions in it)
    278 	genMultisampleTexture();
    279 
    280 	// verify queried samples are in a valid range
    281 	for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
    282 	{
    283 		if (m_samplePositions[sampleNdx].x() < 0.0f || m_samplePositions[sampleNdx].x() > 1.0f ||
    284 			m_samplePositions[sampleNdx].y() < 0.0f || m_samplePositions[sampleNdx].y() > 1.0f)
    285 		{
    286 			m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Sample position of sample " << sampleNdx << " should be in range ([0, 1], [0, 1]). Got " << m_samplePositions[sampleNdx] << tcu::TestLog::EndMessage;
    287 			throw tcu::TestError("invalid sample position");
    288 		}
    289 	}
    290 
    291 	// generate sampler program
    292 	genSamplerProgram();
    293 }
    294 
    295 void SamplePosRasterizationTest::deinit (void)
    296 {
    297 	if (m_vboID)
    298 	{
    299 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
    300 		m_vboID = 0;
    301 	}
    302 
    303 	if (m_vaoID)
    304 	{
    305 		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
    306 		m_vaoID = 0;
    307 	}
    308 
    309 	if (m_texID)
    310 	{
    311 		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
    312 		m_texID = 0;
    313 	}
    314 
    315 	if (m_samplerProgram)
    316 	{
    317 		delete m_samplerProgram;
    318 		m_samplerProgram = DE_NULL;
    319 	}
    320 }
    321 
    322 SamplePosRasterizationTest::IterateResult SamplePosRasterizationTest::iterate (void)
    323 {
    324 	m_allIterationsOk &= testMultisampleTexture(m_iteration);
    325 	m_iteration++;
    326 
    327 	if (m_iteration < m_samples)
    328 		return CONTINUE;
    329 
    330 	// End result
    331 	if (m_allIterationsOk)
    332 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    333 	else
    334 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Pixel comparison failed");
    335 
    336 	return STOP;
    337 }
    338 
    339 void SamplePosRasterizationTest::genMultisampleTexture (void)
    340 {
    341 	const char* const vertexShaderSource	=	"${GLSL_VERSION_DECL}\n"
    342 												"in highp vec4 a_position;\n"
    343 												"void main (void)\n"
    344 												"{\n"
    345 												"	gl_Position = a_position;\n"
    346 												"}\n";
    347 	const char* const fragmentShaderSource	=	"${GLSL_VERSION_DECL}\n"
    348 												"layout(location = 0) out highp vec4 fragColor;\n"
    349 												"void main (void)\n"
    350 												"{\n"
    351 												"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
    352 												"}\n";
    353 
    354 	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
    355 	const glu::ShaderProgram	program			(m_context.getRenderContext(), glu::ProgramSources()
    356 																			<< glu::VertexSource(specializeShader(m_context, vertexShaderSource))
    357 																			<< glu::FragmentSource(specializeShader(m_context, fragmentShaderSource)));
    358 	const GLuint				posLoc			= gl.getAttribLocation(program.getProgram(), "a_position");
    359 	GLuint						fboID			= 0;
    360 
    361 	if (!program.isOk())
    362 	{
    363 		m_testCtx.getLog() << program;
    364 		throw tcu::TestError("Failed to build shader.");
    365 	}
    366 
    367 	gl.bindTexture			(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
    368 	gl.bindVertexArray		(m_vaoID);
    369 	gl.bindBuffer			(GL_ARRAY_BUFFER, m_vboID);
    370 
    371 	// Setup fbo for drawing and for sample position query
    372 
    373 	m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
    374 
    375 	gl.genFramebuffers		(1, &fboID);
    376 	gl.bindFramebuffer		(GL_FRAMEBUFFER, fboID);
    377 	gl.framebufferTexture2D	(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
    378 	GLU_EXPECT_NO_ERROR		(gl.getError(), "framebufferTexture2D");
    379 
    380 	// Query sample positions of the multisample texture by querying the sample positions
    381 	// from an fbo which has the multisample texture as attachment.
    382 
    383 	m_testCtx.getLog() << tcu::TestLog::Message << "Sample locations:" << tcu::TestLog::EndMessage;
    384 
    385 	for (int sampleNdx = 0; sampleNdx < m_samples; ++sampleNdx)
    386 	{
    387 		gls::StateQueryUtil::StateQueryMemoryWriteGuard<float[2]> position;
    388 
    389 		gl.getMultisamplefv(GL_SAMPLE_POSITION, (deUint32)sampleNdx, position);
    390 		if (!position.verifyValidity(m_testCtx))
    391 			throw tcu::TestError("Error while querying sample positions");
    392 
    393 		m_testCtx.getLog() << tcu::TestLog::Message << "\t" << sampleNdx << ": (" << position[0] << ", " << position[1] << ")" << tcu::TestLog::EndMessage;
    394 		m_samplePositions.push_back(tcu::Vec2(position[0], position[1]));
    395 	}
    396 
    397 	// Draw test pattern to texture
    398 
    399 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern to the texture" << tcu::TestLog::EndMessage;
    400 
    401 	gl.bufferData				(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(m_testTriangles.size() * sizeof(Triangle)), &m_testTriangles[0], GL_STATIC_DRAW);
    402 	GLU_EXPECT_NO_ERROR			(gl.getError(), "bufferData");
    403 
    404 	gl.viewport					(0, 0, m_canvasSize, m_canvasSize);
    405 	gl.clearColor				(0, 0, 0, 1);
    406 	gl.clear					(GL_COLOR_BUFFER_BIT);
    407 	gl.vertexAttribPointer		(posLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    408 	gl.enableVertexAttribArray	(posLoc);
    409 	GLU_EXPECT_NO_ERROR			(gl.getError(), "vertexAttribPointer");
    410 
    411 	gl.useProgram				(program.getProgram());
    412 	gl.drawArrays				(GL_TRIANGLES, 0, (glw::GLsizei)(m_testTriangles.size() * 3));
    413 	GLU_EXPECT_NO_ERROR			(gl.getError(), "drawArrays");
    414 
    415 	gl.disableVertexAttribArray	(posLoc);
    416 	gl.useProgram				(0);
    417 	gl.deleteFramebuffers		(1, &fboID);
    418 	GLU_EXPECT_NO_ERROR			(gl.getError(), "cleanup");
    419 }
    420 
    421 void SamplePosRasterizationTest::genSamplerProgram (void)
    422 {
    423 	const char* const	vertexShaderSource	=	"${GLSL_VERSION_DECL}\n"
    424 												"in highp vec4 a_position;\n"
    425 												"void main (void)\n"
    426 												"{\n"
    427 												"	gl_Position = a_position;\n"
    428 												"}\n";
    429 	const char* const	fragShaderSource	=	"${GLSL_VERSION_DECL}\n"
    430 												"layout(location = 0) out highp vec4 fragColor;\n"
    431 												"uniform highp sampler2DMS u_sampler;\n"
    432 												"uniform highp int u_sample;\n"
    433 												"void main (void)\n"
    434 												"{\n"
    435 												"	fragColor = texelFetch(u_sampler, ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y))), u_sample);\n"
    436 												"}\n";
    437 	const tcu::ScopedLogSection	section			(m_testCtx.getLog(), "Generate sampler shader", "Generate sampler shader");
    438 	const glw::Functions&		gl			=	m_context.getRenderContext().getFunctions();
    439 
    440 	m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
    441 	m_testCtx.getLog() << *m_samplerProgram;
    442 
    443 	if (!m_samplerProgram->isOk())
    444 		throw tcu::TestError("Could not create sampler program.");
    445 
    446 	m_samplerProgramPosLoc			= gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
    447 	m_samplerProgramSamplerLoc		= gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
    448 	m_samplerProgramSampleNdxLoc	= gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
    449 }
    450 
    451 bool SamplePosRasterizationTest::testMultisampleTexture (int sampleNdx)
    452 {
    453 	tcu::Surface		glSurface(m_canvasSize, m_canvasSize);
    454 	TriangleSceneSpec	scene;
    455 
    456 	// Draw sample
    457 	drawSample(glSurface, sampleNdx);
    458 
    459 	// Draw reference(s)
    460 	convertToSceneSpec(scene, m_samplePositions[sampleNdx]);
    461 
    462 	// Compare
    463 	{
    464 		RasterizationArguments args;
    465 		args.redBits		= m_context.getRenderTarget().getPixelFormat().redBits;
    466 		args.greenBits		= m_context.getRenderTarget().getPixelFormat().greenBits;
    467 		args.blueBits		= m_context.getRenderTarget().getPixelFormat().blueBits;
    468 		args.numSamples		= 0;
    469 		args.subpixelBits	= m_subpixelBits;
    470 
    471 		return tcu::verifyTriangleGroupRasterization(glSurface, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_STRICT);
    472 	}
    473 }
    474 
    475 void SamplePosRasterizationTest::drawSample (tcu::Surface& dst, int sampleNdx)
    476 {
    477 	// Downsample using only one sample
    478 	static const tcu::Vec4 fullscreenQuad[] =
    479 	{
    480 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
    481 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
    482 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
    483 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
    484 	};
    485 
    486 	const tcu::ScopedLogSection section	(m_testCtx.getLog(), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples), "Test sample position " + de::toString(sampleNdx+1) + "/" + de::toString(m_samples));
    487 	const glw::Functions&		gl		= m_context.getRenderContext().getFunctions();
    488 
    489 	gl.bindTexture				(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
    490 	gl.bindVertexArray			(m_vaoID);
    491 	gl.bindBuffer				(GL_ARRAY_BUFFER, m_vboID);
    492 
    493 	gl.bufferData				(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
    494 	GLU_EXPECT_NO_ERROR			(gl.getError(), "bufferData");
    495 
    496 	gl.viewport					(0, 0, m_canvasSize, m_canvasSize);
    497 	gl.clearColor				(0, 0, 0, 1);
    498 	gl.clear					(GL_COLOR_BUFFER_BIT);
    499 	gl.vertexAttribPointer		(m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    500 	gl.enableVertexAttribArray	(m_samplerProgramPosLoc);
    501 	GLU_EXPECT_NO_ERROR			(gl.getError(), "vertexAttribPointer");
    502 
    503 	gl.useProgram				(m_samplerProgram->getProgram());
    504 	gl.uniform1i				(m_samplerProgramSamplerLoc, 0);
    505 	gl.uniform1i				(m_samplerProgramSampleNdxLoc, (deInt32)sampleNdx);
    506 	GLU_EXPECT_NO_ERROR			(gl.getError(), "useprogram");
    507 
    508 	m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sample index " << sampleNdx << tcu::TestLog::EndMessage;
    509 
    510 	gl.drawArrays				(GL_TRIANGLE_STRIP, 0, 4);
    511 	GLU_EXPECT_NO_ERROR			(gl.getError(), "drawArrays");
    512 
    513 	gl.disableVertexAttribArray	(m_samplerProgramPosLoc);
    514 	gl.useProgram				(0);
    515 	GLU_EXPECT_NO_ERROR			(gl.getError(), "cleanup");
    516 
    517 	gl.finish					();
    518 	glu::readPixels				(m_context.getRenderContext(), 0, 0, dst.getAccess());
    519 	GLU_EXPECT_NO_ERROR			(gl.getError(), "readPixels");
    520 }
    521 
    522 void SamplePosRasterizationTest::convertToSceneSpec (TriangleSceneSpec& scene, const tcu::Vec2& samplePos) const
    523 {
    524 	// Triangles are offset from the pixel center by "offset". Move the triangles back to take this into account.
    525 	const tcu::Vec4 offset = tcu::Vec4(samplePos.x() - 0.5f, samplePos.y() - 0.5f, 0.0f, 0.0f) / tcu::Vec4((float)m_canvasSize, (float)m_canvasSize, 1.0f, 1.0f) * 2.0f;
    526 
    527 	for (int triangleNdx = 0; triangleNdx < (int)m_testTriangles.size(); ++triangleNdx)
    528 	{
    529 		TriangleSceneSpec::SceneTriangle triangle;
    530 
    531 		triangle.positions[0] = m_testTriangles[triangleNdx].p1 - offset;
    532 		triangle.positions[1] = m_testTriangles[triangleNdx].p2 - offset;
    533 		triangle.positions[2] = m_testTriangles[triangleNdx].p3 - offset;
    534 
    535 		triangle.sharedEdge[0] = false;
    536 		triangle.sharedEdge[1] = false;
    537 		triangle.sharedEdge[2] = false;
    538 
    539 		scene.triangles.push_back(triangle);
    540 	}
    541 }
    542 
    543 class SampleMaskCase : public TestCase
    544 {
    545 public:
    546 	enum CaseFlags
    547 	{
    548 		FLAGS_NONE					= 0,
    549 		FLAGS_ALPHA_TO_COVERAGE		= (1ULL << 0),
    550 		FLAGS_SAMPLE_COVERAGE		= (1ULL << 1),
    551 		FLAGS_HIGH_BITS				= (1ULL << 2),
    552 	};
    553 
    554 								SampleMaskCase				(Context& context, const char* name, const char* desc, int samples, int flags);
    555 								~SampleMaskCase				(void);
    556 
    557 private:
    558 	void						init						(void);
    559 	void						deinit						(void);
    560 	IterateResult				iterate						(void);
    561 
    562 	void						genSamplerProgram			(void);
    563 	void						genAlphaProgram				(void);
    564 	void						updateTexture				(int sample);
    565 	bool						verifyTexture				(int sample);
    566 	void						drawSample					(tcu::Surface& dst, int sample);
    567 
    568 	const int					m_samples;
    569 	const int					m_canvasSize;
    570 	const int					m_gridsize;
    571 	const int					m_effectiveSampleMaskWordCount;
    572 
    573 	int							m_flags;
    574 	int							m_currentSample;
    575 	int							m_allIterationsOk;
    576 
    577 	glw::GLuint					m_texID;
    578 	glw::GLuint					m_vaoID;
    579 	glw::GLuint					m_vboID;
    580 	glw::GLuint					m_fboID;
    581 
    582 	const glu::ShaderProgram*	m_samplerProgram;
    583 	glw::GLint					m_samplerProgramPosLoc;
    584 	glw::GLint					m_samplerProgramSamplerLoc;
    585 	glw::GLint					m_samplerProgramSampleNdxLoc;
    586 
    587 	const glu::ShaderProgram*	m_alphaProgram;
    588 	glw::GLint					m_alphaProgramPosLoc;
    589 };
    590 
    591 SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags)
    592 	: TestCase						(context, name, desc)
    593 	, m_samples						(samples)
    594 	, m_canvasSize					(256)
    595 	, m_gridsize					(16)
    596 	, m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1))
    597 	, m_flags						(flags)
    598 	, m_currentSample				(-1)
    599 	, m_allIterationsOk				(true)
    600 	, m_texID						(0)
    601 	, m_vaoID						(0)
    602 	, m_vboID						(0)
    603 	, m_fboID						(0)
    604 	, m_samplerProgram				(DE_NULL)
    605 	, m_samplerProgramPosLoc		(-1)
    606 	, m_samplerProgramSamplerLoc	(-1)
    607 	, m_samplerProgramSampleNdxLoc	(-1)
    608 	, m_alphaProgram				(DE_NULL)
    609 	, m_alphaProgramPosLoc			(-1)
    610 {
    611 }
    612 
    613 SampleMaskCase::~SampleMaskCase (void)
    614 {
    615 	deinit();
    616 }
    617 
    618 void SampleMaskCase::init (void)
    619 {
    620 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
    621 	glw::GLint				maxSamples			= 0;
    622 	glw::GLint				maxSampleMaskWords	= 0;
    623 
    624 	// requirements
    625 
    626 	if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
    627 		throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
    628 
    629 	gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
    630 	if (m_effectiveSampleMaskWordCount > maxSampleMaskWords)
    631 		throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
    632 
    633 	gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
    634 	if (m_samples > maxSamples)
    635 		throw tcu::NotSupportedError("Requested sample count is greater than GL_MAX_COLOR_TEXTURE_SAMPLES");
    636 
    637 	m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_COLOR_TEXTURE_SAMPLES = " << maxSamples << tcu::TestLog::EndMessage;
    638 
    639 	// Don't even try to test high bits if there are none
    640 
    641 	if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0))
    642 	{
    643 		m_testCtx.getLog() << tcu::TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << tcu::TestLog::EndMessage;
    644 		throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)");
    645 	}
    646 
    647 	// generate textures
    648 
    649 	m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples << tcu::TestLog::EndMessage;
    650 
    651 	gl.genTextures				(1, &m_texID);
    652 	gl.bindTexture				(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
    653 	gl.texStorage2DMultisample	(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE);
    654 	GLU_EXPECT_NO_ERROR			(gl.getError(), "texStorage2DMultisample");
    655 
    656 	// attach texture to fbo
    657 
    658 	m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
    659 
    660 	gl.genFramebuffers		(1, &m_fboID);
    661 	gl.bindFramebuffer		(GL_FRAMEBUFFER, m_fboID);
    662 	gl.framebufferTexture2D	(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
    663 	GLU_EXPECT_NO_ERROR		(gl.getError(), "framebufferTexture2D");
    664 
    665 	// buffers
    666 
    667 	gl.genVertexArrays		(1, &m_vaoID);
    668 	GLU_EXPECT_NO_ERROR		(gl.getError(), "genVertexArrays");
    669 
    670 	gl.genBuffers			(1, &m_vboID);
    671 	gl.bindBuffer			(GL_ARRAY_BUFFER, m_vboID);
    672 	GLU_EXPECT_NO_ERROR		(gl.getError(), "genBuffers");
    673 
    674 	// generate grid pattern
    675 	{
    676 		std::vector<tcu::Vec4> gridData(m_gridsize*m_gridsize*6);
    677 
    678 		for (int y = 0; y < m_gridsize; ++y)
    679 		for (int x = 0; x < m_gridsize; ++x)
    680 		{
    681 			gridData[(y * m_gridsize + x)*6 + 0] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
    682 			gridData[(y * m_gridsize + x)*6 + 1] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
    683 			gridData[(y * m_gridsize + x)*6 + 2] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
    684 			gridData[(y * m_gridsize + x)*6 + 3] = tcu::Vec4(((float)(x+0) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
    685 			gridData[(y * m_gridsize + x)*6 + 4] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+1) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
    686 			gridData[(y * m_gridsize + x)*6 + 5] = tcu::Vec4(((float)(x+1) / (float)m_gridsize) * 2.0f - 1.0f, ((float)(y+0) / (float)m_gridsize) * 2.0f - 1.0f, 0.0f, 1.0f);
    687 		}
    688 
    689 		gl.bufferData			(GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(), GL_STATIC_DRAW);
    690 		GLU_EXPECT_NO_ERROR		(gl.getError(), "bufferData");
    691 	}
    692 
    693 	// generate programs
    694 
    695 	genSamplerProgram();
    696 	genAlphaProgram();
    697 }
    698 
    699 void SampleMaskCase::deinit (void)
    700 {
    701 	if (m_texID)
    702 	{
    703 		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
    704 		m_texID = 0;
    705 	}
    706 	if (m_vaoID)
    707 	{
    708 		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
    709 		m_vaoID = 0;
    710 	}
    711 	if (m_vboID)
    712 	{
    713 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
    714 		m_vboID = 0;
    715 	}
    716 	if (m_fboID)
    717 	{
    718 		m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
    719 		m_fboID = 0;
    720 	}
    721 
    722 	if (m_samplerProgram)
    723 	{
    724 		delete m_samplerProgram;
    725 		m_samplerProgram = DE_NULL;
    726 	}
    727 	if (m_alphaProgram)
    728 	{
    729 		delete m_alphaProgram;
    730 		m_alphaProgram = DE_NULL;
    731 	}
    732 }
    733 
    734 SampleMaskCase::IterateResult SampleMaskCase::iterate (void)
    735 {
    736 	const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Iteration", (m_currentSample == -1) ? ("Verifying with zero mask") : (std::string() + "Verifying sample " + de::toString(m_currentSample + 1) + "/" + de::toString(m_samples)));
    737 
    738 	bool iterationOk;
    739 
    740 	// Mask only one sample, clear rest
    741 
    742 	updateTexture(m_currentSample);
    743 
    744 	// Verify only one sample set is in the texture
    745 
    746 	iterationOk = verifyTexture(m_currentSample);
    747 	if (!iterationOk)
    748 		m_allIterationsOk = false;
    749 
    750 	m_currentSample++;
    751 	if (m_currentSample < m_samples)
    752 		return CONTINUE;
    753 
    754 	// End result
    755 
    756 	if (m_allIterationsOk)
    757 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    758 	else if (m_flags & FLAGS_HIGH_BITS)
    759 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect");
    760 	else
    761 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed");
    762 
    763 	return STOP;
    764 }
    765 
    766 void SampleMaskCase::genSamplerProgram (void)
    767 {
    768 	const char* const	vertexShaderSource			= "${GLSL_VERSION_DECL}\n"
    769 													  "in highp vec4 a_position;\n"
    770 													  "void main (void)\n"
    771 													  "{\n"
    772 													  "	gl_Position = a_position;\n"
    773 													  "}\n";
    774 	const char* const	fragShaderSource			= "${GLSL_VERSION_DECL}\n"
    775 													  "layout(location = 0) out highp vec4 fragColor;\n"
    776 													  "uniform highp sampler2DMS u_sampler;\n"
    777 													  "uniform highp int u_sample;\n"
    778 													  "void main (void)\n"
    779 													  "{\n"
    780 													  "	highp float correctCoverage = 0.0;\n"
    781 													  "	highp float incorrectCoverage = 0.0;\n"
    782 													  "	highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n"
    783 													  "\n"
    784 													  "	for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n"
    785 													  "	{\n"
    786 													  "		highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n"
    787 													  "		if (sampleNdx == u_sample)\n"
    788 													  "			correctCoverage += sampleColor;\n"
    789 													  "		else\n"
    790 													  "			incorrectCoverage += sampleColor;\n"
    791 													  "	}\n"
    792 													  "	fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n"
    793 													  "}\n";
    794 	const tcu::ScopedLogSection			section		(m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader");
    795 	const glw::Functions&				gl			= m_context.getRenderContext().getFunctions();
    796 	std::map<std::string, std::string>	args;
    797 	const glu::GLSLVersion				glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
    798 
    799 	args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
    800 	args["NUMSAMPLES"] = de::toString(m_samples);
    801 
    802 	m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args)));
    803 	m_testCtx.getLog() << *m_samplerProgram;
    804 
    805 	if (!m_samplerProgram->isOk())
    806 		throw tcu::TestError("Could not create sampler program.");
    807 
    808 	m_samplerProgramPosLoc			= gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
    809 	m_samplerProgramSamplerLoc		= gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
    810 	m_samplerProgramSampleNdxLoc	= gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
    811 }
    812 
    813 void SampleMaskCase::genAlphaProgram (void)
    814 {
    815 	const char* const	vertexShaderSource	=	"${GLSL_VERSION_DECL}\n"
    816 												"in highp vec4 a_position;\n"
    817 												"out highp float v_alpha;\n"
    818 												"void main (void)\n"
    819 												"{\n"
    820 												"	gl_Position = a_position;\n"
    821 												"	v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n"
    822 												"}\n";
    823 	const char* const	fragShaderSource	=	"${GLSL_VERSION_DECL}\n"
    824 												"layout(location = 0) out highp vec4 fragColor;\n"
    825 												"in mediump float v_alpha;\n"
    826 												"void main (void)\n"
    827 												"{\n"
    828 												"	fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n"
    829 												"}\n";
    830 	const glw::Functions&		gl			=	m_context.getRenderContext().getFunctions();
    831 
    832 	m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
    833 
    834 	if (!m_alphaProgram->isOk())
    835 	{
    836 		m_testCtx.getLog() << *m_alphaProgram;
    837 		throw tcu::TestError("Could not create aplha program.");
    838 	}
    839 
    840 	m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position");
    841 }
    842 
    843 void SampleMaskCase::updateTexture (int sample)
    844 {
    845 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    846 
    847 	// prepare draw
    848 
    849 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
    850 	gl.viewport(0, 0, m_canvasSize, m_canvasSize);
    851 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    852 
    853 	// clear all samples
    854 
    855 	m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage;
    856 	gl.clear(GL_COLOR_BUFFER_BIT);
    857 
    858 	// set mask state
    859 
    860 	if (m_flags & FLAGS_HIGH_BITS)
    861 	{
    862 		const std::vector<deUint32> bitmask			= genSetNthBitSampleMask(sample);
    863 		const std::vector<deUint32>	effectiveMask	= genAllSetToNthBitSampleMask(m_samples);
    864 		std::vector<deUint32>		totalBitmask	(effectiveMask.size());
    865 
    866 		DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount);
    867 
    868 		// set some arbitrary high bits to non-effective bits
    869 		for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx)
    870 		{
    871 			const deUint32 randomMask	= (deUint32)deUint32Hash(wordNdx << 2 ^ sample);
    872 			const deUint32 sampleMask	= (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0);
    873 			const deUint32 maskMask		= effectiveMask[wordNdx];
    874 
    875 			totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask);
    876 		}
    877 
    878 		m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32) << tcu::TestLog::EndMessage;
    879 
    880 		gl.enable(GL_SAMPLE_MASK);
    881 		for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
    882 		{
    883 			const GLbitfield wordmask = (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0);
    884 			gl.sampleMaski((deUint32)wordNdx, wordmask);
    885 		}
    886 	}
    887 	else
    888 	{
    889 		const std::vector<deUint32> bitmask = genSetNthBitSampleMask(sample);
    890 		DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount);
    891 
    892 		m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage;
    893 
    894 		gl.enable(GL_SAMPLE_MASK);
    895 		for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
    896 		{
    897 			const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0);
    898 			gl.sampleMaski((deUint32)wordNdx, wordmask);
    899 		}
    900 	}
    901 	if (m_flags & FLAGS_ALPHA_TO_COVERAGE)
    902 	{
    903 		m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage;
    904 		gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
    905 	}
    906 	if (m_flags & FLAGS_SAMPLE_COVERAGE)
    907 	{
    908 		m_testCtx.getLog() << tcu::TestLog::Message << "Enabling sample coverage. Varying sample coverage for grid cells." << tcu::TestLog::EndMessage;
    909 		gl.enable(GL_SAMPLE_COVERAGE);
    910 	}
    911 
    912 	// draw test pattern
    913 
    914 	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage;
    915 
    916 	gl.bindVertexArray			(m_vaoID);
    917 	gl.bindBuffer				(GL_ARRAY_BUFFER, m_vboID);
    918 	gl.vertexAttribPointer		(m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    919 	gl.enableVertexAttribArray	(m_alphaProgramPosLoc);
    920 	GLU_EXPECT_NO_ERROR			(gl.getError(), "vertexAttribPointer");
    921 
    922 	gl.useProgram				(m_alphaProgram->getProgram());
    923 
    924 	for (int y = 0; y < m_gridsize; ++y)
    925 	for (int x = 0; x < m_gridsize; ++x)
    926 	{
    927 		if (m_flags & FLAGS_SAMPLE_COVERAGE)
    928 			gl.sampleCoverage((float)(y*m_gridsize + x) / float(m_gridsize*m_gridsize), GL_FALSE);
    929 
    930 		gl.drawArrays				(GL_TRIANGLES, (y*m_gridsize + x) * 6, 6);
    931 		GLU_EXPECT_NO_ERROR			(gl.getError(), "drawArrays");
    932 	}
    933 
    934 	// clean state
    935 
    936 	gl.disableVertexAttribArray	(m_alphaProgramPosLoc);
    937 	gl.useProgram				(0);
    938 	gl.bindFramebuffer			(GL_FRAMEBUFFER, 0);
    939 	gl.disable					(GL_SAMPLE_MASK);
    940 	gl.disable					(GL_SAMPLE_ALPHA_TO_COVERAGE);
    941 	gl.disable					(GL_SAMPLE_COVERAGE);
    942 	GLU_EXPECT_NO_ERROR			(gl.getError(), "clean");
    943 }
    944 
    945 bool SampleMaskCase::verifyTexture (int sample)
    946 {
    947 	tcu::Surface	result		(m_canvasSize, m_canvasSize);
    948 	tcu::Surface	errorMask	(m_canvasSize, m_canvasSize);
    949 	bool			error		= false;
    950 
    951 	tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
    952 
    953 	// Draw sample:
    954 	//	Sample sampleNdx is set to red channel
    955 	//	Other samples are set to green channel
    956 	drawSample(result, sample);
    957 
    958 	// Check surface contains only sampleNdx
    959 	for (int y = 0; y < m_canvasSize; ++y)
    960 	for (int x = 0; x < m_canvasSize; ++x)
    961 	{
    962 		const tcu::RGBA color					= result.getPixel(x, y);
    963 
    964 		// Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled
    965 		const bool		allowMissingCoverage	= ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1);
    966 
    967 		// disabled sample was written to
    968 		if (color.getGreen() != 0)
    969 		{
    970 			error = true;
    971 			errorMask.setPixel(x, y, tcu::RGBA::red());
    972 		}
    973 		// enabled sample was not written to
    974 		else if (color.getRed() != 255 && !allowMissingCoverage)
    975 		{
    976 			error = true;
    977 			errorMask.setPixel(x, y, tcu::RGBA::red());
    978 		}
    979 	}
    980 
    981 	if (error)
    982 	{
    983 		m_testCtx.getLog()
    984 			<< tcu::TestLog::Message << "Image verification failed, disabled samples found." << tcu::TestLog::EndMessage
    985 			<< tcu::TestLog::ImageSet("VerificationResult", "Result of rendering")
    986 			<< tcu::TestLog::Image("Result",	"Result",		result)
    987 			<< tcu::TestLog::Image("ErrorMask",	"Error Mask",	errorMask)
    988 			<< tcu::TestLog::EndImageSet;
    989 		return false;
    990 	}
    991 	else
    992 	{
    993 		m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found." << tcu::TestLog::EndMessage;
    994 		return true;
    995 	}
    996 }
    997 
    998 void SampleMaskCase::drawSample (tcu::Surface& dst, int sample)
    999 {
   1000 	// Downsample using only one sample
   1001 	static const tcu::Vec4 fullscreenQuad[] =
   1002 	{
   1003 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
   1004 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
   1005 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
   1006 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
   1007 	};
   1008 
   1009 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
   1010 	glu::Buffer				vertexBuffer	(m_context.getRenderContext());
   1011 
   1012 	gl.bindTexture				(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
   1013 	gl.bindVertexArray			(m_vaoID);
   1014 
   1015 	gl.bindBuffer				(GL_ARRAY_BUFFER, *vertexBuffer);
   1016 	gl.bufferData				(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
   1017 	GLU_EXPECT_NO_ERROR			(gl.getError(), "bufferData");
   1018 
   1019 	gl.viewport					(0, 0, m_canvasSize, m_canvasSize);
   1020 	gl.clearColor				(0, 0, 0, 1);
   1021 	gl.clear					(GL_COLOR_BUFFER_BIT);
   1022 	gl.vertexAttribPointer		(m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   1023 	gl.enableVertexAttribArray	(m_samplerProgramPosLoc);
   1024 	GLU_EXPECT_NO_ERROR			(gl.getError(), "vertexAttribPointer");
   1025 
   1026 	gl.useProgram				(m_samplerProgram->getProgram());
   1027 	gl.uniform1i				(m_samplerProgramSamplerLoc, 0);
   1028 	gl.uniform1i				(m_samplerProgramSampleNdxLoc, (deInt32)sample);
   1029 	GLU_EXPECT_NO_ERROR			(gl.getError(), "useprogram");
   1030 
   1031 	m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample << tcu::TestLog::EndMessage;
   1032 
   1033 	gl.drawArrays				(GL_TRIANGLE_STRIP, 0, 4);
   1034 	GLU_EXPECT_NO_ERROR			(gl.getError(), "drawArrays");
   1035 
   1036 	gl.disableVertexAttribArray	(m_samplerProgramPosLoc);
   1037 	gl.useProgram				(0);
   1038 	GLU_EXPECT_NO_ERROR			(gl.getError(), "cleanup");
   1039 
   1040 	gl.finish					();
   1041 	glu::readPixels				(m_context.getRenderContext(), 0, 0, dst.getAccess());
   1042 	GLU_EXPECT_NO_ERROR			(gl.getError(), "readPixels");
   1043 }
   1044 
   1045 class MultisampleTextureUsageCase : public TestCase
   1046 {
   1047 public:
   1048 
   1049 	enum TextureType
   1050 	{
   1051 		TEXTURE_COLOR_2D = 0,
   1052 		TEXTURE_COLOR_2D_ARRAY,
   1053 		TEXTURE_INT_2D,
   1054 		TEXTURE_INT_2D_ARRAY,
   1055 		TEXTURE_UINT_2D,
   1056 		TEXTURE_UINT_2D_ARRAY,
   1057 		TEXTURE_DEPTH_2D,
   1058 		TEXTURE_DEPTH_2D_ARRAY,
   1059 
   1060 		TEXTURE_LAST
   1061 	};
   1062 
   1063 						MultisampleTextureUsageCase		(Context& ctx, const char* name, const char* desc, int samples, TextureType type);
   1064 						~MultisampleTextureUsageCase	(void);
   1065 
   1066 private:
   1067 	void				init							(void);
   1068 	void				deinit							(void);
   1069 	IterateResult		iterate							(void);
   1070 
   1071 	void				genDrawShader					(void);
   1072 	void				genSamplerShader				(void);
   1073 
   1074 	void				renderToTexture					(float value);
   1075 	void				sampleTexture					(tcu::Surface& dst, float value);
   1076 	bool				verifyImage						(const tcu::Surface& dst);
   1077 
   1078 	static const int	s_textureSize					= 256;
   1079 	static const int	s_textureArraySize				= 8;
   1080 	static const int	s_textureLayer					= 3;
   1081 
   1082 	const TextureType	m_type;
   1083 	const int			m_numSamples;
   1084 
   1085 	glw::GLuint			m_fboID;
   1086 	glw::GLuint			m_textureID;
   1087 
   1088 	glu::ShaderProgram*	m_drawShader;
   1089 	glu::ShaderProgram*	m_samplerShader;
   1090 
   1091 	const bool			m_isColorFormat;
   1092 	const bool			m_isSignedFormat;
   1093 	const bool			m_isUnsignedFormat;
   1094 	const bool			m_isDepthFormat;
   1095 	const bool			m_isArrayType;
   1096 };
   1097 
   1098 MultisampleTextureUsageCase::MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type)
   1099 	: TestCase			(ctx, name, desc)
   1100 	, m_type			(type)
   1101 	, m_numSamples		(samples)
   1102 	, m_fboID			(0)
   1103 	, m_textureID		(0)
   1104 	, m_drawShader		(DE_NULL)
   1105 	, m_samplerShader	(DE_NULL)
   1106 	, m_isColorFormat	(m_type == TEXTURE_COLOR_2D	|| m_type == TEXTURE_COLOR_2D_ARRAY)
   1107 	, m_isSignedFormat	(m_type == TEXTURE_INT_2D	|| m_type == TEXTURE_INT_2D_ARRAY)
   1108 	, m_isUnsignedFormat(m_type == TEXTURE_UINT_2D	|| m_type == TEXTURE_UINT_2D_ARRAY)
   1109 	, m_isDepthFormat	(m_type == TEXTURE_DEPTH_2D	|| m_type == TEXTURE_DEPTH_2D_ARRAY)
   1110 	, m_isArrayType		(m_type == TEXTURE_COLOR_2D_ARRAY || m_type == TEXTURE_INT_2D_ARRAY || m_type == TEXTURE_UINT_2D_ARRAY || m_type == TEXTURE_DEPTH_2D_ARRAY)
   1111 {
   1112 	DE_ASSERT(m_type < TEXTURE_LAST);
   1113 }
   1114 
   1115 MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void)
   1116 {
   1117 	deinit();
   1118 }
   1119 
   1120 void MultisampleTextureUsageCase::init (void)
   1121 {
   1122 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
   1123 	const glw::GLenum		internalFormat	= (m_isColorFormat) ? (GL_R8) : (m_isSignedFormat) ? (GL_R8I) : (m_isUnsignedFormat) ? (GL_R8UI) : (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) : (0);
   1124 	const glw::GLenum		textureTarget	= (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
   1125 	const glw::GLenum		fboAttachment	= (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0);
   1126 	const bool				supportsES32	= glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
   1127 
   1128 	DE_ASSERT(internalFormat);
   1129 
   1130 	// requirements
   1131 
   1132 	if (m_isArrayType && !supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
   1133 		throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
   1134 	if (m_context.getRenderTarget().getWidth() < s_textureSize || m_context.getRenderTarget().getHeight() < s_textureSize)
   1135 		throw tcu::NotSupportedError("render target size must be at least " + de::toString(static_cast<int>(s_textureSize)) + "x" + de::toString(static_cast<int>(s_textureSize)));
   1136 
   1137 	{
   1138 		glw::GLint maxSamples = 0;
   1139 		gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples);
   1140 
   1141 		if (m_numSamples > maxSamples)
   1142 			throw tcu::NotSupportedError("Requested sample count is greater than supported");
   1143 
   1144 		m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for " << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples << tcu::TestLog::EndMessage;
   1145 	}
   1146 
   1147 	{
   1148 		GLint maxTextureSize = 0;
   1149 		gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
   1150 
   1151 		if (s_textureSize > maxTextureSize)
   1152 			throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required");
   1153 	}
   1154 
   1155 	if (m_isArrayType)
   1156 	{
   1157 		GLint maxTextureLayers = 0;
   1158 		gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
   1159 
   1160 		if (s_textureArraySize > maxTextureLayers)
   1161 			throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required");
   1162 	}
   1163 
   1164 	// create texture
   1165 
   1166 	m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : ("")) << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage;
   1167 
   1168 	gl.genTextures(1, &m_textureID);
   1169 	gl.bindTexture(textureTarget, m_textureID);
   1170 	GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
   1171 
   1172 	if (m_isArrayType)
   1173 		gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize, s_textureSize, s_textureArraySize, GL_FALSE);
   1174 	else
   1175 		gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize, s_textureSize, GL_FALSE);
   1176 	GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage");
   1177 
   1178 	// create fbo for drawing
   1179 
   1180 	gl.genFramebuffers(1, &m_fboID);
   1181 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
   1182 
   1183 	if (m_isArrayType)
   1184 	{
   1185 		m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer " << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage;
   1186 		gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer);
   1187 	}
   1188 	else
   1189 	{
   1190 		m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo" << tcu::TestLog::EndMessage;
   1191 		gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0);
   1192 	}
   1193 	GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
   1194 
   1195 	// create shader for rendering to fbo
   1196 	genDrawShader();
   1197 
   1198 	// create shader for sampling the texture rendered to
   1199 	genSamplerShader();
   1200 }
   1201 
   1202 void MultisampleTextureUsageCase::deinit (void)
   1203 {
   1204 	if (m_textureID)
   1205 	{
   1206 		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID);
   1207 		m_textureID = 0;
   1208 	}
   1209 
   1210 	if (m_fboID)
   1211 	{
   1212 		m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
   1213 		m_fboID = 0;
   1214 	}
   1215 
   1216 	if (m_drawShader)
   1217 	{
   1218 		delete m_drawShader;
   1219 		m_drawShader = DE_NULL;
   1220 	}
   1221 
   1222 	if (m_samplerShader)
   1223 	{
   1224 		delete m_samplerShader;
   1225 		m_samplerShader = DE_NULL;
   1226 	}
   1227 }
   1228 
   1229 MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate (void)
   1230 {
   1231 	const tcu::ScopedLogSection	section			(m_testCtx.getLog(), "Sample", "Render to texture and sample texture");
   1232 	tcu::Surface				result			(s_textureSize, s_textureSize);
   1233 	const float					minValue		= (m_isColorFormat || m_isDepthFormat) ? (0.0f) : (m_isSignedFormat) ? (-100.0f) : (m_isUnsignedFormat) ? (0.0f)	: ( 1.0f);
   1234 	const float					maxValue		= (m_isColorFormat || m_isDepthFormat) ? (1.0f) : (m_isSignedFormat) ? ( 100.0f) : (m_isUnsignedFormat) ? (200.0f)	: (-1.0f);
   1235 	de::Random					rnd				(deUint32Hash((deUint32)m_type));
   1236 	const float					rawValue		= rnd.getFloat(minValue, maxValue);
   1237 	const float					preparedValue	= (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue);
   1238 
   1239 	// draw to fbo with a random value
   1240 
   1241 	renderToTexture(preparedValue);
   1242 
   1243 	// draw from texture to front buffer
   1244 
   1245 	sampleTexture(result, preparedValue);
   1246 
   1247 	// result is ok?
   1248 
   1249 	if (verifyImage(result))
   1250 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1251 	else
   1252 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
   1253 
   1254 	return STOP;
   1255 }
   1256 
   1257 void MultisampleTextureUsageCase::genDrawShader (void)
   1258 {
   1259 	const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader");
   1260 
   1261 	static const char* const	vertexShaderSource =		"${GLSL_VERSION_DECL}\n"
   1262 															"in highp vec4 a_position;\n"
   1263 															"void main (void)\n"
   1264 															"{\n"
   1265 															"	gl_Position = a_position;\n"
   1266 															"}\n";
   1267 	static const char* const	fragmentShaderSourceColor =	"${GLSL_VERSION_DECL}\n"
   1268 															"layout(location = 0) out highp ${OUTTYPE} fragColor;\n"
   1269 															"uniform highp float u_writeValue;\n"
   1270 															"void main (void)\n"
   1271 															"{\n"
   1272 															"	fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n"
   1273 															"}\n";
   1274 	static const char* const	fragmentShaderSourceDepth =	"${GLSL_VERSION_DECL}\n"
   1275 															"layout(location = 0) out highp vec4 fragColor;\n"
   1276 															"uniform highp float u_writeValue;\n"
   1277 															"void main (void)\n"
   1278 															"{\n"
   1279 															"	fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
   1280 															"	gl_FragDepth = u_writeValue;\n"
   1281 															"}\n";
   1282 	const char* const			fragmentSource =			(m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor);
   1283 
   1284 	std::map<std::string, std::string> fragmentArguments;
   1285 
   1286 	const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
   1287 	fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
   1288 
   1289 	if (m_isColorFormat || m_isDepthFormat)
   1290 		fragmentArguments["OUTTYPE"] = "vec4";
   1291 	else if (m_isSignedFormat)
   1292 		fragmentArguments["OUTTYPE"] = "ivec4";
   1293 	else if (m_isUnsignedFormat)
   1294 		fragmentArguments["OUTTYPE"] = "uvec4";
   1295 	else
   1296 		DE_ASSERT(DE_FALSE);
   1297 
   1298 	m_drawShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentSource).specialize(fragmentArguments)));
   1299 	m_testCtx.getLog() << *m_drawShader;
   1300 
   1301 	if (!m_drawShader->isOk())
   1302 		throw tcu::TestError("could not build shader");
   1303 }
   1304 
   1305 void MultisampleTextureUsageCase::genSamplerShader (void)
   1306 {
   1307 	const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader");
   1308 
   1309 	static const char* const vertexShaderSource =	"${GLSL_VERSION_DECL}\n"
   1310 													"in highp vec4 a_position;\n"
   1311 													"out highp float v_gradient;\n"
   1312 													"void main (void)\n"
   1313 													"{\n"
   1314 													"	gl_Position = a_position;\n"
   1315 													"	v_gradient = a_position.x * 0.5 + 0.5;\n"
   1316 													"}\n";
   1317 	static const char* const fragmentShaderSource =	"${GLSL_VERSION_DECL}\n"
   1318 													"${EXTENSION_STATEMENT}"
   1319 													"layout(location = 0) out highp vec4 fragColor;\n"
   1320 													"uniform highp ${SAMPLERTYPE} u_sampler;\n"
   1321 													"uniform highp int u_maxSamples;\n"
   1322 													"uniform highp int u_layer;\n"
   1323 													"uniform highp float u_cmpValue;\n"
   1324 													"in highp float v_gradient;\n"
   1325 													"void main (void)\n"
   1326 													"{\n"
   1327 													"	const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
   1328 													"	const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
   1329 													"	const highp float epsilon = ${EPSILON};\n"
   1330 													"\n"
   1331 													"	highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n"
   1332 													"	highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n"
   1333 													"	fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n"
   1334 													"}\n";
   1335 
   1336 	std::map<std::string, std::string> fragmentArguments;
   1337 
   1338 	const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
   1339 	fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
   1340 
   1341 	if (m_isArrayType)
   1342 		fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)";
   1343 	else
   1344 		fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))";
   1345 
   1346 	if (m_isColorFormat || m_isDepthFormat)
   1347 		fragmentArguments["EPSILON"] = "0.1";
   1348 	else
   1349 		fragmentArguments["EPSILON"] = "1.0";
   1350 
   1351 	if (m_isArrayType && !glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)))
   1352 		fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
   1353 	else
   1354 		fragmentArguments["EXTENSION_STATEMENT"] = "";
   1355 
   1356 	switch (m_type)
   1357 	{
   1358 		case TEXTURE_COLOR_2D:			fragmentArguments["SAMPLERTYPE"] = "sampler2DMS";		break;
   1359 		case TEXTURE_COLOR_2D_ARRAY:	fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray";	break;
   1360 		case TEXTURE_INT_2D:			fragmentArguments["SAMPLERTYPE"] = "isampler2DMS";		break;
   1361 		case TEXTURE_INT_2D_ARRAY:		fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray";	break;
   1362 		case TEXTURE_UINT_2D:			fragmentArguments["SAMPLERTYPE"] = "usampler2DMS";		break;
   1363 		case TEXTURE_UINT_2D_ARRAY:		fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray";	break;
   1364 		case TEXTURE_DEPTH_2D:			fragmentArguments["SAMPLERTYPE"] = "sampler2DMS";		break;
   1365 		case TEXTURE_DEPTH_2D_ARRAY:	fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray";	break;
   1366 
   1367 		default:
   1368 			DE_ASSERT(DE_FALSE);
   1369 	}
   1370 
   1371 	m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments)));
   1372 	m_testCtx.getLog() << *m_samplerShader;
   1373 
   1374 	if (!m_samplerShader->isOk())
   1375 		throw tcu::TestError("could not build shader");
   1376 }
   1377 
   1378 void MultisampleTextureUsageCase::renderToTexture (float value)
   1379 {
   1380 	static const tcu::Vec4 fullscreenQuad[] =
   1381 	{
   1382 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
   1383 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
   1384 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
   1385 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
   1386 	};
   1387 
   1388 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   1389 	const int				posLocation			= gl.getAttribLocation(m_drawShader->getProgram(), "a_position");
   1390 	const int				valueLocation		= gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue");
   1391 	glu::Buffer				vertexAttibBuffer	(m_context.getRenderContext());
   1392 
   1393 	m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value  << tcu::TestLog::EndMessage;
   1394 
   1395 	// upload data
   1396 
   1397 	gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
   1398 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
   1399 	GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
   1400 
   1401 	// clear buffer
   1402 
   1403 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
   1404 	gl.viewport(0, 0, s_textureSize, s_textureSize);
   1405 
   1406 	if (m_isColorFormat)
   1407 	{
   1408 		const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
   1409 		gl.clearBufferfv(GL_COLOR, 0, clearColor);
   1410 	}
   1411 	else if (m_isSignedFormat)
   1412 	{
   1413 		const deInt32 clearColor[4] = { 0, 0, 0, 0 };
   1414 		gl.clearBufferiv(GL_COLOR, 0, clearColor);
   1415 	}
   1416 	else if (m_isUnsignedFormat)
   1417 	{
   1418 		const deUint32 clearColor[4] = { 0, 0, 0, 0 };
   1419 		gl.clearBufferuiv(GL_COLOR, 0, clearColor);
   1420 	}
   1421 	else if (m_isDepthFormat)
   1422 	{
   1423 		const float clearDepth = 0.5f;
   1424 		gl.clearBufferfv(GL_DEPTH, 0, &clearDepth);
   1425 	}
   1426 
   1427 	GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
   1428 
   1429 	// setup shader and draw
   1430 
   1431 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   1432 	gl.enableVertexAttribArray(posLocation);
   1433 
   1434 	gl.useProgram(m_drawShader->getProgram());
   1435 	gl.uniform1f(valueLocation, value);
   1436 
   1437 	GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
   1438 
   1439 	if (m_isDepthFormat)
   1440 	{
   1441 		gl.enable(GL_DEPTH_TEST);
   1442 		gl.depthFunc(GL_ALWAYS);
   1443 	}
   1444 
   1445 	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
   1446 	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
   1447 
   1448 	// clean state
   1449 
   1450 	if (m_isDepthFormat)
   1451 		gl.disable(GL_DEPTH_TEST);
   1452 
   1453 	gl.disableVertexAttribArray(posLocation);
   1454 	gl.useProgram(0);
   1455 	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
   1456 	GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
   1457 }
   1458 
   1459 void MultisampleTextureUsageCase::sampleTexture (tcu::Surface& dst, float value)
   1460 {
   1461 	static const tcu::Vec4 fullscreenQuad[] =
   1462 	{
   1463 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
   1464 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
   1465 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
   1466 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
   1467 	};
   1468 
   1469 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   1470 	const int				posLocation			= gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
   1471 	const int				samplerLocation		= gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
   1472 	const int				maxSamplesLocation	= gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples");
   1473 	const int				layerLocation		= gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer");
   1474 	const int				valueLocation		= gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue");
   1475 	const glw::GLenum		textureTarget		= (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
   1476 	glu::Buffer				vertexAttibBuffer	(m_context.getRenderContext());
   1477 
   1478 	m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage;
   1479 
   1480 	// upload data
   1481 
   1482 	gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
   1483 	gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
   1484 	GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
   1485 
   1486 	// clear
   1487 
   1488 	gl.viewport(0, 0, s_textureSize, s_textureSize);
   1489 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1490 	gl.clear(GL_COLOR_BUFFER_BIT);
   1491 
   1492 	// setup shader and draw
   1493 
   1494 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   1495 	gl.enableVertexAttribArray(posLocation);
   1496 
   1497 	gl.useProgram(m_samplerShader->getProgram());
   1498 	gl.uniform1i(samplerLocation, 0);
   1499 	gl.uniform1i(maxSamplesLocation, m_numSamples);
   1500 	if (m_isArrayType)
   1501 		gl.uniform1i(layerLocation, s_textureLayer);
   1502 	gl.uniform1f(valueLocation, value);
   1503 	gl.bindTexture(textureTarget, m_textureID);
   1504 	GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
   1505 
   1506 	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
   1507 	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
   1508 
   1509 	// clean state
   1510 
   1511 	gl.disableVertexAttribArray(posLocation);
   1512 	gl.useProgram(0);
   1513 	GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
   1514 
   1515 	// read results
   1516 	gl.finish();
   1517 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
   1518 }
   1519 
   1520 bool MultisampleTextureUsageCase::verifyImage (const tcu::Surface& dst)
   1521 {
   1522 	bool error = false;
   1523 
   1524 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
   1525 
   1526 	for (int y = 0; y < dst.getHeight(); ++y)
   1527 	for (int x = 0; x < dst.getWidth(); ++x)
   1528 	{
   1529 		const tcu::RGBA color				= dst.getPixel(x, y);
   1530 		const int		colorThresholdRed	= 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
   1531 		const int		colorThresholdGreen	= 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
   1532 		const int		colorThresholdBlue	= 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
   1533 
   1534 		// only green is accepted
   1535 		if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen || color.getBlue() > colorThresholdBlue)
   1536 			error = true;
   1537 	}
   1538 
   1539 	if (error)
   1540 	{
   1541 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage;
   1542 		m_testCtx.getLog()
   1543 			<< tcu::TestLog::ImageSet("Verification result", "Result of rendering")
   1544 			<< tcu::TestLog::Image("Result", "Result", dst)
   1545 			<< tcu::TestLog::EndImageSet;
   1546 
   1547 		return false;
   1548 	}
   1549 	else
   1550 	{
   1551 		m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
   1552 		return true;
   1553 	}
   1554 }
   1555 
   1556 class NegativeFramebufferCase : public TestCase
   1557 {
   1558 public:
   1559 	enum CaseType
   1560 	{
   1561 		CASE_DIFFERENT_N_SAMPLES_TEX = 0,
   1562 		CASE_DIFFERENT_N_SAMPLES_RBO,
   1563 		CASE_DIFFERENT_FIXED_TEX,
   1564 		CASE_DIFFERENT_FIXED_RBO,
   1565 		CASE_NON_ZERO_LEVEL,
   1566 
   1567 		CASE_LAST
   1568 	};
   1569 
   1570 						NegativeFramebufferCase		(Context& context, const char* name, const char* desc, CaseType caseType);
   1571 						~NegativeFramebufferCase	(void);
   1572 
   1573 private:
   1574 	void				init						(void);
   1575 	void				deinit						(void);
   1576 	IterateResult		iterate						(void);
   1577 
   1578 	void				getFormatSamples			(glw::GLenum target, std::vector<int>& samples);
   1579 
   1580 	const CaseType		m_caseType;
   1581 	const int			m_fboSize;
   1582 	const glw::GLenum	m_internalFormat;
   1583 
   1584 	int					m_numSamples0;	// !< samples for attachment 0
   1585 	int					m_numSamples1;	// !< samples for attachment 1
   1586 };
   1587 
   1588 NegativeFramebufferCase::NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType)
   1589 	: TestCase			(context, name, desc)
   1590 	, m_caseType		(caseType)
   1591 	, m_fboSize			(64)
   1592 	, m_internalFormat	(GL_RGBA8)
   1593 	, m_numSamples0		(-1)
   1594 	, m_numSamples1		(-1)
   1595 {
   1596 }
   1597 
   1598 NegativeFramebufferCase::~NegativeFramebufferCase (void)
   1599 {
   1600 	deinit();
   1601 }
   1602 
   1603 void NegativeFramebufferCase::init (void)
   1604 {
   1605 	const bool				colorAttachmentTexture	= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
   1606 	const bool				colorAttachmentRbo		= (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
   1607 	const bool				useDifferentSampleCounts= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO);
   1608 	std::vector<int>		textureSamples;
   1609 	std::vector<int>		rboSamples;
   1610 
   1611 	getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples);
   1612 	getFormatSamples(GL_RENDERBUFFER, rboSamples);
   1613 
   1614 	TCU_CHECK(!textureSamples.empty());
   1615 	TCU_CHECK(!rboSamples.empty());
   1616 
   1617 	// select sample counts
   1618 
   1619 	if (useDifferentSampleCounts)
   1620 	{
   1621 		if (colorAttachmentTexture)
   1622 		{
   1623 			m_numSamples0 = textureSamples[0];
   1624 
   1625 			if (textureSamples.size() >= 2)
   1626 				m_numSamples1 = textureSamples[1];
   1627 			else
   1628 				throw tcu::NotSupportedError("Test requires multiple supported sample counts");
   1629 		}
   1630 		else if (colorAttachmentRbo)
   1631 		{
   1632 			for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
   1633 			for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
   1634 			{
   1635 				if (textureSamples[texNdx] != rboSamples[rboNdx])
   1636 				{
   1637 					m_numSamples0 = textureSamples[texNdx];
   1638 					m_numSamples1 = rboSamples[rboNdx];
   1639 					return;
   1640 				}
   1641 			}
   1642 
   1643 			throw tcu::NotSupportedError("Test requires multiple supported sample counts");
   1644 		}
   1645 		else
   1646 			DE_ASSERT(DE_FALSE);
   1647 	}
   1648 	else
   1649 	{
   1650 		if (colorAttachmentTexture)
   1651 		{
   1652 			m_numSamples0 = textureSamples[0];
   1653 			m_numSamples1 = textureSamples[0];
   1654 		}
   1655 		else if (colorAttachmentRbo)
   1656 		{
   1657 			for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
   1658 			for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
   1659 			{
   1660 				if (textureSamples[texNdx] == rboSamples[rboNdx])
   1661 				{
   1662 					m_numSamples0 = textureSamples[texNdx];
   1663 					m_numSamples1 = rboSamples[rboNdx];
   1664 					return;
   1665 				}
   1666 			}
   1667 
   1668 			throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture");
   1669 		}
   1670 		else
   1671 		{
   1672 			m_numSamples0 = textureSamples[0];
   1673 		}
   1674 	}
   1675 }
   1676 
   1677 void NegativeFramebufferCase::deinit (void)
   1678 {
   1679 }
   1680 
   1681 NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate (void)
   1682 {
   1683 	const bool				colorAttachmentTexture	= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
   1684 	const bool				colorAttachmentRbo		= (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
   1685 	const glw::GLboolean	fixedSampleLocations0	= (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE);
   1686 	const glw::GLboolean	fixedSampleLocations1	= ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE);
   1687 	glu::CallLogWrapper		gl						(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
   1688 	glw::GLuint				fboId					= 0;
   1689 	glw::GLuint				rboId					= 0;
   1690 	glw::GLuint				tex0Id					= 0;
   1691 	glw::GLuint				tex1Id					= 0;
   1692 
   1693 	bool					testFailed				= false;
   1694 
   1695 	gl.enableLogging(true);
   1696 
   1697 	try
   1698 	{
   1699 		gl.glGenFramebuffers(1, &fboId);
   1700 		gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId);
   1701 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo");
   1702 
   1703 		gl.glGenTextures(1, &tex0Id);
   1704 		gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id);
   1705 		gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations0);
   1706 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0");
   1707 
   1708 		if (m_caseType == CASE_NON_ZERO_LEVEL)
   1709 		{
   1710 			glw::GLenum error;
   1711 
   1712 			// attaching non-zero level generates invalid value
   1713 			gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5);
   1714 			error = gl.glGetError();
   1715 
   1716 			if (error != GL_INVALID_VALUE)
   1717 			{
   1718 				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
   1719 				testFailed = true;
   1720 			}
   1721 		}
   1722 		else
   1723 		{
   1724 			gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0);
   1725 			GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0");
   1726 
   1727 			if (colorAttachmentTexture)
   1728 			{
   1729 				gl.glGenTextures(1, &tex1Id);
   1730 				gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id);
   1731 				gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations1);
   1732 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1");
   1733 
   1734 				gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0);
   1735 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
   1736 			}
   1737 			else if (colorAttachmentRbo)
   1738 			{
   1739 				gl.glGenRenderbuffers(1, &rboId);
   1740 				gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId);
   1741 				gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize);
   1742 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb");
   1743 
   1744 				gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId);
   1745 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
   1746 			}
   1747 			else
   1748 				DE_ASSERT(DE_FALSE);
   1749 
   1750 			// should not be complete
   1751 			{
   1752 				glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER);
   1753 
   1754 				if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE)
   1755 				{
   1756 					m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
   1757 					testFailed = true;
   1758 				}
   1759 			}
   1760 		}
   1761 	}
   1762 	catch (...)
   1763 	{
   1764 		gl.glDeleteFramebuffers(1, &fboId);
   1765 		gl.glDeleteRenderbuffers(1, &rboId);
   1766 		gl.glDeleteTextures(1, &tex0Id);
   1767 		gl.glDeleteTextures(1, &tex1Id);
   1768 		throw;
   1769 	}
   1770 
   1771 	gl.glDeleteFramebuffers(1, &fboId);
   1772 	gl.glDeleteRenderbuffers(1, &rboId);
   1773 	gl.glDeleteTextures(1, &tex0Id);
   1774 	gl.glDeleteTextures(1, &tex1Id);
   1775 
   1776 	if (testFailed)
   1777 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
   1778 	else
   1779 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1780 	return STOP;
   1781 }
   1782 
   1783 void NegativeFramebufferCase::getFormatSamples (glw::GLenum target, std::vector<int>& samples)
   1784 {
   1785 	const glw::Functions	gl			= m_context.getRenderContext().getFunctions();
   1786 	int						sampleCount	= 0;
   1787 
   1788 	gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
   1789 	samples.resize(sampleCount);
   1790 
   1791 	if (sampleCount > 0)
   1792 	{
   1793 		gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]);
   1794 		GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples");
   1795 	}
   1796 }
   1797 
   1798 class NegativeTexParameterCase : public TestCase
   1799 {
   1800 public:
   1801 	enum TexParam
   1802 	{
   1803 		TEXTURE_MIN_FILTER = 0,
   1804 		TEXTURE_MAG_FILTER,
   1805 		TEXTURE_WRAP_S,
   1806 		TEXTURE_WRAP_T,
   1807 		TEXTURE_WRAP_R,
   1808 		TEXTURE_MIN_LOD,
   1809 		TEXTURE_MAX_LOD,
   1810 		TEXTURE_COMPARE_MODE,
   1811 		TEXTURE_COMPARE_FUNC,
   1812 		TEXTURE_BASE_LEVEL,
   1813 
   1814 		TEXTURE_LAST
   1815 	};
   1816 
   1817 					NegativeTexParameterCase	(Context& context, const char* name, const char* desc, TexParam param);
   1818 					~NegativeTexParameterCase	(void);
   1819 
   1820 private:
   1821 	void			init						(void);
   1822 	void			deinit						(void);
   1823 	IterateResult	iterate						(void);
   1824 
   1825 	glw::GLenum		getParamGLEnum				(void) const;
   1826 	glw::GLint		getParamValue				(void) const;
   1827 	glw::GLenum		getExpectedError			(void) const;
   1828 
   1829 	const TexParam	m_texParam;
   1830 	int				m_iteration;
   1831 };
   1832 
   1833 NegativeTexParameterCase::NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param)
   1834 	: TestCase		(context, name, desc)
   1835 	, m_texParam	(param)
   1836 	, m_iteration	(0)
   1837 {
   1838 	DE_ASSERT(param < TEXTURE_LAST);
   1839 }
   1840 
   1841 NegativeTexParameterCase::~NegativeTexParameterCase	(void)
   1842 {
   1843 	deinit();
   1844 }
   1845 
   1846 void NegativeTexParameterCase::init (void)
   1847 {
   1848 	// default value
   1849 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1850 }
   1851 
   1852 void NegativeTexParameterCase::deinit (void)
   1853 {
   1854 }
   1855 
   1856 NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate (void)
   1857 {
   1858 	static const struct TextureType
   1859 	{
   1860 		const char*	name;
   1861 		glw::GLenum	target;
   1862 		glw::GLenum	internalFormat;
   1863 		bool		isArrayType;
   1864 	} types[] =
   1865 	{
   1866 		{ "color",					GL_TEXTURE_2D_MULTISAMPLE,			GL_RGBA8,	false	},
   1867 		{ "color array",			GL_TEXTURE_2D_MULTISAMPLE_ARRAY,	GL_RGBA8,	true	},
   1868 		{ "signed integer",			GL_TEXTURE_2D_MULTISAMPLE,			GL_R8I,		false	},
   1869 		{ "signed integer array",	GL_TEXTURE_2D_MULTISAMPLE_ARRAY,	GL_R8I,		true	},
   1870 		{ "unsigned integer",		GL_TEXTURE_2D_MULTISAMPLE,			GL_R8UI,	false	},
   1871 		{ "unsigned integer array",	GL_TEXTURE_2D_MULTISAMPLE_ARRAY,	GL_R8UI,	true	},
   1872 	};
   1873 
   1874 	const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration", std::string() + "Testing parameter with " + types[m_iteration].name + " texture");
   1875 	const bool					supportsES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));
   1876 
   1877 	if (types[m_iteration].isArrayType && !supportsES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
   1878 		m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target" << tcu::TestLog::EndMessage;
   1879 	else
   1880 	{
   1881 		glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
   1882 		glu::Texture			texture	(m_context.getRenderContext());
   1883 		glw::GLenum				error;
   1884 
   1885 		gl.enableLogging(true);
   1886 
   1887 		// gen texture
   1888 
   1889 		gl.glBindTexture(types[m_iteration].target, *texture);
   1890 
   1891 		if (types[m_iteration].isArrayType)
   1892 			gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16, GL_FALSE);
   1893 		else
   1894 			gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, GL_FALSE);
   1895 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture");
   1896 
   1897 		// set param
   1898 
   1899 		gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue());
   1900 		error = gl.glGetError();
   1901 
   1902 		// expect failure
   1903 
   1904 		if (error != getExpectedError())
   1905 		{
   1906 			m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage;
   1907 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
   1908 		}
   1909 	}
   1910 
   1911 	if (++m_iteration < DE_LENGTH_OF_ARRAY(types))
   1912 		return CONTINUE;
   1913 	return STOP;
   1914 }
   1915 
   1916 glw::GLenum NegativeTexParameterCase::getParamGLEnum (void) const
   1917 {
   1918 	switch (m_texParam)
   1919 	{
   1920 		case TEXTURE_MIN_FILTER:	return GL_TEXTURE_MIN_FILTER;
   1921 		case TEXTURE_MAG_FILTER:	return GL_TEXTURE_MAG_FILTER;
   1922 		case TEXTURE_WRAP_S:		return GL_TEXTURE_WRAP_S;
   1923 		case TEXTURE_WRAP_T:		return GL_TEXTURE_WRAP_T;
   1924 		case TEXTURE_WRAP_R:		return GL_TEXTURE_WRAP_R;
   1925 		case TEXTURE_MIN_LOD:		return GL_TEXTURE_MIN_LOD;
   1926 		case TEXTURE_MAX_LOD:		return GL_TEXTURE_MAX_LOD;
   1927 		case TEXTURE_COMPARE_MODE:	return GL_TEXTURE_COMPARE_MODE;
   1928 		case TEXTURE_COMPARE_FUNC:	return GL_TEXTURE_COMPARE_FUNC;
   1929 		case TEXTURE_BASE_LEVEL:	return GL_TEXTURE_BASE_LEVEL;
   1930 		default:
   1931 			DE_ASSERT(DE_FALSE);
   1932 			return 0;
   1933 	}
   1934 }
   1935 
   1936 glw::GLint NegativeTexParameterCase::getParamValue (void) const
   1937 {
   1938 	switch (m_texParam)
   1939 	{
   1940 		case TEXTURE_MIN_FILTER:	return GL_LINEAR;
   1941 		case TEXTURE_MAG_FILTER:	return GL_LINEAR;
   1942 		case TEXTURE_WRAP_S:		return GL_CLAMP_TO_EDGE;
   1943 		case TEXTURE_WRAP_T:		return GL_CLAMP_TO_EDGE;
   1944 		case TEXTURE_WRAP_R:		return GL_CLAMP_TO_EDGE;
   1945 		case TEXTURE_MIN_LOD:		return 1;
   1946 		case TEXTURE_MAX_LOD:		return 5;
   1947 		case TEXTURE_COMPARE_MODE:	return GL_NONE;
   1948 		case TEXTURE_COMPARE_FUNC:	return GL_NOTEQUAL;
   1949 		case TEXTURE_BASE_LEVEL:	return 2;
   1950 		default:
   1951 			DE_ASSERT(DE_FALSE);
   1952 			return 0;
   1953 	}
   1954 }
   1955 
   1956 glw::GLenum NegativeTexParameterCase::getExpectedError (void) const
   1957 {
   1958 	switch (m_texParam)
   1959 	{
   1960 		case TEXTURE_MIN_FILTER:	return GL_INVALID_ENUM;
   1961 		case TEXTURE_MAG_FILTER:	return GL_INVALID_ENUM;
   1962 		case TEXTURE_WRAP_S:		return GL_INVALID_ENUM;
   1963 		case TEXTURE_WRAP_T:		return GL_INVALID_ENUM;
   1964 		case TEXTURE_WRAP_R:		return GL_INVALID_ENUM;
   1965 		case TEXTURE_MIN_LOD:		return GL_INVALID_ENUM;
   1966 		case TEXTURE_MAX_LOD:		return GL_INVALID_ENUM;
   1967 		case TEXTURE_COMPARE_MODE:	return GL_INVALID_ENUM;
   1968 		case TEXTURE_COMPARE_FUNC:	return GL_INVALID_ENUM;
   1969 		case TEXTURE_BASE_LEVEL:	return GL_INVALID_OPERATION;
   1970 		default:
   1971 			DE_ASSERT(DE_FALSE);
   1972 			return 0;
   1973 	}
   1974 }
   1975 
   1976 class NegativeTexureSampleCase : public TestCase
   1977 {
   1978 public:
   1979 	enum SampleCountParam
   1980 	{
   1981 		SAMPLECOUNT_HIGH = 0,
   1982 		SAMPLECOUNT_ZERO,
   1983 
   1984 		SAMPLECOUNT_LAST
   1985 	};
   1986 
   1987 							NegativeTexureSampleCase	(Context& context, const char* name, const char* desc, SampleCountParam param);
   1988 private:
   1989 	IterateResult			iterate						(void);
   1990 
   1991 	const SampleCountParam	m_sampleParam;
   1992 };
   1993 
   1994 NegativeTexureSampleCase::NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param)
   1995 	: TestCase		(context, name, desc)
   1996 	, m_sampleParam	(param)
   1997 {
   1998 	DE_ASSERT(param < SAMPLECOUNT_LAST);
   1999 }
   2000 
   2001 NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate (void)
   2002 {
   2003 	const glw::GLenum		expectedError	= (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE);
   2004 	glu::CallLogWrapper		gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
   2005 	glu::Texture			texture			(m_context.getRenderContext());
   2006 	glw::GLenum				error;
   2007 	int						samples			= -1;
   2008 
   2009 	gl.enableLogging(true);
   2010 
   2011 	// calc samples
   2012 
   2013 	if (m_sampleParam == SAMPLECOUNT_HIGH)
   2014 	{
   2015 		int maxSamples = 0;
   2016 
   2017 		gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
   2018 		GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ");
   2019 
   2020 		samples = maxSamples + 1;
   2021 	}
   2022 	else if (m_sampleParam == SAMPLECOUNT_ZERO)
   2023 		samples = 0;
   2024 	else
   2025 		DE_ASSERT(DE_FALSE);
   2026 
   2027 	// create texture with bad values
   2028 
   2029 	gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture);
   2030 	gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE);
   2031 	error = gl.glGetError();
   2032 
   2033 	// expect failure
   2034 
   2035 	if (error == expectedError)
   2036 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   2037 	else
   2038 	{
   2039 		m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage;
   2040 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
   2041 	}
   2042 
   2043 	return STOP;
   2044 }
   2045 
   2046 
   2047 } // anonymous
   2048 
   2049 TextureMultisampleTests::TextureMultisampleTests (Context& context)
   2050 	: TestCaseGroup(context, "multisample", "Multisample texture tests")
   2051 {
   2052 }
   2053 
   2054 TextureMultisampleTests::~TextureMultisampleTests (void)
   2055 {
   2056 }
   2057 
   2058 void TextureMultisampleTests::init (void)
   2059 {
   2060 	static const int sampleCounts[] = { 1, 2, 3, 4, 8, 10, 12, 13, 16, 64 };
   2061 
   2062 	static const struct TextureType
   2063 	{
   2064 		const char*									name;
   2065 		MultisampleTextureUsageCase::TextureType	type;
   2066 	} textureTypes[] =
   2067 	{
   2068 		{ "texture_color_2d",		MultisampleTextureUsageCase::TEXTURE_COLOR_2D		},
   2069 		{ "texture_color_2d_array",	MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY	},
   2070 		{ "texture_int_2d",			MultisampleTextureUsageCase::TEXTURE_INT_2D			},
   2071 		{ "texture_int_2d_array",	MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY	},
   2072 		{ "texture_uint_2d",		MultisampleTextureUsageCase::TEXTURE_UINT_2D		},
   2073 		{ "texture_uint_2d_array",	MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY	},
   2074 		{ "texture_depth_2d",		MultisampleTextureUsageCase::TEXTURE_DEPTH_2D		},
   2075 		{ "texture_depth_2d_array",	MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY	},
   2076 	};
   2077 
   2078 	// .samples_x
   2079 	for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx)
   2080 	{
   2081 		tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(), "Test with N samples");
   2082 		addChild(sampleGroup);
   2083 
   2084 		// position query works
   2085 		sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION", sampleCounts[sampleNdx]));
   2086 
   2087 		// sample mask is ANDed properly
   2088 		sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only",											"Test with SampleMask only",									sampleCounts[sampleNdx],	SampleMaskCase::FLAGS_NONE));
   2089 		sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_alpha_to_coverage",						"Test with SampleMask and alpha to coverage",					sampleCounts[sampleNdx],	SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE));
   2090 		sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage",							"Test with SampleMask and sample coverage",						sampleCounts[sampleNdx],	SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
   2091 		sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage_and_alpha_to_coverage",	"Test with SampleMask, sample coverage, and alpha to coverage",	sampleCounts[sampleNdx],	SampleMaskCase::FLAGS_ALPHA_TO_COVERAGE | SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
   2092 
   2093 		// high bits cause no unexpected behavior
   2094 		sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_non_effective_bits",							"Test with SampleMask, set higher bits than sample count",		sampleCounts[sampleNdx],	SampleMaskCase::FLAGS_HIGH_BITS));
   2095 
   2096 		// usage
   2097 		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx)
   2098 			sampleGroup->addChild(new MultisampleTextureUsageCase(m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name, sampleCounts[sampleNdx], textureTypes[typeNdx].type));
   2099 	}
   2100 
   2101 	// .negative
   2102 	{
   2103 		tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
   2104 		addChild(negativeGroup);
   2105 
   2106 		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_sample_count_tex_tex",	"Attach different sample counts",	NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX));
   2107 		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_sample_count_tex_rbo",	"Attach different sample counts",	NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO));
   2108 		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_fixed_state_tex_tex",		"Attach fixed and non fixed",		NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX));
   2109 		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_fixed_state_tex_rbo",		"Attach fixed and non fixed",		NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO));
   2110 		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_non_zero_level",					"Attach non-zero level",			NegativeFramebufferCase::CASE_NON_ZERO_LEVEL));
   2111 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter",							"set TEXTURE_MIN_FILTER",			NegativeTexParameterCase::TEXTURE_MIN_FILTER));
   2112 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter",							"set TEXTURE_MAG_FILTER",			NegativeTexParameterCase::TEXTURE_MAG_FILTER));
   2113 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s",								"set TEXTURE_WRAP_S",				NegativeTexParameterCase::TEXTURE_WRAP_S));
   2114 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t",								"set TEXTURE_WRAP_T",				NegativeTexParameterCase::TEXTURE_WRAP_T));
   2115 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r",								"set TEXTURE_WRAP_R",				NegativeTexParameterCase::TEXTURE_WRAP_R));
   2116 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod",								"set TEXTURE_MIN_LOD",				NegativeTexParameterCase::TEXTURE_MIN_LOD));
   2117 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod",								"set TEXTURE_MAX_LOD",				NegativeTexParameterCase::TEXTURE_MAX_LOD));
   2118 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode",							"set TEXTURE_COMPARE_MODE",			NegativeTexParameterCase::TEXTURE_COMPARE_MODE));
   2119 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func",							"set TEXTURE_COMPARE_FUNC",			NegativeTexParameterCase::TEXTURE_COMPARE_FUNC));
   2120 		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level",							"set TEXTURE_BASE_LEVEL",			NegativeTexParameterCase::TEXTURE_BASE_LEVEL));
   2121 		negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count",					"TexStorage with high numSamples",	NegativeTexureSampleCase::SAMPLECOUNT_HIGH));
   2122 		negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count",					"TexStorage with zero numSamples",	NegativeTexureSampleCase::SAMPLECOUNT_ZERO));
   2123 	}
   2124 }
   2125 
   2126 } // Functional
   2127 } // gles31
   2128 } // deqp
   2129