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