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