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