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
44using namespace glw;
45
46namespace deqp
47{
48namespace gles31
49{
50namespace Functional
51{
52namespace
53{
54
55using tcu::RasterizationArguments;
56using tcu::TriangleSceneSpec;
57
58static 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 *//*--------------------------------------------------------------------*/
84static 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 *//*--------------------------------------------------------------------*/
95static 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 *//*--------------------------------------------------------------------*/
112static 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
126std::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
137class SamplePosRasterizationTest : public TestCase
138{
139public:
140								SamplePosRasterizationTest	(Context& context, const char* name, const char* desc, int samples);
141								~SamplePosRasterizationTest	(void);
142
143private:
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
179SamplePosRasterizationTest::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
196SamplePosRasterizationTest::~SamplePosRasterizationTest (void)
197{
198	deinit();
199}
200
201void 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
295void 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
322SamplePosRasterizationTest::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
339void 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
421void 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
451bool 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
475void 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
522void 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
543class SampleMaskCase : public TestCase
544{
545public:
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
557private:
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	glw::GLint					getMaxConformantSampleCount	(glw::GLenum target, glw::GLenum internalFormat);
569
570	const int					m_samples;
571	const int					m_canvasSize;
572	const int					m_gridsize;
573	const int					m_effectiveSampleMaskWordCount;
574
575	int							m_flags;
576	int							m_currentSample;
577	int							m_allIterationsOk;
578
579	glw::GLuint					m_texID;
580	glw::GLuint					m_vaoID;
581	glw::GLuint					m_vboID;
582	glw::GLuint					m_fboID;
583
584	const glu::ShaderProgram*	m_samplerProgram;
585	glw::GLint					m_samplerProgramPosLoc;
586	glw::GLint					m_samplerProgramSamplerLoc;
587	glw::GLint					m_samplerProgramSampleNdxLoc;
588
589	const glu::ShaderProgram*	m_alphaProgram;
590	glw::GLint					m_alphaProgramPosLoc;
591};
592
593SampleMaskCase::SampleMaskCase (Context& context, const char* name, const char* desc, int samples, int flags)
594	: TestCase						(context, name, desc)
595	, m_samples						(samples)
596	, m_canvasSize					(256)
597	, m_gridsize					(16)
598	, m_effectiveSampleMaskWordCount(getEffectiveSampleMaskWordCount(samples - 1))
599	, m_flags						(flags)
600	, m_currentSample				(-1)
601	, m_allIterationsOk				(true)
602	, m_texID						(0)
603	, m_vaoID						(0)
604	, m_vboID						(0)
605	, m_fboID						(0)
606	, m_samplerProgram				(DE_NULL)
607	, m_samplerProgramPosLoc		(-1)
608	, m_samplerProgramSamplerLoc	(-1)
609	, m_samplerProgramSampleNdxLoc	(-1)
610	, m_alphaProgram				(DE_NULL)
611	, m_alphaProgramPosLoc			(-1)
612{
613}
614
615SampleMaskCase::~SampleMaskCase (void)
616{
617	deinit();
618}
619
620void SampleMaskCase::init (void)
621{
622	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
623	glw::GLint				maxSamples			= 0;
624	glw::GLint				maxSampleMaskWords	= 0;
625
626	// requirements
627
628	if (m_context.getRenderTarget().getWidth() < m_canvasSize || m_context.getRenderTarget().getHeight() < m_canvasSize)
629		throw tcu::NotSupportedError("render target size must be at least " + de::toString(m_canvasSize) + "x" + de::toString(m_canvasSize));
630
631	gl.getIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &maxSampleMaskWords);
632	if (m_effectiveSampleMaskWordCount > maxSampleMaskWords)
633		throw tcu::NotSupportedError("Test requires larger GL_MAX_SAMPLE_MASK_WORDS");
634
635	maxSamples = getMaxConformantSampleCount(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8);
636	if (m_samples > maxSamples)
637		throw tcu::NotSupportedError("Requested sample count is greater than glGetInternalformativ(GL_SAMPLES) for this target/format");
638
639	m_testCtx.getLog() << tcu::TestLog::Message << "glGetInternalformativ(GL_SAMPLES) = " << maxSamples << tcu::TestLog::EndMessage;
640
641	// Don't even try to test high bits if there are none
642
643	if ((m_flags & FLAGS_HIGH_BITS) && (m_samples % 32 == 0))
644	{
645		m_testCtx.getLog() << tcu::TestLog::Message << "Sample count is multiple of word size. No unused high bits in sample mask.\nSkipping." << tcu::TestLog::EndMessage;
646		throw tcu::NotSupportedError("Test requires unused high bits (sample count not multiple of 32)");
647	}
648
649	// generate textures
650
651	m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample texture with sample count " << m_samples << tcu::TestLog::EndMessage;
652
653	gl.genTextures				(1, &m_texID);
654	gl.bindTexture				(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
655	gl.texStorage2DMultisample	(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, m_canvasSize, m_canvasSize, GL_FALSE);
656	GLU_EXPECT_NO_ERROR			(gl.getError(), "texStorage2DMultisample");
657
658	// attach texture to fbo
659
660	m_testCtx.getLog() << tcu::TestLog::Message << "Attaching texture to FBO" << tcu::TestLog::EndMessage;
661
662	gl.genFramebuffers		(1, &m_fboID);
663	gl.bindFramebuffer		(GL_FRAMEBUFFER, m_fboID);
664	gl.framebufferTexture2D	(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, m_texID, 0);
665	GLU_EXPECT_NO_ERROR		(gl.getError(), "framebufferTexture2D");
666
667	// buffers
668
669	gl.genVertexArrays		(1, &m_vaoID);
670	GLU_EXPECT_NO_ERROR		(gl.getError(), "genVertexArrays");
671
672	gl.genBuffers			(1, &m_vboID);
673	gl.bindBuffer			(GL_ARRAY_BUFFER, m_vboID);
674	GLU_EXPECT_NO_ERROR		(gl.getError(), "genBuffers");
675
676	// generate grid pattern
677	{
678		std::vector<tcu::Vec4> gridData(m_gridsize*m_gridsize*6);
679
680		for (int y = 0; y < m_gridsize; ++y)
681		for (int x = 0; x < m_gridsize; ++x)
682		{
683			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);
684			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);
685			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);
686			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);
687			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);
688			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);
689		}
690
691		gl.bufferData			(GL_ARRAY_BUFFER, (int)(gridData.size() * sizeof(tcu::Vec4)), gridData[0].getPtr(), GL_STATIC_DRAW);
692		GLU_EXPECT_NO_ERROR		(gl.getError(), "bufferData");
693	}
694
695	// generate programs
696
697	genSamplerProgram();
698	genAlphaProgram();
699}
700
701void SampleMaskCase::deinit (void)
702{
703	if (m_texID)
704	{
705		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texID);
706		m_texID = 0;
707	}
708	if (m_vaoID)
709	{
710		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
711		m_vaoID = 0;
712	}
713	if (m_vboID)
714	{
715		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_vboID);
716		m_vboID = 0;
717	}
718	if (m_fboID)
719	{
720		m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
721		m_fboID = 0;
722	}
723
724	if (m_samplerProgram)
725	{
726		delete m_samplerProgram;
727		m_samplerProgram = DE_NULL;
728	}
729	if (m_alphaProgram)
730	{
731		delete m_alphaProgram;
732		m_alphaProgram = DE_NULL;
733	}
734}
735
736SampleMaskCase::IterateResult SampleMaskCase::iterate (void)
737{
738	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)));
739
740	bool iterationOk;
741
742	// Mask only one sample, clear rest
743
744	updateTexture(m_currentSample);
745
746	// Verify only one sample set is in the texture
747
748	iterationOk = verifyTexture(m_currentSample);
749	if (!iterationOk)
750		m_allIterationsOk = false;
751
752	m_currentSample++;
753	if (m_currentSample < m_samples)
754		return CONTINUE;
755
756	// End result
757
758	if (m_allIterationsOk)
759		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
760	else if (m_flags & FLAGS_HIGH_BITS)
761		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Unused mask bits have effect");
762	else
763		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Sample test failed");
764
765	return STOP;
766}
767
768void SampleMaskCase::genSamplerProgram (void)
769{
770	const char* const	vertexShaderSource			= "${GLSL_VERSION_DECL}\n"
771													  "in highp vec4 a_position;\n"
772													  "void main (void)\n"
773													  "{\n"
774													  "	gl_Position = a_position;\n"
775													  "}\n";
776	const char* const	fragShaderSource			= "${GLSL_VERSION_DECL}\n"
777													  "layout(location = 0) out highp vec4 fragColor;\n"
778													  "uniform highp sampler2DMS u_sampler;\n"
779													  "uniform highp int u_sample;\n"
780													  "void main (void)\n"
781													  "{\n"
782													  "	highp float correctCoverage = 0.0;\n"
783													  "	highp float incorrectCoverage = 0.0;\n"
784													  "	highp ivec2 texelPos = ivec2(int(floor(gl_FragCoord.x)), int(floor(gl_FragCoord.y)));\n"
785													  "\n"
786													  "	for (int sampleNdx = 0; sampleNdx < ${NUMSAMPLES}; ++sampleNdx)\n"
787													  "	{\n"
788													  "		highp float sampleColor = texelFetch(u_sampler, texelPos, sampleNdx).r;\n"
789													  "		if (sampleNdx == u_sample)\n"
790													  "			correctCoverage += sampleColor;\n"
791													  "		else\n"
792													  "			incorrectCoverage += sampleColor;\n"
793													  "	}\n"
794													  "	fragColor = vec4(correctCoverage, incorrectCoverage, 0.0, 1.0);\n"
795													  "}\n";
796	const tcu::ScopedLogSection			section		(m_testCtx.getLog(), "GenerateSamplerShader", "Generate sampler shader");
797	const glw::Functions&				gl			= m_context.getRenderContext().getFunctions();
798	std::map<std::string, std::string>	args;
799	const glu::GLSLVersion				glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
800
801	args["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
802	args["NUMSAMPLES"] = de::toString(m_samples);
803
804	m_samplerProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragShaderSource).specialize(args)));
805	m_testCtx.getLog() << *m_samplerProgram;
806
807	if (!m_samplerProgram->isOk())
808		throw tcu::TestError("Could not create sampler program.");
809
810	m_samplerProgramPosLoc			= gl.getAttribLocation(m_samplerProgram->getProgram(), "a_position");
811	m_samplerProgramSamplerLoc		= gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sampler");
812	m_samplerProgramSampleNdxLoc	= gl.getUniformLocation(m_samplerProgram->getProgram(), "u_sample");
813}
814
815void SampleMaskCase::genAlphaProgram (void)
816{
817	const char* const	vertexShaderSource	=	"${GLSL_VERSION_DECL}\n"
818												"in highp vec4 a_position;\n"
819												"out highp float v_alpha;\n"
820												"void main (void)\n"
821												"{\n"
822												"	gl_Position = a_position;\n"
823												"	v_alpha = (a_position.x * 0.5 + 0.5)*(a_position.y * 0.5 + 0.5);\n"
824												"}\n";
825	const char* const	fragShaderSource	=	"${GLSL_VERSION_DECL}\n"
826												"layout(location = 0) out highp vec4 fragColor;\n"
827												"in mediump float v_alpha;\n"
828												"void main (void)\n"
829												"{\n"
830												"	fragColor = vec4(1.0, 1.0, 1.0, v_alpha);\n"
831												"}\n";
832	const glw::Functions&		gl			=	m_context.getRenderContext().getFunctions();
833
834	m_alphaProgram = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(specializeShader(m_context, fragShaderSource)));
835
836	if (!m_alphaProgram->isOk())
837	{
838		m_testCtx.getLog() << *m_alphaProgram;
839		throw tcu::TestError("Could not create aplha program.");
840	}
841
842	m_alphaProgramPosLoc = gl.getAttribLocation(m_alphaProgram->getProgram(), "a_position");
843}
844
845void SampleMaskCase::updateTexture (int sample)
846{
847	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
848
849	// prepare draw
850
851	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
852	gl.viewport(0, 0, m_canvasSize, m_canvasSize);
853	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
854
855	// clear all samples
856
857	m_testCtx.getLog() << tcu::TestLog::Message << "Clearing image" << tcu::TestLog::EndMessage;
858	gl.clear(GL_COLOR_BUFFER_BIT);
859
860	// set mask state
861
862	if (m_flags & FLAGS_HIGH_BITS)
863	{
864		const std::vector<deUint32> bitmask			= genSetNthBitSampleMask(sample);
865		const std::vector<deUint32>	effectiveMask	= genAllSetToNthBitSampleMask(m_samples);
866		std::vector<deUint32>		totalBitmask	(effectiveMask.size());
867
868		DE_ASSERT((int)totalBitmask.size() == m_effectiveSampleMaskWordCount);
869
870		// set some arbitrary high bits to non-effective bits
871		for (int wordNdx = 0; wordNdx < (int)effectiveMask.size(); ++wordNdx)
872		{
873			const deUint32 randomMask	= (deUint32)deUint32Hash(wordNdx << 2 ^ sample);
874			const deUint32 sampleMask	= (wordNdx < (int)bitmask.size()) ? (bitmask[wordNdx]) : (0);
875			const deUint32 maskMask		= effectiveMask[wordNdx];
876
877			totalBitmask[wordNdx] = (sampleMask & maskMask) | (randomMask & ~maskMask);
878		}
879
880		m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(totalBitmask, (int)totalBitmask.size() * 32) << tcu::TestLog::EndMessage;
881
882		gl.enable(GL_SAMPLE_MASK);
883		for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
884		{
885			const GLbitfield wordmask = (wordNdx < (int)totalBitmask.size()) ? ((GLbitfield)(totalBitmask[wordNdx])) : (0);
886			gl.sampleMaski((deUint32)wordNdx, wordmask);
887		}
888	}
889	else
890	{
891		const std::vector<deUint32> bitmask = sample < 0 ? std::vector<deUint32>(m_effectiveSampleMaskWordCount, 0) : genSetNthBitSampleMask(sample);
892		DE_ASSERT((int)bitmask.size() <= m_effectiveSampleMaskWordCount);
893
894		m_testCtx.getLog() << tcu::TestLog::Message << "Setting sample mask to 0b" << sampleMaskToString(bitmask, m_samples) << tcu::TestLog::EndMessage;
895
896		gl.enable(GL_SAMPLE_MASK);
897		for (int wordNdx = 0; wordNdx < m_effectiveSampleMaskWordCount; ++wordNdx)
898		{
899			const GLbitfield wordmask = (wordNdx < (int)bitmask.size()) ? ((GLbitfield)(bitmask[wordNdx])) : (0);
900			gl.sampleMaski((deUint32)wordNdx, wordmask);
901		}
902	}
903	if (m_flags & FLAGS_ALPHA_TO_COVERAGE)
904	{
905		m_testCtx.getLog() << tcu::TestLog::Message << "Enabling alpha to coverage." << tcu::TestLog::EndMessage;
906		gl.enable(GL_SAMPLE_ALPHA_TO_COVERAGE);
907	}
908	if (m_flags & FLAGS_SAMPLE_COVERAGE)
909	{
910		m_testCtx.getLog() << tcu::TestLog::Message << "Enabling sample coverage. Varying sample coverage for grid cells." << tcu::TestLog::EndMessage;
911		gl.enable(GL_SAMPLE_COVERAGE);
912	}
913
914	// draw test pattern
915
916	m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test grid" << tcu::TestLog::EndMessage;
917
918	gl.bindVertexArray			(m_vaoID);
919	gl.bindBuffer				(GL_ARRAY_BUFFER, m_vboID);
920	gl.vertexAttribPointer		(m_alphaProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
921	gl.enableVertexAttribArray	(m_alphaProgramPosLoc);
922	GLU_EXPECT_NO_ERROR			(gl.getError(), "vertexAttribPointer");
923
924	gl.useProgram				(m_alphaProgram->getProgram());
925
926	for (int y = 0; y < m_gridsize; ++y)
927	for (int x = 0; x < m_gridsize; ++x)
928	{
929		if (m_flags & FLAGS_SAMPLE_COVERAGE)
930			gl.sampleCoverage((float)(y*m_gridsize + x) / float(m_gridsize*m_gridsize), GL_FALSE);
931
932		gl.drawArrays				(GL_TRIANGLES, (y*m_gridsize + x) * 6, 6);
933		GLU_EXPECT_NO_ERROR			(gl.getError(), "drawArrays");
934	}
935
936	// clean state
937
938	gl.disableVertexAttribArray	(m_alphaProgramPosLoc);
939	gl.useProgram				(0);
940	gl.bindFramebuffer			(GL_FRAMEBUFFER, 0);
941	gl.disable					(GL_SAMPLE_MASK);
942	gl.disable					(GL_SAMPLE_ALPHA_TO_COVERAGE);
943	gl.disable					(GL_SAMPLE_COVERAGE);
944	GLU_EXPECT_NO_ERROR			(gl.getError(), "clean");
945}
946
947bool SampleMaskCase::verifyTexture (int sample)
948{
949	tcu::Surface	result		(m_canvasSize, m_canvasSize);
950	tcu::Surface	errorMask	(m_canvasSize, m_canvasSize);
951	bool			error		= false;
952
953	tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
954
955	// Draw sample:
956	//	Sample sampleNdx is set to red channel
957	//	Other samples are set to green channel
958	drawSample(result, sample);
959
960	// Check surface contains only sampleNdx
961	for (int y = 0; y < m_canvasSize; ++y)
962	for (int x = 0; x < m_canvasSize; ++x)
963	{
964		const tcu::RGBA color					= result.getPixel(x, y);
965
966		// Allow missing coverage with FLAGS_ALPHA_TO_COVERAGE and FLAGS_SAMPLE_COVERAGE, or if there are no samples enabled
967		const bool		allowMissingCoverage	= ((m_flags & (FLAGS_ALPHA_TO_COVERAGE | FLAGS_SAMPLE_COVERAGE)) != 0) || (sample == -1);
968
969		// disabled sample was written to
970		if (color.getGreen() != 0)
971		{
972			error = true;
973			errorMask.setPixel(x, y, tcu::RGBA::red());
974		}
975		// enabled sample was not written to
976		else if (color.getRed() != 255 && !allowMissingCoverage)
977		{
978			error = true;
979			errorMask.setPixel(x, y, tcu::RGBA::red());
980		}
981	}
982
983	if (error)
984	{
985		m_testCtx.getLog()
986			<< tcu::TestLog::Message << "Image verification failed, disabled samples found." << tcu::TestLog::EndMessage
987			<< tcu::TestLog::ImageSet("VerificationResult", "Result of rendering")
988			<< tcu::TestLog::Image("Result",	"Result",		result)
989			<< tcu::TestLog::Image("ErrorMask",	"Error Mask",	errorMask)
990			<< tcu::TestLog::EndImageSet;
991		return false;
992	}
993	else
994	{
995		m_testCtx.getLog() << tcu::TestLog::Message << "Image verification ok, no disabled samples found." << tcu::TestLog::EndMessage;
996		return true;
997	}
998}
999
1000void SampleMaskCase::drawSample (tcu::Surface& dst, int sample)
1001{
1002	// Downsample using only one sample
1003	static const tcu::Vec4 fullscreenQuad[] =
1004	{
1005		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
1006		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1007		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
1008		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f)
1009	};
1010
1011	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
1012	glu::Buffer				vertexBuffer	(m_context.getRenderContext());
1013
1014	gl.bindTexture				(GL_TEXTURE_2D_MULTISAMPLE, m_texID);
1015	gl.bindVertexArray			(m_vaoID);
1016
1017	gl.bindBuffer				(GL_ARRAY_BUFFER, *vertexBuffer);
1018	gl.bufferData				(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), &fullscreenQuad[0], GL_STATIC_DRAW);
1019	GLU_EXPECT_NO_ERROR			(gl.getError(), "bufferData");
1020
1021	gl.viewport					(0, 0, m_canvasSize, m_canvasSize);
1022	gl.clearColor				(0, 0, 0, 1);
1023	gl.clear					(GL_COLOR_BUFFER_BIT);
1024	gl.vertexAttribPointer		(m_samplerProgramPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1025	gl.enableVertexAttribArray	(m_samplerProgramPosLoc);
1026	GLU_EXPECT_NO_ERROR			(gl.getError(), "vertexAttribPointer");
1027
1028	gl.useProgram				(m_samplerProgram->getProgram());
1029	gl.uniform1i				(m_samplerProgramSamplerLoc, 0);
1030	gl.uniform1i				(m_samplerProgramSampleNdxLoc, (deInt32)sample);
1031	GLU_EXPECT_NO_ERROR			(gl.getError(), "useprogram");
1032
1033	m_testCtx.getLog() << tcu::TestLog::Message << "Reading from texture with sampler shader, u_sample = " << sample << tcu::TestLog::EndMessage;
1034
1035	gl.drawArrays				(GL_TRIANGLE_STRIP, 0, 4);
1036	GLU_EXPECT_NO_ERROR			(gl.getError(), "drawArrays");
1037
1038	gl.disableVertexAttribArray	(m_samplerProgramPosLoc);
1039	gl.useProgram				(0);
1040	GLU_EXPECT_NO_ERROR			(gl.getError(), "cleanup");
1041
1042	gl.finish					();
1043	glu::readPixels				(m_context.getRenderContext(), 0, 0, dst.getAccess());
1044	GLU_EXPECT_NO_ERROR			(gl.getError(), "readPixels");
1045}
1046
1047glw::GLint SampleMaskCase::getMaxConformantSampleCount(glw::GLenum target, glw::GLenum internalFormat)
1048{
1049	deInt32					maxTextureSamples	= 0;
1050	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
1051	if (m_context.getContextInfo().isExtensionSupported("GL_NV_internalformat_sample_query"))
1052	{
1053		glw::GLint gl_sample_counts = 0;
1054		gl.getInternalformativ(target, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &gl_sample_counts);
1055		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformativ() failed for GL_NUM_SAMPLE_COUNTS pname");
1056		/* Check and return the first conformant sample count */
1057		glw::GLint* gl_supported_samples = new glw::GLint[gl_sample_counts];
1058		if (gl_supported_samples)
1059		{
1060			gl.getInternalformativ(target, internalFormat, GL_SAMPLES, gl_sample_counts, gl_supported_samples);
1061			for (glw::GLint i = 0; i < gl_sample_counts; i++)
1062			{
1063				glw::GLint isConformant = 0;
1064				gl.getInternalformatSampleivNV(target, internalFormat, gl_supported_samples[i], GL_CONFORMANT_NV, 1,
1065					&isConformant);
1066				GLU_EXPECT_NO_ERROR(gl.getError(), "glGetInternalformatSampleivNV() call(s) failed");
1067				if (isConformant && gl_supported_samples[i] > maxTextureSamples)
1068				{
1069					maxTextureSamples = gl_supported_samples[i];
1070				}
1071			}
1072			delete[] gl_supported_samples;
1073		}
1074	}
1075	else
1076	{
1077		gl.getInternalformativ(target, internalFormat, GL_SAMPLES, 1, &maxTextureSamples);
1078	}
1079	return maxTextureSamples;
1080}
1081
1082
1083class MultisampleTextureUsageCase : public TestCase
1084{
1085public:
1086
1087	enum TextureType
1088	{
1089		TEXTURE_COLOR_2D = 0,
1090		TEXTURE_COLOR_2D_ARRAY,
1091		TEXTURE_INT_2D,
1092		TEXTURE_INT_2D_ARRAY,
1093		TEXTURE_UINT_2D,
1094		TEXTURE_UINT_2D_ARRAY,
1095		TEXTURE_DEPTH_2D,
1096		TEXTURE_DEPTH_2D_ARRAY,
1097
1098		TEXTURE_LAST
1099	};
1100
1101						MultisampleTextureUsageCase		(Context& ctx, const char* name, const char* desc, int samples, TextureType type);
1102						~MultisampleTextureUsageCase	(void);
1103
1104private:
1105	void				init							(void);
1106	void				deinit							(void);
1107	IterateResult		iterate							(void);
1108
1109	void				genDrawShader					(void);
1110	void				genSamplerShader				(void);
1111
1112	void				renderToTexture					(float value);
1113	void				sampleTexture					(tcu::Surface& dst, float value);
1114	bool				verifyImage						(const tcu::Surface& dst);
1115
1116	static const int	s_textureSize					= 256;
1117	static const int	s_textureArraySize				= 8;
1118	static const int	s_textureLayer					= 3;
1119
1120	const TextureType	m_type;
1121	const int			m_numSamples;
1122
1123	glw::GLuint			m_fboID;
1124	glw::GLuint			m_vaoID;
1125	glw::GLuint			m_textureID;
1126
1127	glu::ShaderProgram*	m_drawShader;
1128	glu::ShaderProgram*	m_samplerShader;
1129
1130	const bool			m_isColorFormat;
1131	const bool			m_isSignedFormat;
1132	const bool			m_isUnsignedFormat;
1133	const bool			m_isDepthFormat;
1134	const bool			m_isArrayType;
1135};
1136
1137MultisampleTextureUsageCase::MultisampleTextureUsageCase (Context& ctx, const char* name, const char* desc, int samples, TextureType type)
1138	: TestCase			(ctx, name, desc)
1139	, m_type			(type)
1140	, m_numSamples		(samples)
1141	, m_fboID			(0)
1142	, m_vaoID			(0)
1143	, m_textureID		(0)
1144	, m_drawShader		(DE_NULL)
1145	, m_samplerShader	(DE_NULL)
1146	, m_isColorFormat	(m_type == TEXTURE_COLOR_2D	|| m_type == TEXTURE_COLOR_2D_ARRAY)
1147	, m_isSignedFormat	(m_type == TEXTURE_INT_2D	|| m_type == TEXTURE_INT_2D_ARRAY)
1148	, m_isUnsignedFormat(m_type == TEXTURE_UINT_2D	|| m_type == TEXTURE_UINT_2D_ARRAY)
1149	, m_isDepthFormat	(m_type == TEXTURE_DEPTH_2D	|| m_type == TEXTURE_DEPTH_2D_ARRAY)
1150	, 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)
1151{
1152	DE_ASSERT(m_type < TEXTURE_LAST);
1153}
1154
1155MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void)
1156{
1157	deinit();
1158}
1159
1160void MultisampleTextureUsageCase::init (void)
1161{
1162	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
1163	const glw::GLenum		internalFormat		= (m_isColorFormat) ? (GL_R8) : (m_isSignedFormat) ? (GL_R8I) : (m_isUnsignedFormat) ? (GL_R8UI) : (m_isDepthFormat) ? (GL_DEPTH_COMPONENT32F) : (0);
1164	const glw::GLenum		textureTarget		= (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1165	const glw::GLenum		fboAttachment		= (m_isDepthFormat) ? (GL_DEPTH_ATTACHMENT) : (GL_COLOR_ATTACHMENT0);
1166	const bool				supportsES32orGL45	= glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1167												  glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1168
1169	DE_ASSERT(internalFormat);
1170
1171	// requirements
1172
1173	if (m_isArrayType && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1174		throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
1175	if (m_context.getRenderTarget().getWidth() < s_textureSize || m_context.getRenderTarget().getHeight() < s_textureSize)
1176		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)));
1177
1178	{
1179		glw::GLint maxSamples = 0;
1180		gl.getInternalformativ(textureTarget, internalFormat, GL_SAMPLES, 1, &maxSamples);
1181
1182		if (m_numSamples > maxSamples)
1183			throw tcu::NotSupportedError("Requested sample count is greater than supported");
1184
1185		m_testCtx.getLog() << tcu::TestLog::Message << "Max sample count for " << glu::getTextureFormatStr(internalFormat) << ": " << maxSamples << tcu::TestLog::EndMessage;
1186	}
1187
1188	{
1189		GLint maxTextureSize = 0;
1190		gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1191
1192		if (s_textureSize > maxTextureSize)
1193			throw tcu::NotSupportedError("Larger GL_MAX_TEXTURE_SIZE is required");
1194	}
1195
1196	if (m_isArrayType)
1197	{
1198		GLint maxTextureLayers = 0;
1199		gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureLayers);
1200
1201		if (s_textureArraySize > maxTextureLayers)
1202			throw tcu::NotSupportedError("Larger GL_MAX_ARRAY_TEXTURE_LAYERS is required");
1203	}
1204
1205	// create texture
1206
1207	m_testCtx.getLog() << tcu::TestLog::Message << "Creating multisample " << ((m_isDepthFormat) ? ("depth") : ("")) << " texture" << ((m_isArrayType) ? (" array") : ("")) << tcu::TestLog::EndMessage;
1208
1209	gl.genTextures(1, &m_textureID);
1210	gl.bindTexture(textureTarget, m_textureID);
1211	GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
1212
1213	if (m_isArrayType)
1214		gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_numSamples, internalFormat, s_textureSize, s_textureSize, s_textureArraySize, GL_FALSE);
1215	else
1216		gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples, internalFormat, s_textureSize, s_textureSize, GL_FALSE);
1217	GLU_EXPECT_NO_ERROR(gl.getError(), "texstorage");
1218
1219	// create fbo for drawing
1220
1221	gl.genFramebuffers(1, &m_fboID);
1222	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1223
1224	if (m_isArrayType)
1225	{
1226		m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture array layer " << static_cast<int>(s_textureLayer) << " to fbo" << tcu::TestLog::EndMessage;
1227		gl.framebufferTextureLayer(GL_FRAMEBUFFER, fboAttachment, m_textureID, 0, s_textureLayer);
1228	}
1229	else
1230	{
1231		m_testCtx.getLog() << tcu::TestLog::Message << "Attaching multisample texture to fbo" << tcu::TestLog::EndMessage;
1232		gl.framebufferTexture2D(GL_FRAMEBUFFER, fboAttachment, textureTarget, m_textureID, 0);
1233	}
1234	GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
1235
1236	// create vao if context is GL4.5
1237	if (!glu::isContextTypeES(m_context.getRenderContext().getType()))
1238		gl.genVertexArrays(1, &m_vaoID);
1239
1240	// create shader for rendering to fbo
1241	genDrawShader();
1242
1243	// create shader for sampling the texture rendered to
1244	genSamplerShader();
1245}
1246
1247void MultisampleTextureUsageCase::deinit (void)
1248{
1249	if (m_textureID)
1250	{
1251		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_textureID);
1252		m_textureID = 0;
1253	}
1254
1255	if (m_fboID)
1256	{
1257		m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fboID);
1258		m_fboID = 0;
1259	}
1260
1261	if (m_vaoID)
1262	{
1263		m_context.getRenderContext().getFunctions().deleteVertexArrays(1, &m_vaoID);
1264		m_vaoID = 0;
1265	}
1266
1267	if (m_drawShader)
1268	{
1269		delete m_drawShader;
1270		m_drawShader = DE_NULL;
1271	}
1272
1273	if (m_samplerShader)
1274	{
1275		delete m_samplerShader;
1276		m_samplerShader = DE_NULL;
1277	}
1278}
1279
1280MultisampleTextureUsageCase::IterateResult MultisampleTextureUsageCase::iterate (void)
1281{
1282	const tcu::ScopedLogSection	section			(m_testCtx.getLog(), "Sample", "Render to texture and sample texture");
1283	tcu::Surface				result			(s_textureSize, s_textureSize);
1284	const float					minValue		= (m_isColorFormat || m_isDepthFormat) ? (0.0f) : (m_isSignedFormat) ? (-100.0f) : (m_isUnsignedFormat) ? (0.0f)	: ( 1.0f);
1285	const float					maxValue		= (m_isColorFormat || m_isDepthFormat) ? (1.0f) : (m_isSignedFormat) ? ( 100.0f) : (m_isUnsignedFormat) ? (200.0f)	: (-1.0f);
1286	de::Random					rnd				(deUint32Hash((deUint32)m_type));
1287	const float					rawValue		= rnd.getFloat(minValue, maxValue);
1288	const float					preparedValue	= (m_isSignedFormat || m_isUnsignedFormat) ? (deFloatFloor(rawValue)) : (rawValue);
1289
1290	// draw to fbo with a random value
1291
1292	renderToTexture(preparedValue);
1293
1294	// draw from texture to front buffer
1295
1296	sampleTexture(result, preparedValue);
1297
1298	// result is ok?
1299
1300	if (verifyImage(result))
1301		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1302	else
1303		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1304
1305	return STOP;
1306}
1307
1308void MultisampleTextureUsageCase::genDrawShader (void)
1309{
1310	const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderShader", "Generate render-to-texture shader");
1311
1312	static const char* const	vertexShaderSource =		"${GLSL_VERSION_DECL}\n"
1313															"in highp vec4 a_position;\n"
1314															"void main (void)\n"
1315															"{\n"
1316															"	gl_Position = a_position;\n"
1317															"}\n";
1318	static const char* const	fragmentShaderSourceColor =	"${GLSL_VERSION_DECL}\n"
1319															"layout(location = 0) out highp ${OUTTYPE} fragColor;\n"
1320															"uniform highp float u_writeValue;\n"
1321															"void main (void)\n"
1322															"{\n"
1323															"	fragColor = ${OUTTYPE}(vec4(u_writeValue, 1.0, 1.0, 1.0));\n"
1324															"}\n";
1325	static const char* const	fragmentShaderSourceDepth =	"${GLSL_VERSION_DECL}\n"
1326															"layout(location = 0) out highp vec4 fragColor;\n"
1327															"uniform highp float u_writeValue;\n"
1328															"void main (void)\n"
1329															"{\n"
1330															"	fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
1331															"	gl_FragDepth = u_writeValue;\n"
1332															"}\n";
1333	const char* const			fragmentSource =			(m_isDepthFormat) ? (fragmentShaderSourceDepth) : (fragmentShaderSourceColor);
1334
1335	std::map<std::string, std::string> fragmentArguments;
1336
1337	const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1338	fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1339
1340	if (m_isColorFormat || m_isDepthFormat)
1341		fragmentArguments["OUTTYPE"] = "vec4";
1342	else if (m_isSignedFormat)
1343		fragmentArguments["OUTTYPE"] = "ivec4";
1344	else if (m_isUnsignedFormat)
1345		fragmentArguments["OUTTYPE"] = "uvec4";
1346	else
1347		DE_ASSERT(DE_FALSE);
1348
1349	m_drawShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentSource).specialize(fragmentArguments)));
1350	m_testCtx.getLog() << *m_drawShader;
1351
1352	if (!m_drawShader->isOk())
1353		throw tcu::TestError("could not build shader");
1354}
1355
1356void MultisampleTextureUsageCase::genSamplerShader (void)
1357{
1358	const tcu::ScopedLogSection section(m_testCtx.getLog(), "SamplerShader", "Generate texture sampler shader");
1359
1360	static const char* const vertexShaderSource =	"${GLSL_VERSION_DECL}\n"
1361													"in highp vec4 a_position;\n"
1362													"out highp float v_gradient;\n"
1363													"void main (void)\n"
1364													"{\n"
1365													"	gl_Position = a_position;\n"
1366													"	v_gradient = a_position.x * 0.5 + 0.5;\n"
1367													"}\n";
1368	static const char* const fragmentShaderSource =	"${GLSL_VERSION_DECL}\n"
1369													"${EXTENSION_STATEMENT}"
1370													"layout(location = 0) out highp vec4 fragColor;\n"
1371													"uniform highp ${SAMPLERTYPE} u_sampler;\n"
1372													"uniform highp int u_maxSamples;\n"
1373													"uniform highp int u_layer;\n"
1374													"uniform highp float u_cmpValue;\n"
1375													"in highp float v_gradient;\n"
1376													"void main (void)\n"
1377													"{\n"
1378													"	const highp vec4 okColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
1379													"	const highp vec4 failColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
1380													"	const highp float epsilon = ${EPSILON};\n"
1381													"\n"
1382													"	highp int sampleNdx = clamp(int(floor(v_gradient * float(u_maxSamples))), 0, u_maxSamples-1);\n"
1383													"	highp float value = float(texelFetch(u_sampler, ${FETCHPOS}, sampleNdx).r);\n"
1384													"	fragColor = (abs(u_cmpValue - value) < epsilon) ? (okColor) : (failColor);\n"
1385													"}\n";
1386
1387	std::map<std::string, std::string> fragmentArguments;
1388
1389	const glu::GLSLVersion glslVersion = glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType());
1390	fragmentArguments["GLSL_VERSION_DECL"] = glu::getGLSLVersionDeclaration(glslVersion);
1391
1392	const bool supportsES32orGL45 =
1393		glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1394		glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1395
1396	if (m_isArrayType)
1397		fragmentArguments["FETCHPOS"] = "ivec3(floor(gl_FragCoord.xy), u_layer)";
1398	else
1399		fragmentArguments["FETCHPOS"] = "ivec2(floor(gl_FragCoord.xy))";
1400
1401	if (m_isColorFormat || m_isDepthFormat)
1402		fragmentArguments["EPSILON"] = "0.1";
1403	else
1404		fragmentArguments["EPSILON"] = "1.0";
1405
1406	if (m_isArrayType && !supportsES32orGL45)
1407		fragmentArguments["EXTENSION_STATEMENT"] = "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
1408	else
1409		fragmentArguments["EXTENSION_STATEMENT"] = "";
1410
1411	switch (m_type)
1412	{
1413		case TEXTURE_COLOR_2D:			fragmentArguments["SAMPLERTYPE"] = "sampler2DMS";		break;
1414		case TEXTURE_COLOR_2D_ARRAY:	fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray";	break;
1415		case TEXTURE_INT_2D:			fragmentArguments["SAMPLERTYPE"] = "isampler2DMS";		break;
1416		case TEXTURE_INT_2D_ARRAY:		fragmentArguments["SAMPLERTYPE"] = "isampler2DMSArray";	break;
1417		case TEXTURE_UINT_2D:			fragmentArguments["SAMPLERTYPE"] = "usampler2DMS";		break;
1418		case TEXTURE_UINT_2D_ARRAY:		fragmentArguments["SAMPLERTYPE"] = "usampler2DMSArray";	break;
1419		case TEXTURE_DEPTH_2D:			fragmentArguments["SAMPLERTYPE"] = "sampler2DMS";		break;
1420		case TEXTURE_DEPTH_2D_ARRAY:	fragmentArguments["SAMPLERTYPE"] = "sampler2DMSArray";	break;
1421
1422		default:
1423			DE_ASSERT(DE_FALSE);
1424	}
1425
1426	m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(specializeShader(m_context, vertexShaderSource)) << glu::FragmentSource(tcu::StringTemplate(fragmentShaderSource).specialize(fragmentArguments)));
1427	m_testCtx.getLog() << *m_samplerShader;
1428
1429	if (!m_samplerShader->isOk())
1430		throw tcu::TestError("could not build shader");
1431}
1432
1433void MultisampleTextureUsageCase::renderToTexture (float value)
1434{
1435	static const tcu::Vec4 fullscreenQuad[] =
1436	{
1437		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1438		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
1439		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1440		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
1441	};
1442
1443	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
1444	const int				posLocation			= gl.getAttribLocation(m_drawShader->getProgram(), "a_position");
1445	const int				valueLocation		= gl.getUniformLocation(m_drawShader->getProgram(), "u_writeValue");
1446	glu::Buffer				vertexAttibBuffer	(m_context.getRenderContext());
1447
1448	m_testCtx.getLog() << tcu::TestLog::Message << "Filling multisample texture with value " << value  << tcu::TestLog::EndMessage;
1449
1450	// upload data
1451
1452	gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1453	gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1454	GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1455
1456	// clear buffer
1457
1458	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fboID);
1459	gl.viewport(0, 0, s_textureSize, s_textureSize);
1460
1461	if (m_isColorFormat)
1462	{
1463		const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1464		gl.clearBufferfv(GL_COLOR, 0, clearColor);
1465	}
1466	else if (m_isSignedFormat)
1467	{
1468		const deInt32 clearColor[4] = { 0, 0, 0, 0 };
1469		gl.clearBufferiv(GL_COLOR, 0, clearColor);
1470	}
1471	else if (m_isUnsignedFormat)
1472	{
1473		const deUint32 clearColor[4] = { 0, 0, 0, 0 };
1474		gl.clearBufferuiv(GL_COLOR, 0, clearColor);
1475	}
1476	else if (m_isDepthFormat)
1477	{
1478		const float clearDepth = 0.5f;
1479		gl.clearBufferfv(GL_DEPTH, 0, &clearDepth);
1480	}
1481
1482	GLU_EXPECT_NO_ERROR(gl.getError(), "clear buffer");
1483
1484	// setup shader and draw
1485	if (m_vaoID)
1486		gl.bindVertexArray(m_vaoID);
1487
1488	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1489	gl.enableVertexAttribArray(posLocation);
1490
1491	gl.useProgram(m_drawShader->getProgram());
1492	gl.uniform1f(valueLocation, value);
1493
1494	GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1495
1496	if (m_isDepthFormat)
1497	{
1498		gl.enable(GL_DEPTH_TEST);
1499		gl.depthFunc(GL_ALWAYS);
1500	}
1501
1502	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1503	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1504
1505	// clean state
1506
1507	if (m_isDepthFormat)
1508		gl.disable(GL_DEPTH_TEST);
1509
1510	gl.disableVertexAttribArray(posLocation);
1511	gl.useProgram(0);
1512	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
1513	GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1514}
1515
1516void MultisampleTextureUsageCase::sampleTexture (tcu::Surface& dst, float value)
1517{
1518	static const tcu::Vec4 fullscreenQuad[] =
1519	{
1520		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1521		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
1522		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
1523		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
1524	};
1525
1526	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
1527	const int				posLocation			= gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
1528	const int				samplerLocation		= gl.getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
1529	const int				maxSamplesLocation	= gl.getUniformLocation(m_samplerShader->getProgram(), "u_maxSamples");
1530	const int				layerLocation		= gl.getUniformLocation(m_samplerShader->getProgram(), "u_layer");
1531	const int				valueLocation		= gl.getUniformLocation(m_samplerShader->getProgram(), "u_cmpValue");
1532	const glw::GLenum		textureTarget		= (m_isArrayType) ? (GL_TEXTURE_2D_MULTISAMPLE_ARRAY) : (GL_TEXTURE_2D_MULTISAMPLE);
1533	glu::Buffer				vertexAttibBuffer	(m_context.getRenderContext());
1534
1535	m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture." << tcu::TestLog::EndMessage;
1536
1537	// upload data
1538
1539	gl.bindBuffer(GL_ARRAY_BUFFER, *vertexAttibBuffer);
1540	gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad[0].getPtr(), GL_STATIC_DRAW);
1541	GLU_EXPECT_NO_ERROR(gl.getError(), "bufferdata");
1542
1543	// clear
1544
1545	gl.viewport(0, 0, s_textureSize, s_textureSize);
1546	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1547	gl.clear(GL_COLOR_BUFFER_BIT);
1548
1549	// setup shader and draw
1550
1551	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
1552	gl.enableVertexAttribArray(posLocation);
1553
1554	gl.useProgram(m_samplerShader->getProgram());
1555	gl.uniform1i(samplerLocation, 0);
1556	gl.uniform1i(maxSamplesLocation, m_numSamples);
1557	if (m_isArrayType)
1558		gl.uniform1i(layerLocation, s_textureLayer);
1559	gl.uniform1f(valueLocation, value);
1560	gl.bindTexture(textureTarget, m_textureID);
1561	GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
1562
1563	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
1564	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
1565
1566	// clean state
1567
1568	gl.disableVertexAttribArray(posLocation);
1569	gl.useProgram(0);
1570	GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
1571
1572	// read results
1573	gl.finish();
1574	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
1575}
1576
1577bool MultisampleTextureUsageCase::verifyImage (const tcu::Surface& dst)
1578{
1579	bool error = false;
1580
1581	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying image." << tcu::TestLog::EndMessage;
1582
1583	for (int y = 0; y < dst.getHeight(); ++y)
1584	for (int x = 0; x < dst.getWidth(); ++x)
1585	{
1586		const tcu::RGBA color				= dst.getPixel(x, y);
1587		const int		colorThresholdRed	= 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits);
1588		const int		colorThresholdGreen	= 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits);
1589		const int		colorThresholdBlue	= 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits);
1590
1591		// only green is accepted
1592		if (color.getRed() > colorThresholdRed || color.getGreen() < 255 - colorThresholdGreen || color.getBlue() > colorThresholdBlue)
1593			error = true;
1594	}
1595
1596	if (error)
1597	{
1598		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found." << tcu::TestLog::EndMessage;
1599		m_testCtx.getLog()
1600			<< tcu::TestLog::ImageSet("Verification result", "Result of rendering")
1601			<< tcu::TestLog::Image("Result", "Result", dst)
1602			<< tcu::TestLog::EndImageSet;
1603
1604		return false;
1605	}
1606	else
1607	{
1608		m_testCtx.getLog() << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
1609		return true;
1610	}
1611}
1612
1613class NegativeFramebufferCase : public TestCase
1614{
1615public:
1616	enum CaseType
1617	{
1618		CASE_DIFFERENT_N_SAMPLES_TEX = 0,
1619		CASE_DIFFERENT_N_SAMPLES_RBO,
1620		CASE_DIFFERENT_FIXED_TEX,
1621		CASE_DIFFERENT_FIXED_RBO,
1622		CASE_NON_ZERO_LEVEL,
1623
1624		CASE_LAST
1625	};
1626
1627						NegativeFramebufferCase		(Context& context, const char* name, const char* desc, CaseType caseType);
1628						~NegativeFramebufferCase	(void);
1629
1630private:
1631	void				init						(void);
1632	void				deinit						(void);
1633	IterateResult		iterate						(void);
1634
1635	void				getFormatSamples			(glw::GLenum target, std::vector<int>& samples);
1636
1637	const CaseType		m_caseType;
1638	const int			m_fboSize;
1639	const glw::GLenum	m_internalFormat;
1640
1641	int					m_numSamples0;	// !< samples for attachment 0
1642	int					m_numSamples1;	// !< samples for attachment 1
1643};
1644
1645NegativeFramebufferCase::NegativeFramebufferCase (Context& context, const char* name, const char* desc, CaseType caseType)
1646	: TestCase			(context, name, desc)
1647	, m_caseType		(caseType)
1648	, m_fboSize			(64)
1649	, m_internalFormat	(GL_RGBA8)
1650	, m_numSamples0		(-1)
1651	, m_numSamples1		(-1)
1652{
1653}
1654
1655NegativeFramebufferCase::~NegativeFramebufferCase (void)
1656{
1657	deinit();
1658}
1659
1660void NegativeFramebufferCase::init (void)
1661{
1662	const bool				colorAttachmentTexture	= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1663	const bool				colorAttachmentRbo		= (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1664	const bool				useDifferentSampleCounts= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO);
1665	std::vector<int>		textureSamples;
1666	std::vector<int>		rboSamples;
1667
1668	getFormatSamples(GL_TEXTURE_2D_MULTISAMPLE, textureSamples);
1669	getFormatSamples(GL_RENDERBUFFER, rboSamples);
1670
1671	TCU_CHECK(!textureSamples.empty());
1672	TCU_CHECK(!rboSamples.empty());
1673
1674	// select sample counts
1675
1676	if (useDifferentSampleCounts)
1677	{
1678		if (colorAttachmentTexture)
1679		{
1680			m_numSamples0 = textureSamples[0];
1681
1682			if (textureSamples.size() >= 2)
1683				m_numSamples1 = textureSamples[1];
1684			else
1685				throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1686		}
1687		else if (colorAttachmentRbo)
1688		{
1689			for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1690			for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1691			{
1692				if (textureSamples[texNdx] != rboSamples[rboNdx])
1693				{
1694					m_numSamples0 = textureSamples[texNdx];
1695					m_numSamples1 = rboSamples[rboNdx];
1696					return;
1697				}
1698			}
1699
1700			throw tcu::NotSupportedError("Test requires multiple supported sample counts");
1701		}
1702		else
1703			DE_ASSERT(DE_FALSE);
1704	}
1705	else
1706	{
1707		if (colorAttachmentTexture)
1708		{
1709			m_numSamples0 = textureSamples[0];
1710			m_numSamples1 = textureSamples[0];
1711		}
1712		else if (colorAttachmentRbo)
1713		{
1714			for (int texNdx = 0; texNdx < (int)textureSamples.size(); ++texNdx)
1715			for (int rboNdx = 0; rboNdx < (int)rboSamples.size(); ++rboNdx)
1716			{
1717				if (textureSamples[texNdx] == rboSamples[rboNdx])
1718				{
1719					m_numSamples0 = textureSamples[texNdx];
1720					m_numSamples1 = rboSamples[rboNdx];
1721					return;
1722				}
1723			}
1724
1725			throw tcu::NotSupportedError("Test requires a sample count supported in both rbo and texture");
1726		}
1727		else
1728		{
1729			m_numSamples0 = textureSamples[0];
1730		}
1731	}
1732}
1733
1734void NegativeFramebufferCase::deinit (void)
1735{
1736}
1737
1738NegativeFramebufferCase::IterateResult NegativeFramebufferCase::iterate (void)
1739{
1740	const bool				colorAttachmentTexture	= (m_caseType == CASE_DIFFERENT_N_SAMPLES_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_TEX);
1741	const bool				colorAttachmentRbo		= (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) || (m_caseType == CASE_DIFFERENT_FIXED_RBO);
1742	const glw::GLboolean	fixedSampleLocations0	= (m_caseType == CASE_DIFFERENT_N_SAMPLES_RBO) ? (GL_TRUE) : (GL_FALSE);
1743	const glw::GLboolean	fixedSampleLocations1	= ((m_caseType == CASE_DIFFERENT_FIXED_TEX) || (m_caseType == CASE_DIFFERENT_FIXED_RBO)) ? (GL_TRUE) : (GL_FALSE);
1744	glu::CallLogWrapper		gl						(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1745	glw::GLuint				fboId					= 0;
1746	glw::GLuint				rboId					= 0;
1747	glw::GLuint				tex0Id					= 0;
1748	glw::GLuint				tex1Id					= 0;
1749
1750	bool					testFailed				= false;
1751
1752	gl.enableLogging(true);
1753
1754	try
1755	{
1756		gl.glGenFramebuffers(1, &fboId);
1757		gl.glBindFramebuffer(GL_FRAMEBUFFER, fboId);
1758		GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen fbo");
1759
1760		gl.glGenTextures(1, &tex0Id);
1761		gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex0Id);
1762		gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples0, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations0);
1763		GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 0");
1764
1765		int textureSamples;
1766		gl.glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &textureSamples);
1767
1768		if (m_caseType == CASE_NON_ZERO_LEVEL)
1769		{
1770			glw::GLenum error;
1771
1772			// attaching non-zero level generates invalid value
1773			gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 5);
1774			error = gl.glGetError();
1775
1776			if (error != GL_INVALID_VALUE)
1777			{
1778				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_INVALID_VALUE, got " << glu::getErrorStr(error) << tcu::TestLog::EndMessage;
1779				testFailed = true;
1780			}
1781		}
1782		else
1783		{
1784			gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex0Id, 0);
1785			GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c0");
1786
1787			int fbSamples = 0;
1788
1789			if (colorAttachmentTexture)
1790			{
1791				gl.glGenTextures(1, &tex1Id);
1792				gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex1Id);
1793				gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize, fixedSampleLocations1);
1794				GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen texture 1");
1795				gl.glGetTexLevelParameteriv(GL_TEXTURE_2D_MULTISAMPLE, 0, GL_TEXTURE_SAMPLES, &fbSamples);
1796
1797				gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, tex1Id, 0);
1798				GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1799			}
1800			else if (colorAttachmentRbo)
1801			{
1802				gl.glGenRenderbuffers(1, &rboId);
1803				gl.glBindRenderbuffer(GL_RENDERBUFFER, rboId);
1804				gl.glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_numSamples1, m_internalFormat, m_fboSize, m_fboSize);
1805				GLU_EXPECT_NO_ERROR(gl.glGetError(), "gen rb");
1806				gl.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &fbSamples);
1807
1808				gl.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboId);
1809				GLU_EXPECT_NO_ERROR(gl.glGetError(), "attach to c1");
1810			}
1811			else
1812				DE_ASSERT(DE_FALSE);
1813
1814			{
1815				glw::GLenum status = gl.glCheckFramebufferStatus(GL_FRAMEBUFFER);
1816
1817				if ((textureSamples != fbSamples) || (fixedSampleLocations0 != fixedSampleLocations1))
1818				{
1819					if (status != GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) // should not be complete
1820					{
1821						m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
1822						testFailed = true;
1823					}
1824				}
1825				else
1826				{
1827					if (status != GL_FRAMEBUFFER_COMPLETE) // should be complete
1828					{
1829						m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Expected GL_FRAMEBUFFER_COMPLETE, got " << glu::getFramebufferStatusName(status) << tcu::TestLog::EndMessage;
1830						testFailed = true;
1831					}
1832				}
1833			}
1834		}
1835	}
1836	catch (...)
1837	{
1838		gl.glDeleteFramebuffers(1, &fboId);
1839		gl.glDeleteRenderbuffers(1, &rboId);
1840		gl.glDeleteTextures(1, &tex0Id);
1841		gl.glDeleteTextures(1, &tex1Id);
1842		throw;
1843	}
1844
1845	gl.glDeleteFramebuffers(1, &fboId);
1846	gl.glDeleteRenderbuffers(1, &rboId);
1847	gl.glDeleteTextures(1, &tex0Id);
1848	gl.glDeleteTextures(1, &tex1Id);
1849
1850	if (testFailed)
1851		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1852	else
1853		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1854	return STOP;
1855}
1856
1857void NegativeFramebufferCase::getFormatSamples (glw::GLenum target, std::vector<int>& samples)
1858{
1859	const glw::Functions	gl			= m_context.getRenderContext().getFunctions();
1860	int						sampleCount	= 0;
1861
1862	gl.getInternalformativ(target, m_internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
1863	samples.resize(sampleCount);
1864
1865	if (sampleCount > 0)
1866	{
1867		gl.getInternalformativ(target, m_internalFormat, GL_SAMPLES, sampleCount, &samples[0]);
1868		GLU_EXPECT_NO_ERROR(gl.getError(), "get max samples");
1869	}
1870}
1871
1872class NegativeTexParameterCase : public TestCase
1873{
1874public:
1875	enum TexParam
1876	{
1877		TEXTURE_MIN_FILTER = 0,
1878		TEXTURE_MAG_FILTER,
1879		TEXTURE_WRAP_S,
1880		TEXTURE_WRAP_T,
1881		TEXTURE_WRAP_R,
1882		TEXTURE_MIN_LOD,
1883		TEXTURE_MAX_LOD,
1884		TEXTURE_COMPARE_MODE,
1885		TEXTURE_COMPARE_FUNC,
1886		TEXTURE_BASE_LEVEL,
1887
1888		TEXTURE_LAST
1889	};
1890
1891					NegativeTexParameterCase	(Context& context, const char* name, const char* desc, TexParam param);
1892					~NegativeTexParameterCase	(void);
1893
1894private:
1895	void			init						(void);
1896	void			deinit						(void);
1897	IterateResult	iterate						(void);
1898
1899	glw::GLenum		getParamGLEnum				(void) const;
1900	glw::GLint		getParamValue				(void) const;
1901	glw::GLenum		getExpectedError			(void) const;
1902
1903	const TexParam	m_texParam;
1904	int				m_iteration;
1905};
1906
1907NegativeTexParameterCase::NegativeTexParameterCase (Context& context, const char* name, const char* desc, TexParam param)
1908	: TestCase		(context, name, desc)
1909	, m_texParam	(param)
1910	, m_iteration	(0)
1911{
1912	DE_ASSERT(param < TEXTURE_LAST);
1913}
1914
1915NegativeTexParameterCase::~NegativeTexParameterCase	(void)
1916{
1917	deinit();
1918}
1919
1920void NegativeTexParameterCase::init (void)
1921{
1922	// default value
1923	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1924}
1925
1926void NegativeTexParameterCase::deinit (void)
1927{
1928}
1929
1930NegativeTexParameterCase::IterateResult NegativeTexParameterCase::iterate (void)
1931{
1932	static const struct TextureType
1933	{
1934		const char*	name;
1935		glw::GLenum	target;
1936		glw::GLenum	internalFormat;
1937		bool		isArrayType;
1938	} types[] =
1939	{
1940		{ "color",					GL_TEXTURE_2D_MULTISAMPLE,			GL_RGBA8,	false	},
1941		{ "color array",			GL_TEXTURE_2D_MULTISAMPLE_ARRAY,	GL_RGBA8,	true	},
1942		{ "signed integer",			GL_TEXTURE_2D_MULTISAMPLE,			GL_R8I,		false	},
1943		{ "signed integer array",	GL_TEXTURE_2D_MULTISAMPLE_ARRAY,	GL_R8I,		true	},
1944		{ "unsigned integer",		GL_TEXTURE_2D_MULTISAMPLE,			GL_R8UI,	false	},
1945		{ "unsigned integer array",	GL_TEXTURE_2D_MULTISAMPLE_ARRAY,	GL_R8UI,	true	},
1946	};
1947
1948	const tcu::ScopedLogSection scope(m_testCtx.getLog(), "Iteration", std::string() + "Testing parameter with " + types[m_iteration].name + " texture");
1949	const bool supportsES32orGL45 =
1950		glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2)) ||
1951		glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1952
1953	if (types[m_iteration].isArrayType && !supportsES32orGL45 && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
1954		m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping target" << tcu::TestLog::EndMessage;
1955	else
1956	{
1957		glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
1958		glu::Texture			texture	(m_context.getRenderContext());
1959		glw::GLenum				error;
1960
1961		gl.enableLogging(true);
1962
1963		// gen texture
1964
1965		gl.glBindTexture(types[m_iteration].target, *texture);
1966
1967		if (types[m_iteration].isArrayType)
1968			gl.glTexStorage3DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, 16, GL_FALSE);
1969		else
1970			gl.glTexStorage2DMultisample(types[m_iteration].target, 1, types[m_iteration].internalFormat, 16, 16, GL_FALSE);
1971		GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup texture");
1972
1973		// set param
1974
1975		gl.glTexParameteri(types[m_iteration].target, getParamGLEnum(), getParamValue());
1976		error = gl.glGetError();
1977
1978		// expect failure
1979
1980		if (error != getExpectedError())
1981		{
1982			m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(getExpectedError()) << tcu::TestLog::EndMessage;
1983			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
1984		}
1985	}
1986
1987	if (++m_iteration < DE_LENGTH_OF_ARRAY(types))
1988		return CONTINUE;
1989	return STOP;
1990}
1991
1992glw::GLenum NegativeTexParameterCase::getParamGLEnum (void) const
1993{
1994	switch (m_texParam)
1995	{
1996		case TEXTURE_MIN_FILTER:	return GL_TEXTURE_MIN_FILTER;
1997		case TEXTURE_MAG_FILTER:	return GL_TEXTURE_MAG_FILTER;
1998		case TEXTURE_WRAP_S:		return GL_TEXTURE_WRAP_S;
1999		case TEXTURE_WRAP_T:		return GL_TEXTURE_WRAP_T;
2000		case TEXTURE_WRAP_R:		return GL_TEXTURE_WRAP_R;
2001		case TEXTURE_MIN_LOD:		return GL_TEXTURE_MIN_LOD;
2002		case TEXTURE_MAX_LOD:		return GL_TEXTURE_MAX_LOD;
2003		case TEXTURE_COMPARE_MODE:	return GL_TEXTURE_COMPARE_MODE;
2004		case TEXTURE_COMPARE_FUNC:	return GL_TEXTURE_COMPARE_FUNC;
2005		case TEXTURE_BASE_LEVEL:	return GL_TEXTURE_BASE_LEVEL;
2006		default:
2007			DE_ASSERT(DE_FALSE);
2008			return 0;
2009	}
2010}
2011
2012glw::GLint NegativeTexParameterCase::getParamValue (void) const
2013{
2014	switch (m_texParam)
2015	{
2016		case TEXTURE_MIN_FILTER:	return GL_LINEAR;
2017		case TEXTURE_MAG_FILTER:	return GL_LINEAR;
2018		case TEXTURE_WRAP_S:		return GL_CLAMP_TO_EDGE;
2019		case TEXTURE_WRAP_T:		return GL_CLAMP_TO_EDGE;
2020		case TEXTURE_WRAP_R:		return GL_CLAMP_TO_EDGE;
2021		case TEXTURE_MIN_LOD:		return 1;
2022		case TEXTURE_MAX_LOD:		return 5;
2023		case TEXTURE_COMPARE_MODE:	return GL_NONE;
2024		case TEXTURE_COMPARE_FUNC:	return GL_NOTEQUAL;
2025		case TEXTURE_BASE_LEVEL:	return 2;
2026		default:
2027			DE_ASSERT(DE_FALSE);
2028			return 0;
2029	}
2030}
2031
2032glw::GLenum NegativeTexParameterCase::getExpectedError (void) const
2033{
2034	switch (m_texParam)
2035	{
2036		case TEXTURE_MIN_FILTER:	return GL_INVALID_ENUM;
2037		case TEXTURE_MAG_FILTER:	return GL_INVALID_ENUM;
2038		case TEXTURE_WRAP_S:		return GL_INVALID_ENUM;
2039		case TEXTURE_WRAP_T:		return GL_INVALID_ENUM;
2040		case TEXTURE_WRAP_R:		return GL_INVALID_ENUM;
2041		case TEXTURE_MIN_LOD:		return GL_INVALID_ENUM;
2042		case TEXTURE_MAX_LOD:		return GL_INVALID_ENUM;
2043		case TEXTURE_COMPARE_MODE:	return GL_INVALID_ENUM;
2044		case TEXTURE_COMPARE_FUNC:	return GL_INVALID_ENUM;
2045		case TEXTURE_BASE_LEVEL:	return GL_INVALID_OPERATION;
2046		default:
2047			DE_ASSERT(DE_FALSE);
2048			return 0;
2049	}
2050}
2051
2052class NegativeTexureSampleCase : public TestCase
2053{
2054public:
2055	enum SampleCountParam
2056	{
2057		SAMPLECOUNT_HIGH = 0,
2058		SAMPLECOUNT_ZERO,
2059
2060		SAMPLECOUNT_LAST
2061	};
2062
2063							NegativeTexureSampleCase	(Context& context, const char* name, const char* desc, SampleCountParam param);
2064private:
2065	IterateResult			iterate						(void);
2066
2067	const SampleCountParam	m_sampleParam;
2068};
2069
2070NegativeTexureSampleCase::NegativeTexureSampleCase (Context& context, const char* name, const char* desc, SampleCountParam param)
2071	: TestCase		(context, name, desc)
2072	, m_sampleParam	(param)
2073{
2074	DE_ASSERT(param < SAMPLECOUNT_LAST);
2075}
2076
2077NegativeTexureSampleCase::IterateResult NegativeTexureSampleCase::iterate (void)
2078{
2079	const glw::GLenum		expectedError	= (m_sampleParam == SAMPLECOUNT_HIGH) ? (GL_INVALID_OPERATION) : (GL_INVALID_VALUE);
2080	glu::CallLogWrapper		gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
2081	glu::Texture			texture			(m_context.getRenderContext());
2082	glw::GLenum				error;
2083	int						samples			= -1;
2084
2085	gl.enableLogging(true);
2086
2087	// calc samples
2088
2089	if (m_sampleParam == SAMPLECOUNT_HIGH)
2090	{
2091		int maxSamples = 0;
2092
2093		gl.glGetInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, GL_RGBA8, GL_SAMPLES, 1, &maxSamples);
2094		GLU_EXPECT_NO_ERROR(gl.glGetError(), "glGetInternalformativ");
2095
2096		samples = maxSamples + 1;
2097	}
2098	else if (m_sampleParam == SAMPLECOUNT_ZERO)
2099		samples = 0;
2100	else
2101		DE_ASSERT(DE_FALSE);
2102
2103	// create texture with bad values
2104
2105	gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture);
2106	gl.glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, 64, 64, GL_FALSE);
2107	error = gl.glGetError();
2108
2109	// expect failure
2110
2111	if (error == expectedError)
2112		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2113	else
2114	{
2115		m_testCtx.getLog() << tcu::TestLog::Message << "Got unexpected error: " << glu::getErrorStr(error) << ", expected: " << glu::getErrorStr(expectedError) << tcu::TestLog::EndMessage;
2116		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2117	}
2118
2119	return STOP;
2120}
2121
2122
2123} // anonymous
2124
2125TextureMultisampleTests::TextureMultisampleTests (Context& context)
2126	: TestCaseGroup(context, "multisample", "Multisample texture tests")
2127{
2128}
2129
2130TextureMultisampleTests::~TextureMultisampleTests (void)
2131{
2132}
2133
2134void TextureMultisampleTests::init (void)
2135{
2136	static const int sampleCounts[] = { 1, 2, 3, 4, 8, 10, 12, 13, 16, 64 };
2137
2138	static const struct TextureType
2139	{
2140		const char*									name;
2141		MultisampleTextureUsageCase::TextureType	type;
2142	} textureTypes[] =
2143	{
2144		{ "texture_color_2d",		MultisampleTextureUsageCase::TEXTURE_COLOR_2D		},
2145		{ "texture_color_2d_array",	MultisampleTextureUsageCase::TEXTURE_COLOR_2D_ARRAY	},
2146		{ "texture_int_2d",			MultisampleTextureUsageCase::TEXTURE_INT_2D			},
2147		{ "texture_int_2d_array",	MultisampleTextureUsageCase::TEXTURE_INT_2D_ARRAY	},
2148		{ "texture_uint_2d",		MultisampleTextureUsageCase::TEXTURE_UINT_2D		},
2149		{ "texture_uint_2d_array",	MultisampleTextureUsageCase::TEXTURE_UINT_2D_ARRAY	},
2150		{ "texture_depth_2d",		MultisampleTextureUsageCase::TEXTURE_DEPTH_2D		},
2151		{ "texture_depth_2d_array",	MultisampleTextureUsageCase::TEXTURE_DEPTH_2D_ARRAY	},
2152	};
2153
2154	// .samples_x
2155	for (int sampleNdx = 0; sampleNdx < DE_LENGTH_OF_ARRAY(sampleCounts); ++sampleNdx)
2156	{
2157		tcu::TestCaseGroup* const sampleGroup = new tcu::TestCaseGroup(m_testCtx, (std::string("samples_") + de::toString(sampleCounts[sampleNdx])).c_str(), "Test with N samples");
2158		addChild(sampleGroup);
2159
2160		// position query works
2161		sampleGroup->addChild(new SamplePosRasterizationTest(m_context, "sample_position", "test SAMPLE_POSITION", sampleCounts[sampleNdx]));
2162
2163		// sample mask is ANDed properly
2164		sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_only",											"Test with SampleMask only",									sampleCounts[sampleNdx],	SampleMaskCase::FLAGS_NONE));
2165		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));
2166		sampleGroup->addChild(new SampleMaskCase(m_context, "sample_mask_and_sample_coverage",							"Test with SampleMask and sample coverage",						sampleCounts[sampleNdx],	SampleMaskCase::FLAGS_SAMPLE_COVERAGE));
2167		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));
2168
2169		// high bits cause no unexpected behavior
2170		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));
2171
2172		// usage
2173		for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(textureTypes); ++typeNdx)
2174			sampleGroup->addChild(new MultisampleTextureUsageCase(m_context, (std::string("use_") + textureTypes[typeNdx].name).c_str(), textureTypes[typeNdx].name, sampleCounts[sampleNdx], textureTypes[typeNdx].type));
2175	}
2176
2177	// .negative
2178	{
2179		tcu::TestCaseGroup* const negativeGroup = new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests");
2180		addChild(negativeGroup);
2181
2182		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_sample_count_tex_tex",	"Attach different sample counts",	NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_TEX));
2183		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_sample_count_tex_rbo",	"Attach different sample counts",	NegativeFramebufferCase::CASE_DIFFERENT_N_SAMPLES_RBO));
2184		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_fixed_state_tex_tex",		"Attach fixed and non fixed",		NegativeFramebufferCase::CASE_DIFFERENT_FIXED_TEX));
2185		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_different_fixed_state_tex_rbo",		"Attach fixed and non fixed",		NegativeFramebufferCase::CASE_DIFFERENT_FIXED_RBO));
2186		negativeGroup->addChild(new NegativeFramebufferCase	(m_context, "fbo_attach_non_zero_level",					"Attach non-zero level",			NegativeFramebufferCase::CASE_NON_ZERO_LEVEL));
2187		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_filter",							"set TEXTURE_MIN_FILTER",			NegativeTexParameterCase::TEXTURE_MIN_FILTER));
2188		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_mag_filter",							"set TEXTURE_MAG_FILTER",			NegativeTexParameterCase::TEXTURE_MAG_FILTER));
2189		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_s",								"set TEXTURE_WRAP_S",				NegativeTexParameterCase::TEXTURE_WRAP_S));
2190		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_t",								"set TEXTURE_WRAP_T",				NegativeTexParameterCase::TEXTURE_WRAP_T));
2191		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_wrap_r",								"set TEXTURE_WRAP_R",				NegativeTexParameterCase::TEXTURE_WRAP_R));
2192		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_min_lod",								"set TEXTURE_MIN_LOD",				NegativeTexParameterCase::TEXTURE_MIN_LOD));
2193		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_max_lod",								"set TEXTURE_MAX_LOD",				NegativeTexParameterCase::TEXTURE_MAX_LOD));
2194		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_mode",							"set TEXTURE_COMPARE_MODE",			NegativeTexParameterCase::TEXTURE_COMPARE_MODE));
2195		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_compare_func",							"set TEXTURE_COMPARE_FUNC",			NegativeTexParameterCase::TEXTURE_COMPARE_FUNC));
2196		negativeGroup->addChild(new NegativeTexParameterCase(m_context, "texture_base_level",							"set TEXTURE_BASE_LEVEL",			NegativeTexParameterCase::TEXTURE_BASE_LEVEL));
2197		negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_high_sample_count",					"TexStorage with high numSamples",	NegativeTexureSampleCase::SAMPLECOUNT_HIGH));
2198		negativeGroup->addChild(new NegativeTexureSampleCase(m_context, "texture_zero_sample_count",					"TexStorage with zero numSamples",	NegativeTexureSampleCase::SAMPLECOUNT_ZERO));
2199	}
2200}
2201
2202} // Functional
2203} // gles31
2204} // deqp
2205