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