Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.1 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Tessellation and geometry shader interaction tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es31fTessellationGeometryInteractionTests.hpp"
     25 
     26 #include "tcuTestLog.hpp"
     27 #include "tcuRenderTarget.hpp"
     28 #include "tcuSurface.hpp"
     29 #include "tcuImageCompare.hpp"
     30 #include "tcuVectorUtil.hpp"
     31 #include "tcuTextureUtil.hpp"
     32 #include "gluRenderContext.hpp"
     33 #include "gluShaderProgram.hpp"
     34 #include "gluStrUtil.hpp"
     35 #include "gluContextInfo.hpp"
     36 #include "gluObjectWrapper.hpp"
     37 #include "gluPixelTransfer.hpp"
     38 #include "glwFunctions.hpp"
     39 #include "glwEnums.hpp"
     40 #include "deStringUtil.hpp"
     41 #include "deUniquePtr.hpp"
     42 
     43 #include <sstream>
     44 #include <algorithm>
     45 #include <iterator>
     46 
     47 namespace deqp
     48 {
     49 namespace gles31
     50 {
     51 namespace Functional
     52 {
     53 namespace
     54 {
     55 
     56 static const char* const s_positionVertexShader =		"#version 310 es\n"
     57 														"in highp vec4 a_position;\n"
     58 														"void main (void)\n"
     59 														"{\n"
     60 														"	gl_Position = a_position;\n"
     61 														"}\n";
     62 static const char* const s_whiteOutputFragmentShader =	"#version 310 es\n"
     63 														"layout(location = 0) out mediump vec4 fragColor;\n"
     64 														"void main (void)\n"
     65 														"{\n"
     66 														"	fragColor = vec4(1.0);\n"
     67 														"}\n";
     68 
     69 static bool isBlack (const tcu::RGBA& c)
     70 {
     71 	return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
     72 }
     73 
     74 class IdentityShaderCase : public TestCase
     75 {
     76 public:
     77 					IdentityShaderCase	(Context& context, const char* name, const char* description);
     78 
     79 protected:
     80 	const char*		getVertexSource		(void) const;
     81 	const char*		getFragmentSource	(void) const;
     82 };
     83 
     84 IdentityShaderCase::IdentityShaderCase (Context& context, const char* name, const char* description)
     85 	: TestCase(context, name, description)
     86 {
     87 }
     88 
     89 const char* IdentityShaderCase::getVertexSource (void) const
     90 {
     91 	return	"#version 310 es\n"
     92 			"in highp vec4 a_position;\n"
     93 			"out highp vec4 v_vertex_color;\n"
     94 			"void main (void)\n"
     95 			"{\n"
     96 			"	gl_Position = a_position;\n"
     97 			"	v_vertex_color = vec4(a_position.x * 0.5 + 0.5, a_position.y * 0.5 + 0.5, 1.0, 0.4);\n"
     98 			"}\n";
     99 }
    100 
    101 const char* IdentityShaderCase::getFragmentSource (void) const
    102 {
    103 	return	"#version 310 es\n"
    104 			"in mediump vec4 v_fragment_color;\n"
    105 			"layout(location = 0) out mediump vec4 fragColor;\n"
    106 			"void main (void)\n"
    107 			"{\n"
    108 			"	fragColor = v_fragment_color;\n"
    109 			"}\n";
    110 }
    111 
    112 class IdentityGeometryShaderCase : public IdentityShaderCase
    113 {
    114 public:
    115 	enum CaseType
    116 	{
    117 		CASE_TRIANGLES = 0,
    118 		CASE_QUADS,
    119 		CASE_ISOLINES,
    120 	};
    121 
    122 					IdentityGeometryShaderCase			(Context& context, const char* name, const char* description, CaseType caseType);
    123 					~IdentityGeometryShaderCase			(void);
    124 
    125 private:
    126 	void			init								(void);
    127 	void			deinit								(void);
    128 	IterateResult	iterate								(void);
    129 
    130 	std::string		getTessellationControlSource		(void) const;
    131 	std::string		getTessellationEvaluationSource		(bool geometryActive) const;
    132 	std::string		getGeometrySource					(void) const;
    133 
    134 	enum
    135 	{
    136 		RENDER_SIZE = 128,
    137 	};
    138 
    139 	const CaseType	m_case;
    140 	deUint32		m_patchBuffer;
    141 };
    142 
    143 IdentityGeometryShaderCase::IdentityGeometryShaderCase (Context& context, const char* name, const char* description, CaseType caseType)
    144 	: IdentityShaderCase	(context, name, description)
    145 	, m_case				(caseType)
    146 	, m_patchBuffer			(0)
    147 {
    148 }
    149 
    150 IdentityGeometryShaderCase::~IdentityGeometryShaderCase (void)
    151 {
    152 	deinit();
    153 }
    154 
    155 void IdentityGeometryShaderCase::init (void)
    156 {
    157 	// Requirements
    158 
    159 	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
    160 		!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
    161 		throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
    162 
    163 	if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
    164 		m_context.getRenderTarget().getHeight() < RENDER_SIZE)
    165 		throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
    166 
    167 	// Log
    168 
    169 	m_testCtx.getLog()
    170 		<< tcu::TestLog::Message
    171 		<< "Testing tessellating shader program output does not change when a passthrough geometry shader is attached.\n"
    172 		<< "Rendering two images, first with and second without a geometry shader. Expecting similar results.\n"
    173 		<< "Using additive blending to detect overlap.\n"
    174 		<< tcu::TestLog::EndMessage;
    175 
    176 	// Resources
    177 
    178 	{
    179 		static const tcu::Vec4 patchBufferData[4] =
    180 		{
    181 			tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ),
    182 			tcu::Vec4( -0.9f,  0.9f, 0.0f, 1.0f ),
    183 			tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f ),
    184 			tcu::Vec4(  0.9f,  0.9f, 0.0f, 1.0f ),
    185 		};
    186 
    187 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    188 
    189 		gl.genBuffers(1, &m_patchBuffer);
    190 		gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
    191 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(patchBufferData), patchBufferData, GL_STATIC_DRAW);
    192 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
    193 	}
    194 }
    195 
    196 void IdentityGeometryShaderCase::deinit (void)
    197 {
    198 	if (m_patchBuffer)
    199 	{
    200 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_patchBuffer);
    201 		m_patchBuffer = 0;
    202 	}
    203 }
    204 
    205 IdentityGeometryShaderCase::IterateResult IdentityGeometryShaderCase::iterate (void)
    206 {
    207 	const float				innerTessellationLevel	= 14.0f;
    208 	const float				outerTessellationLevel	= 14.0f;
    209 	const glw::Functions&	gl						= m_context.getRenderContext().getFunctions();
    210 	tcu::Surface			resultWithGeometry		(RENDER_SIZE, RENDER_SIZE);
    211 	tcu::Surface			resultWithoutGeometry	(RENDER_SIZE, RENDER_SIZE);
    212 
    213 	const struct
    214 	{
    215 		const char*				name;
    216 		const char*				description;
    217 		bool					containsGeometryShader;
    218 		tcu::PixelBufferAccess	surfaceAccess;
    219 	} renderTargets[] =
    220 	{
    221 		{ "RenderWithGeometryShader",		"Render with geometry shader",		true,	resultWithGeometry.getAccess()		},
    222 		{ "RenderWithoutGeometryShader",	"Render without geometry shader",	false,	resultWithoutGeometry.getAccess()	},
    223 	};
    224 
    225 	gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
    226 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    227 	GLU_EXPECT_NO_ERROR(gl.getError(), "set viewport");
    228 
    229 	gl.enable(GL_BLEND);
    230 	gl.blendFunc(GL_SRC_ALPHA, GL_ONE);
    231 	gl.blendEquation(GL_FUNC_ADD);
    232 	GLU_EXPECT_NO_ERROR(gl.getError(), "set blend");
    233 
    234 	m_testCtx.getLog() << tcu::TestLog::Message << "Tessellation level: inner " << innerTessellationLevel << ", outer " << outerTessellationLevel << tcu::TestLog::EndMessage;
    235 
    236 	// render with and without geometry shader
    237 	for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++renderNdx)
    238 	{
    239 		const tcu::ScopedLogSection	section	(m_testCtx.getLog(), renderTargets[renderNdx].name, renderTargets[renderNdx].description);
    240 		glu::ProgramSources			sources;
    241 
    242 		sources	<< glu::VertexSource(getVertexSource())
    243 				<< glu::FragmentSource(getFragmentSource())
    244 				<< glu::TessellationControlSource(getTessellationControlSource())
    245 				<< glu::TessellationEvaluationSource(getTessellationEvaluationSource(renderTargets[renderNdx].containsGeometryShader));
    246 
    247 		if (renderTargets[renderNdx].containsGeometryShader)
    248 			sources << glu::GeometrySource(getGeometrySource());
    249 
    250 		{
    251 			const glu::ShaderProgram	program					(m_context.getRenderContext(), sources);
    252 			const glu::VertexArray		vao						(m_context.getRenderContext());
    253 			const int					posLocation				= gl.getAttribLocation(program.getProgram(), "a_position");
    254 			const int					innerTessellationLoc	= gl.getUniformLocation(program.getProgram(), "u_innerTessellationLevel");
    255 			const int					outerTessellationLoc	= gl.getUniformLocation(program.getProgram(), "u_outerTessellationLevel");
    256 
    257 			m_testCtx.getLog() << program;
    258 
    259 			if (!program.isOk())
    260 				throw tcu::TestError("could not build program");
    261 			if (posLocation == -1)
    262 				throw tcu::TestError("a_position location was -1");
    263 			if (outerTessellationLoc == -1)
    264 				throw tcu::TestError("u_outerTessellationLevel location was -1");
    265 
    266 			gl.bindVertexArray(*vao);
    267 			gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
    268 			gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    269 			gl.enableVertexAttribArray(posLocation);
    270 			GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
    271 
    272 			gl.useProgram(program.getProgram());
    273 			gl.uniform1f(outerTessellationLoc, outerTessellationLevel);
    274 
    275 			if (innerTessellationLoc == -1)
    276 				gl.uniform1f(innerTessellationLoc, innerTessellationLevel);
    277 
    278 			GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
    279 
    280 			gl.patchParameteri(GL_PATCH_VERTICES, (m_case == CASE_TRIANGLES) ? (3): (4));
    281 			GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
    282 
    283 			gl.clear(GL_COLOR_BUFFER_BIT);
    284 			GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
    285 
    286 			gl.drawArrays(GL_PATCHES, 0, 4);
    287 			GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
    288 
    289 			glu::readPixels(m_context.getRenderContext(), 0, 0, renderTargets[renderNdx].surfaceAccess);
    290 		}
    291 	}
    292 
    293 	if (tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
    294 												  "ImageCompare",
    295 												  "Image comparison",
    296 												  resultWithoutGeometry.getAccess(),
    297 												  resultWithGeometry.getAccess(),
    298 												  tcu::UVec4(8, 8, 8, 255),
    299 												  tcu::IVec3(1, 1, 0),
    300 												  true,
    301 												  tcu::COMPARE_LOG_RESULT))
    302 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    303 	else
    304 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    305 
    306 	return STOP;
    307 }
    308 
    309 std::string IdentityGeometryShaderCase::getTessellationControlSource (void) const
    310 {
    311 	std::ostringstream buf;
    312 
    313 	buf <<	"#version 310 es\n"
    314 			"#extension GL_EXT_tessellation_shader : require\n"
    315 			"layout(vertices = 4) out;\n"
    316 			"\n"
    317 			"uniform highp float u_innerTessellationLevel;\n"
    318 			"uniform highp float u_outerTessellationLevel;\n"
    319 			"in highp vec4 v_vertex_color[];\n"
    320 			"out highp vec4 v_patch_color[];\n"
    321 			"\n"
    322 			"void main (void)\n"
    323 			"{\n"
    324 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
    325 			"	v_patch_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
    326 			"\n";
    327 
    328 	if (m_case == CASE_TRIANGLES)
    329 		buf <<	"	gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
    330 				"	gl_TessLevelOuter[1] = u_outerTessellationLevel;\n"
    331 				"	gl_TessLevelOuter[2] = u_outerTessellationLevel;\n"
    332 				"	gl_TessLevelInner[0] = u_innerTessellationLevel;\n";
    333 	else if (m_case == CASE_QUADS)
    334 		buf <<	"	gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
    335 				"	gl_TessLevelOuter[1] = u_outerTessellationLevel;\n"
    336 				"	gl_TessLevelOuter[2] = u_outerTessellationLevel;\n"
    337 				"	gl_TessLevelOuter[3] = u_outerTessellationLevel;\n"
    338 				"	gl_TessLevelInner[0] = u_innerTessellationLevel;\n"
    339 				"	gl_TessLevelInner[1] = u_innerTessellationLevel;\n";
    340 	else if (m_case == CASE_ISOLINES)
    341 		buf <<	"	gl_TessLevelOuter[0] = u_outerTessellationLevel;\n"
    342 				"	gl_TessLevelOuter[1] = u_outerTessellationLevel;\n";
    343 	else
    344 		DE_ASSERT(false);
    345 
    346 	buf <<	"}\n";
    347 
    348 	return buf.str();
    349 }
    350 
    351 std::string IdentityGeometryShaderCase::getTessellationEvaluationSource (bool geometryActive) const
    352 {
    353 	const char* const	colorOutputName = ((geometryActive) ? ("v_evaluated_color") : ("v_fragment_color"));
    354 	std::ostringstream	buf;
    355 
    356 	buf <<	"#version 310 es\n"
    357 			"#extension GL_EXT_tessellation_shader : require\n"
    358 			"layout("
    359 				<< ((m_case == CASE_TRIANGLES) ? ("triangles") : (m_case == CASE_QUADS) ? ("quads") : ("isolines"))
    360 				<< ") in;\n"
    361 			"\n"
    362 			"in highp vec4 v_patch_color[];\n"
    363 			"out highp vec4 " << colorOutputName << ";\n"
    364 			"\n"
    365 			"// note: No need to use precise gl_Position since we do not require gapless geometry\n"
    366 			"void main (void)\n"
    367 			"{\n";
    368 
    369 	if (m_case == CASE_TRIANGLES)
    370 		buf <<	"	vec3 weights = vec3(pow(gl_TessCoord.x, 1.3), pow(gl_TessCoord.y, 1.3), pow(gl_TessCoord.z, 1.3));\n"
    371 				"	vec3 cweights = gl_TessCoord;\n"
    372 				"	gl_Position = vec4(weights.x * gl_in[0].gl_Position.xyz + weights.y * gl_in[1].gl_Position.xyz + weights.z * gl_in[2].gl_Position.xyz, 1.0);\n"
    373 				"	" << colorOutputName << " = cweights.x * v_patch_color[0] + cweights.y * v_patch_color[1] + cweights.z * v_patch_color[2];\n";
    374 	else if (m_case == CASE_QUADS || m_case == CASE_ISOLINES)
    375 		buf <<	"	vec2 normalizedCoord = (gl_TessCoord.xy * 2.0 - vec2(1.0));\n"
    376 				"	vec2 normalizedWeights = normalizedCoord * (vec2(1.0) - 0.3 * cos(normalizedCoord.yx * 1.57));\n"
    377 				"	vec2 weights = normalizedWeights * 0.5 + vec2(0.5);\n"
    378 				"	vec2 cweights = gl_TessCoord.xy;\n"
    379 				"	gl_Position = mix(mix(gl_in[0].gl_Position, gl_in[1].gl_Position, weights.y), mix(gl_in[2].gl_Position, gl_in[3].gl_Position, weights.y), weights.x);\n"
    380 				"	" << colorOutputName << " = mix(mix(v_patch_color[0], v_patch_color[1], cweights.y), mix(v_patch_color[2], v_patch_color[3], cweights.y), cweights.x);\n";
    381 	else
    382 		DE_ASSERT(false);
    383 
    384 	buf <<	"}\n";
    385 
    386 	return buf.str();
    387 }
    388 
    389 std::string IdentityGeometryShaderCase::getGeometrySource (void) const
    390 {
    391 	const char* const	geometryInputPrimitive			= (m_case == CASE_ISOLINES) ? ("lines") : ("triangles");
    392 	const char* const	geometryOutputPrimitive			= (m_case == CASE_ISOLINES) ? ("line_strip") : ("triangle_strip");
    393 	const int			numEmitVertices					= (m_case == CASE_ISOLINES) ? (2) : (3);
    394 	std::ostringstream	buf;
    395 
    396 	buf <<	"#version 310 es\n"
    397 			"#extension GL_EXT_geometry_shader : require\n"
    398 			"layout(" << geometryInputPrimitive << ") in;\n"
    399 			"layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
    400 			"\n"
    401 			"in highp vec4 v_evaluated_color[];\n"
    402 			"out highp vec4 v_fragment_color;\n"
    403 			"\n"
    404 			"void main (void)\n"
    405 			"{\n"
    406 			"	for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
    407 			"	{\n"
    408 			"		gl_Position = gl_in[ndx].gl_Position;\n"
    409 			"		v_fragment_color = v_evaluated_color[ndx];\n"
    410 			"		EmitVertex();\n"
    411 			"	}\n"
    412 			"}\n";
    413 
    414 	return buf.str();
    415 }
    416 
    417 class IdentityTessellationShaderCase : public IdentityShaderCase
    418 {
    419 public:
    420 	enum CaseType
    421 	{
    422 		CASE_TRIANGLES = 0,
    423 		CASE_ISOLINES,
    424 	};
    425 
    426 					IdentityTessellationShaderCase		(Context& context, const char* name, const char* description, CaseType caseType);
    427 					~IdentityTessellationShaderCase		(void);
    428 
    429 private:
    430 	void			init								(void);
    431 	void			deinit								(void);
    432 	IterateResult	iterate								(void);
    433 
    434 	std::string		getTessellationControlSource		(void) const;
    435 	std::string		getTessellationEvaluationSource		(void) const;
    436 	std::string		getGeometrySource					(bool tessellationActive) const;
    437 
    438 	enum
    439 	{
    440 		RENDER_SIZE = 256,
    441 	};
    442 
    443 	const CaseType	m_case;
    444 	deUint32		m_dataBuffer;
    445 };
    446 
    447 IdentityTessellationShaderCase::IdentityTessellationShaderCase (Context& context, const char* name, const char* description, CaseType caseType)
    448 	: IdentityShaderCase	(context, name, description)
    449 	, m_case				(caseType)
    450 	, m_dataBuffer			(0)
    451 {
    452 }
    453 
    454 IdentityTessellationShaderCase::~IdentityTessellationShaderCase (void)
    455 {
    456 	deinit();
    457 }
    458 
    459 void IdentityTessellationShaderCase::init (void)
    460 {
    461 	// Requirements
    462 
    463 	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
    464 		!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
    465 		throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
    466 
    467 	if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
    468 		m_context.getRenderTarget().getHeight() < RENDER_SIZE)
    469 		throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
    470 
    471 	// Log
    472 
    473 	m_testCtx.getLog()
    474 		<< tcu::TestLog::Message
    475 		<< "Testing geometry shading shader program output does not change when a passthrough tessellation shader is attached.\n"
    476 		<< "Rendering two images, first with and second without a tessellation shader. Expecting similar results.\n"
    477 		<< "Using additive blending to detect overlap.\n"
    478 		<< tcu::TestLog::EndMessage;
    479 
    480 	// Resources
    481 
    482 	{
    483 		static const tcu::Vec4	pointData[]	=
    484 		{
    485 			tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f ),
    486 			tcu::Vec4(  0.0f, -0.5f, 0.0f, 1.0f ),
    487 			tcu::Vec4(  0.4f,  0.4f, 0.0f, 1.0f ),
    488 		};
    489 		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
    490 
    491 		gl.genBuffers(1, &m_dataBuffer);
    492 		gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBuffer);
    493 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(pointData), pointData, GL_STATIC_DRAW);
    494 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
    495 	}
    496 }
    497 
    498 void IdentityTessellationShaderCase::deinit (void)
    499 {
    500 	if (m_dataBuffer)
    501 	{
    502 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_dataBuffer);
    503 		m_dataBuffer = 0;
    504 	}
    505 }
    506 
    507 IdentityTessellationShaderCase::IterateResult IdentityTessellationShaderCase::iterate (void)
    508 {
    509 	const glw::Functions&	gl							= m_context.getRenderContext().getFunctions();
    510 	tcu::Surface			resultWithTessellation		(RENDER_SIZE, RENDER_SIZE);
    511 	tcu::Surface			resultWithoutTessellation	(RENDER_SIZE, RENDER_SIZE);
    512 	const int				numPrimitiveVertices		= (m_case == CASE_TRIANGLES) ? (3) : (2);
    513 
    514 	const struct
    515 	{
    516 		const char*				name;
    517 		const char*				description;
    518 		bool					containsTessellationShaders;
    519 		tcu::PixelBufferAccess	surfaceAccess;
    520 	} renderTargets[] =
    521 	{
    522 		{ "RenderWithTessellationShader",		"Render with tessellation shader",		true,	resultWithTessellation.getAccess()		},
    523 		{ "RenderWithoutTessellationShader",	"Render without tessellation shader",	false,	resultWithoutTessellation.getAccess()	},
    524 	};
    525 
    526 	gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
    527 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    528 	GLU_EXPECT_NO_ERROR(gl.getError(), "set viewport");
    529 
    530 	gl.enable(GL_BLEND);
    531 	gl.blendFunc(GL_SRC_ALPHA, GL_ONE);
    532 	gl.blendEquation(GL_FUNC_ADD);
    533 	GLU_EXPECT_NO_ERROR(gl.getError(), "set blend");
    534 
    535 	// render with and without tessellation shader
    536 	for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderTargets); ++renderNdx)
    537 	{
    538 		const tcu::ScopedLogSection	section	(m_testCtx.getLog(), renderTargets[renderNdx].name, renderTargets[renderNdx].description);
    539 		glu::ProgramSources			sources;
    540 
    541 		sources	<< glu::VertexSource(getVertexSource())
    542 				<< glu::FragmentSource(getFragmentSource())
    543 				<< glu::GeometrySource(getGeometrySource(renderTargets[renderNdx].containsTessellationShaders));
    544 
    545 		if (renderTargets[renderNdx].containsTessellationShaders)
    546 			sources	<< glu::TessellationControlSource(getTessellationControlSource())
    547 					<< glu::TessellationEvaluationSource(getTessellationEvaluationSource());
    548 
    549 		{
    550 			const glu::ShaderProgram	program					(m_context.getRenderContext(), sources);
    551 			const glu::VertexArray		vao						(m_context.getRenderContext());
    552 			const int					posLocation				= gl.getAttribLocation(program.getProgram(), "a_position");
    553 
    554 			m_testCtx.getLog() << program;
    555 
    556 			if (!program.isOk())
    557 				throw tcu::TestError("could not build program");
    558 			if (posLocation == -1)
    559 				throw tcu::TestError("a_position location was -1");
    560 
    561 			gl.bindVertexArray(*vao);
    562 			gl.bindBuffer(GL_ARRAY_BUFFER, m_dataBuffer);
    563 			gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
    564 			gl.enableVertexAttribArray(posLocation);
    565 			GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
    566 
    567 			gl.useProgram(program.getProgram());
    568 			GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
    569 
    570 			gl.clear(GL_COLOR_BUFFER_BIT);
    571 			GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
    572 
    573 			if (renderTargets[renderNdx].containsTessellationShaders)
    574 			{
    575 				gl.patchParameteri(GL_PATCH_VERTICES, numPrimitiveVertices);
    576 				GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
    577 
    578 				gl.drawArrays(GL_PATCHES, 0, numPrimitiveVertices);
    579 				GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
    580 			}
    581 			else
    582 			{
    583 				gl.drawArrays((m_case == CASE_TRIANGLES) ? (GL_TRIANGLES) : (GL_LINES), 0, numPrimitiveVertices);
    584 				GLU_EXPECT_NO_ERROR(gl.getError(), "draw primitives");
    585 			}
    586 
    587 			glu::readPixels(m_context.getRenderContext(), 0, 0, renderTargets[renderNdx].surfaceAccess);
    588 		}
    589 	}
    590 
    591 	// compare
    592 	{
    593 		bool imageOk;
    594 
    595 		if (m_context.getRenderTarget().getNumSamples() > 1)
    596 			imageOk = tcu::fuzzyCompare(m_testCtx.getLog(),
    597 										"ImageCompare",
    598 										"Image comparison",
    599 										resultWithoutTessellation.getAccess(),
    600 										resultWithTessellation.getAccess(),
    601 										0.03f,
    602 										tcu::COMPARE_LOG_RESULT);
    603 		else
    604 			imageOk = tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
    605 																"ImageCompare",
    606 																"Image comparison",
    607 																resultWithoutTessellation.getAccess(),
    608 																resultWithTessellation.getAccess(),
    609 																tcu::UVec4(8, 8, 8, 255),				//!< threshold
    610 																tcu::IVec3(1, 1, 0),					//!< 3x3 search kernel
    611 																true,									//!< fragments may end up over the viewport, just ignore them
    612 																tcu::COMPARE_LOG_RESULT);
    613 
    614 		if (imageOk)
    615 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    616 		else
    617 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    618 	}
    619 
    620 	return STOP;
    621 }
    622 
    623 std::string IdentityTessellationShaderCase::getTessellationControlSource (void) const
    624 {
    625 	std::ostringstream buf;
    626 
    627 	buf <<	"#version 310 es\n"
    628 			"#extension GL_EXT_tessellation_shader : require\n"
    629 			"layout(vertices = " << ((m_case == CASE_TRIANGLES) ? (3) : (2)) << ") out;\n"
    630 			"\n"
    631 			"in highp vec4 v_vertex_color[];\n"
    632 			"out highp vec4 v_control_color[];\n"
    633 			"\n"
    634 			"void main (void)\n"
    635 			"{\n"
    636 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
    637 			"	v_control_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
    638 			"\n";
    639 
    640 	if (m_case == CASE_TRIANGLES)
    641 		buf <<	"	gl_TessLevelOuter[0] = 1.0;\n"
    642 				"	gl_TessLevelOuter[1] = 1.0;\n"
    643 				"	gl_TessLevelOuter[2] = 1.0;\n"
    644 				"	gl_TessLevelInner[0] = 1.0;\n";
    645 	else if (m_case == CASE_ISOLINES)
    646 		buf <<	"	gl_TessLevelOuter[0] = 1.0;\n"
    647 				"	gl_TessLevelOuter[1] = 1.0;\n";
    648 	else
    649 		DE_ASSERT(false);
    650 
    651 	buf <<	"}\n";
    652 
    653 	return buf.str();
    654 }
    655 
    656 std::string IdentityTessellationShaderCase::getTessellationEvaluationSource (void) const
    657 {
    658 	std::ostringstream buf;
    659 
    660 	buf <<	"#version 310 es\n"
    661 			"#extension GL_EXT_tessellation_shader : require\n"
    662 			"layout("
    663 				<< ((m_case == CASE_TRIANGLES) ? ("triangles") : ("isolines"))
    664 				<< ") in;\n"
    665 			"\n"
    666 			"in highp vec4 v_control_color[];\n"
    667 			"out highp vec4 v_evaluated_color;\n"
    668 			"\n"
    669 			"// note: No need to use precise gl_Position since we do not require gapless geometry\n"
    670 			"void main (void)\n"
    671 			"{\n";
    672 
    673 	if (m_case == CASE_TRIANGLES)
    674 		buf <<	"	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
    675 				"	v_evaluated_color = gl_TessCoord.x * v_control_color[0] + gl_TessCoord.y * v_control_color[1] + gl_TessCoord.z * v_control_color[2];\n";
    676 	else if (m_case == CASE_ISOLINES)
    677 		buf <<	"	gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
    678 				"	v_evaluated_color = mix(v_control_color[0], v_control_color[1], gl_TessCoord.x);\n";
    679 	else
    680 		DE_ASSERT(false);
    681 
    682 	buf <<	"}\n";
    683 
    684 	return buf.str();
    685 }
    686 
    687 std::string IdentityTessellationShaderCase::getGeometrySource (bool tessellationActive) const
    688 {
    689 	const char* const	colorSourceName			= (tessellationActive) ? ("v_evaluated_color") : ("v_vertex_color");
    690 	const char* const	geometryInputPrimitive	= (m_case == CASE_ISOLINES) ? ("lines") : ("triangles");
    691 	const char* const	geometryOutputPrimitive	= (m_case == CASE_ISOLINES) ? ("line_strip") : ("triangle_strip");
    692 	const int			numEmitVertices			= (m_case == CASE_ISOLINES) ? (11) : (8);
    693 	std::ostringstream	buf;
    694 
    695 	buf <<	"#version 310 es\n"
    696 			"#extension GL_EXT_geometry_shader : require\n"
    697 			"layout(" << geometryInputPrimitive << ") in;\n"
    698 			"layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
    699 			"\n"
    700 			"in highp vec4 " << colorSourceName << "[];\n"
    701 			"out highp vec4 v_fragment_color;\n"
    702 			"\n"
    703 			"void main (void)\n"
    704 			"{\n";
    705 
    706 	if (m_case == CASE_TRIANGLES)
    707 	{
    708 		buf <<	"	vec4 centerPos = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3.0f;\n"
    709 				"\n"
    710 				"	for (int ndx = 0; ndx < 4; ++ndx)\n"
    711 				"	{\n"
    712 				"		gl_Position = centerPos + (centerPos - gl_in[ndx % 3].gl_Position);\n"
    713 				"		v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
    714 				"		EmitVertex();\n"
    715 				"\n"
    716 				"		gl_Position = centerPos + 0.7 * (centerPos - gl_in[ndx % 3].gl_Position);\n"
    717 				"		v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
    718 				"		EmitVertex();\n"
    719 				"	}\n";
    720 
    721 	}
    722 	else if (m_case == CASE_ISOLINES)
    723 	{
    724 		buf <<	"	vec4 mdir = vec4(gl_in[0].gl_Position.y - gl_in[1].gl_Position.y, gl_in[1].gl_Position.x - gl_in[0].gl_Position.x, 0.0, 0.0);\n"
    725 				"	for (int i = 0; i <= 10; ++i)\n"
    726 				"	{\n"
    727 				"		float xweight = cos(float(i) / 10.0 * 6.28) * 0.5 + 0.5;\n"
    728 				"		float mweight = sin(float(i) / 10.0 * 6.28) * 0.1 + 0.1;\n"
    729 				"		gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, xweight) + mweight * mdir;\n"
    730 				"		v_fragment_color = mix(" << colorSourceName << "[0], " << colorSourceName << "[1], xweight);\n"
    731 				"		EmitVertex();\n"
    732 				"	}\n";
    733 	}
    734 	else
    735 		DE_ASSERT(false);
    736 
    737 	buf <<	"}\n";
    738 
    739 	return buf.str();
    740 }
    741 
    742 class FeedbackPrimitiveTypeCase : public TestCase
    743 {
    744 public:
    745 	enum TessellationOutputType
    746 	{
    747 		TESSELLATION_OUT_TRIANGLES = 0,
    748 		TESSELLATION_OUT_QUADS,
    749 		TESSELLATION_OUT_ISOLINES,
    750 
    751 		TESSELLATION_OUT_LAST
    752 	};
    753 	enum TessellationPointMode
    754 	{
    755 		TESSELLATION_POINTMODE_OFF = 0,
    756 		TESSELLATION_POINTMODE_ON,
    757 
    758 		TESSELLATION_POINTMODE_LAST
    759 	};
    760 	enum GeometryOutputType
    761 	{
    762 		GEOMETRY_OUTPUT_POINTS = 0,
    763 		GEOMETRY_OUTPUT_LINES,
    764 		GEOMETRY_OUTPUT_TRIANGLES,
    765 
    766 		GEOMETRY_OUTPUT_LAST
    767 	};
    768 
    769 									FeedbackPrimitiveTypeCase				(Context& context,
    770 																			 const char* name,
    771 																			 const char* description,
    772 																			 TessellationOutputType tessellationOutput,
    773 																			 TessellationPointMode tessellationPointMode,
    774 																			 GeometryOutputType geometryOutputType);
    775 									~FeedbackPrimitiveTypeCase				(void);
    776 
    777 private:
    778 	void							init									(void);
    779 	void							deinit									(void);
    780 	IterateResult					iterate									(void);
    781 
    782 	void							renderWithFeedback						(tcu::Surface& dst);
    783 	void							renderWithoutFeedback					(tcu::Surface& dst);
    784 	void							verifyFeedbackResults					(const std::vector<tcu::Vec4>& feedbackResult);
    785 	void							verifyRenderedImage						(const tcu::Surface& image, const std::vector<tcu::Vec4>& vertices);
    786 
    787 	void							genTransformFeedback					(void);
    788 	int								getNumGeneratedElementsPerPrimitive		(void) const;
    789 	int								getNumGeneratedPrimitives				(void) const;
    790 	int								getNumTessellatedPrimitives				(void) const;
    791 	int								getGeometryAmplification				(void) const;
    792 
    793 	const char*						getVertexSource							(void) const;
    794 	const char*						getFragmentSource						(void) const;
    795 	std::string						getTessellationControlSource			(void) const;
    796 	std::string						getTessellationEvaluationSource			(void) const;
    797 	std::string						getGeometrySource						(void) const;
    798 
    799 	static const char*				getTessellationOutputDescription		(TessellationOutputType tessellationOutput,
    800 																			 TessellationPointMode tessellationPointMode);
    801 	static const char*				getGeometryInputDescription				(TessellationOutputType tessellationOutput,
    802 																			 TessellationPointMode tessellationPointMode);
    803 	static const char*				getGeometryOutputDescription			(GeometryOutputType geometryOutput);
    804 	glw::GLenum						getOutputPrimitiveGLType				(void) const;
    805 
    806 	enum
    807 	{
    808 		RENDER_SIZE = 128,
    809 	};
    810 
    811 	const TessellationOutputType	m_tessellationOutput;
    812 	const TessellationPointMode		m_tessellationPointMode;
    813 	const GeometryOutputType		m_geometryOutputType;
    814 
    815 	glu::ShaderProgram*				m_feedbackProgram;
    816 	glu::ShaderProgram*				m_nonFeedbackProgram;
    817 	deUint32						m_patchBuffer;
    818 	deUint32						m_feedbackID;
    819 	deUint32						m_feedbackBuffer;
    820 };
    821 
    822 FeedbackPrimitiveTypeCase::FeedbackPrimitiveTypeCase (Context& context,
    823 									  const char* name,
    824 									  const char* description,
    825 									  TessellationOutputType tessellationOutput,
    826 									  TessellationPointMode tessellationPointMode,
    827 									  GeometryOutputType geometryOutputType)
    828 	: TestCase					(context, name, description)
    829 	, m_tessellationOutput		(tessellationOutput)
    830 	, m_tessellationPointMode	(tessellationPointMode)
    831 	, m_geometryOutputType		(geometryOutputType)
    832 	, m_feedbackProgram			(DE_NULL)
    833 	, m_nonFeedbackProgram		(DE_NULL)
    834 	, m_patchBuffer				(0)
    835 	, m_feedbackID				(0)
    836 	, m_feedbackBuffer			(0)
    837 {
    838 	DE_ASSERT(tessellationOutput < TESSELLATION_OUT_LAST);
    839 	DE_ASSERT(tessellationPointMode < TESSELLATION_POINTMODE_LAST);
    840 	DE_ASSERT(geometryOutputType < GEOMETRY_OUTPUT_LAST);
    841 }
    842 
    843 FeedbackPrimitiveTypeCase::~FeedbackPrimitiveTypeCase (void)
    844 {
    845 	deinit();
    846 }
    847 
    848 void FeedbackPrimitiveTypeCase::init (void)
    849 {
    850 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    851 
    852 	// Requirements
    853 
    854 	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
    855 		!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
    856 		throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
    857 
    858 	if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
    859 		m_context.getRenderTarget().getHeight() < RENDER_SIZE)
    860 		throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
    861 
    862 	// Log
    863 
    864 	m_testCtx.getLog()
    865 		<< tcu::TestLog::Message
    866 		<< "Testing "
    867 			<< getTessellationOutputDescription(m_tessellationOutput, m_tessellationPointMode)
    868 			<< "->"
    869 			<< getGeometryInputDescription(m_tessellationOutput, m_tessellationPointMode)
    870 			<< " primitive conversion with and without transform feedback.\n"
    871 		<< "Sending a patch of 4 vertices (2x2 uniform grid) to tessellation control shader.\n"
    872 		<< "Control shader emits a patch of 9 vertices (3x3 uniform grid).\n"
    873 		<< "Setting outer tessellation level = 3, inner = 3.\n"
    874 		<< "Primitive generator emits " << getTessellationOutputDescription(m_tessellationOutput, m_tessellationPointMode) << "\n"
    875 		<< "Geometry shader transforms emitted primitives to " << getGeometryOutputDescription(m_geometryOutputType) << "\n"
    876 		<< "Reading back vertex positions of generated primitives using transform feedback.\n"
    877 		<< "Verifying rendered image and feedback vertices are consistent.\n"
    878 		<< "Rendering scene again with identical shader program, but without setting feedback varying. Expecting similar output image."
    879 		<< tcu::TestLog::EndMessage;
    880 
    881 	// Resources
    882 
    883 	{
    884 		static const tcu::Vec4 patchBufferData[4] =
    885 		{
    886 			tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ),
    887 			tcu::Vec4( -0.9f,  0.9f, 0.0f, 1.0f ),
    888 			tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f ),
    889 			tcu::Vec4(  0.9f,  0.9f, 0.0f, 1.0f ),
    890 		};
    891 
    892 		gl.genBuffers(1, &m_patchBuffer);
    893 		gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
    894 		gl.bufferData(GL_ARRAY_BUFFER, sizeof(patchBufferData), patchBufferData, GL_STATIC_DRAW);
    895 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buffer");
    896 	}
    897 
    898 	m_feedbackProgram = new glu::ShaderProgram(m_context.getRenderContext(),
    899 											   glu::ProgramSources()
    900 												<< glu::VertexSource(getVertexSource())
    901 												<< glu::FragmentSource(getFragmentSource())
    902 												<< glu::TessellationControlSource(getTessellationControlSource())
    903 												<< glu::TessellationEvaluationSource(getTessellationEvaluationSource())
    904 												<< glu::GeometrySource(getGeometrySource())
    905 												<< glu::TransformFeedbackVarying("tf_someVertexPosition")
    906 												<< glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
    907 	m_testCtx.getLog() << *m_feedbackProgram;
    908 	if (!m_feedbackProgram->isOk())
    909 		throw tcu::TestError("failed to build program");
    910 
    911 	m_nonFeedbackProgram = new glu::ShaderProgram(m_context.getRenderContext(),
    912 												  glu::ProgramSources()
    913 													<< glu::VertexSource(getVertexSource())
    914 													<< glu::FragmentSource(getFragmentSource())
    915 													<< glu::TessellationControlSource(getTessellationControlSource())
    916 													<< glu::TessellationEvaluationSource(getTessellationEvaluationSource())
    917 													<< glu::GeometrySource(getGeometrySource()));
    918 	if (!m_nonFeedbackProgram->isOk())
    919 	{
    920 		m_testCtx.getLog() << *m_nonFeedbackProgram;
    921 		throw tcu::TestError("failed to build program");
    922 	}
    923 
    924 	genTransformFeedback();
    925 }
    926 
    927 void FeedbackPrimitiveTypeCase::deinit (void)
    928 {
    929 	if (m_patchBuffer)
    930 	{
    931 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_patchBuffer);
    932 		m_patchBuffer = 0;
    933 	}
    934 
    935 	if (m_feedbackBuffer)
    936 	{
    937 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuffer);
    938 		m_feedbackBuffer = 0;
    939 	}
    940 
    941 	if (m_feedbackID)
    942 	{
    943 		m_context.getRenderContext().getFunctions().deleteTransformFeedbacks(1, &m_feedbackID);
    944 		m_feedbackID = 0;
    945 	}
    946 
    947 	if (m_feedbackProgram)
    948 	{
    949 		delete m_feedbackProgram;
    950 		m_feedbackProgram = DE_NULL;
    951 	}
    952 
    953 	if (m_nonFeedbackProgram)
    954 	{
    955 		delete m_nonFeedbackProgram;
    956 		m_nonFeedbackProgram = DE_NULL;
    957 	}
    958 }
    959 
    960 FeedbackPrimitiveTypeCase::IterateResult FeedbackPrimitiveTypeCase::iterate (void)
    961 {
    962 	tcu::Surface feedbackResult		(RENDER_SIZE, RENDER_SIZE);
    963 	tcu::Surface nonFeedbackResult	(RENDER_SIZE, RENDER_SIZE);
    964 
    965 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    966 
    967 	// render with and without XFB
    968 	renderWithFeedback(feedbackResult);
    969 	renderWithoutFeedback(nonFeedbackResult);
    970 
    971 	// compare
    972 	{
    973 		bool imageOk;
    974 
    975 		m_testCtx.getLog() << tcu::TestLog::Message << "Comparing the image rendered with no transform feedback against the image rendered with enabled transform feedback." << tcu::TestLog::EndMessage;
    976 
    977 		if (m_context.getRenderTarget().getNumSamples() > 1)
    978 			imageOk = tcu::fuzzyCompare(m_testCtx.getLog(),
    979 										"ImageCompare",
    980 										"Image comparison",
    981 										feedbackResult.getAccess(),
    982 										nonFeedbackResult.getAccess(),
    983 										0.03f,
    984 										tcu::COMPARE_LOG_RESULT);
    985 		else
    986 			imageOk = tcu::intThresholdPositionDeviationCompare(m_testCtx.getLog(),
    987 																"ImageCompare",
    988 																"Image comparison",
    989 																feedbackResult.getAccess(),
    990 																nonFeedbackResult.getAccess(),
    991 																tcu::UVec4(8, 8, 8, 255),						//!< threshold
    992 																tcu::IVec3(1, 1, 0),							//!< 3x3 search kernel
    993 																true,											//!< fragments may end up over the viewport, just ignore them
    994 																tcu::COMPARE_LOG_RESULT);
    995 
    996 		if (!imageOk)
    997 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    998 	}
    999 
   1000 	return STOP;
   1001 }
   1002 
   1003 void FeedbackPrimitiveTypeCase::renderWithFeedback(tcu::Surface& dst)
   1004 {
   1005 	const glw::Functions&			gl							= m_context.getRenderContext().getFunctions();
   1006 	const glu::VertexArray			vao							(m_context.getRenderContext());
   1007 	const glu::Query				primitivesGeneratedQuery	(m_context.getRenderContext());
   1008 	const int						posLocation					= gl.getAttribLocation(m_feedbackProgram->getProgram(), "a_position");
   1009 	const glw::GLenum				feedbackPrimitiveMode		= getOutputPrimitiveGLType();
   1010 
   1011 	if (posLocation == -1)
   1012 		throw tcu::TestError("a_position was -1");
   1013 
   1014 	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering with transform feedback" << tcu::TestLog::EndMessage;
   1015 
   1016 	gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
   1017 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1018 	gl.clear(GL_COLOR_BUFFER_BIT);
   1019 	GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
   1020 
   1021 	gl.bindVertexArray(*vao);
   1022 	gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
   1023 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   1024 	gl.enableVertexAttribArray(posLocation);
   1025 	GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
   1026 
   1027 	gl.useProgram(m_feedbackProgram->getProgram());
   1028 	GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
   1029 
   1030 	gl.patchParameteri(GL_PATCH_VERTICES, 4);
   1031 	GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
   1032 
   1033 	gl.beginQuery(GL_PRIMITIVES_GENERATED, *primitivesGeneratedQuery);
   1034 	GLU_EXPECT_NO_ERROR(gl.getError(), "begin GL_PRIMITIVES_GENERATED query");
   1035 
   1036 	m_testCtx.getLog() << tcu::TestLog::Message << "Begin transform feedback with mode " << glu::getPrimitiveTypeStr(feedbackPrimitiveMode) << tcu::TestLog::EndMessage;
   1037 
   1038 	gl.beginTransformFeedback(feedbackPrimitiveMode);
   1039 	GLU_EXPECT_NO_ERROR(gl.getError(), "begin xfb");
   1040 
   1041 	m_testCtx.getLog() << tcu::TestLog::Message << "Calling drawArrays with mode GL_PATCHES" << tcu::TestLog::EndMessage;
   1042 
   1043 	gl.drawArrays(GL_PATCHES, 0, 4);
   1044 	GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
   1045 
   1046 	gl.endTransformFeedback();
   1047 	GLU_EXPECT_NO_ERROR(gl.getError(), "end xfb");
   1048 
   1049 	gl.endQuery(GL_PRIMITIVES_GENERATED);
   1050 	GLU_EXPECT_NO_ERROR(gl.getError(), "end GL_PRIMITIVES_GENERATED query");
   1051 
   1052 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
   1053 	GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
   1054 
   1055 	// verify GL_PRIMITIVES_GENERATED
   1056 	{
   1057 		glw::GLuint primitivesGeneratedResult = 0;
   1058 		gl.getQueryObjectuiv(*primitivesGeneratedQuery, GL_QUERY_RESULT, &primitivesGeneratedResult);
   1059 		GLU_EXPECT_NO_ERROR(gl.getError(), "get GL_PRIMITIVES_GENERATED value");
   1060 
   1061 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying GL_PRIMITIVES_GENERATED, expecting " << getNumGeneratedPrimitives() << tcu::TestLog::EndMessage;
   1062 
   1063 		if ((int)primitivesGeneratedResult != getNumGeneratedPrimitives())
   1064 		{
   1065 			m_testCtx.getLog() << tcu::TestLog::Message << "Error, GL_PRIMITIVES_GENERATED was " << primitivesGeneratedResult << tcu::TestLog::EndMessage;
   1066 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected GL_PRIMITIVES_GENERATED");
   1067 		}
   1068 		else
   1069 			m_testCtx.getLog() << tcu::TestLog::Message << "GL_PRIMITIVES_GENERATED valid." << tcu::TestLog::EndMessage;
   1070 	}
   1071 
   1072 	// feedback
   1073 	{
   1074 		std::vector<tcu::Vec4>	feedbackResults		(getNumGeneratedElementsPerPrimitive() * getNumGeneratedPrimitives());
   1075 		const void*				mappedPtr			= gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, (glw::GLsizeiptr)(feedbackResults.size() * sizeof(tcu::Vec4)), GL_MAP_READ_BIT);
   1076 		glw::GLboolean			unmapResult;
   1077 
   1078 		GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
   1079 
   1080 		m_testCtx.getLog() << tcu::TestLog::Message << "Reading transform feedback buffer." << tcu::TestLog::EndMessage;
   1081 		if (!mappedPtr)
   1082 			throw tcu::TestError("mapBufferRange returned null");
   1083 
   1084 		deMemcpy(feedbackResults[0].getPtr(), mappedPtr, (int)(feedbackResults.size() * sizeof(tcu::Vec4)));
   1085 
   1086 		unmapResult = gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
   1087 		GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer");
   1088 
   1089 		if (unmapResult != GL_TRUE)
   1090 			throw tcu::TestError("unmapBuffer failed, did not return true");
   1091 
   1092 		// verify transform results
   1093 		verifyFeedbackResults(feedbackResults);
   1094 
   1095 		// verify feedback results are consistent with rendered image
   1096 		verifyRenderedImage(dst, feedbackResults);
   1097 	}
   1098 }
   1099 
   1100 void FeedbackPrimitiveTypeCase::renderWithoutFeedback (tcu::Surface& dst)
   1101 {
   1102 	const glw::Functions&			gl							= m_context.getRenderContext().getFunctions();
   1103 	const glu::VertexArray			vao							(m_context.getRenderContext());
   1104 	const int						posLocation					= gl.getAttribLocation(m_nonFeedbackProgram->getProgram(), "a_position");
   1105 
   1106 	if (posLocation == -1)
   1107 		throw tcu::TestError("a_position was -1");
   1108 
   1109 	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering without transform feedback" << tcu::TestLog::EndMessage;
   1110 
   1111 	gl.viewport(0, 0, dst.getWidth(), dst.getHeight());
   1112 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1113 	gl.clear(GL_COLOR_BUFFER_BIT);
   1114 	GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
   1115 
   1116 	gl.bindVertexArray(*vao);
   1117 	gl.bindBuffer(GL_ARRAY_BUFFER, m_patchBuffer);
   1118 	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
   1119 	gl.enableVertexAttribArray(posLocation);
   1120 	GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
   1121 
   1122 	gl.useProgram(m_nonFeedbackProgram->getProgram());
   1123 	GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
   1124 
   1125 	gl.patchParameteri(GL_PATCH_VERTICES, 4);
   1126 	GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
   1127 
   1128 	m_testCtx.getLog() << tcu::TestLog::Message << "Calling drawArrays with mode GL_PATCHES" << tcu::TestLog::EndMessage;
   1129 
   1130 	gl.drawArrays(GL_PATCHES, 0, 4);
   1131 	GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
   1132 
   1133 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
   1134 	GLU_EXPECT_NO_ERROR(gl.getError(), "readPixels");
   1135 }
   1136 
   1137 void FeedbackPrimitiveTypeCase::verifyFeedbackResults (const std::vector<tcu::Vec4>& feedbackResult)
   1138 {
   1139 	const int	geometryAmplification	= getGeometryAmplification();
   1140 	const int	elementsPerPrimitive	= getNumGeneratedElementsPerPrimitive();
   1141 	const int	errorFloodThreshold		= 8;
   1142 	int			readNdx					= 0;
   1143 	int			numErrors				= 0;
   1144 
   1145 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying feedback results." << tcu::TestLog::EndMessage;
   1146 
   1147 	for (int tessellatedPrimitiveNdx = 0; tessellatedPrimitiveNdx < getNumTessellatedPrimitives(); ++tessellatedPrimitiveNdx)
   1148 	{
   1149 		const tcu::Vec4	primitiveVertex = feedbackResult[readNdx];
   1150 
   1151 		// check the generated vertices are in the proper range (range: -0.4 <-> 0.4)
   1152 		{
   1153 			const float	equalThreshold	=	1.0e-6f;
   1154 			const bool	centroidOk		=	(primitiveVertex.x() >= -0.4f - equalThreshold) &&
   1155 											(primitiveVertex.x() <=  0.4f + equalThreshold) &&
   1156 											(primitiveVertex.y() >= -0.4f - equalThreshold) &&
   1157 											(primitiveVertex.y() <=  0.4f + equalThreshold) &&
   1158 											(de::abs(primitiveVertex.z()) < equalThreshold) &&
   1159 											(de::abs(primitiveVertex.w() - 1.0f) < equalThreshold);
   1160 
   1161 			if (!centroidOk && numErrors++ < errorFloodThreshold)
   1162 			{
   1163 				m_testCtx.getLog()
   1164 					<< tcu::TestLog::Message
   1165 					<< "Element at index " << (readNdx) << " (tessellation invocation " << tessellatedPrimitiveNdx << ")\n"
   1166 					<< "\texpected vertex in range: ( [-0.4, 0.4], [-0.4, 0.4], 0.0, 1.0 )\n"
   1167 					<< "\tgot: " << primitiveVertex
   1168 					<< tcu::TestLog::EndMessage;
   1169 
   1170 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid feedback output");
   1171 
   1172 				++readNdx;
   1173 				continue;
   1174 			}
   1175 		}
   1176 
   1177 		// check all other primitives generated from this tessellated primitive have the same feedback value
   1178 		for (int generatedPrimitiveNdx = 0; generatedPrimitiveNdx < geometryAmplification; ++generatedPrimitiveNdx)
   1179 		for (int primitiveVertexNdx = 0; primitiveVertexNdx < elementsPerPrimitive; ++primitiveVertexNdx)
   1180 		{
   1181 			const tcu::Vec4 generatedElementVertex	= feedbackResult[readNdx];
   1182 			const tcu::Vec4 equalThreshold			(1.0e-6f);
   1183 
   1184 			if (tcu::boolAny(tcu::greaterThan(tcu::abs(primitiveVertex - generatedElementVertex), equalThreshold)))
   1185 			{
   1186 				if (numErrors++ < errorFloodThreshold)
   1187 				{
   1188 					m_testCtx.getLog()
   1189 						<< tcu::TestLog::Message
   1190 						<< "Element at index " << (readNdx) << " (tessellation invocation " << tessellatedPrimitiveNdx << ", geometry primitive " << generatedPrimitiveNdx << ", emitted vertex " << primitiveVertexNdx << "):\n"
   1191 						<< "\tfeedback result was not contant over whole primitive.\n"
   1192 						<< "\tfirst emitted value: " << primitiveVertex << "\n"
   1193 						<< "\tcurrent emitted value:" << generatedElementVertex << "\n"
   1194 						<< tcu::TestLog::EndMessage;
   1195 				}
   1196 
   1197 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got multiple different feedback values for a single primitive");
   1198 			}
   1199 
   1200 			readNdx++;
   1201 		}
   1202 	}
   1203 
   1204 	if (numErrors > errorFloodThreshold)
   1205 		m_testCtx.getLog() << tcu::TestLog::Message << "Omitted " << (numErrors - errorFloodThreshold) << " error(s)." << tcu::TestLog::EndMessage;
   1206 }
   1207 
   1208 static bool feedbackResultCompare (const tcu::Vec4& a, const tcu::Vec4& b)
   1209 {
   1210 	if (a.x() < b.x())
   1211 		return true;
   1212 	if (a.x() > b.x())
   1213 		return false;
   1214 
   1215 	return a.y() < b.y();
   1216 }
   1217 
   1218 void FeedbackPrimitiveTypeCase::verifyRenderedImage (const tcu::Surface& image, const std::vector<tcu::Vec4>& tfVertices)
   1219 {
   1220 	std::vector<tcu::Vec4> vertices;
   1221 
   1222 	m_testCtx.getLog() << tcu::TestLog::Message << "Comparing result image against feedback results." << tcu::TestLog::EndMessage;
   1223 
   1224 	// Check only unique vertices
   1225 	std::unique_copy(tfVertices.begin(), tfVertices.end(), std::back_insert_iterator<std::vector<tcu::Vec4> >(vertices));
   1226 	std::sort(vertices.begin(), vertices.end(), feedbackResultCompare);
   1227 	vertices.erase(std::unique(vertices.begin(), vertices.end()), vertices.end());
   1228 
   1229 	// Verifying vertices recorded with feedback actually ended up on the result image
   1230 	for (int ndx = 0; ndx < (int)vertices.size(); ++ndx)
   1231 	{
   1232 		// Rasterization (of lines) may deviate by one pixel. In addition to that, allow minimal errors in rasterized position vs. feedback result.
   1233 		// This minimal error could result in a difference in rounding => allow one additional pixel in deviation
   1234 
   1235 		const int			rasterDeviation	= 2;
   1236 		const tcu::IVec2	rasterPos		((int)deFloatRound((vertices[ndx].x() * 0.5f + 0.5f) * image.getWidth()), (int)deFloatRound((vertices[ndx].y() * 0.5f + 0.5f) * image.getHeight()));
   1237 
   1238 		// Find produced rasterization results
   1239 		bool				found			= false;
   1240 
   1241 		for (int dy = -rasterDeviation; dy <= rasterDeviation && !found; ++dy)
   1242 		for (int dx = -rasterDeviation; dx <= rasterDeviation && !found; ++dx)
   1243 		{
   1244 			// Raster result could end up outside the viewport
   1245 			if (rasterPos.x() + dx < 0 || rasterPos.x() + dx >= image.getWidth() ||
   1246 				rasterPos.y() + dy < 0 || rasterPos.y() + dy >= image.getHeight())
   1247 				found = true;
   1248 			else
   1249 			{
   1250 				const tcu::RGBA result = image.getPixel(rasterPos.x() + dx, rasterPos.y() + dy);
   1251 
   1252 				if(!isBlack(result))
   1253 					found = true;
   1254 			}
   1255 		}
   1256 
   1257 		if (!found)
   1258 		{
   1259 			m_testCtx.getLog()
   1260 				<< tcu::TestLog::Message
   1261 				<< "Vertex " << vertices[ndx] << "\n"
   1262 				<< "\tCould not find rasterization output for vertex.\n"
   1263 				<< "\tExpected non-black pixels near " << rasterPos
   1264 				<< tcu::TestLog::EndMessage;
   1265 
   1266 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid result image");
   1267 		}
   1268 	}
   1269 }
   1270 
   1271 void FeedbackPrimitiveTypeCase::genTransformFeedback (void)
   1272 {
   1273 	const glw::Functions&			gl						= m_context.getRenderContext().getFunctions();
   1274 	const int						elementsPerPrimitive	= getNumGeneratedElementsPerPrimitive();
   1275 	const int						feedbackPrimitives		= getNumGeneratedPrimitives();
   1276 	const int						feedbackElements		= elementsPerPrimitive * feedbackPrimitives;
   1277 	const std::vector<tcu::Vec4>	initialBuffer			(feedbackElements, tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f));
   1278 
   1279 	gl.genTransformFeedbacks(1, &m_feedbackID);
   1280 	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_feedbackID);
   1281 	GLU_EXPECT_NO_ERROR(gl.getError(), "gen transform feedback");
   1282 
   1283 	gl.genBuffers(1, &m_feedbackBuffer);
   1284 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuffer);
   1285 	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(tcu::Vec4) * initialBuffer.size(), initialBuffer[0].getPtr(), GL_STATIC_COPY);
   1286 	GLU_EXPECT_NO_ERROR(gl.getError(), "gen feedback buffer");
   1287 
   1288 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuffer);
   1289 	GLU_EXPECT_NO_ERROR(gl.getError(), "bind feedback buffer");
   1290 }
   1291 
   1292 static int getTriangleNumOutputPrimitives (int tessellationLevel)
   1293 {
   1294 	if (tessellationLevel == 1)
   1295 		return 1;
   1296 	else if (tessellationLevel == 2)
   1297 		return 6;
   1298 	else
   1299 		return 3 * (2 + 2 * (tessellationLevel - 2)) + getTriangleNumOutputPrimitives(tessellationLevel - 2);
   1300 }
   1301 
   1302 static int getTriangleNumOutputPrimitivesPoints (int tessellationLevel)
   1303 {
   1304 	if (tessellationLevel == 0)
   1305 		return 1;
   1306 	else if (tessellationLevel == 1)
   1307 		return 3;
   1308 	else
   1309 		return 3 + 3 * (tessellationLevel - 1) + getTriangleNumOutputPrimitivesPoints(tessellationLevel - 2);
   1310 }
   1311 
   1312 int FeedbackPrimitiveTypeCase::getNumGeneratedElementsPerPrimitive (void) const
   1313 {
   1314 	if (m_geometryOutputType == GEOMETRY_OUTPUT_TRIANGLES)
   1315 		return 3;
   1316 	else if (m_geometryOutputType == GEOMETRY_OUTPUT_LINES)
   1317 		return 2;
   1318 	else if (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS)
   1319 		return 1;
   1320 	else
   1321 	{
   1322 		DE_ASSERT(false);
   1323 		return -1;
   1324 	}
   1325 }
   1326 
   1327 int FeedbackPrimitiveTypeCase::getNumGeneratedPrimitives (void) const
   1328 {
   1329 	return getNumTessellatedPrimitives() * getGeometryAmplification();
   1330 }
   1331 
   1332 int FeedbackPrimitiveTypeCase::getNumTessellatedPrimitives (void) const
   1333 {
   1334 	const int tessellationLevel = 3;
   1335 
   1336 	if (m_tessellationPointMode == TESSELLATION_POINTMODE_OFF)
   1337 	{
   1338 		if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
   1339 			return getTriangleNumOutputPrimitives(tessellationLevel);
   1340 		else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
   1341 			return tessellationLevel * tessellationLevel * 2; // tessellated as triangles
   1342 		else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
   1343 			return tessellationLevel * tessellationLevel;
   1344 	}
   1345 	else if (m_tessellationPointMode == TESSELLATION_POINTMODE_ON)
   1346 	{
   1347 		if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
   1348 			return getTriangleNumOutputPrimitivesPoints(tessellationLevel);
   1349 		else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
   1350 			return (tessellationLevel + 1) * (tessellationLevel + 1);
   1351 		else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
   1352 			return tessellationLevel * (tessellationLevel + 1);
   1353 	}
   1354 
   1355 	DE_ASSERT(false);
   1356 	return -1;
   1357 }
   1358 
   1359 int FeedbackPrimitiveTypeCase::getGeometryAmplification (void) const
   1360 {
   1361 	const int outputAmplification	= (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? (2) : (1);
   1362 	const int numInputVertices		= (m_tessellationPointMode) ? (1) : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? (2) : (3);
   1363 
   1364 	return outputAmplification * numInputVertices;
   1365 }
   1366 
   1367 glw::GLenum FeedbackPrimitiveTypeCase::getOutputPrimitiveGLType (void) const
   1368 {
   1369 	if (m_geometryOutputType == GEOMETRY_OUTPUT_TRIANGLES)
   1370 		return GL_TRIANGLES;
   1371 	else if (m_geometryOutputType == GEOMETRY_OUTPUT_LINES)
   1372 		return GL_LINES;
   1373 	else if (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS)
   1374 		return GL_POINTS;
   1375 	else
   1376 	{
   1377 		DE_ASSERT(false);
   1378 		return -1;
   1379 	}
   1380 }
   1381 
   1382 const char* FeedbackPrimitiveTypeCase::getVertexSource (void) const
   1383 {
   1384 	return s_positionVertexShader;
   1385 }
   1386 
   1387 const char* FeedbackPrimitiveTypeCase::getFragmentSource (void) const
   1388 {
   1389 	return s_whiteOutputFragmentShader;
   1390 }
   1391 
   1392 std::string FeedbackPrimitiveTypeCase::getTessellationControlSource (void) const
   1393 {
   1394 	std::ostringstream buf;
   1395 
   1396 	buf <<	"#version 310 es\n"
   1397 			"#extension GL_EXT_tessellation_shader : require\n"
   1398 			"layout(vertices = 9) out;\n"
   1399 			"\n"
   1400 			"uniform highp float u_innerTessellationLevel;\n"
   1401 			"uniform highp float u_outerTessellationLevel;\n"
   1402 			"\n"
   1403 			"void main (void)\n"
   1404 			"{\n"
   1405 			"	if (gl_PatchVerticesIn != 4)\n"
   1406 			"		return;\n"
   1407 			"\n"
   1408 			"	// Convert input 2x2 grid to 3x3 grid\n"
   1409 			"	float xweight = float(gl_InvocationID % 3) / 2.0f;\n"
   1410 			"	float yweight = float(gl_InvocationID / 3) / 2.0f;\n"
   1411 			"\n"
   1412 			"	vec4 y0 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, yweight);\n"
   1413 			"	vec4 y1 = mix(gl_in[2].gl_Position, gl_in[3].gl_Position, yweight);\n"
   1414 			"\n"
   1415 			"	gl_out[gl_InvocationID].gl_Position = mix(y0, y1, xweight);\n"
   1416 			"\n";
   1417 
   1418 	if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
   1419 		buf <<	"	gl_TessLevelOuter[0] = 3.0;\n"
   1420 				"	gl_TessLevelOuter[1] = 3.0;\n"
   1421 				"	gl_TessLevelOuter[2] = 3.0;\n"
   1422 				"	gl_TessLevelInner[0] = 3.0;\n";
   1423 	else if (m_tessellationOutput == TESSELLATION_OUT_QUADS)
   1424 		buf <<	"	gl_TessLevelOuter[0] = 3.0;\n"
   1425 				"	gl_TessLevelOuter[1] = 3.0;\n"
   1426 				"	gl_TessLevelOuter[2] = 3.0;\n"
   1427 				"	gl_TessLevelOuter[3] = 3.0;\n"
   1428 				"	gl_TessLevelInner[0] = 3.0;\n"
   1429 				"	gl_TessLevelInner[1] = 3.0;\n";
   1430 	else if (m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
   1431 		buf <<	"	gl_TessLevelOuter[0] = 3.0;\n"
   1432 				"	gl_TessLevelOuter[1] = 3.0;\n";
   1433 	else
   1434 		DE_ASSERT(false);
   1435 
   1436 	buf <<	"}\n";
   1437 
   1438 	return buf.str();
   1439 }
   1440 
   1441 std::string FeedbackPrimitiveTypeCase::getTessellationEvaluationSource (void) const
   1442 {
   1443 	std::ostringstream buf;
   1444 
   1445 	buf <<	"#version 310 es\n"
   1446 			"#extension GL_EXT_tessellation_shader : require\n"
   1447 			"layout("
   1448 				<< ((m_tessellationOutput == TESSELLATION_OUT_TRIANGLES) ? ("triangles") : (m_tessellationOutput == TESSELLATION_OUT_QUADS) ? ("quads") : ("isolines"))
   1449 				<< ((m_tessellationPointMode) ? (", point_mode") : (""))
   1450 				<< ") in;\n"
   1451 			"\n"
   1452 			"out highp vec4 v_tessellationCoords;\n"
   1453 			"\n"
   1454 			"// note: No need to use precise gl_Position since we do not require gapless geometry\n"
   1455 			"void main (void)\n"
   1456 			"{\n"
   1457 			"	if (gl_PatchVerticesIn != 9)\n"
   1458 			"		return;\n"
   1459 			"\n"
   1460 			"	vec4 patchCentroid = vec4(0.0);\n"
   1461 			"	for (int ndx = 0; ndx < gl_PatchVerticesIn; ++ndx)\n"
   1462 			"		patchCentroid += gl_in[ndx].gl_Position;\n"
   1463 			"	patchCentroid /= patchCentroid.w;\n"
   1464 			"\n";
   1465 
   1466 	if (m_tessellationOutput == TESSELLATION_OUT_TRIANGLES)
   1467 		buf <<	"	// map barycentric coords to 2d coords\n"
   1468 				"	const vec3 tessDirX = vec3( 0.4,  0.4, 0.0);\n"
   1469 				"	const vec3 tessDirY = vec3( 0.0, -0.4, 0.0);\n"
   1470 				"	const vec3 tessDirZ = vec3(-0.4,  0.4, 0.0);\n"
   1471 				"	gl_Position = patchCentroid + vec4(gl_TessCoord.x * tessDirX + gl_TessCoord.y * tessDirY + gl_TessCoord.z * tessDirZ, 0.0);\n";
   1472 	else if (m_tessellationOutput == TESSELLATION_OUT_QUADS || m_tessellationOutput == TESSELLATION_OUT_ISOLINES)
   1473 		buf <<	"	gl_Position = patchCentroid + vec4(gl_TessCoord.x * 0.8 - 0.4, gl_TessCoord.y * 0.8 - 0.4, 0.0, 0.0);\n";
   1474 	else
   1475 		DE_ASSERT(false);
   1476 
   1477 	buf <<	"	v_tessellationCoords = vec4(gl_TessCoord, 0.0);\n"
   1478 			"}\n";
   1479 
   1480 	return buf.str();
   1481 }
   1482 
   1483 std::string FeedbackPrimitiveTypeCase::getGeometrySource (void) const
   1484 {
   1485 	const char* const	geometryInputPrimitive			= (m_tessellationPointMode) ? ("points") : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? ("lines") : ("triangles");
   1486 	const char* const	geometryOutputPrimitive			= (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS) ? ("points") : (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? ("line_strip") : ("triangle_strip");
   1487 	const int			numInputVertices				= (m_tessellationPointMode) ? (1) : (m_tessellationOutput == TESSELLATION_OUT_ISOLINES) ? (2) : (3);
   1488 	const int			numSingleVertexOutputVertices	= (m_geometryOutputType == GEOMETRY_OUTPUT_POINTS) ? (1) : (m_geometryOutputType == GEOMETRY_OUTPUT_LINES) ? (4) : (3);
   1489 	const int			numEmitVertices					= numInputVertices * numSingleVertexOutputVertices;
   1490 	std::ostringstream	buf;
   1491 
   1492 	buf <<	"#version 310 es\n"
   1493 			"#extension GL_EXT_geometry_shader : require\n"
   1494 			"layout(" << geometryInputPrimitive << ") in;\n"
   1495 			"layout(" << geometryOutputPrimitive << ", max_vertices=" << numEmitVertices <<") out;\n"
   1496 			"\n"
   1497 			"in highp vec4 v_tessellationCoords[];\n"
   1498 			"out highp vec4 tf_someVertexPosition;\n"
   1499 			"\n"
   1500 			"void main (void)\n"
   1501 			"{\n"
   1502 			"	// Emit primitive\n"
   1503 			"	for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
   1504 			"	{\n";
   1505 
   1506 	switch (m_geometryOutputType)
   1507 	{
   1508 		case GEOMETRY_OUTPUT_POINTS:
   1509 			buf <<	"		// Draw point on vertex\n"
   1510 					"		gl_Position = gl_in[ndx].gl_Position;\n"
   1511 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1512 					"		EmitVertex();\n";
   1513 			break;
   1514 
   1515 		case GEOMETRY_OUTPUT_LINES:
   1516 			buf <<	"		// Draw cross on vertex\n"
   1517 					"		gl_Position = gl_in[ndx].gl_Position + vec4(-0.02, -0.02, 0.0, 0.0);\n"
   1518 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1519 					"		EmitVertex();\n"
   1520 					"		gl_Position = gl_in[ndx].gl_Position + vec4( 0.02,  0.02, 0.0, 0.0);\n"
   1521 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1522 					"		EmitVertex();\n"
   1523 					"		EndPrimitive();\n"
   1524 					"		gl_Position = gl_in[ndx].gl_Position + vec4( 0.02, -0.02, 0.0, 0.0);\n"
   1525 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1526 					"		EmitVertex();\n"
   1527 					"		gl_Position = gl_in[ndx].gl_Position + vec4(-0.02,  0.02, 0.0, 0.0);\n"
   1528 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1529 					"		EmitVertex();\n"
   1530 					"		EndPrimitive();\n";
   1531 			break;
   1532 
   1533 		case GEOMETRY_OUTPUT_TRIANGLES:
   1534 			buf <<	"		// Draw triangle on vertex\n"
   1535 					"		gl_Position = gl_in[ndx].gl_Position + vec4(  0.00, -0.02, 0.0, 0.0);\n"
   1536 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1537 					"		EmitVertex();\n"
   1538 					"		gl_Position = gl_in[ndx].gl_Position + vec4(  0.02,  0.00, 0.0, 0.0);\n"
   1539 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1540 					"		EmitVertex();\n"
   1541 					"		gl_Position = gl_in[ndx].gl_Position + vec4( -0.02,  0.00, 0.0, 0.0);\n"
   1542 					"		tf_someVertexPosition = gl_in[gl_in.length() - 1].gl_Position;\n"
   1543 					"		EmitVertex();\n"
   1544 					"		EndPrimitive();\n";
   1545 			break;
   1546 
   1547 		default:
   1548 			DE_ASSERT(false);
   1549 			return "";
   1550 	}
   1551 
   1552 	buf <<	"	}\n"
   1553 			"}\n";
   1554 
   1555 	return buf.str();
   1556 }
   1557 
   1558 const char* FeedbackPrimitiveTypeCase::getTessellationOutputDescription (TessellationOutputType tessellationOutput, TessellationPointMode pointMode)
   1559 {
   1560 	switch (tessellationOutput)
   1561 	{
   1562 		case TESSELLATION_OUT_TRIANGLES:	return (pointMode) ? ("points (triangles in point mode)") : ("triangles");
   1563 		case TESSELLATION_OUT_QUADS:		return (pointMode) ? ("points (quads in point mode)")     : ("quads");
   1564 		case TESSELLATION_OUT_ISOLINES:		return (pointMode) ? ("points (isolines in point mode)")  : ("isolines");
   1565 		default:
   1566 			DE_ASSERT(false);
   1567 			return DE_NULL;
   1568 	}
   1569 }
   1570 
   1571 const char* FeedbackPrimitiveTypeCase::getGeometryInputDescription (TessellationOutputType tessellationOutput, TessellationPointMode pointMode)
   1572 {
   1573 	switch (tessellationOutput)
   1574 	{
   1575 		case TESSELLATION_OUT_TRIANGLES:	return (pointMode) ? ("points") : ("triangles");
   1576 		case TESSELLATION_OUT_QUADS:		return (pointMode) ? ("points") : ("triangles");
   1577 		case TESSELLATION_OUT_ISOLINES:		return (pointMode) ? ("points") : ("lines");
   1578 		default:
   1579 			DE_ASSERT(false);
   1580 			return DE_NULL;
   1581 	}
   1582 }
   1583 
   1584 const char* FeedbackPrimitiveTypeCase::getGeometryOutputDescription (GeometryOutputType geometryOutput)
   1585 {
   1586 	switch (geometryOutput)
   1587 	{
   1588 		case GEOMETRY_OUTPUT_POINTS:		return "points";
   1589 		case GEOMETRY_OUTPUT_LINES:			return "lines";
   1590 		case GEOMETRY_OUTPUT_TRIANGLES:		return "triangles";
   1591 		default:
   1592 			DE_ASSERT(false);
   1593 			return DE_NULL;
   1594 	}
   1595 }
   1596 
   1597 class PointSizeCase : public TestCase
   1598 {
   1599 public:
   1600 	enum Flags
   1601 	{
   1602 		FLAG_VERTEX_SET						= 0x01,		// !< set gl_PointSize in vertex shader
   1603 		FLAG_TESSELLATION_CONTROL_SET		= 0x02,		// !< set gl_PointSize in tessellation evaluation shader
   1604 		FLAG_TESSELLATION_EVALUATION_SET	= 0x04,		// !< set gl_PointSize in tessellation control shader
   1605 		FLAG_TESSELLATION_ADD				= 0x08,		// !< read and add to gl_PointSize in tessellation shader pair
   1606 		FLAG_TESSELLATION_DONT_SET			= 0x10,		// !< don't set gl_PointSize in tessellation shader
   1607 		FLAG_GEOMETRY_SET					= 0x20,		// !< set gl_PointSize in geometry shader
   1608 		FLAG_GEOMETRY_ADD					= 0x40,		// !< read and add to gl_PointSize in geometry shader
   1609 		FLAG_GEOMETRY_DONT_SET				= 0x80,		// !< don't set gl_PointSize in geometry shader
   1610 	};
   1611 
   1612 						PointSizeCase					(Context& context, const char* name, const char* description, int flags);
   1613 						~PointSizeCase					(void);
   1614 
   1615 	static std::string	genTestCaseName					(int flags);
   1616 	static std::string	genTestCaseDescription			(int flags);
   1617 
   1618 private:
   1619 	void				init							(void);
   1620 	void				deinit							(void);
   1621 	IterateResult		iterate							(void);
   1622 
   1623 	void				checkExtensions					(void) const;
   1624 	void				checkPointSizeRequirements		(void) const;
   1625 
   1626 	void				renderTo						(tcu::Surface& dst);
   1627 	bool				verifyImage						(const tcu::Surface& src);
   1628 	int					getExpectedPointSize			(void) const;
   1629 
   1630 	std::string			genVertexSource					(void) const;
   1631 	const char*			genFragmentSource				(void) const;
   1632 	std::string			genTessellationControlSource	(void) const;
   1633 	std::string			genTessellationEvaluationSource	(void) const;
   1634 	std::string			genGeometrySource				(void) const;
   1635 
   1636 	enum
   1637 	{
   1638 		RENDER_SIZE = 32,
   1639 	};
   1640 
   1641 	const int			m_flags;
   1642 	glu::ShaderProgram*	m_program;
   1643 };
   1644 
   1645 PointSizeCase::PointSizeCase (Context& context, const char* name, const char* description, int flags)
   1646 	: TestCase	(context, name, description)
   1647 	, m_flags	(flags)
   1648 	, m_program	(DE_NULL)
   1649 {
   1650 }
   1651 
   1652 PointSizeCase::~PointSizeCase (void)
   1653 {
   1654 	deinit();
   1655 }
   1656 
   1657 std::string PointSizeCase::genTestCaseName (int flags)
   1658 {
   1659 	std::ostringstream buf;
   1660 
   1661 	// join per-bit descriptions into a single string with '_' separator
   1662 	if (flags & FLAG_VERTEX_SET)					buf																		<< "vertex_set";
   1663 	if (flags & FLAG_TESSELLATION_CONTROL_SET)		buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1))		? ("_") : (""))	<< "control_set";
   1664 	if (flags & FLAG_TESSELLATION_EVALUATION_SET)	buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1))	? ("_") : (""))	<< "evaluation_set";
   1665 	if (flags & FLAG_TESSELLATION_ADD)				buf << ((flags & (FLAG_TESSELLATION_ADD-1))				? ("_") : (""))	<< "control_pass_eval_add";
   1666 	if (flags & FLAG_TESSELLATION_DONT_SET)			buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1))		? ("_") : (""))	<< "eval_default";
   1667 	if (flags & FLAG_GEOMETRY_SET)					buf << ((flags & (FLAG_GEOMETRY_SET-1))					? ("_") : (""))	<< "geometry_set";
   1668 	if (flags & FLAG_GEOMETRY_ADD)					buf << ((flags & (FLAG_GEOMETRY_ADD-1))					? ("_") : (""))	<< "geometry_add";
   1669 	if (flags & FLAG_GEOMETRY_DONT_SET)				buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1))			? ("_") : (""))	<< "geometry_default";
   1670 
   1671 	return buf.str();
   1672 }
   1673 
   1674 std::string PointSizeCase::genTestCaseDescription (int flags)
   1675 {
   1676 	std::ostringstream buf;
   1677 
   1678 	// join per-bit descriptions into a single string with ", " separator
   1679 	if (flags & FLAG_VERTEX_SET)					buf																			<< "set point size in vertex shader";
   1680 	if (flags & FLAG_TESSELLATION_CONTROL_SET)		buf << ((flags & (FLAG_TESSELLATION_CONTROL_SET-1))		? (", ") : (""))	<< "set point size in tessellation control shader";
   1681 	if (flags & FLAG_TESSELLATION_EVALUATION_SET)	buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1))	? (", ") : (""))	<< "set point size in tessellation evaluation shader";
   1682 	if (flags & FLAG_TESSELLATION_ADD)				buf << ((flags & (FLAG_TESSELLATION_ADD-1))				? (", ") : (""))	<< "add to point size in tessellation shader";
   1683 	if (flags & FLAG_TESSELLATION_DONT_SET)			buf << ((flags & (FLAG_TESSELLATION_DONT_SET-1))		? (", ") : (""))	<< "don't set point size in tessellation evaluation shader";
   1684 	if (flags & FLAG_GEOMETRY_SET)					buf << ((flags & (FLAG_GEOMETRY_SET-1))					? (", ") : (""))	<< "set point size in geometry shader";
   1685 	if (flags & FLAG_GEOMETRY_ADD)					buf << ((flags & (FLAG_GEOMETRY_ADD-1))					? (", ") : (""))	<< "add to point size in geometry shader";
   1686 	if (flags & FLAG_GEOMETRY_DONT_SET)				buf << ((flags & (FLAG_GEOMETRY_DONT_SET-1))			? (", ") : (""))	<< "don't set point size in geometry shader";
   1687 
   1688 	return buf.str();
   1689 }
   1690 
   1691 void PointSizeCase::init (void)
   1692 {
   1693 	checkExtensions();
   1694 	checkPointSizeRequirements();
   1695 
   1696 	// log
   1697 
   1698 	if (m_flags & FLAG_VERTEX_SET)
   1699 		m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in vertex shader to 2.0." << tcu::TestLog::EndMessage;
   1700 	if (m_flags & FLAG_TESSELLATION_CONTROL_SET)
   1701 		m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in tessellation control shader to 4.0. (And ignoring it in evaluation)." << tcu::TestLog::EndMessage;
   1702 	if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
   1703 		m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in tessellation evaluation shader to 4.0." << tcu::TestLog::EndMessage;
   1704 	if (m_flags & FLAG_TESSELLATION_ADD)
   1705 		m_testCtx.getLog() << tcu::TestLog::Message << "Reading point size in tessellation control shader and adding 2.0 to it in evaluation." << tcu::TestLog::EndMessage;
   1706 	if (m_flags & FLAG_TESSELLATION_DONT_SET)
   1707 		m_testCtx.getLog() << tcu::TestLog::Message << "Not setting point size in tessellation evaluation shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
   1708 	if (m_flags & FLAG_GEOMETRY_SET)
   1709 		m_testCtx.getLog() << tcu::TestLog::Message << "Setting point size in geometry shader to 6.0." << tcu::TestLog::EndMessage;
   1710 	if (m_flags & FLAG_GEOMETRY_ADD)
   1711 		m_testCtx.getLog() << tcu::TestLog::Message << "Reading point size in geometry shader and adding 2.0." << tcu::TestLog::EndMessage;
   1712 	if (m_flags & FLAG_GEOMETRY_DONT_SET)
   1713 		m_testCtx.getLog() << tcu::TestLog::Message << "Not setting point size in geometry shader (resulting in the default point size)." << tcu::TestLog::EndMessage;
   1714 
   1715 	// program
   1716 
   1717 	{
   1718 		glu::ProgramSources sources;
   1719 		sources	<< glu::VertexSource(genVertexSource())
   1720 				<< glu::FragmentSource(genFragmentSource());
   1721 
   1722 		if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET))
   1723 			sources << glu::TessellationControlSource(genTessellationControlSource())
   1724 					<< glu::TessellationEvaluationSource(genTessellationEvaluationSource());
   1725 
   1726 		if (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD | FLAG_GEOMETRY_DONT_SET))
   1727 			sources << glu::GeometrySource(genGeometrySource());
   1728 
   1729 		m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
   1730 
   1731 		m_testCtx.getLog() << *m_program;
   1732 		if (!m_program->isOk())
   1733 			throw tcu::TestError("failed to build program");
   1734 	}
   1735 }
   1736 
   1737 void PointSizeCase::deinit (void)
   1738 {
   1739 	delete m_program;
   1740 	m_program = DE_NULL;
   1741 }
   1742 
   1743 PointSizeCase::IterateResult PointSizeCase::iterate (void)
   1744 {
   1745 	tcu::Surface resultImage(RENDER_SIZE, RENDER_SIZE);
   1746 
   1747 	renderTo(resultImage);
   1748 
   1749 	if (verifyImage(resultImage))
   1750 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   1751 	else
   1752 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
   1753 
   1754 	return STOP;
   1755 }
   1756 
   1757 void PointSizeCase::checkExtensions (void) const
   1758 {
   1759 	std::vector<std::string>	requiredExtensions;
   1760 	bool						allOk				= true;
   1761 
   1762 	if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET))
   1763 		requiredExtensions.push_back("GL_EXT_tessellation_shader");
   1764 
   1765 	if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD))
   1766 		requiredExtensions.push_back("GL_EXT_tessellation_point_size");
   1767 
   1768 	if (m_flags & (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD | FLAG_GEOMETRY_DONT_SET)))
   1769 		requiredExtensions.push_back("GL_EXT_geometry_shader");
   1770 
   1771 	if (m_flags & (m_flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD)))
   1772 		requiredExtensions.push_back("GL_EXT_geometry_point_size");
   1773 
   1774 	for (int ndx = 0; ndx < (int)requiredExtensions.size(); ++ndx)
   1775 		if (!m_context.getContextInfo().isExtensionSupported(requiredExtensions[ndx].c_str()))
   1776 			allOk = false;
   1777 
   1778 	if (!allOk)
   1779 	{
   1780 		std::ostringstream extensionList;
   1781 
   1782 		for (int ndx = 0; ndx < (int)requiredExtensions.size(); ++ndx)
   1783 		{
   1784 			if (ndx != 0)
   1785 				extensionList << ", ";
   1786 			extensionList << requiredExtensions[ndx];
   1787 		}
   1788 
   1789 		throw tcu::NotSupportedError("Test requires {" + extensionList.str() + "} extension(s)");
   1790 	}
   1791 }
   1792 
   1793 void PointSizeCase::checkPointSizeRequirements (void) const
   1794 {
   1795 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   1796 	float					aliasedSizeRange[2]	= { 0.0f, 0.0f };
   1797 	const int				requiredSize		= getExpectedPointSize();
   1798 
   1799 	gl.getFloatv(GL_ALIASED_POINT_SIZE_RANGE, aliasedSizeRange);
   1800 
   1801 	if (float(requiredSize) > aliasedSizeRange[1])
   1802 		throw tcu::NotSupportedError("Test requires point size " + de::toString(requiredSize));
   1803 }
   1804 
   1805 void PointSizeCase::renderTo (tcu::Surface& dst)
   1806 {
   1807 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
   1808 	const bool				tessellationActive	= (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD | FLAG_TESSELLATION_DONT_SET)) != 0;
   1809 	const int				positionLocation	= gl.getAttribLocation(m_program->getProgram(), "a_position");
   1810 	const glu::VertexArray	vao					(m_context.getRenderContext());
   1811 
   1812 	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point." << tcu::TestLog::EndMessage;
   1813 
   1814 	if (positionLocation == -1)
   1815 		throw tcu::TestError("Attribute a_position location was -1");
   1816 
   1817 	gl.viewport(0, 0, RENDER_SIZE, RENDER_SIZE);
   1818 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   1819 	gl.clear(GL_COLOR_BUFFER_BIT);
   1820 	GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
   1821 
   1822 	gl.bindVertexArray(*vao);
   1823 	GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
   1824 
   1825 	gl.useProgram(m_program->getProgram());
   1826 	GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
   1827 
   1828 	gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
   1829 
   1830 	if (tessellationActive)
   1831 	{
   1832 		gl.patchParameteri(GL_PATCH_VERTICES, 1);
   1833 		GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
   1834 
   1835 		gl.drawArrays(GL_PATCHES, 0, 1);
   1836 		GLU_EXPECT_NO_ERROR(gl.getError(), "draw patches");
   1837 	}
   1838 	else
   1839 	{
   1840 		gl.drawArrays(GL_POINTS, 0, 1);
   1841 		GLU_EXPECT_NO_ERROR(gl.getError(), "draw points");
   1842 	}
   1843 
   1844 	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
   1845 }
   1846 
   1847 bool PointSizeCase::verifyImage (const tcu::Surface& src)
   1848 {
   1849 	const bool MSAATarget	= (m_context.getRenderTarget().getNumSamples() > 1);
   1850 	const int expectedSize	= getExpectedPointSize();
   1851 
   1852 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying rendered point size. Expecting " << expectedSize << " pixels." << tcu::TestLog::EndMessage;
   1853 	m_testCtx.getLog() << tcu::TestLog::Image("RenderImage", "Rendered image", src.getAccess());
   1854 
   1855 	{
   1856 		bool		resultAreaFound	= false;
   1857 		tcu::IVec4	resultArea;
   1858 
   1859 		// Find rasterization output area
   1860 
   1861 		for (int y = 0; y < src.getHeight(); ++y)
   1862 		for (int x = 0; x < src.getWidth();  ++x)
   1863 		{
   1864 			if (!isBlack(src.getPixel(x, y)))
   1865 			{
   1866 				if (!resultAreaFound)
   1867 				{
   1868 					// first fragment
   1869 					resultArea = tcu::IVec4(x, y, x + 1, y + 1);
   1870 					resultAreaFound = true;
   1871 				}
   1872 				else
   1873 				{
   1874 					// union area
   1875 					resultArea.x() = de::min(resultArea.x(), x);
   1876 					resultArea.y() = de::min(resultArea.y(), y);
   1877 					resultArea.z() = de::max(resultArea.z(), x+1);
   1878 					resultArea.w() = de::max(resultArea.w(), y+1);
   1879 				}
   1880 			}
   1881 		}
   1882 
   1883 		if (!resultAreaFound)
   1884 		{
   1885 			m_testCtx.getLog() << tcu::TestLog::Message << "Verification failed, could not find any point fragments." << tcu::TestLog::EndMessage;
   1886 			return false;
   1887 		}
   1888 
   1889 		// verify area size
   1890 		if (MSAATarget)
   1891 		{
   1892 			const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
   1893 
   1894 			// MSAA: edges may be a little fuzzy
   1895 			if (de::abs(pointSize.x() - pointSize.y()) > 1)
   1896 			{
   1897 				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Detected point size was " << pointSize << tcu::TestLog::EndMessage;
   1898 				return false;
   1899 			}
   1900 
   1901 			// MSAA may produce larger areas, allow one pixel larger
   1902 			if (expectedSize != de::max(pointSize.x(), pointSize.y()) && (expectedSize+1) != de::max(pointSize.x(), pointSize.y()))
   1903 			{
   1904 				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << de::max(pointSize.x(), pointSize.y()) << tcu::TestLog::EndMessage;
   1905 				return false;
   1906 			}
   1907 		}
   1908 		else
   1909 		{
   1910 			const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
   1911 
   1912 			if (pointSize.x() != pointSize.y())
   1913 			{
   1914 				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Point size was " << pointSize << tcu::TestLog::EndMessage;
   1915 				return false;
   1916 			}
   1917 
   1918 			if (pointSize.x() != expectedSize)
   1919 			{
   1920 				m_testCtx.getLog() << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << pointSize.x() << tcu::TestLog::EndMessage;
   1921 				return false;
   1922 			}
   1923 		}
   1924 	}
   1925 
   1926 	return true;
   1927 }
   1928 
   1929 int PointSizeCase::getExpectedPointSize (void) const
   1930 {
   1931 	int addition = 0;
   1932 
   1933 	// geometry
   1934 	if (m_flags & FLAG_GEOMETRY_DONT_SET)
   1935 		return 1;
   1936 	else if (m_flags & FLAG_GEOMETRY_SET)
   1937 		return 6;
   1938 	else if (m_flags & FLAG_GEOMETRY_ADD)
   1939 		addition += 2;
   1940 
   1941 	// tessellation
   1942 	if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
   1943 		return 4 + addition;
   1944 	else if (m_flags & FLAG_TESSELLATION_ADD)
   1945 		addition += 2;
   1946 	else if (m_flags & (FLAG_TESSELLATION_CONTROL_SET | FLAG_TESSELLATION_DONT_SET))
   1947 	{
   1948 		DE_ASSERT((m_flags & FLAG_GEOMETRY_ADD) == 0); // reading pointSize undefined
   1949 		return 1;
   1950 	}
   1951 
   1952 	// vertex
   1953 	if (m_flags & FLAG_VERTEX_SET)
   1954 		return 2 + addition;
   1955 
   1956 	// undefined
   1957 	DE_ASSERT(false);
   1958 	return -1;
   1959 }
   1960 
   1961 std::string PointSizeCase::genVertexSource (void) const
   1962 {
   1963 	std::ostringstream buf;
   1964 
   1965 	buf	<< "#version 310 es\n"
   1966 		<< "in highp vec4 a_position;\n"
   1967 		<< "void main ()\n"
   1968 		<< "{\n"
   1969 		<< "	gl_Position = a_position;\n";
   1970 
   1971 	if (m_flags & FLAG_VERTEX_SET)
   1972 		buf << "	gl_PointSize = 2.0;\n";
   1973 
   1974 	buf	<< "}\n";
   1975 
   1976 	return buf.str();
   1977 }
   1978 
   1979 const char* PointSizeCase::genFragmentSource (void) const
   1980 {
   1981 	return s_whiteOutputFragmentShader;
   1982 }
   1983 
   1984 std::string PointSizeCase::genTessellationControlSource (void) const
   1985 {
   1986 	std::ostringstream buf;
   1987 
   1988 	buf	<< "#version 310 es\n"
   1989 		<< "#extension GL_EXT_tessellation_shader : require\n"
   1990 		<< ((m_flags & FLAG_TESSELLATION_DONT_SET) ? ("") : ("#extension GL_EXT_tessellation_point_size : require\n"))
   1991 		<< "layout(vertices = 1) out;\n"
   1992 		<< "void main ()\n"
   1993 		<< "{\n"
   1994 		<< "	gl_TessLevelOuter[0] = 3.0;\n"
   1995 		<< "	gl_TessLevelOuter[1] = 3.0;\n"
   1996 		<< "	gl_TessLevelOuter[2] = 3.0;\n"
   1997 		<< "	gl_TessLevelInner[0] = 3.0;\n"
   1998 		<< "	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n";
   1999 
   2000 	if (m_flags & FLAG_TESSELLATION_ADD)
   2001 		buf << "	// pass as is to eval\n"
   2002 			<< "	gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n";
   2003 	else if (m_flags & FLAG_TESSELLATION_CONTROL_SET)
   2004 		buf << "	// thrown away\n"
   2005 			<< "	gl_out[gl_InvocationID].gl_PointSize = 4.0;\n";
   2006 
   2007 	buf	<< "}\n";
   2008 
   2009 	return buf.str();
   2010 }
   2011 
   2012 std::string PointSizeCase::genTessellationEvaluationSource (void) const
   2013 {
   2014 	std::ostringstream buf;
   2015 
   2016 	buf	<< "#version 310 es\n"
   2017 		<< "#extension GL_EXT_tessellation_shader : require\n"
   2018 		<< ((m_flags & FLAG_TESSELLATION_DONT_SET) ? ("") : ("#extension GL_EXT_tessellation_point_size : require\n"))
   2019 		<< "layout(triangles, point_mode) in;\n"
   2020 		<< "void main ()\n"
   2021 		<< "{\n"
   2022 		<< "	// hide all but one vertex\n"
   2023 		<< "	if (gl_TessCoord.x < 0.99)\n"
   2024 		<< "		gl_Position = vec4(-2.0, 0.0, 0.0, 1.0);\n"
   2025 		<< "	else\n"
   2026 		<< "		gl_Position = gl_in[0].gl_Position;\n";
   2027 
   2028 	if (m_flags & FLAG_TESSELLATION_ADD)
   2029 		buf << "\n"
   2030 			<< "	// add to point size\n"
   2031 			<< "	gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
   2032 	else if (m_flags & FLAG_TESSELLATION_EVALUATION_SET)
   2033 		buf << "\n"
   2034 			<< "	// set point size\n"
   2035 			<< "	gl_PointSize = 4.0;\n";
   2036 
   2037 	buf	<< "}\n";
   2038 
   2039 	return buf.str();
   2040 }
   2041 
   2042 std::string PointSizeCase::genGeometrySource (void) const
   2043 {
   2044 	std::ostringstream buf;
   2045 
   2046 	buf	<< "#version 310 es\n"
   2047 		<< "#extension GL_EXT_geometry_shader : require\n"
   2048 		<< ((m_flags & FLAG_GEOMETRY_DONT_SET) ? ("") : ("#extension GL_EXT_geometry_point_size : require\n"))
   2049 		<< "layout (points) in;\n"
   2050 		<< "layout (points, max_vertices=1) out;\n"
   2051 		<< "\n"
   2052 		<< "void main ()\n"
   2053 		<< "{\n";
   2054 
   2055 	if (m_flags & FLAG_GEOMETRY_SET)
   2056 		buf	<< "	gl_Position = gl_in[0].gl_Position;\n"
   2057 			<< "	gl_PointSize = 6.0;\n";
   2058 	else if (m_flags & FLAG_GEOMETRY_ADD)
   2059 		buf	<< "	gl_Position = gl_in[0].gl_Position;\n"
   2060 			<< "	gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
   2061 	else if (m_flags & FLAG_GEOMETRY_DONT_SET)
   2062 		buf	<< "	gl_Position = gl_in[0].gl_Position;\n";
   2063 
   2064 	buf	<< "	EmitVertex();\n"
   2065 		<< "}\n";
   2066 
   2067 	return buf.str();
   2068 }
   2069 
   2070 class AllowedRenderFailureException : public std::runtime_error
   2071 {
   2072 public:
   2073 	AllowedRenderFailureException (const char* message) : std::runtime_error(message) { }
   2074 };
   2075 
   2076 class GridRenderCase : public TestCase
   2077 {
   2078 public:
   2079 	enum Flags
   2080 	{
   2081 		FLAG_TESSELLATION_MAX_SPEC						= 0x0001,
   2082 		FLAG_TESSELLATION_MAX_IMPLEMENTATION			= 0x0002,
   2083 		FLAG_GEOMETRY_MAX_SPEC							= 0x0004,
   2084 		FLAG_GEOMETRY_MAX_IMPLEMENTATION				= 0x0008,
   2085 		FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC				= 0x0010,
   2086 		FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION	= 0x0020,
   2087 
   2088 		FLAG_GEOMETRY_SCATTER_INSTANCES					= 0x0040,
   2089 		FLAG_GEOMETRY_SCATTER_PRIMITIVES				= 0x0080,
   2090 		FLAG_GEOMETRY_SEPARATE_PRIMITIVES				= 0x0100, //!< if set, geometry shader outputs separate grid cells and not continuous slices
   2091 		FLAG_GEOMETRY_SCATTER_LAYERS					= 0x0200,
   2092 
   2093 		FLAG_ALLOW_OUT_OF_MEMORY						= 0x0400, //!< allow draw command to set GL_OUT_OF_MEMORY
   2094 	};
   2095 
   2096 						GridRenderCase					(Context& context, const char* name, const char* description, int flags);
   2097 						~GridRenderCase					(void);
   2098 
   2099 private:
   2100 	void				init							(void);
   2101 	void				deinit							(void);
   2102 	IterateResult		iterate							(void);
   2103 
   2104 	void				renderTo						(std::vector<tcu::Surface>& dst);
   2105 	bool				verifyResultLayer				(int layerNdx, const tcu::Surface& dst);
   2106 
   2107 	const char*			getVertexSource					(void);
   2108 	const char*			getFragmentSource				(void);
   2109 	std::string			getTessellationControlSource	(int tessLevel);
   2110 	std::string			getTessellationEvaluationSource	(int tessLevel);
   2111 	std::string			getGeometryShaderSource			(int numPrimitives, int numInstances, int tessLevel);
   2112 
   2113 	enum
   2114 	{
   2115 		RENDER_SIZE = 256
   2116 	};
   2117 
   2118 	const int			m_flags;
   2119 
   2120 	glu::ShaderProgram*	m_program;
   2121 	deUint32			m_texture;
   2122 	int					m_numLayers;
   2123 };
   2124 
   2125 GridRenderCase::GridRenderCase (Context& context, const char* name, const char* description, int flags)
   2126 	: TestCase		(context, name, description)
   2127 	, m_flags		(flags)
   2128 	, m_program		(DE_NULL)
   2129 	, m_texture		(0)
   2130 	, m_numLayers	(1)
   2131 {
   2132 	DE_ASSERT(((m_flags & FLAG_TESSELLATION_MAX_SPEC) == 0)			|| ((m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION) == 0));
   2133 	DE_ASSERT(((m_flags & FLAG_GEOMETRY_MAX_SPEC) == 0)				|| ((m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION) == 0));
   2134 	DE_ASSERT(((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) == 0)	|| ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION) == 0));
   2135 	DE_ASSERT(((m_flags & (FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS)) != 0) == ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0));
   2136 }
   2137 
   2138 GridRenderCase::~GridRenderCase (void)
   2139 {
   2140 	deinit();
   2141 }
   2142 
   2143 void GridRenderCase::init (void)
   2144 {
   2145 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2146 
   2147 	// Requirements
   2148 
   2149 	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
   2150 		!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
   2151 		throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
   2152 
   2153 	if ((m_flags & FLAG_GEOMETRY_SCATTER_LAYERS) == 0)
   2154 	{
   2155 		if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
   2156 			m_context.getRenderTarget().getHeight() < RENDER_SIZE)
   2157 			throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
   2158 	}
   2159 
   2160 	// Log
   2161 
   2162 	m_testCtx.getLog()
   2163 		<< tcu::TestLog::Message
   2164 		<< "Testing tessellation and geometry shaders that output a large number of primitives.\n"
   2165 		<< getDescription()
   2166 		<< tcu::TestLog::EndMessage;
   2167 
   2168 	// Render target
   2169 	if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
   2170 	{
   2171 		// set limits
   2172 		m_numLayers = 8;
   2173 
   2174 		m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to 2d texture array, numLayers = " << m_numLayers << tcu::TestLog::EndMessage;
   2175 
   2176 		gl.genTextures(1, &m_texture);
   2177 		gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
   2178 		gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, RENDER_SIZE, RENDER_SIZE, m_numLayers);
   2179 
   2180 		gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   2181 		gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   2182 		gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   2183 		gl.texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   2184 
   2185 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen texture");
   2186 	}
   2187 
   2188 	// Gen program
   2189 	{
   2190 		glu::ProgramSources	sources;
   2191 		int					tessGenLevel = -1;
   2192 
   2193 		sources	<< glu::VertexSource(getVertexSource())
   2194 				<< glu::FragmentSource(getFragmentSource());
   2195 
   2196 		// Tessellation limits
   2197 		{
   2198 			if (m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION)
   2199 			{
   2200 				gl.getIntegerv(GL_MAX_TESS_GEN_LEVEL, &tessGenLevel);
   2201 				GLU_EXPECT_NO_ERROR(gl.getError(), "query tessellation limits");
   2202 			}
   2203 			else if (m_flags & FLAG_TESSELLATION_MAX_SPEC)
   2204 			{
   2205 				tessGenLevel = 64;
   2206 			}
   2207 			else
   2208 			{
   2209 				tessGenLevel = 5;
   2210 			}
   2211 
   2212 			m_testCtx.getLog()
   2213 					<< tcu::TestLog::Message
   2214 					<< "Tessellation level: " << tessGenLevel << ", mode = quad.\n"
   2215 					<< "\tEach input patch produces " << (tessGenLevel*tessGenLevel) << " (" << (tessGenLevel*tessGenLevel*2) << " triangles)\n"
   2216 					<< tcu::TestLog::EndMessage;
   2217 
   2218 			sources << glu::TessellationControlSource(getTessellationControlSource(tessGenLevel))
   2219 					<< glu::TessellationEvaluationSource(getTessellationEvaluationSource(tessGenLevel));
   2220 		}
   2221 
   2222 		// Geometry limits
   2223 		{
   2224 			int		geometryOutputComponents		= -1;
   2225 			int		geometryOutputVertices			= -1;
   2226 			int		geometryTotalOutputComponents	= -1;
   2227 			int		geometryShaderInvocations		= -1;
   2228 			bool	logGeometryLimits				= false;
   2229 			bool	logInvocationLimits				= false;
   2230 
   2231 			if (m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION)
   2232 			{
   2233 				m_testCtx.getLog() << tcu::TestLog::Message << "Using implementation maximum geometry shader output limits." << tcu::TestLog::EndMessage;
   2234 
   2235 				gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &geometryOutputComponents);
   2236 				gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &geometryOutputVertices);
   2237 				gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &geometryTotalOutputComponents);
   2238 				GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry limits");
   2239 
   2240 				logGeometryLimits = true;
   2241 			}
   2242 			else if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
   2243 			{
   2244 				m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader extension minimum maximum output limits." << tcu::TestLog::EndMessage;
   2245 
   2246 				geometryOutputComponents = 128;
   2247 				geometryOutputVertices = 256;
   2248 				geometryTotalOutputComponents = 1024;
   2249 				logGeometryLimits = true;
   2250 			}
   2251 			else
   2252 			{
   2253 				geometryOutputComponents = 128;
   2254 				geometryOutputVertices = 16;
   2255 				geometryTotalOutputComponents = 1024;
   2256 			}
   2257 
   2258 			if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION)
   2259 			{
   2260 				gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &geometryShaderInvocations);
   2261 				GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry invocation limits");
   2262 
   2263 				logInvocationLimits = true;
   2264 			}
   2265 			else if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC)
   2266 			{
   2267 				geometryShaderInvocations = 32;
   2268 				logInvocationLimits = true;
   2269 			}
   2270 			else
   2271 			{
   2272 				geometryShaderInvocations = 4;
   2273 			}
   2274 
   2275 			if (logGeometryLimits || logInvocationLimits)
   2276 			{
   2277 				tcu::MessageBuilder msg(&m_testCtx.getLog());
   2278 
   2279 				msg << "Geometry shader, targeting following limits:\n";
   2280 
   2281 				if (logGeometryLimits)
   2282 					msg	<< "\tGL_MAX_GEOMETRY_OUTPUT_COMPONENTS = " << geometryOutputComponents << "\n"
   2283 						<< "\tGL_MAX_GEOMETRY_OUTPUT_VERTICES = " << geometryOutputVertices << "\n"
   2284 						<< "\tGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << geometryTotalOutputComponents << "\n";
   2285 
   2286 				if (logInvocationLimits)
   2287 					msg << "\tGL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << geometryShaderInvocations;
   2288 
   2289 				msg << tcu::TestLog::EndMessage;
   2290 			}
   2291 
   2292 			{
   2293 				const bool	separatePrimitives			= (m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) != 0;
   2294 				const int	numComponentsPerVertex		= 8; // vec4 pos, vec4 color
   2295 				int			numVerticesPerInvocation;
   2296 				int			numPrimitivesPerInvocation;
   2297 				int			geometryVerticesPerPrimitive;
   2298 				int			geometryPrimitivesOutPerPrimitive;
   2299 
   2300 				if (separatePrimitives)
   2301 				{
   2302 					const int	numComponentLimit	= geometryTotalOutputComponents / (4 * numComponentsPerVertex);
   2303 					const int	numOutputLimit		= geometryOutputVertices / 4;
   2304 
   2305 					numPrimitivesPerInvocation		= de::min(numComponentLimit, numOutputLimit);
   2306 					numVerticesPerInvocation		= numPrimitivesPerInvocation * 4;
   2307 				}
   2308 				else
   2309 				{
   2310 					// If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices.
   2311 					// Each slice is a triangle strip and is generated by a single shader invocation.
   2312 					// One slice with 4 segment ends (nodes) and 3 segments:
   2313 					//    .__.__.__.
   2314 					//    |\ |\ |\ |
   2315 					//    |_\|_\|_\|
   2316 
   2317 					const int	numSliceNodesComponentLimit	= geometryTotalOutputComponents / (2 * numComponentsPerVertex);			// each node 2 vertices
   2318 					const int	numSliceNodesOutputLimit	= geometryOutputVertices / 2;											// each node 2 vertices
   2319 					const int	numSliceNodes				= de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit);
   2320 
   2321 					numVerticesPerInvocation				= numSliceNodes * 2;
   2322 					numPrimitivesPerInvocation				= (numSliceNodes - 1) * 2;
   2323 				}
   2324 
   2325 				geometryVerticesPerPrimitive = numVerticesPerInvocation * geometryShaderInvocations;
   2326 				geometryPrimitivesOutPerPrimitive = numPrimitivesPerInvocation * geometryShaderInvocations;
   2327 
   2328 				m_testCtx.getLog()
   2329 					<< tcu::TestLog::Message
   2330 					<< "Geometry shader:\n"
   2331 					<< "\tTotal output vertex count per invocation: " << (numVerticesPerInvocation) << "\n"
   2332 					<< "\tTotal output primitive count per invocation: " << (numPrimitivesPerInvocation) << "\n"
   2333 					<< "\tNumber of invocations per primitive: " << geometryShaderInvocations << "\n"
   2334 					<< "\tTotal output vertex count per input primitive: " << (geometryVerticesPerPrimitive) << "\n"
   2335 					<< "\tTotal output primitive count per input primitive: " << (geometryPrimitivesOutPerPrimitive) << "\n"
   2336 					<< tcu::TestLog::EndMessage;
   2337 
   2338 				sources	<< glu::GeometrySource(getGeometryShaderSource(numPrimitivesPerInvocation, geometryShaderInvocations, tessGenLevel));
   2339 
   2340 				m_testCtx.getLog()
   2341 					<< tcu::TestLog::Message
   2342 					<< "Program:\n"
   2343 					<< "\tTotal program output vertices count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n"
   2344 					<< "\tTotal program output primitive count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n"
   2345 					<< tcu::TestLog::EndMessage;
   2346 			}
   2347 		}
   2348 
   2349 		m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
   2350 		m_testCtx.getLog() << *m_program;
   2351 		if (!m_program->isOk())
   2352 			throw tcu::TestError("failed to build program");
   2353 	}
   2354 }
   2355 
   2356 void GridRenderCase::deinit (void)
   2357 {
   2358 	delete m_program;
   2359 	m_program = DE_NULL;
   2360 
   2361 	if (m_texture)
   2362 	{
   2363 		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture);
   2364 		m_texture = 0;
   2365 	}
   2366 }
   2367 
   2368 GridRenderCase::IterateResult GridRenderCase::iterate (void)
   2369 {
   2370 	std::vector<tcu::Surface>	renderedLayers	(m_numLayers);
   2371 	bool						allLayersOk		= true;
   2372 
   2373 	for (int ndx = 0; ndx < m_numLayers; ++ndx)
   2374 		renderedLayers[ndx].setSize(RENDER_SIZE, RENDER_SIZE);
   2375 
   2376 	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point at the origin. Expecting yellow and green colored grid-like image. (High-frequency grid may appear unicolored)." << tcu::TestLog::EndMessage;
   2377 
   2378 	try
   2379 	{
   2380 		renderTo(renderedLayers);
   2381 	}
   2382 	catch (const AllowedRenderFailureException& ex)
   2383 	{
   2384 		// Got accepted failure
   2385 		m_testCtx.getLog()
   2386 			<< tcu::TestLog::Message
   2387 			<< "Could not render, reason: " << ex.what() << "\n"
   2388 			<< "Failure is allowed."
   2389 			<< tcu::TestLog::EndMessage;
   2390 
   2391 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   2392 		return STOP;
   2393 	}
   2394 
   2395 	for (int ndx = 0; ndx < m_numLayers; ++ndx)
   2396 		allLayersOk &= verifyResultLayer(ndx, renderedLayers[ndx]);
   2397 
   2398 	if (allLayersOk)
   2399 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   2400 	else
   2401 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
   2402 	return STOP;
   2403 }
   2404 
   2405 void GridRenderCase::renderTo (std::vector<tcu::Surface>& dst)
   2406 {
   2407 	const glw::Functions&			gl					= m_context.getRenderContext().getFunctions();
   2408 	const int						positionLocation	= gl.getAttribLocation(m_program->getProgram(), "a_position");
   2409 	const glu::VertexArray			vao					(m_context.getRenderContext());
   2410 	de::MovePtr<glu::Framebuffer>	fbo;
   2411 
   2412 	if (positionLocation == -1)
   2413 		throw tcu::TestError("Attribute a_position location was -1");
   2414 
   2415 	gl.viewport(0, 0, dst.front().getWidth(), dst.front().getHeight());
   2416 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   2417 	GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
   2418 
   2419 	gl.bindVertexArray(*vao);
   2420 	GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
   2421 
   2422 	gl.useProgram(m_program->getProgram());
   2423 	GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
   2424 
   2425 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
   2426 	GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
   2427 
   2428 	gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
   2429 
   2430 	if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
   2431 	{
   2432 		// clear texture contents
   2433 		{
   2434 			glu::Framebuffer clearFbo(m_context.getRenderContext());
   2435 			gl.bindFramebuffer(GL_FRAMEBUFFER, *clearFbo);
   2436 
   2437 			for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
   2438 			{
   2439 				gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, layerNdx);
   2440 				gl.clear(GL_COLOR_BUFFER_BIT);
   2441 			}
   2442 
   2443 			GLU_EXPECT_NO_ERROR(gl.getError(), "clear tex contents");
   2444 		}
   2445 
   2446 		// create and bind layered fbo
   2447 
   2448 		fbo = de::MovePtr<glu::Framebuffer>(new glu::Framebuffer(m_context.getRenderContext()));
   2449 
   2450 		gl.bindFramebuffer(GL_FRAMEBUFFER, **fbo);
   2451 		gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
   2452 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen fbo");
   2453 	}
   2454 	else
   2455 	{
   2456 		// clear viewport
   2457 		gl.clear(GL_COLOR_BUFFER_BIT);
   2458 	}
   2459 
   2460 	// draw
   2461 	{
   2462 		glw::GLenum glerror;
   2463 
   2464 		gl.drawArrays(GL_PATCHES, 0, 1);
   2465 
   2466 		glerror = gl.getError();
   2467 		if (glerror == GL_OUT_OF_MEMORY && (m_flags & FLAG_ALLOW_OUT_OF_MEMORY))
   2468 			throw AllowedRenderFailureException("got GL_OUT_OF_MEMORY while drawing");
   2469 
   2470 		GLU_EXPECT_NO_ERROR(glerror, "draw patches");
   2471 	}
   2472 
   2473 	// Read layers
   2474 
   2475 	if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
   2476 	{
   2477 		glu::Framebuffer readFbo(m_context.getRenderContext());
   2478 		gl.bindFramebuffer(GL_FRAMEBUFFER, *readFbo);
   2479 
   2480 		for (int layerNdx = 0; layerNdx < m_numLayers; ++layerNdx)
   2481 		{
   2482 			gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0, layerNdx);
   2483 			glu::readPixels(m_context.getRenderContext(), 0, 0, dst[layerNdx].getAccess());
   2484 			GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
   2485 		}
   2486 	}
   2487 	else
   2488 	{
   2489 		glu::readPixels(m_context.getRenderContext(), 0, 0, dst.front().getAccess());
   2490 		GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
   2491 	}
   2492 }
   2493 
   2494 bool GridRenderCase::verifyResultLayer (int layerNdx, const tcu::Surface& image)
   2495 {
   2496 	tcu::Surface	errorMask	(image.getWidth(), image.getHeight());
   2497 	bool			foundError	= false;
   2498 
   2499 	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
   2500 
   2501 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output layer " << layerNdx  << tcu::TestLog::EndMessage;
   2502 
   2503 	for (int y = 0; y < image.getHeight(); ++y)
   2504 	for (int x = 0; x < image.getWidth(); ++x)
   2505 	{
   2506 		const int		threshold	= 8;
   2507 		const tcu::RGBA	color		= image.getPixel(x, y);
   2508 
   2509 		// Color must be a linear combination of green and yellow
   2510 		if (color.getGreen() < 255 - threshold || color.getBlue() > threshold)
   2511 		{
   2512 			errorMask.setPixel(x, y, tcu::RGBA::red);
   2513 			foundError = true;
   2514 		}
   2515 	}
   2516 
   2517 	if (!foundError)
   2518 	{
   2519 		m_testCtx.getLog()
   2520 			<< tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage
   2521 			<< tcu::TestLog::ImageSet("ImageVerification", "Image verification")
   2522 			<< tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
   2523 			<< tcu::TestLog::EndImageSet;
   2524 		return true;
   2525 	}
   2526 	else
   2527 	{
   2528 		m_testCtx.getLog()
   2529 			<< tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage
   2530 			<< tcu::TestLog::ImageSet("ImageVerification", "Image verification")
   2531 			<< tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
   2532 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
   2533 			<< tcu::TestLog::EndImageSet;
   2534 		return false;
   2535 	}
   2536 }
   2537 
   2538 const char* GridRenderCase::getVertexSource (void)
   2539 {
   2540 	return s_positionVertexShader;
   2541 }
   2542 
   2543 const char* GridRenderCase::getFragmentSource (void)
   2544 {
   2545 	return	"#version 310 es\n"
   2546 			"flat in mediump vec4 v_color;\n"
   2547 			"layout(location = 0) out mediump vec4 fragColor;\n"
   2548 			"void main (void)\n"
   2549 			"{\n"
   2550 			"	fragColor = v_color;\n"
   2551 			"}\n";
   2552 }
   2553 
   2554 std::string GridRenderCase::getTessellationControlSource (int tessLevel)
   2555 {
   2556 	std::ostringstream buf;
   2557 
   2558 	buf <<	"#version 310 es\n"
   2559 			"#extension GL_EXT_tessellation_shader : require\n"
   2560 			"layout(vertices=1) out;\n"
   2561 			"\n"
   2562 			"void main()\n"
   2563 			"{\n"
   2564 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
   2565 			"	gl_TessLevelOuter[0] = " << tessLevel << ".0;\n"
   2566 			"	gl_TessLevelOuter[1] = " << tessLevel << ".0;\n"
   2567 			"	gl_TessLevelOuter[2] = " << tessLevel << ".0;\n"
   2568 			"	gl_TessLevelOuter[3] = " << tessLevel << ".0;\n"
   2569 			"	gl_TessLevelInner[0] = " << tessLevel << ".0;\n"
   2570 			"	gl_TessLevelInner[1] = " << tessLevel << ".0;\n"
   2571 			"}\n";
   2572 
   2573 	return buf.str();
   2574 }
   2575 
   2576 std::string GridRenderCase::getTessellationEvaluationSource (int tessLevel)
   2577 {
   2578 	std::ostringstream buf;
   2579 
   2580 	buf <<	"#version 310 es\n"
   2581 			"#extension GL_EXT_tessellation_shader : require\n"
   2582 			"layout(quads) in;\n"
   2583 			"\n"
   2584 			"out mediump ivec2 v_tessellationGridPosition;\n"
   2585 			"\n"
   2586 			"// note: No need to use precise gl_Position since position does not depend on order\n"
   2587 			"void main (void)\n"
   2588 			"{\n";
   2589 
   2590 	if (m_flags & (FLAG_GEOMETRY_SCATTER_INSTANCES | FLAG_GEOMETRY_SCATTER_PRIMITIVES | FLAG_GEOMETRY_SCATTER_LAYERS))
   2591 		buf <<	"	// Cover only a small area in a corner. The area will be expanded in geometry shader to cover whole viewport\n"
   2592 				"	gl_Position = vec4(gl_TessCoord.x * 0.3 - 1.0, gl_TessCoord.y * 0.3 - 1.0, 0.0, 1.0);\n";
   2593 	else
   2594 		buf <<	"	// Fill the whole viewport\n"
   2595 				"	gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n";
   2596 
   2597 	buf <<	"	// Calculate position in tessellation grid\n"
   2598 			"	v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << tessLevel << ")));\n"
   2599 			"}\n";
   2600 
   2601 	return buf.str();
   2602 }
   2603 
   2604 std::string GridRenderCase::getGeometryShaderSource (int numPrimitives, int numInstances, int tessLevel)
   2605 {
   2606 	std::ostringstream buf;
   2607 
   2608 	buf	<<	"#version 310 es\n"
   2609 			"#extension GL_EXT_geometry_shader : require\n"
   2610 			"layout(triangles, invocations=" << numInstances << ") in;\n"
   2611 			"layout(triangle_strip, max_vertices=" << ((m_flags & FLAG_GEOMETRY_SEPARATE_PRIMITIVES) ? (4 * numPrimitives) : (numPrimitives + 2)) << ") out;\n"
   2612 			"\n"
   2613 			"in mediump ivec2 v_tessellationGridPosition[];\n"
   2614 			"flat out highp vec4 v_color;\n"
   2615 			"\n"
   2616 			"void main ()\n"
   2617 			"{\n"
   2618 			"	const float equalThreshold = 0.001;\n"
   2619 			"	const float gapOffset = 0.0001; // subdivision performed by the geometry shader might produce gaps. Fill potential gaps by enlarging the output slice a little.\n"
   2620 			"\n"
   2621 			"	// Input triangle is generated from an axis-aligned rectangle by splitting it in half\n"
   2622 			"	// Original rectangle can be found by finding the bounding AABB of the triangle\n"
   2623 			"	vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
   2624 			"	                 min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n"
   2625 			"	                 max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
   2626 			"	                 max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n"
   2627 			"\n"
   2628 			"	// Location in tessellation grid\n"
   2629 			"	ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n"
   2630 			"\n"
   2631 			"	// Which triangle of the two that split the grid cell\n"
   2632 			"	int numVerticesOnBottomEdge = 0;\n"
   2633 			"	for (int ndx = 0; ndx < 3; ++ndx)\n"
   2634 			"		if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n"
   2635 			"			++numVerticesOnBottomEdge;\n"
   2636 			"	bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n"
   2637 			"\n";
   2638 
   2639 	if (m_flags & FLAG_GEOMETRY_SCATTER_PRIMITIVES)
   2640 	{
   2641 		// scatter primitives
   2642 		buf <<	"	// Draw grid cells\n"
   2643 				"	int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
   2644 				"	for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
   2645 				"	{\n"
   2646 				"		ivec2 dstGridSize = ivec2(" << tessLevel << " * " << numPrimitives << ", 2 * " << tessLevel << " * " << numInstances << ");\n"
   2647 				"		ivec2 dstGridNdx = ivec2(" << tessLevel << " * ndx + gridPosition.x, " << tessLevel << " * inputTriangleNdx + 2 * gridPosition.y + ndx * 127) % dstGridSize;\n"
   2648 				"		vec4 dstArea;\n"
   2649 				"		dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
   2650 				"		dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
   2651 				"		dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
   2652 				"		dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
   2653 				"\n"
   2654 				"		vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
   2655 				"		vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
   2656 				"		vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
   2657 				"\n"
   2658 				"		gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
   2659 				"		v_color = outputColor;\n"
   2660 				"		EmitVertex();\n"
   2661 				"\n"
   2662 				"		gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
   2663 				"		v_color = outputColor;\n"
   2664 				"		EmitVertex();\n"
   2665 				"\n"
   2666 				"		gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
   2667 				"		v_color = outputColor;\n"
   2668 				"		EmitVertex();\n"
   2669 				"\n"
   2670 				"		gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
   2671 				"		v_color = outputColor;\n"
   2672 				"		EmitVertex();\n"
   2673 				"		EndPrimitive();\n"
   2674 				"	}\n";
   2675 	}
   2676 	else if (m_flags & FLAG_GEOMETRY_SCATTER_LAYERS)
   2677 	{
   2678 		// Number of subrectangle instances = num layers
   2679 		DE_ASSERT(m_numLayers == numInstances * 2);
   2680 
   2681 		buf <<	"	// Draw grid cells, send each primitive to a separate layer\n"
   2682 				"	int baseLayer = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
   2683 				"	for (int ndx = 0; ndx < " << numPrimitives << "; ++ndx)\n"
   2684 				"	{\n"
   2685 				"		ivec2 dstGridSize = ivec2(" << tessLevel << " * " << numPrimitives << ", " << tessLevel << ");\n"
   2686 				"		ivec2 dstGridNdx = ivec2((gridPosition.x * " << numPrimitives << " * 7 + ndx)*13, (gridPosition.y * 127 + ndx) * 19) % dstGridSize;\n"
   2687 				"		vec4 dstArea;\n"
   2688 				"		dstArea.x = float(dstGridNdx.x) / float(dstGridSize.x) * 2.0 - 1.0 - gapOffset;\n"
   2689 				"		dstArea.y = float(dstGridNdx.y) / float(dstGridSize.y) * 2.0 - 1.0 - gapOffset;\n"
   2690 				"		dstArea.z = float(dstGridNdx.x+1) / float(dstGridSize.x) * 2.0 - 1.0 + gapOffset;\n"
   2691 				"		dstArea.w = float(dstGridNdx.y+1) / float(dstGridSize.y) * 2.0 - 1.0 + gapOffset;\n"
   2692 				"\n"
   2693 				"		vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
   2694 				"		vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
   2695 				"		vec4 outputColor = (((dstGridNdx.y + dstGridNdx.x) % 2) == 0) ? (green) : (yellow);\n"
   2696 				"\n"
   2697 				"		gl_Position = vec4(dstArea.x, dstArea.y, 0.0, 1.0);\n"
   2698 				"		v_color = outputColor;\n"
   2699 				"		gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
   2700 				"		EmitVertex();\n"
   2701 				"\n"
   2702 				"		gl_Position = vec4(dstArea.x, dstArea.w, 0.0, 1.0);\n"
   2703 				"		v_color = outputColor;\n"
   2704 				"		gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
   2705 				"		EmitVertex();\n"
   2706 				"\n"
   2707 				"		gl_Position = vec4(dstArea.z, dstArea.y, 0.0, 1.0);\n"
   2708 				"		v_color = outputColor;\n"
   2709 				"		gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
   2710 				"		EmitVertex();\n"
   2711 				"\n"
   2712 				"		gl_Position = vec4(dstArea.z, dstArea.w, 0.0, 1.0);\n"
   2713 				"		v_color = outputColor;\n"
   2714 				"		gl_Layer = ((baseLayer + ndx) * 11) % " << m_numLayers << ";\n"
   2715 				"		EmitVertex();\n"
   2716 				"		EndPrimitive();\n"
   2717 				"	}\n";
   2718 	}
   2719 	else
   2720 	{
   2721 		if (m_flags & FLAG_GEOMETRY_SCATTER_INSTANCES)
   2722 		{
   2723 			buf <<	"	// Scatter slices\n"
   2724 					"	int inputTriangleNdx = gl_InvocationID * 2 + ((isBottomTriangle) ? (1) : (0));\n"
   2725 					"	ivec2 srcSliceNdx = ivec2(gridPosition.x, gridPosition.y * " << (numInstances*2) << " + inputTriangleNdx);\n"
   2726 					"	ivec2 dstSliceNdx = ivec2(7 * srcSliceNdx.x, 127 * srcSliceNdx.y) % ivec2(" << tessLevel << ", " << tessLevel << " * " << (numInstances*2) << ");\n"
   2727 					"\n"
   2728 					"	// Draw slice to the dstSlice slot\n"
   2729 					"	vec4 outputSliceArea;\n"
   2730 					"	outputSliceArea.x = float(dstSliceNdx.x) / float(" << tessLevel << ") * 2.0 - 1.0 - gapOffset;\n"
   2731 					"	outputSliceArea.y = float(dstSliceNdx.y) / float(" << (tessLevel * numInstances * 2) << ") * 2.0 - 1.0 - gapOffset;\n"
   2732 					"	outputSliceArea.z = float(dstSliceNdx.x+1) / float(" << tessLevel << ") * 2.0 - 1.0 + gapOffset;\n"
   2733 					"	outputSliceArea.w = float(dstSliceNdx.y+1) / float(" << (tessLevel * numInstances * 2) << ") * 2.0 - 1.0 + gapOffset;\n";
   2734 		}
   2735 		else
   2736 		{
   2737 			buf <<	"	// Fill the input area with slices\n"
   2738 					"	// Upper triangle produces slices only to the upper half of the quad and vice-versa\n"
   2739 					"	float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n"
   2740 					"	// Each slice is a invocation\n"
   2741 					"	float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInstances << ");\n"
   2742 					"	float invocationOffset = float(gl_InvocationID) * sliceHeight;\n"
   2743 					"\n"
   2744 					"	vec4 outputSliceArea;\n"
   2745 					"	outputSliceArea.x = aabb.x - gapOffset;\n"
   2746 					"	outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n"
   2747 					"	outputSliceArea.z = aabb.z + gapOffset;\n"
   2748 					"	outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n";
   2749 		}
   2750 
   2751 		buf <<	"\n"
   2752 				"	// Draw slice\n"
   2753 				"	for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n"
   2754 				"	{\n"
   2755 				"		vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
   2756 				"		vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
   2757 				"		vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n"
   2758 				"		float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n"
   2759 				"\n"
   2760 				"		gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n"
   2761 				"		v_color = outputColor;\n"
   2762 				"		EmitVertex();\n"
   2763 				"\n"
   2764 				"		gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n"
   2765 				"		v_color = outputColor;\n"
   2766 				"		EmitVertex();\n"
   2767 				"	}\n";
   2768 	}
   2769 
   2770 	buf <<	"}\n";
   2771 
   2772 	return buf.str();
   2773 }
   2774 
   2775 class FeedbackRecordVariableSelectionCase : public TestCase
   2776 {
   2777 public:
   2778 						FeedbackRecordVariableSelectionCase		(Context& context, const char* name, const char* description);
   2779 						~FeedbackRecordVariableSelectionCase	(void);
   2780 
   2781 private:
   2782 	void				init									(void);
   2783 	void				deinit									(void);
   2784 	IterateResult		iterate									(void);
   2785 
   2786 	const char*			getVertexSource							(void);
   2787 	const char*			getFragmentSource						(void);
   2788 	const char*			getTessellationControlSource			(void);
   2789 	const char*			getTessellationEvaluationSource			(void);
   2790 	const char*			getGeometrySource						(void);
   2791 
   2792 	glu::ShaderProgram*	m_program;
   2793 	deUint32			m_xfbBuf;
   2794 };
   2795 
   2796 FeedbackRecordVariableSelectionCase::FeedbackRecordVariableSelectionCase (Context& context, const char* name, const char* description)
   2797 	: TestCase	(context, name, description)
   2798 	, m_program	(DE_NULL)
   2799 	, m_xfbBuf	(0)
   2800 {
   2801 }
   2802 
   2803 FeedbackRecordVariableSelectionCase::~FeedbackRecordVariableSelectionCase (void)
   2804 {
   2805 	deinit();
   2806 }
   2807 
   2808 void FeedbackRecordVariableSelectionCase::init (void)
   2809 {
   2810 	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
   2811 		!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
   2812 		throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
   2813 
   2814 	m_testCtx.getLog() << tcu::TestLog::Message << "Declaring multiple output variables with the same name in multiple shader stages. Capturing the value of the varying using transform feedback." << tcu::TestLog::EndMessage;
   2815 
   2816 	// gen feedback buffer fit for 1 triangle (4 components)
   2817 	{
   2818 		static const tcu::Vec4 initialData[3] =
   2819 		{
   2820 			tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
   2821 			tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
   2822 			tcu::Vec4(-1.0f, -1.0f, -1.0f, -1.0f),
   2823 		};
   2824 
   2825 		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
   2826 
   2827 		m_testCtx.getLog() << tcu::TestLog::Message << "Creating buffer for transform feedback. Allocating storage for one triangle. Filling with -1.0" << tcu::TestLog::EndMessage;
   2828 
   2829 		gl.genBuffers(1, &m_xfbBuf);
   2830 		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_xfbBuf);
   2831 		gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (int)(sizeof(tcu::Vec4[3])), initialData, GL_DYNAMIC_READ);
   2832 		GLU_EXPECT_NO_ERROR(gl.getError(), "gen xfb buf");
   2833 	}
   2834 
   2835 	// gen shader
   2836 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
   2837 																	 << glu::VertexSource(getVertexSource())
   2838 																	 << glu::FragmentSource(getFragmentSource())
   2839 																	 << glu::TessellationControlSource(getTessellationControlSource())
   2840 																	 << glu::TessellationEvaluationSource(getTessellationEvaluationSource())
   2841 																	 << glu::GeometrySource(getGeometrySource())
   2842 																	 << glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS)
   2843 																	 << glu::TransformFeedbackVarying("tf_feedback"));
   2844 	m_testCtx.getLog() << *m_program;
   2845 
   2846 	if (!m_program->isOk())
   2847 		throw tcu::TestError("could not build program");
   2848 }
   2849 
   2850 void FeedbackRecordVariableSelectionCase::deinit (void)
   2851 {
   2852 	delete m_program;
   2853 	m_program = DE_NULL;
   2854 
   2855 	if (m_xfbBuf)
   2856 	{
   2857 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_xfbBuf);
   2858 		m_xfbBuf = 0;
   2859 	}
   2860 }
   2861 
   2862 FeedbackRecordVariableSelectionCase::IterateResult FeedbackRecordVariableSelectionCase::iterate (void)
   2863 {
   2864 	const glw::Functions&	gl		= m_context.getRenderContext().getFunctions();
   2865 	const int				posLoc	= gl.getAttribLocation(m_program->getProgram(), "a_position");
   2866 	const glu::VertexArray	vao		(m_context.getRenderContext());
   2867 
   2868 	if (posLoc == -1)
   2869 		throw tcu::TestError("a_position attribute location was -1");
   2870 
   2871 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
   2872 
   2873 	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering a patch of size 3." << tcu::TestLog::EndMessage;
   2874 
   2875 	// Render and feed back
   2876 
   2877 	gl.viewport(0, 0, 1, 1);
   2878 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
   2879 	gl.clear(GL_COLOR_BUFFER_BIT);
   2880 	GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
   2881 
   2882 	gl.bindVertexArray(*vao);
   2883 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindVertexArray");
   2884 
   2885 	gl.vertexAttrib4f(posLoc, 0.0f, 0.0f, 0.0f, 1.0f);
   2886 	GLU_EXPECT_NO_ERROR(gl.getError(), "vertexAttrib4f");
   2887 
   2888 	gl.useProgram(m_program->getProgram());
   2889 	GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
   2890 
   2891 	gl.patchParameteri(GL_PATCH_VERTICES, 3);
   2892 	GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
   2893 
   2894 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_xfbBuf);
   2895 	GLU_EXPECT_NO_ERROR(gl.getError(), "bind xfb buf");
   2896 
   2897 	gl.beginTransformFeedback(GL_TRIANGLES);
   2898 	GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
   2899 
   2900 	gl.drawArrays(GL_PATCHES, 0, 3);
   2901 	GLU_EXPECT_NO_ERROR(gl.getError(), "drawArrays");
   2902 
   2903 	gl.endTransformFeedback();
   2904 	GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
   2905 
   2906 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying the value of tf_feedback using transform feedback, expecting (3.0, 3.0, 3.0, 3.0)." << tcu::TestLog::EndMessage;
   2907 
   2908 	// Read back result (one triangle)
   2909 	{
   2910 		tcu::Vec4	feedbackValues[3];
   2911 		const void* mapPtr				= gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, (int)sizeof(feedbackValues), GL_MAP_READ_BIT);
   2912 		GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
   2913 
   2914 		if (mapPtr == DE_NULL)
   2915 			throw tcu::TestError("mapBufferRange returned null");
   2916 
   2917 		deMemcpy(feedbackValues, mapPtr, sizeof(feedbackValues));
   2918 
   2919 		if (gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER) != GL_TRUE)
   2920 			throw tcu::TestError("unmapBuffer did not return TRUE");
   2921 
   2922 		for (int ndx = 0; ndx < 3; ++ndx)
   2923 		{
   2924 			if (!tcu::boolAll(tcu::lessThan(tcu::abs(feedbackValues[ndx] - tcu::Vec4(3.0f)), tcu::Vec4(0.001f))))
   2925 			{
   2926 				m_testCtx.getLog() << tcu::TestLog::Message << "Feedback vertex " << ndx << ": expected (3.0, 3.0, 3.0, 3.0), got " << feedbackValues[ndx] << tcu::TestLog::EndMessage;
   2927 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected feedback results");
   2928 			}
   2929 		}
   2930 	}
   2931 
   2932 	return STOP;
   2933 }
   2934 
   2935 const char* FeedbackRecordVariableSelectionCase::getVertexSource (void)
   2936 {
   2937 	return	"#version 310 es\n"
   2938 			"in highp vec4 a_position;\n"
   2939 			"out highp vec4 tf_feedback;\n"
   2940 			"void main()\n"
   2941 			"{\n"
   2942 			"	gl_Position = a_position;\n"
   2943 			"	tf_feedback = vec4(1.0, 1.0, 1.0, 1.0);\n"
   2944 			"}\n";
   2945 }
   2946 
   2947 const char* FeedbackRecordVariableSelectionCase::getFragmentSource (void)
   2948 {
   2949 	return s_whiteOutputFragmentShader;
   2950 }
   2951 
   2952 const char* FeedbackRecordVariableSelectionCase::getTessellationControlSource (void)
   2953 {
   2954 	return	"#version 310 es\n"
   2955 			"#extension GL_EXT_tessellation_shader : require\n"
   2956 			"layout(vertices=3) out;\n"
   2957 			"void main()\n"
   2958 			"{\n"
   2959 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
   2960 			"	gl_TessLevelOuter[0] = 1.0;\n"
   2961 			"	gl_TessLevelOuter[1] = 1.0;\n"
   2962 			"	gl_TessLevelOuter[2] = 1.0;\n"
   2963 			"	gl_TessLevelInner[0] = 1.0;\n"
   2964 			"}\n";
   2965 }
   2966 
   2967 const char* FeedbackRecordVariableSelectionCase::getTessellationEvaluationSource (void)
   2968 {
   2969 	return	"#version 310 es\n"
   2970 			"#extension GL_EXT_tessellation_shader : require\n"
   2971 			"layout(triangles) in;\n"
   2972 			"out highp vec4 tf_feedback;\n"
   2973 			"void main()\n"
   2974 			"{\n"
   2975 			"	gl_Position = gl_in[0].gl_Position * gl_TessCoord.x + gl_in[1].gl_Position * gl_TessCoord.y + gl_in[2].gl_Position * gl_TessCoord.z;\n"
   2976 			"	tf_feedback = vec4(2.0, 2.0, 2.0, 2.0);\n"
   2977 			"}\n";
   2978 }
   2979 
   2980 const char* FeedbackRecordVariableSelectionCase::getGeometrySource (void)
   2981 {
   2982 	return	"#version 310 es\n"
   2983 			"#extension GL_EXT_geometry_shader : require\n"
   2984 			"layout (triangles) in;\n"
   2985 			"layout (triangle_strip, max_vertices=3) out;\n"
   2986 			"out highp vec4 tf_feedback;\n"
   2987 			"void main()\n"
   2988 			"{\n"
   2989 			"	for (int ndx = 0; ndx < 3; ++ndx)\n"
   2990 			"	{\n"
   2991 			"		gl_Position = gl_in[ndx].gl_Position + vec4(float(ndx), float(ndx)*float(ndx), 0.0, 0.0);\n"
   2992 			"		tf_feedback = vec4(3.0, 3.0, 3.0, 3.0);\n"
   2993 			"		EmitVertex();\n"
   2994 			"	}\n"
   2995 			"	EndPrimitive();\n"
   2996 			"}\n";
   2997 }
   2998 
   2999 } // anonymous
   3000 
   3001 TessellationGeometryInteractionTests::TessellationGeometryInteractionTests (Context& context)
   3002 	: TestCaseGroup(context, "tessellation_geometry_interaction", "Tessellation and geometry shader interaction tests")
   3003 {
   3004 }
   3005 
   3006 TessellationGeometryInteractionTests::~TessellationGeometryInteractionTests (void)
   3007 {
   3008 }
   3009 
   3010 void TessellationGeometryInteractionTests::init (void)
   3011 {
   3012 	tcu::TestCaseGroup* const renderGroup		= new tcu::TestCaseGroup(m_testCtx, "render",		"Various render tests");
   3013 	tcu::TestCaseGroup* const feedbackGroup		= new tcu::TestCaseGroup(m_testCtx, "feedback",		"Test transform feedback");
   3014 	tcu::TestCaseGroup* const pointSizeGroup	= new tcu::TestCaseGroup(m_testCtx, "point_size",	"Test point size");
   3015 
   3016 	addChild(renderGroup);
   3017 	addChild(feedbackGroup);
   3018 	addChild(pointSizeGroup);
   3019 
   3020 	// .render
   3021 	{
   3022 		tcu::TestCaseGroup* const passthroughGroup	= new tcu::TestCaseGroup(m_testCtx, "passthrough",	"Render various types with either passthrough geometry or tessellation shader");
   3023 		tcu::TestCaseGroup* const limitGroup		= new tcu::TestCaseGroup(m_testCtx, "limits",		"Render with properties near their limits");
   3024 		tcu::TestCaseGroup* const scatterGroup		= new tcu::TestCaseGroup(m_testCtx, "scatter",		"Scatter output primitives");
   3025 
   3026 		renderGroup->addChild(passthroughGroup);
   3027 		renderGroup->addChild(limitGroup);
   3028 		renderGroup->addChild(scatterGroup);
   3029 
   3030 		// .passthrough
   3031 		{
   3032 			// tessellate_tris_passthrough_geometry_no_change
   3033 			// tessellate_quads_passthrough_geometry_no_change
   3034 			// tessellate_isolines_passthrough_geometry_no_change
   3035 			passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_tris_passthrough_geometry_no_change",		"Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_TRIANGLES));
   3036 			passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_quads_passthrough_geometry_no_change",		"Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_QUADS));
   3037 			passthroughGroup->addChild(new IdentityGeometryShaderCase(m_context, "tessellate_isolines_passthrough_geometry_no_change",	"Passthrough geometry shader has no effect", IdentityGeometryShaderCase::CASE_ISOLINES));
   3038 
   3039 			// passthrough_tessellation_geometry_shade_triangles_no_change
   3040 			// passthrough_tessellation_geometry_shade_lines_no_change
   3041 			passthroughGroup->addChild(new IdentityTessellationShaderCase(m_context, "passthrough_tessellation_geometry_shade_triangles_no_change",	"Passthrough tessellation shader has no effect", IdentityTessellationShaderCase::CASE_TRIANGLES));
   3042 			passthroughGroup->addChild(new IdentityTessellationShaderCase(m_context, "passthrough_tessellation_geometry_shade_lines_no_change",		"Passthrough tessellation shader has no effect", IdentityTessellationShaderCase::CASE_ISOLINES));
   3043 		}
   3044 
   3045 		// .limits
   3046 		{
   3047 			static const struct LimitCaseDef
   3048 			{
   3049 				const char*	name;
   3050 				const char*	desc;
   3051 				int			flags;
   3052 			} cases[] =
   3053 			{
   3054 				// Test single limit
   3055 				{
   3056 					"output_required_max_tessellation",
   3057 					"Minimum maximum tessellation level",
   3058 					GridRenderCase::FLAG_TESSELLATION_MAX_SPEC
   3059 				},
   3060 				{
   3061 					"output_implementation_max_tessellation",
   3062 					"Maximum tessellation level supported by the implementation",
   3063 					GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION
   3064 				},
   3065 				{
   3066 					"output_required_max_geometry",
   3067 					"Output minimum maximum number of vertices the geometry shader",
   3068 					GridRenderCase::FLAG_GEOMETRY_MAX_SPEC
   3069 				},
   3070 				{
   3071 					"output_implementation_max_geometry",
   3072 					"Output maximum number of vertices in the geometry shader supported by the implementation",
   3073 					GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION
   3074 				},
   3075 				{
   3076 					"output_required_max_invocations",
   3077 					"Minimum maximum number of geometry shader invocations",
   3078 					GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
   3079 				},
   3080 				{
   3081 					"output_implementation_max_invocations",
   3082 					"Maximum number of geometry shader invocations supported by the implementation",
   3083 					GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
   3084 				},
   3085 			};
   3086 
   3087 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
   3088 				limitGroup->addChild(new GridRenderCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
   3089 		}
   3090 
   3091 		// .scatter
   3092 		{
   3093 			scatterGroup->addChild(new GridRenderCase(m_context,
   3094 													  "geometry_scatter_instances",
   3095 													  "Each geometry shader instance outputs its primitives far from other instances of the same execution",
   3096 													  GridRenderCase::FLAG_GEOMETRY_SCATTER_INSTANCES));
   3097 			scatterGroup->addChild(new GridRenderCase(m_context,
   3098 													  "geometry_scatter_primitives",
   3099 													  "Each geometry shader instance outputs its primitives far from other primitives of the same instance",
   3100 													  GridRenderCase::FLAG_GEOMETRY_SCATTER_PRIMITIVES | GridRenderCase::FLAG_GEOMETRY_SEPARATE_PRIMITIVES));
   3101 			scatterGroup->addChild(new GridRenderCase(m_context,
   3102 													  "geometry_scatter_layers",
   3103 													  "Each geometry shader instance outputs its primitives to multiple layers and far from other primitives of the same instance",
   3104 													  GridRenderCase::FLAG_GEOMETRY_SCATTER_LAYERS | GridRenderCase::FLAG_GEOMETRY_SEPARATE_PRIMITIVES));
   3105 		}
   3106 	}
   3107 
   3108 	// .feedback
   3109 	{
   3110 		static const struct PrimitiveCaseConfig
   3111 		{
   3112 			const char*											name;
   3113 			const char*											description;
   3114 			FeedbackPrimitiveTypeCase::TessellationOutputType	tessellationOutput;
   3115 			FeedbackPrimitiveTypeCase::TessellationPointMode	tessellationPointMode;
   3116 			FeedbackPrimitiveTypeCase::GeometryOutputType		geometryOutputType;
   3117 		} caseConfigs[] =
   3118 		{
   3119 			// tess output triangles -> geo input triangles, output points
   3120 			{
   3121 				"tessellation_output_triangles_geometry_output_points",
   3122 				"Tessellation outputs triangles, geometry outputs points",
   3123 				FeedbackPrimitiveTypeCase::TESSELLATION_OUT_TRIANGLES,
   3124 				FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
   3125 				FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
   3126 			},
   3127 
   3128 			// tess output quads <-> geo input triangles, output points
   3129 			{
   3130 				"tessellation_output_quads_geometry_output_points",
   3131 				"Tessellation outputs quads, geometry outputs points",
   3132 				FeedbackPrimitiveTypeCase::TESSELLATION_OUT_QUADS,
   3133 				FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
   3134 				FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
   3135 			},
   3136 
   3137 			// tess output isolines <-> geo input lines, output points
   3138 			{
   3139 				"tessellation_output_isolines_geometry_output_points",
   3140 				"Tessellation outputs isolines, geometry outputs points",
   3141 				FeedbackPrimitiveTypeCase::TESSELLATION_OUT_ISOLINES,
   3142 				FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_OFF,
   3143 				FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_POINTS
   3144 			},
   3145 
   3146 			// tess output triangles, point_mode <-> geo input points, output lines
   3147 			{
   3148 				"tessellation_output_triangles_point_mode_geometry_output_lines",
   3149 				"Tessellation outputs triangles in point mode, geometry outputs lines",
   3150 				FeedbackPrimitiveTypeCase::TESSELLATION_OUT_TRIANGLES,
   3151 				FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
   3152 				FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_LINES
   3153 			},
   3154 
   3155 			// tess output quads, point_mode <-> geo input points, output lines
   3156 			{
   3157 				"tessellation_output_quads_point_mode_geometry_output_lines",
   3158 				"Tessellation outputs quads in point mode, geometry outputs lines",
   3159 				FeedbackPrimitiveTypeCase::TESSELLATION_OUT_QUADS,
   3160 				FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
   3161 				FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_LINES
   3162 			},
   3163 
   3164 			// tess output isolines, point_mode <-> geo input points, output triangles
   3165 			{
   3166 				"tessellation_output_isolines_point_mode_geometry_output_triangles",
   3167 				"Tessellation outputs isolines in point mode, geometry outputs triangles",
   3168 				FeedbackPrimitiveTypeCase::TESSELLATION_OUT_ISOLINES,
   3169 				FeedbackPrimitiveTypeCase::TESSELLATION_POINTMODE_ON,
   3170 				FeedbackPrimitiveTypeCase::GEOMETRY_OUTPUT_TRIANGLES
   3171 			},
   3172 		};
   3173 
   3174 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseConfigs); ++ndx)
   3175 		{
   3176 			feedbackGroup->addChild(new FeedbackPrimitiveTypeCase(m_context,
   3177 																  caseConfigs[ndx].name,
   3178 																  caseConfigs[ndx].description,
   3179 																  caseConfigs[ndx].tessellationOutput,
   3180 																  caseConfigs[ndx].tessellationPointMode,
   3181 																  caseConfigs[ndx].geometryOutputType));
   3182 		}
   3183 
   3184 		feedbackGroup->addChild(new FeedbackRecordVariableSelectionCase(m_context, "record_variable_selection", "Record a variable that has been declared as an output variable in multiple shader stages"));
   3185 	}
   3186 
   3187 	// .point_size
   3188 	{
   3189 		static const int caseFlags[] =
   3190 		{
   3191 			PointSizeCase::FLAG_VERTEX_SET,
   3192 												PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET,
   3193 																										PointSizeCase::FLAG_GEOMETRY_SET,
   3194 			PointSizeCase::FLAG_VERTEX_SET	|	PointSizeCase::FLAG_TESSELLATION_CONTROL_SET,
   3195 			PointSizeCase::FLAG_VERTEX_SET	|	PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET,
   3196 			PointSizeCase::FLAG_VERTEX_SET	|	PointSizeCase::FLAG_TESSELLATION_DONT_SET,
   3197 			PointSizeCase::FLAG_VERTEX_SET 	|															PointSizeCase::FLAG_GEOMETRY_SET,
   3198 			PointSizeCase::FLAG_VERTEX_SET	|	PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET		|	PointSizeCase::FLAG_GEOMETRY_SET,
   3199 			PointSizeCase::FLAG_VERTEX_SET	|	PointSizeCase::FLAG_TESSELLATION_ADD				|	PointSizeCase::FLAG_GEOMETRY_ADD,
   3200 			PointSizeCase::FLAG_VERTEX_SET	|	PointSizeCase::FLAG_TESSELLATION_EVALUATION_SET		|	PointSizeCase::FLAG_GEOMETRY_DONT_SET,
   3201 		};
   3202 
   3203 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseFlags); ++ndx)
   3204 		{
   3205 			const std::string name = PointSizeCase::genTestCaseName(caseFlags[ndx]);
   3206 			const std::string desc = PointSizeCase::genTestCaseDescription(caseFlags[ndx]);
   3207 
   3208 			pointSizeGroup->addChild(new PointSizeCase(m_context, name.c_str(), desc.c_str(), caseFlags[ndx]));
   3209 		}
   3210 	}
   3211 }
   3212 
   3213 } // Functional
   3214 } // gles31
   3215 } // deqp
   3216