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