Home | History | Annotate | Download | only in common
      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 {
     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 
     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 
     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 
    106 SampleShadingExtensionCase::~SampleShadingExtensionCase()
    107 {
    108 }
    109 
    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 
    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 
    221 SampleShadingMaskCase::~SampleShadingMaskCase()
    222 {
    223 }
    224 
    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 
    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 
    574 SampleShadingPositionCase::~SampleShadingPositionCase()
    575 {
    576 }
    577 
    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 
    846 SampleVariablesTests::SampleVariablesTests(Context& context, glu::GLSLVersion glslVersion)
    847 	: TestCaseGroup(context, "sample_variables", "Sample Variables tests"), m_glslVersion(glslVersion)
    848 {
    849 }
    850 
    851 SampleVariablesTests::~SampleVariablesTests()
    852 {
    853 }
    854 
    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