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