• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Multisample texture test
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fTextureMultisampleTests.hpp"
25 #include "tcuTestLog.hpp"
26 #include "tcuRenderTarget.hpp"
27 #include "tcuSurface.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "glsStateQueryUtil.hpp"
31 #include "tcuRasterizationVerifier.hpp"
32 #include "gluRenderContext.hpp"
33 #include "gluCallLogWrapper.hpp"
34 #include "gluObjectWrapper.hpp"
35 #include "gluShaderProgram.hpp"
36 #include "gluPixelTransfer.hpp"
37 #include "gluStrUtil.hpp"
38 #include "gluContextInfo.hpp"
39 #include "glwEnums.hpp"
40 #include "glwFunctions.hpp"
41 #include "deStringUtil.hpp"
42 #include "deRandom.hpp"
43 
44 using namespace glw;
45 
46 namespace deqp
47 {
48 namespace gles31
49 {
50 namespace Functional
51 {
52 namespace
53 {
54 
55 using tcu::RasterizationArguments;
56 using tcu::TriangleSceneSpec;
57 
sampleMaskToString(const std::vector<deUint32> & bitfield,int numBits)58 static std::string sampleMaskToString (const std::vector<deUint32>& bitfield, int numBits)
59 {
60 	std::string result(numBits, '0');
61 
62 	// move from back to front and set chars to 1
63 	for (int wordNdx = 0; wordNdx < (int)bitfield.size(); ++wordNdx)
64 	{
65 		for (int bit = 0; bit < 32; ++bit)
66 		{
67 			const int targetCharNdx = numBits - (wordNdx*32+bit) - 1;
68 
69 			// beginning of the string reached
70 			if (targetCharNdx < 0)
71 				return result;
72 
73 			if ((bitfield[wordNdx] >> bit) & 0x01)
74 				result[targetCharNdx] = '1';
75 		}
76 	}
77 
78 	return result;
79 }
80 
81 /*--------------------------------------------------------------------*//*!
82  * \brief Returns the number of words needed to represent mask of given length
83  *//*--------------------------------------------------------------------*/
getEffectiveSampleMaskWordCount(int highestBitNdx)84 static int getEffectiveSampleMaskWordCount (int highestBitNdx)
85 {
86 	const int wordSize	= 32;
87 	const int maskLen	= highestBitNdx + 1;
88 
89 	return ((maskLen - 1) / wordSize) + 1; // round_up(mask_len /  wordSize)
90 }
91 
92 /*--------------------------------------------------------------------*//*!
93  * \brief Creates sample mask with all less significant bits than nthBit set
94  *//*--------------------------------------------------------------------*/
genAllSetToNthBitSampleMask(int nthBit)95 static std::vector<deUint32> genAllSetToNthBitSampleMask (int nthBit)
96 {
97 	const int				wordSize	= 32;
98 	const int				numWords	= getEffectiveSampleMaskWordCount(nthBit - 1);
99 	const deUint32			topWordBits	= (deUint32)(nthBit - (numWords - 1) * wordSize);
100 	std::vector<deUint32>	mask		(numWords);
101 
102 	for (int ndx = 0; ndx < numWords - 1; ++ndx)
103 		mask[ndx] = 0xFFFFFFFF;
104 
105 	mask[numWords - 1] = (deUint32)((1ULL << topWordBits) - (deUint32)1);
106 	return mask;
107 }
108 
109 /*--------------------------------------------------------------------*//*!
110  * \brief Creates sample mask with nthBit set
111  *//*--------------------------------------------------------------------*/
genSetNthBitSampleMask(int nthBit)112 static std::vector<deUint32> genSetNthBitSampleMask (int nthBit)
113 {
114 	const int				wordSize	= 32;
115 	const int				numWords	= getEffectiveSampleMaskWordCount(nthBit);
116 	const deUint32			topWordBits	= (deUint32)(nthBit - (numWords - 1) * wordSize);
117 	std::vector<deUint32>	mask		(numWords);
118 
119 	for (int ndx = 0; ndx < numWords - 1; ++ndx)
120 		mask[ndx] = 0;
121 
122 	mask[numWords - 1] = (deUint32)(1ULL << topWordBits);
123 	return mask;
124 }
125 
126 class SamplePosRasterizationTest : public TestCase
127 {
128 public:
129 								SamplePosRasterizationTest	(Context& context, const char* name, const char* desc, int samples);
130 								~SamplePosRasterizationTest	(void);
131 
132 private:
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 
SamplePosRasterizationTest(Context & context,const char * name,const char * desc,int samples)168 SamplePosRasterizationTest::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 
~SamplePosRasterizationTest(void)185 SamplePosRasterizationTest::~SamplePosRasterizationTest (void)
186 {
187 	deinit();
188 }
189 
init(void)190 void 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 
deinit(void)284 void 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 
iterate(void)311 SamplePosRasterizationTest::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 
genMultisampleTexture(void)328 void 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 
genSamplerProgram(void)410 void 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 
testMultisampleTexture(int sampleNdx)440 bool 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 
drawSample(tcu::Surface & dst,int sampleNdx)464 void 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 
convertToSceneSpec(TriangleSceneSpec & scene,const tcu::Vec2 & samplePos) const511 void 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 
532 class SampleMaskCase : public TestCase
533 {
534 public:
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 
546 private:
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 
SampleMaskCase(Context & context,const char * name,const char * desc,int samples,int flags)580 SampleMaskCase::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 
~SampleMaskCase(void)602 SampleMaskCase::~SampleMaskCase (void)
603 {
604 	deinit();
605 }
606 
init(void)607 void 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 
deinit(void)688 void 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 
iterate(void)723 SampleMaskCase::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 
genSamplerProgram(void)755 void 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 
genAlphaProgram(void)800 void 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 
updateTexture(int sample)830 void 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 
verifyTexture(int sample)932 bool 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 
drawSample(tcu::Surface & dst,int sample)985 void 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 
1032 class MultisampleTextureUsageCase : public TestCase
1033 {
1034 public:
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 
1053 private:
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 
MultisampleTextureUsageCase(Context & ctx,const char * name,const char * desc,int samples,TextureType type)1085 MultisampleTextureUsageCase::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 
~MultisampleTextureUsageCase(void)1102 MultisampleTextureUsageCase::~MultisampleTextureUsageCase (void)
1103 {
1104 	deinit();
1105 }
1106 
init(void)1107 void 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 
deinit(void)1188 void 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 
iterate(void)1215 MultisampleTextureUsageCase::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 
genDrawShader(void)1243 void 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 
genSamplerShader(void)1288 void 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 
renderToTexture(float value)1358 void 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 
sampleTexture(tcu::Surface & dst,float value)1439 void 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 
verifyImage(const tcu::Surface & dst)1500 bool 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 
1536 class NegativeFramebufferCase : public TestCase
1537 {
1538 public:
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 
1553 private:
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 
NegativeFramebufferCase(Context & context,const char * name,const char * desc,CaseType caseType)1568 NegativeFramebufferCase::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 
~NegativeFramebufferCase(void)1578 NegativeFramebufferCase::~NegativeFramebufferCase (void)
1579 {
1580 	deinit();
1581 }
1582 
init(void)1583 void 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 
deinit(void)1657 void NegativeFramebufferCase::deinit (void)
1658 {
1659 }
1660 
iterate(void)1661 NegativeFramebufferCase::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 
getFormatSamples(glw::GLenum target,std::vector<int> & samples)1763 void 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 
1778 class NegativeTexParameterCase : public TestCase
1779 {
1780 public:
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 
1800 private:
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 
NegativeTexParameterCase(Context & context,const char * name,const char * desc,TexParam param)1813 NegativeTexParameterCase::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 
~NegativeTexParameterCase(void)1821 NegativeTexParameterCase::~NegativeTexParameterCase	(void)
1822 {
1823 	deinit();
1824 }
1825 
init(void)1826 void NegativeTexParameterCase::init (void)
1827 {
1828 	// default value
1829 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1830 }
1831 
deinit(void)1832 void NegativeTexParameterCase::deinit (void)
1833 {
1834 }
1835 
iterate(void)1836 NegativeTexParameterCase::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 
getParamGLEnum(void) const1895 glw::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 
getParamValue(void) const1915 glw::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 
getExpectedError(void) const1935 glw::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 
1955 class NegativeTexureSampleCase : public TestCase
1956 {
1957 public:
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);
1967 private:
1968 	IterateResult			iterate						(void);
1969 
1970 	const SampleCountParam	m_sampleParam;
1971 };
1972 
NegativeTexureSampleCase(Context & context,const char * name,const char * desc,SampleCountParam param)1973 NegativeTexureSampleCase::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 
iterate(void)1980 NegativeTexureSampleCase::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 
TextureMultisampleTests(Context & context)2028 TextureMultisampleTests::TextureMultisampleTests (Context& context)
2029 	: TestCaseGroup(context, "multisample", "Multisample texture tests")
2030 {
2031 }
2032 
~TextureMultisampleTests(void)2033 TextureMultisampleTests::~TextureMultisampleTests (void)
2034 {
2035 }
2036 
init(void)2037 void 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