1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2016 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 
24 #include "glcSampleVariablesTests.hpp"
25 #include "deMath.h"
26 #include "deRandom.hpp"
27 #include "deStringUtil.hpp"
28 #include "gluContextInfo.hpp"
29 #include "gluDrawUtil.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "glw.h"
33 #include "glwFunctions.hpp"
34 #include "tcuCommandLine.hpp"
35 #include "tcuStringTemplate.hpp"
36 #include "tcuSurface.hpp"
37 #include "tcuTestLog.hpp"
38 
39 namespace tcu
40 {
operator <(tcu::Vec4 const& k1, tcu::Vec4 const& k2)41 static bool operator<(tcu::Vec4 const& k1, tcu::Vec4 const& k2)
42 {
43 	if (k1.y() < k2.y())
44 	{
45 		return true;
46 	}
47 	else if (k1.y() == k2.y())
48 	{
49 		return k1.x() < k2.x();
50 	}
51 	else
52 	{
53 		return false;
54 	}
55 }
56 }
57 
58 namespace deqp
59 {
60 
61 using tcu::TestLog;
62 using std::string;
63 using std::vector;
64 
specializeVersion(std::string const& source, glu::GLSLVersion version, std::string const& sampler = �, std::string const& outType = �)65 static std::string specializeVersion(std::string const& source, glu::GLSLVersion version,
66 									 std::string const& sampler = "", std::string const& outType = "")
67 {
68 	DE_ASSERT(version == glu::GLSL_VERSION_310_ES || version >= glu::GLSL_VERSION_400);
69 	std::map<std::string, std::string> args;
70 	args["VERSION_DECL"] = glu::getGLSLVersionDeclaration(version);
71 	args["SAMPLER"]		 = sampler;
72 	args["OUT_TYPE"]	 = outType;
73 	if (version == glu::GLSL_VERSION_310_ES)
74 	{
75 		args["OES_SV_RQ"] = "#extension GL_OES_sample_variables : require\n";
76 		args["OES_SV_EN"] = "#extension GL_OES_sample_variables : enable\n";
77 	}
78 	else
79 	{
80 		args["OES_SV_RQ"] = "";
81 		args["OES_SV_EN"] = "";
82 	}
83 	return tcu::StringTemplate(source.c_str()).specialize(args);
84 }
85 
86 class SampleShadingExtensionCase : public TestCase
87 {
88 public:
89 	SampleShadingExtensionCase(Context& context, const char* name, const char* description,
90 							   glu::GLSLVersion glslVersion);
91 	~SampleShadingExtensionCase();
92 
93 	IterateResult iterate();
94 
95 protected:
96 	glu::GLSLVersion m_glslVersion;
97 };
98 
SampleShadingExtensionCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion)99 SampleShadingExtensionCase::SampleShadingExtensionCase(Context& context, const char* name, const char* description,
100 													   glu::GLSLVersion glslVersion)
101 	: TestCase(context, name, description), m_glslVersion(glslVersion)
102 {
103 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES);
104 }
105 
~SampleShadingExtensionCase()106 SampleShadingExtensionCase::~SampleShadingExtensionCase()
107 {
108 }
109 
iterate()110 SampleShadingExtensionCase::IterateResult SampleShadingExtensionCase::iterate()
111 {
112 	TestLog& log = m_testCtx.getLog();
113 
114 	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
115 	{
116 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables");
117 		return STOP;
118 	}
119 
120 	static char const* vss = "${VERSION_DECL}\n"
121 							 "in highp vec4 a_position;\n"
122 							 "void main()\n"
123 							 "{\n"
124 							 "    gl_Position = a_position;\n"
125 							 "}\n";
126 
127 	{
128 		static char const* fss = "${VERSION_DECL}\n"
129 								 "${OES_SV_RQ}"
130 								 "out highp vec4 o_color;\n"
131 								 "void main()\n"
132 								 "{\n"
133 								 "    for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n"
134 								 "        gl_SampleMask[i] = gl_SampleMaskIn[i];\n"
135 								 "    }\n"
136 								 "    o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n"
137 								 "}\n";
138 
139 		glu::ShaderProgram programRequire(m_context.getRenderContext(),
140 										  glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
141 																  specializeVersion(fss, m_glslVersion).c_str()));
142 		log << programRequire;
143 		if (!programRequire.isOk())
144 		{
145 			TCU_FAIL("Compile failed");
146 		}
147 	}
148 
149 	{
150 		static char const* fss = "${VERSION_DECL}\n"
151 								 "${OES_SV_EN}"
152 								 "out highp vec4 o_color;\n"
153 								 "void main()\n"
154 								 "{\n"
155 								 "#if !GL_OES_sample_variables\n"
156 								 "    this is broken\n"
157 								 "#endif\n"
158 								 "    for (int i = 0; i < (gl_MaxSamples + 31) / 32; ++i) {\n"
159 								 "        gl_SampleMask[i] = gl_SampleMaskIn[i];\n"
160 								 "    }\n"
161 								 "    o_color = vec4(gl_SampleID, gl_SamplePosition.x, gl_SamplePosition.y, 1);\n"
162 								 "}\n";
163 
164 		glu::ShaderProgram programEnable(m_context.getRenderContext(),
165 										 glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
166 																 specializeVersion(fss, m_glslVersion).c_str()));
167 		log << programEnable;
168 		if (!programEnable.isOk())
169 		{
170 			TCU_FAIL("Compile failed");
171 		}
172 	}
173 
174 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
175 	return STOP;
176 }
177 
178 class SampleShadingMaskCase : public TestCase
179 {
180 public:
181 	SampleShadingMaskCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
182 						  GLenum internalFormat, tcu::TextureFormat const& texFormat, const char* sampler,
183 						  const char* outType, GLint samples, GLint sampleMask);
184 	~SampleShadingMaskCase();
185 
186 	IterateResult iterate();
187 
188 protected:
189 	glu::GLSLVersion   m_glslVersion;
190 	GLenum			   m_internalFormat;
191 	tcu::TextureFormat m_texFormat;
192 	std::string		   m_sampler;
193 	std::string		   m_outType;
194 	GLint			   m_samples;
195 	GLint			   m_sampleMask;
196 
197 	enum
198 	{
199 		WIDTH		= 16,
200 		HEIGHT		= 16,
201 		MAX_SAMPLES = 4,
202 	};
203 };
204 
SampleShadingMaskCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, GLenum internalFormat, tcu::TextureFormat const& texFormat, const char* sampler, const char* outType, GLint samples, GLint sampleMask)205 SampleShadingMaskCase::SampleShadingMaskCase(Context& context, const char* name, const char* description,
206 											 glu::GLSLVersion glslVersion, GLenum internalFormat,
207 											 tcu::TextureFormat const& texFormat, const char* sampler,
208 											 const char* outType, GLint samples, GLint sampleMask)
209 	: TestCase(context, name, description)
210 	, m_glslVersion(glslVersion)
211 	, m_internalFormat(internalFormat)
212 	, m_texFormat(texFormat)
213 	, m_sampler(sampler)
214 	, m_outType(outType)
215 	, m_samples(samples)
216 	, m_sampleMask(sampleMask)
217 {
218 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400);
219 }
220 
~SampleShadingMaskCase()221 SampleShadingMaskCase::~SampleShadingMaskCase()
222 {
223 }
224 
iterate()225 SampleShadingMaskCase::IterateResult SampleShadingMaskCase::iterate()
226 {
227 	TestLog&			  log			  = m_testCtx.getLog();
228 	const glw::Functions& gl			  = m_context.getRenderContext().getFunctions();
229 	bool				  isOk			  = true;
230 	bool				  supportsRgba32f = false;
231 
232 	if (m_glslVersion == glu::GLSL_VERSION_310_ES &&
233 		!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
234 	{
235 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables");
236 		return STOP;
237 	}
238 
239 	supportsRgba32f = isContextTypeGLCore(m_context.getRenderContext().getType()) ?
240 						  true :
241 						  (m_context.getContextInfo().isExtensionSupported("GL_EXT_color_buffer_float") ||
242 						   m_context.getContextInfo().isExtensionSupported("GL_ARB_color_buffer_float"));
243 
244 	if (m_internalFormat == GL_RGBA32F && !supportsRgba32f)
245 	{
246 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Internalformat rgba32f not supported");
247 		return STOP;
248 	}
249 
250 	GLint maxSamples;
251 	if (((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)) ||
252 		((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::RG)) ||
253 		((m_texFormat.type == tcu::TextureFormat::FLOAT) && (m_texFormat.order == tcu::TextureFormat::R)) ||
254 		((m_texFormat.type == tcu::TextureFormat::HALF_FLOAT) && (m_texFormat.order == tcu::TextureFormat::RGBA)))
255 	{
256 		gl.getInternalformativ(GL_TEXTURE_2D_MULTISAMPLE, m_internalFormat, GL_SAMPLES, 1, &maxSamples);
257 		if (m_samples > maxSamples)
258 		{
259 			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED,
260 									"Test sample count greater than samples that the format supports");
261 			return STOP;
262 		}
263 	}
264 	else if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
265 			 m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8)
266 	{
267 		gl.getIntegerv(GL_MAX_INTEGER_SAMPLES, &maxSamples);
268 		if (m_samples > maxSamples)
269 		{
270 			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_INTEGER_SAMPLES");
271 			return STOP;
272 		}
273 	}
274 	else
275 	{
276 		gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
277 		if (m_samples > maxSamples)
278 		{
279 			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count greater than MAX_SAMPLES");
280 			return STOP;
281 		}
282 	}
283 
284 	// Create a multisample texture, or a regular texture if samples is zero.
285 	GLuint tex;
286 	gl.genTextures(1, &tex);
287 	GLenum target;
288 	if (m_samples)
289 	{
290 		target = GL_TEXTURE_2D_MULTISAMPLE;
291 		gl.bindTexture(target, tex);
292 		gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, m_internalFormat, WIDTH, HEIGHT, GL_FALSE);
293 	}
294 	else
295 	{
296 		target = GL_TEXTURE_2D;
297 		gl.bindTexture(target, tex);
298 		gl.texStorage2D(GL_TEXTURE_2D, 1, m_internalFormat, WIDTH, HEIGHT);
299 		if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8 ||
300 			m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8 || m_texFormat.type == tcu::TextureFormat::FLOAT)
301 		{
302 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
303 			gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
304 		}
305 	}
306 
307 	// Create a framebuffer with the texture attached and clear to "green".
308 	GLuint fboMs;
309 	gl.genFramebuffers(1, &fboMs);
310 	gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs);
311 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex, 0);
312 	gl.viewport(0, 0, WIDTH, HEIGHT);
313 	if (m_texFormat.type == tcu::TextureFormat::SIGNED_INT8)
314 	{
315 		GLint color[4] = { 0, 1, 0, 1 };
316 		gl.clearBufferiv(GL_COLOR, 0, color);
317 	}
318 	else if (m_texFormat.type == tcu::TextureFormat::UNSIGNED_INT8)
319 	{
320 		GLuint color[4] = { 0, 1, 0, 1 };
321 		gl.clearBufferuiv(GL_COLOR, 0, color);
322 	}
323 	else
324 	{
325 		GLfloat color[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
326 		gl.clearBufferfv(GL_COLOR, 0, color);
327 	}
328 
329 	static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
330 
331 	{
332 		// Draw a quad setting all samples to "red". We only expect "red"
333 		// to be written if the sample mask bit for that sample is 1.
334 
335 		static char const* vss = "${VERSION_DECL}\n"
336 								 "in highp vec2 a_position;\n"
337 								 "void main()\n"
338 								 "{\n"
339 								 "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
340 								 "}\n";
341 
342 		static char const* fss = "${VERSION_DECL}\n"
343 								 "${OES_SV_RQ}"
344 								 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
345 								 "uniform int u_sampleMask;\n"
346 								 "void main()\n"
347 								 "{\n"
348 								 "    for (int i = 0; i < (gl_NumSamples + 31) / 32; ++i) {\n"
349 								 "        gl_SampleMask[i] = u_sampleMask & gl_SampleMaskIn[i];\n"
350 								 "    }\n"
351 								 "    o_color = ${OUT_TYPE}(1, 0, 0, 1);\n"
352 								 "}\n";
353 
354 		glu::ShaderProgram program(
355 			m_context.getRenderContext(),
356 			glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(),
357 									specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str()));
358 		log << program;
359 		if (!program.isOk())
360 		{
361 			TCU_FAIL("Compile failed");
362 		}
363 
364 		static float const position[] = {
365 			-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
366 		};
367 
368 		gl.useProgram(program.getProgram());
369 		gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_sampleMask"), m_sampleMask);
370 
371 		glu::VertexArrayBinding vertexArrays[] = {
372 			glu::va::Float("a_position", 2, 4, 0, &position[0]),
373 		};
374 		glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
375 				  &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
376 
377 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
378 	}
379 
380 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
381 	gl.deleteFramebuffers(1, &fboMs);
382 
383 	GLsizei width = WIDTH * ((m_samples) ? m_samples : 1);
384 
385 	GLuint rbo;
386 	gl.genRenderbuffers(1, &rbo);
387 	gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
388 	gl.renderbufferStorage(GL_RENDERBUFFER, m_internalFormat, width, HEIGHT);
389 
390 	GLuint fbo;
391 	gl.genFramebuffers(1, &fbo);
392 	gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
393 	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
394 	gl.viewport(0, 0, width, HEIGHT);
395 
396 	{
397 		// Resolve the multi-sample texture into a render-buffer sized such that
398 		// the width can hold all samples of a pixel.
399 		static char const* vss = "${VERSION_DECL}\n"
400 								 "in highp vec2 a_position;\n"
401 								 "void main(void)\n"
402 								 "{\n"
403 								 "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
404 								 "}\n";
405 
406 		static char const* fss = "${VERSION_DECL}\n"
407 								 "uniform highp ${SAMPLER} u_tex;\n"
408 								 "uniform highp ${SAMPLER}MS u_texMS;\n"
409 								 "uniform int u_samples;\n"
410 								 "layout(location = 0) out highp ${OUT_TYPE} o_color;\n"
411 								 "void main(void)\n"
412 								 "{\n"
413 								 "    if (u_samples > 0) {\n"
414 								 "        ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n"
415 								 "        int sampleId = int(gl_FragCoord.x) % u_samples;\n"
416 								 "        o_color = texelFetch(u_texMS, coord, sampleId);\n"
417 								 "    } else {\n"
418 								 "        ivec2 coord = ivec2(gl_FragCoord.x, gl_FragCoord.y);\n"
419 								 "       o_color = texelFetch(u_tex, coord, 0);\n"
420 								 "    }\n"
421 								 "}\n";
422 
423 		glu::ShaderProgram program(
424 			m_context.getRenderContext(),
425 			glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion, m_sampler, m_outType).c_str(),
426 									specializeVersion(fss, m_glslVersion, m_sampler, m_outType).c_str()));
427 		log << program;
428 		if (!program.isOk())
429 		{
430 			TCU_FAIL("Compile failed");
431 		}
432 
433 		static float const position[] = {
434 			-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
435 		};
436 
437 		gl.useProgram(program.getProgram());
438 		gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples);
439 		if (m_samples > 0)
440 		{
441 			// only MS sampler needed, TU 1 is not used
442 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 1);
443 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0);
444 		}
445 		else
446 		{
447 			// only non-MS sampler needed, TU 1 is not used
448 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 0);
449 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 1);
450 		}
451 
452 		glu::VertexArrayBinding vertexArrays[] = {
453 			glu::va::Float("a_position", 2, 4, 0, &position[0]),
454 		};
455 		glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
456 				  &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
457 
458 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
459 	}
460 
461 	tcu::TextureLevel	  results(m_texFormat, width, HEIGHT);
462 	tcu::PixelBufferAccess pixels = results.getAccess();
463 	std::vector<tcu::Vec4> result(pixels.getHeight() * pixels.getWidth());
464 
465 	if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8)
466 	{
467 		std::vector<GLint> data(pixels.getHeight() * pixels.getWidth() * 4);
468 		gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_INT, &data[0]);
469 		for (unsigned int i = 0; i < data.size(); i += 4)
470 		{
471 			result[i / 4] =
472 				tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
473 		}
474 	}
475 	else if (pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
476 	{
477 		std::vector<GLuint> data(pixels.getHeight() * pixels.getWidth() * 4);
478 		gl.readPixels(0, 0, pixels.getWidth(), pixels.getHeight(), GL_RGBA_INTEGER, GL_UNSIGNED_INT, &data[0]);
479 		for (unsigned int i = 0; i < data.size(); i += 4)
480 		{
481 			result[i / 4] =
482 				tcu::Vec4((GLfloat)data[i], (GLfloat)data[i + 1], (GLfloat)data[i + 2], (GLfloat)data[i + 3]);
483 		}
484 	}
485 	else
486 	{
487 		glu::readPixels(m_context.getRenderContext(), 0, 0, pixels);
488 	}
489 
490 	for (int y = 0; y < HEIGHT; ++y)
491 	{
492 		for (int x = 0; x < WIDTH; ++x)
493 		{
494 			GLint samples = (m_samples) ? m_samples : 1;
495 			for (int sample = 0; sample < samples; ++sample)
496 			{
497 				tcu::Vec4 pixel;
498 				if (pixels.getFormat().type == tcu::TextureFormat::SIGNED_INT8 ||
499 					pixels.getFormat().type == tcu::TextureFormat::UNSIGNED_INT8)
500 				{
501 					pixel = result[y * WIDTH + x * samples + sample];
502 				}
503 				else
504 				{
505 					pixel = pixels.getPixel(x * samples + sample, y);
506 				}
507 
508 				// Make sure only those samples where the sample mask bit is
509 				// non-zero have the "red" pixel values.
510 				if (!m_samples || (m_sampleMask & (1 << sample)))
511 				{
512 					if (pixel != tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f))
513 					{
514 						isOk = false;
515 					}
516 				}
517 				else
518 				{
519 					if (pixel != tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f))
520 					{
521 						isOk = false;
522 					}
523 				}
524 			}
525 		}
526 	}
527 
528 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
529 	gl.deleteFramebuffers(1, &fbo);
530 
531 	gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
532 	gl.deleteRenderbuffers(1, &rbo);
533 
534 	gl.bindTexture(target, 0);
535 	gl.deleteTextures(1, &tex);
536 
537 	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
538 	return STOP;
539 }
540 
541 class SampleShadingPositionCase : public TestCase
542 {
543 public:
544 	SampleShadingPositionCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion,
545 							  GLint samples, GLboolean fixedSampleLocations);
546 	~SampleShadingPositionCase();
547 
548 	IterateResult iterate();
549 
550 protected:
551 	glu::GLSLVersion m_glslVersion;
552 	GLint			 m_samples;
553 	GLboolean		 m_fixedSampleLocations;
554 
555 	enum
556 	{
557 		WIDTH		= 8,
558 		HEIGHT		= 8,
559 		MAX_SAMPLES = 8,
560 	};
561 };
562 
SampleShadingPositionCase(Context& context, const char* name, const char* description, glu::GLSLVersion glslVersion, GLint samples, GLboolean fixedSampleLocations)563 SampleShadingPositionCase::SampleShadingPositionCase(Context& context, const char* name, const char* description,
564 													 glu::GLSLVersion glslVersion, GLint samples,
565 													 GLboolean fixedSampleLocations)
566 	: TestCase(context, name, description)
567 	, m_glslVersion(glslVersion)
568 	, m_samples(samples)
569 	, m_fixedSampleLocations(fixedSampleLocations)
570 {
571 	DE_ASSERT(glslVersion == glu::GLSL_VERSION_310_ES || glslVersion >= glu::GLSL_VERSION_400);
572 }
573 
~SampleShadingPositionCase()574 SampleShadingPositionCase::~SampleShadingPositionCase()
575 {
576 }
577 
iterate()578 SampleShadingPositionCase::IterateResult SampleShadingPositionCase::iterate()
579 {
580 	TestLog&			  log  = m_testCtx.getLog();
581 	const glw::Functions& gl   = m_context.getRenderContext().getFunctions();
582 	bool				  isOk = true;
583 
584 	if (m_glslVersion == glu::GLSL_VERSION_310_ES &&
585 		!m_context.getContextInfo().isExtensionSupported("GL_OES_sample_variables"))
586 	{
587 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "GL_OES_sample_variables");
588 		return STOP;
589 	}
590 
591 	GLint maxSamples;
592 	gl.getIntegerv(GL_MAX_SAMPLES, &maxSamples);
593 	if (m_samples > maxSamples)
594 	{
595 		m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Test sample count great than MAX_SAMPLES");
596 		return STOP;
597 	}
598 
599 	// Create a multisample texture, or a regular texture if samples is zero.
600 	GLuint tex;
601 	gl.genTextures(1, &tex);
602 	GLenum target;
603 	if (m_samples)
604 	{
605 		target = GL_TEXTURE_2D_MULTISAMPLE;
606 		gl.bindTexture(target, tex);
607 		gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_samples, GL_RGBA8, WIDTH, HEIGHT,
608 								   m_fixedSampleLocations);
609 	}
610 	else
611 	{
612 		target = GL_TEXTURE_2D;
613 		gl.bindTexture(target, tex);
614 		gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, WIDTH, HEIGHT);
615 	}
616 
617 	// Attach the texture to the framebuffer to render to it.
618 	GLuint fboMs;
619 	gl.genFramebuffers(1, &fboMs);
620 	gl.bindFramebuffer(GL_FRAMEBUFFER, fboMs);
621 	gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tex, 0);
622 	gl.viewport(0, 0, WIDTH, HEIGHT);
623 
624 	// Save all the sample positions for this multisample framebuffer.
625 	std::vector<tcu::Vec4> samplePositions;
626 	if (m_samples)
627 	{
628 		samplePositions.resize(m_samples);
629 		for (int sample = 0; sample < m_samples; ++sample)
630 		{
631 			GLfloat position[2];
632 			gl.getMultisamplefv(GL_SAMPLE_POSITION, sample, position);
633 			samplePositions[sample] = tcu::Vec4(position[0], position[1], 0.0f, 1.0f);
634 		}
635 	}
636 
637 	static deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
638 
639 	{
640 		// Render all the sample positions to each pixel sample.
641 
642 		static char const* vss = "${VERSION_DECL}\n"
643 								 "in highp vec2 a_position;\n"
644 								 "void main()\n"
645 								 "{\n"
646 								 "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
647 								 "}\n";
648 
649 		static char const* fss = "${VERSION_DECL}\n"
650 								 "${OES_SV_RQ}"
651 								 "layout(location = 0) out highp vec4 o_color;\n"
652 								 "void main()\n"
653 								 "{\n"
654 								 "    o_color = vec4(gl_SamplePosition, 0, 1);\n"
655 								 "}\n";
656 
657 		glu::ShaderProgram program(m_context.getRenderContext(),
658 								   glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
659 														   specializeVersion(fss, m_glslVersion).c_str()));
660 		log << program;
661 		if (!program.isOk())
662 		{
663 			TCU_FAIL("Compile failed");
664 		}
665 
666 		const float position[] = {
667 			-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
668 		};
669 
670 		gl.useProgram(program.getProgram());
671 
672 		glu::VertexArrayBinding vertexArrays[] = {
673 			glu::va::Float("a_position", 2, 4, 0, &position[0]),
674 		};
675 
676 		glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
677 				  &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
678 
679 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
680 	}
681 
682 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
683 	gl.deleteFramebuffers(1, &fboMs);
684 
685 	// Create a regular non-multisample render buffer to resolve to multisample texture into.
686 	// The width is increased to save all samples of the pixel.
687 
688 	GLsizei width = WIDTH * ((m_samples) ? m_samples : 1);
689 
690 	GLuint rbo;
691 	gl.genRenderbuffers(1, &rbo);
692 	gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
693 	gl.renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, HEIGHT);
694 
695 	GLuint fbo;
696 	gl.genFramebuffers(1, &fbo);
697 	gl.bindFramebuffer(GL_FRAMEBUFFER, fbo);
698 	gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
699 	gl.viewport(0, 0, width, HEIGHT);
700 
701 	{
702 		// Resolve the multisample texture to the renderbuffer.
703 
704 		static char const* vss = "${VERSION_DECL}\n"
705 								 "in highp vec2 a_position;\n"
706 								 "void main(void)\n"
707 								 "{\n"
708 								 "   gl_Position = vec4(a_position, 0.0, 1.0);\n"
709 								 "}\n";
710 
711 		static char const* fss = "${VERSION_DECL}\n"
712 								 "uniform highp sampler2D u_tex;\n"
713 								 "uniform highp sampler2DMS u_texMS;\n"
714 								 "uniform int u_samples;\n"
715 								 "layout(location = 0) out highp vec4 o_color;\n"
716 								 "void main(void)\n"
717 								 "{\n"
718 								 "    if (u_samples > 0) {\n"
719 								 "        ivec2 coord = ivec2(int(gl_FragCoord.x) / u_samples, gl_FragCoord.y);\n"
720 								 "        int sampleId = int(gl_FragCoord.x) % u_samples;\n"
721 								 "        o_color = texelFetch(u_texMS, coord, sampleId);\n"
722 								 "    } else {\n"
723 								 "        ivec2 coord = ivec2(gl_FragCoord.x, gl_FragCoord.y);\n"
724 								 "        o_color = texelFetch(u_tex, coord, 0);\n"
725 								 "    }\n"
726 								 "}\n";
727 
728 		glu::ShaderProgram program(m_context.getRenderContext(),
729 								   glu::makeVtxFragSources(specializeVersion(vss, m_glslVersion).c_str(),
730 														   specializeVersion(fss, m_glslVersion).c_str()));
731 		log << program;
732 		if (!program.isOk())
733 		{
734 			TCU_FAIL("Compile failed");
735 		}
736 
737 		static float const position[] = {
738 			-1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f,
739 		};
740 
741 		gl.useProgram(program.getProgram());
742 		gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_samples"), m_samples);
743 		if (m_samples > 0)
744 		{
745 			// only MS sampler needed, TU 1 is not used
746 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 1);
747 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 0);
748 		}
749 		else
750 		{
751 			// only non-MS sampler needed, TU 1 is not used
752 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_tex"), 0);
753 			gl.uniform1i(gl.getUniformLocation(program.getProgram(), "u_texMS"), 1);
754 		}
755 
756 		glu::VertexArrayBinding vertexArrays[] = {
757 			glu::va::Float("a_position", 2, 4, 0, &position[0]),
758 		};
759 		glu::draw(m_context.getRenderContext(), program.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
760 				  &vertexArrays[0], glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), &quadIndices[0]));
761 
762 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw quad");
763 	}
764 
765 	// Read the renderbuffer pixels and verify we get back what we're expecting.
766 	tcu::TextureLevel results(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), width,
767 							  HEIGHT);
768 	tcu::PixelBufferAccess pixels = results.getAccess();
769 	glu::readPixels(m_context.getRenderContext(), 0, 0, pixels);
770 	if (m_samples)
771 	{
772 		// If m_fixedSampleLocations are used make sure the first pixel's samples
773 		// all match the SAMPLE_POSITION state saved earlier.
774 		std::set<tcu::Vec4> fixedSampleLocations;
775 		if (m_fixedSampleLocations)
776 		{
777 			for (int sample = 0; sample < m_samples; ++sample)
778 			{
779 				tcu::Vec4 pixel = pixels.getPixel(sample, 0);
780 				fixedSampleLocations.insert(pixel);
781 				if (deFloatAbs(pixel.x() - samplePositions[sample].x()) > 0.01 ||
782 					deFloatAbs(pixel.y() - samplePositions[sample].y()) > 0.01)
783 				{
784 
785 					isOk = false;
786 				}
787 			}
788 		}
789 
790 		// Verify all samples of every pixel to make sure each position is unique.
791 		for (int y = 0; y < HEIGHT; ++y)
792 		{
793 			for (int x = 0; x < WIDTH; ++x)
794 			{
795 				std::set<tcu::Vec4> uniquePixels;
796 				for (int sample = 0; sample < m_samples; ++sample)
797 				{
798 					uniquePixels.insert(pixels.getPixel(x * m_samples + sample, y));
799 				}
800 				if ((GLint)uniquePixels.size() != m_samples)
801 				{
802 					isOk = false;
803 				}
804 				// For the m_fixedSampleLocations case make sure each position
805 				// matches the sample positions of pixel(0, 0) saved earlier.
806 				if (m_fixedSampleLocations)
807 				{
808 					if (fixedSampleLocations != uniquePixels)
809 					{
810 						isOk = false;
811 					}
812 				}
813 			}
814 		}
815 	}
816 	else
817 	{
818 		// For the non-multisample case make sure all the positions are (0.5,0.5).
819 		for (int y = 0; y < pixels.getHeight(); ++y)
820 		{
821 			for (int x = 0; x < pixels.getWidth(); ++x)
822 			{
823 				tcu::Vec4 pixel = pixels.getPixel(x, y);
824 				if (deFloatAbs(pixel.x() - 0.5f) > 0.01 || deFloatAbs(pixel.y() - 0.5f) > 0.01 || pixel.z() != 0.0f ||
825 					pixel.w() != 1.0f)
826 				{
827 					isOk = false;
828 				}
829 			}
830 		}
831 	}
832 
833 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_context.getRenderContext().getDefaultFramebuffer());
834 	gl.deleteFramebuffers(1, &fbo);
835 
836 	gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
837 	gl.deleteRenderbuffers(1, &rbo);
838 
839 	gl.bindTexture(target, 0);
840 	gl.deleteTextures(1, &tex);
841 
842 	m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, isOk ? "Pass" : "Fail");
843 	return STOP;
844 }
845 
SampleVariablesTests(Context& context, glu::GLSLVersion glslVersion)846 SampleVariablesTests::SampleVariablesTests(Context& context, glu::GLSLVersion glslVersion)
847 	: TestCaseGroup(context, "sample_variables", "Sample Variables tests"), m_glslVersion(glslVersion)
848 {
849 }
850 
~SampleVariablesTests()851 SampleVariablesTests::~SampleVariablesTests()
852 {
853 }
854 
init()855 void SampleVariablesTests::init()
856 {
857 	de::Random rnd(m_context.getTestContext().getCommandLine().getBaseSeed());
858 
859 	struct Sample
860 	{
861 		char const* name;
862 		GLint		samples;
863 	} samples[] = {
864 		{ "samples_0", 0 }, { "samples_1", 1 }, { "samples_2", 2 }, { "samples_4", 4 }, { "samples_8", 8 },
865 	};
866 
867 	// sample_variables.extension
868 	if (m_glslVersion == glu::GLSL_VERSION_310_ES)
869 	{
870 		tcu::TestCaseGroup* extensionCaseGroup = new tcu::TestCaseGroup(m_testCtx, "verification", "");
871 		extensionCaseGroup->addChild(
872 			new SampleShadingExtensionCase(m_context, "extension", "#extension verification", m_glslVersion));
873 		addChild(extensionCaseGroup);
874 	}
875 
876 	// sample_variables.mask
877 	tcu::TestCaseGroup* maskGroup = new tcu::TestCaseGroup(m_testCtx, "mask", "gl_SampleMask tests");
878 	addChild(maskGroup);
879 	struct Format
880 	{
881 		char const*		   name;
882 		GLenum			   internalFormat;
883 		tcu::TextureFormat textureFormat;
884 		char const*		   sampler;
885 		char const*		   outType;
886 	} formats[] = {
887 		{ "rgba8", GL_RGBA8, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), "sampler2D",
888 		  "vec4" },
889 		{ "rgba8i", GL_RGBA8I, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8),
890 		  "isampler2D", "ivec4" },
891 		{ "rgba8ui", GL_RGBA8UI, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8),
892 		  "usampler2D", "uvec4" },
893 		{ "rgba32f", GL_RGBA32F, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), "sampler2D",
894 		  "vec4" },
895 	};
896 	for (int format = 0; format < DE_LENGTH_OF_ARRAY(formats); ++format)
897 	{
898 		tcu::TestCaseGroup* maskFormatGroup = new tcu::TestCaseGroup(m_testCtx, formats[format].name, "");
899 		maskGroup->addChild(maskFormatGroup);
900 
901 		for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample)
902 		{
903 			tcu::TestCaseGroup* maskFormatSampleGroup = new tcu::TestCaseGroup(m_testCtx, samples[sample].name, "");
904 			maskFormatGroup->addChild(maskFormatSampleGroup);
905 
906 			maskFormatSampleGroup->addChild(
907 				new SampleShadingMaskCase(m_context, "mask_zero", "", m_glslVersion, formats[format].internalFormat,
908 										  formats[format].textureFormat, formats[format].sampler,
909 										  formats[format].outType, samples[sample].samples, 0));
910 
911 			for (int mask = 0; mask < SAMPLE_MASKS; ++mask)
912 			{
913 				std::stringstream ss;
914 				ss << "mask_" << mask;
915 				maskFormatSampleGroup->addChild(new SampleShadingMaskCase(
916 					m_context, ss.str().c_str(), "", m_glslVersion, formats[format].internalFormat,
917 					formats[format].textureFormat, formats[format].sampler, formats[format].outType,
918 					samples[sample].samples, rnd.getUint32()));
919 			}
920 		}
921 	}
922 
923 	// sample_variables.position
924 	tcu::TestCaseGroup* positionGroup = new tcu::TestCaseGroup(m_testCtx, "position", "gl_SamplePosition tests");
925 	addChild(positionGroup);
926 	struct Fixed
927 	{
928 		char const* name;
929 		GLboolean   fixedSampleLocations;
930 	} fixed[] = {
931 		{ "non-fixed", GL_FALSE }, { "fixed", GL_TRUE },
932 	};
933 	for (int j = 0; j < DE_LENGTH_OF_ARRAY(fixed); ++j)
934 	{
935 		tcu::TestCaseGroup* positionFixedGroup = new tcu::TestCaseGroup(m_testCtx, fixed[j].name, "");
936 		positionGroup->addChild(positionFixedGroup);
937 		for (int sample = 0; sample < DE_LENGTH_OF_ARRAY(samples); ++sample)
938 		{
939 			positionFixedGroup->addChild(new SampleShadingPositionCase(m_context, samples[sample].name, "",
940 																	   m_glslVersion, samples[sample].samples,
941 																	   fixed[j].fixedSampleLocations));
942 		}
943 	}
944 }
945 
946 } // glcts
947