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 Geometry shader tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31fGeometryShaderTests.hpp"
25
26#include "gluRenderContext.hpp"
27#include "gluTextureUtil.hpp"
28#include "gluObjectWrapper.hpp"
29#include "gluPixelTransfer.hpp"
30#include "gluContextInfo.hpp"
31#include "gluCallLogWrapper.hpp"
32#include "tcuRenderTarget.hpp"
33#include "tcuTestLog.hpp"
34#include "tcuVectorUtil.hpp"
35#include "tcuImageCompare.hpp"
36#include "tcuTextureUtil.hpp"
37#include "glsStateQueryUtil.hpp"
38
39#include "gluStrUtil.hpp"
40#include "deStringUtil.hpp"
41#include "deUniquePtr.hpp"
42#include "deMemory.h"
43
44#include "sglrContext.hpp"
45#include "sglrReferenceContext.hpp"
46#include "sglrGLContext.hpp"
47#include "sglrReferenceUtils.hpp"
48
49#include "glwDefs.hpp"
50#include "glwEnums.hpp"
51#include "glwFunctions.hpp"
52
53#include <algorithm>
54
55using namespace glw;
56
57namespace deqp
58{
59namespace gles31
60{
61namespace Functional
62{
63namespace
64{
65
66using namespace gls::StateQueryUtil;
67
68const int TEST_CANVAS_SIZE = 256;
69
70static const char* const s_commonShaderSourceVertex =		"#version 310 es\n"
71															"in highp vec4 a_position;\n"
72															"in highp vec4 a_color;\n"
73															"out highp vec4 v_geom_FragColor;\n"
74															"void main (void)\n"
75															"{\n"
76															"	gl_Position = a_position;\n"
77															"	gl_PointSize = 1.0;\n"
78															"	v_geom_FragColor = a_color;\n"
79															"}\n";
80static const char* const s_commonShaderSourceFragment =		"#version 310 es\n"
81															"layout(location = 0) out mediump vec4 fragColor;\n"
82															"in mediump vec4 v_frag_FragColor;\n"
83															"void main (void)\n"
84															"{\n"
85															"	fragColor = v_frag_FragColor;\n"
86															"}\n";
87static const char* const s_expandShaderSourceGeometryBody =	"in highp vec4 v_geom_FragColor[];\n"
88															"out highp vec4 v_frag_FragColor;\n"
89															"\n"
90															"void main (void)\n"
91															"{\n"
92															"	const highp vec4 offset0 = vec4(-0.07, -0.01, 0.0, 0.0);\n"
93															"	const highp vec4 offset1 = vec4( 0.03, -0.03, 0.0, 0.0);\n"
94															"	const highp vec4 offset2 = vec4(-0.01,  0.08, 0.0, 0.0);\n"
95															"	      highp vec4 yoffset = float(gl_PrimitiveIDIn) * vec4(0.02, 0.1, 0.0, 0.0);\n"
96															"\n"
97															"	for (highp int ndx = 0; ndx < gl_in.length(); ndx++)\n"
98															"	{\n"
99															"		gl_Position = gl_in[ndx].gl_Position + offset0 + yoffset;\n"
100															"		gl_PrimitiveID = gl_PrimitiveIDIn;\n"
101															"		v_frag_FragColor = v_geom_FragColor[ndx];\n"
102															"		EmitVertex();\n"
103															"\n"
104															"		gl_Position = gl_in[ndx].gl_Position + offset1 + yoffset;\n"
105															"		gl_PrimitiveID = gl_PrimitiveIDIn;\n"
106															"		v_frag_FragColor = v_geom_FragColor[ndx];\n"
107															"		EmitVertex();\n"
108															"\n"
109															"		gl_Position = gl_in[ndx].gl_Position + offset2 + yoffset;\n"
110															"		gl_PrimitiveID = gl_PrimitiveIDIn;\n"
111															"		v_frag_FragColor = v_geom_FragColor[ndx];\n"
112															"		EmitVertex();\n"
113															"		EndPrimitive();\n"
114															"	}\n"
115															"}\n";
116
117std::string inputTypeToGLString (rr::GeometryShaderInputType inputType)
118{
119	switch (inputType)
120	{
121		case rr::GEOMETRYSHADERINPUTTYPE_POINTS:				return "points";
122		case rr::GEOMETRYSHADERINPUTTYPE_LINES:					return "lines";
123		case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY:		return "lines_adjacency";
124		case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES:				return "triangles";
125		case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY:	return "triangles_adjacency";
126		default:
127			DE_ASSERT(DE_FALSE);
128			return "error";
129	}
130}
131
132std::string outputTypeToGLString (rr::GeometryShaderOutputType outputType)
133{
134	switch (outputType)
135	{
136		case rr::GEOMETRYSHADEROUTPUTTYPE_POINTS:				return "points";
137		case rr::GEOMETRYSHADEROUTPUTTYPE_LINE_STRIP:			return "line_strip";
138		case rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP:		return "triangle_strip";
139		default:
140			DE_ASSERT(DE_FALSE);
141			return "error";
142	}
143}
144
145std::string primitiveTypeToString(GLenum primitive)
146{
147	switch (primitive)
148	{
149		case GL_POINTS:						 return "points";
150		case GL_LINES:					   	 return "lines";
151		case GL_LINE_LOOP:				   	 return "line_loop";
152		case GL_LINE_STRIP:				   	 return "line_strip";
153		case GL_LINES_ADJACENCY:		   	 return "lines_adjacency";
154		case GL_LINE_STRIP_ADJACENCY:	   	 return "line_strip_adjacency";
155		case GL_TRIANGLES:				   	 return "triangles";
156		case GL_TRIANGLE_STRIP:			   	 return "triangle_strip";
157		case GL_TRIANGLE_FAN:			   	 return "triangle_fan";
158		case GL_TRIANGLES_ADJACENCY:	   	 return "triangles_adjacency";
159		case GL_TRIANGLE_STRIP_ADJACENCY:  	 return "triangle_strip_adjacency";
160		default:
161			DE_ASSERT(DE_FALSE);
162			return "error";
163	}
164}
165
166struct OutputCountPatternSpec
167{
168						OutputCountPatternSpec (int count);
169						OutputCountPatternSpec (int count0, int count1);
170
171	std::vector<int>	pattern;
172};
173
174OutputCountPatternSpec::OutputCountPatternSpec (int count)
175{
176	pattern.push_back(count);
177}
178
179OutputCountPatternSpec::OutputCountPatternSpec (int count0, int count1)
180{
181	pattern.push_back(count0);
182	pattern.push_back(count1);
183}
184
185class VertexExpanderShader : public sglr::ShaderProgram
186{
187public:
188				VertexExpanderShader	(rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType);
189
190	void		shadeVertices			(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
191	void		shadeFragments			(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
192	void		shadePrimitives			(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
193
194private:
195	size_t		calcOutputVertices		(rr::GeometryShaderInputType inputType) const;
196	std::string	genGeometrySource		(rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType) const;
197};
198
199VertexExpanderShader::VertexExpanderShader (rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType)
200	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
201							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
202							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
203							<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
204							<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
205							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
206							<< sglr::pdec::VertexSource(s_commonShaderSourceVertex)
207							<< sglr::pdec::FragmentSource(s_commonShaderSourceFragment)
208							<< sglr::pdec::GeometryShaderDeclaration(inputType, outputType, calcOutputVertices(inputType))
209							<< sglr::pdec::GeometrySource(genGeometrySource(inputType, outputType).c_str()))
210{
211}
212
213void VertexExpanderShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
214{
215	for (int ndx = 0; ndx < numPackets; ++ndx)
216	{
217		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
218		packets[ndx]->pointSize = 1.0f;
219		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
220	}
221}
222
223void VertexExpanderShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
224{
225	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
226	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
227		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
228}
229
230void VertexExpanderShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
231{
232	DE_UNREF(invocationID);
233
234	for (int ndx = 0; ndx < numPackets; ++ndx)
235	for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
236	{
237		const tcu::Vec4 offsets[] =
238		{
239			tcu::Vec4(-0.07f, -0.01f, 0.0f, 0.0f),
240			tcu::Vec4( 0.03f, -0.03f, 0.0f, 0.0f),
241			tcu::Vec4(-0.01f,  0.08f, 0.0f, 0.0f)
242		};
243		const tcu::Vec4 yoffset = float(packets[ndx].primitiveIDIn) * tcu::Vec4(0.02f, 0.1f, 0, 0);
244
245		// Create new primitive at every input vertice
246		const rr::VertexPacket* vertex = packets[ndx].vertices[verticeNdx];
247
248		output.EmitVertex(vertex->position + offsets[0] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
249		output.EmitVertex(vertex->position + offsets[1] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
250		output.EmitVertex(vertex->position + offsets[2] + yoffset, vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
251		output.EndPrimitive();
252	}
253}
254
255size_t VertexExpanderShader::calcOutputVertices (rr::GeometryShaderInputType inputType) const
256{
257	switch (inputType)
258	{
259		case rr::GEOMETRYSHADERINPUTTYPE_POINTS:				return 1 * 3;
260		case rr::GEOMETRYSHADERINPUTTYPE_LINES:					return 2 * 3;
261		case rr::GEOMETRYSHADERINPUTTYPE_LINES_ADJACENCY:		return 4 * 3;
262		case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES:				return 3 * 3;
263		case rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES_ADJACENCY:	return 6 * 3;
264		default:
265			DE_ASSERT(DE_FALSE);
266			return 0;
267	}
268}
269
270std::string	VertexExpanderShader::genGeometrySource (rr::GeometryShaderInputType inputType, rr::GeometryShaderOutputType outputType) const
271{
272	std::ostringstream str;
273
274	str << "#version 310 es\n";
275	str << "#extension GL_EXT_geometry_shader : require\n";
276	str << "layout(" << inputTypeToGLString(inputType) << ") in;\n";
277	str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << calcOutputVertices(inputType) << ") out;";
278	str << "\n";
279	str << s_expandShaderSourceGeometryBody;
280
281	return str.str();
282}
283
284class VertexEmitterShader : public sglr::ShaderProgram
285{
286public:
287				VertexEmitterShader		(int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType);
288
289	void		shadeVertices			(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
290	void		shadeFragments			(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
291	void		shadePrimitives			(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
292
293private:
294	std::string	genGeometrySource		(int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType) const;
295
296	int			m_emitCountA;
297	int			m_endCountA;
298	int			m_emitCountB;
299	int			m_endCountB;
300};
301
302VertexEmitterShader::VertexEmitterShader (int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType)
303	: sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration()
304							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
305							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
306							<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
307							<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
308							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
309							<< sglr::pdec::VertexSource(s_commonShaderSourceVertex)
310							<< sglr::pdec::FragmentSource(s_commonShaderSourceFragment)
311							<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS, outputType, emitCountA + emitCountB)
312							<< sglr::pdec::GeometrySource(genGeometrySource(emitCountA, endCountA, emitCountB, endCountB, outputType).c_str()))
313	, m_emitCountA		(emitCountA)
314	, m_endCountA		(endCountA)
315	, m_emitCountB		(emitCountB)
316	, m_endCountB		(endCountB)
317{
318}
319
320void VertexEmitterShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
321{
322	for (int ndx = 0; ndx < numPackets; ++ndx)
323	{
324		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
325		packets[ndx]->pointSize = 1.0f;
326		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
327	}
328}
329
330void VertexEmitterShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
331{
332	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
333	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
334		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
335}
336
337void VertexEmitterShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
338{
339	DE_UNREF(verticesIn);
340	DE_UNREF(invocationID);
341
342	for (int ndx = 0; ndx < numPackets; ++ndx)
343	{
344		const tcu::Vec4 positions[] =
345		{
346			tcu::Vec4(-0.5f,   0.5f, 0.0f, 0.0f),
347			tcu::Vec4( 0.0f,   0.1f, 0.0f, 0.0f),
348			tcu::Vec4( 0.5f,   0.5f, 0.0f, 0.0f),
349			tcu::Vec4( 0.7f,  -0.2f, 0.0f, 0.0f),
350			tcu::Vec4( 0.2f,   0.2f, 0.0f, 0.0f),
351			tcu::Vec4( 0.4f,  -0.3f, 0.0f, 0.0f),
352		};
353
354		// Create new primitive at this point
355		const rr::VertexPacket* vertex = packets[ndx].vertices[0];
356
357		for (int i = 0; i < m_emitCountA; ++i)
358			output.EmitVertex(vertex->position + positions[i], vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
359
360		for (int i = 0; i < m_endCountA; ++i)
361			output.EndPrimitive();
362
363		for (int i = 0; i < m_emitCountB; ++i)
364			output.EmitVertex(vertex->position + positions[m_emitCountA + i], vertex->pointSize, vertex->outputs, packets[ndx].primitiveIDIn);
365
366		for (int i = 0; i < m_endCountB; ++i)
367			output.EndPrimitive();
368	}
369}
370
371std::string	VertexEmitterShader::genGeometrySource (int emitCountA, int endCountA, int emitCountB, int endCountB, rr::GeometryShaderOutputType outputType) const
372{
373	std::ostringstream str;
374
375	str << "#version 310 es\n";
376	str << "#extension GL_EXT_geometry_shader : require\n";
377	str << "layout(points) in;\n";
378	str << "layout(" << outputTypeToGLString(outputType) << ", max_vertices = " << (emitCountA+emitCountB) << ") out;";
379	str << "\n";
380
381	str <<	"in highp vec4 v_geom_FragColor[];\n"
382			"out highp vec4 v_frag_FragColor;\n"
383			"\n"
384			"void main (void)\n"
385			"{\n"
386			"	const highp vec4 position0 = vec4(-0.5,  0.5, 0.0, 0.0);\n"
387			"	const highp vec4 position1 = vec4( 0.0,  0.1, 0.0, 0.0);\n"
388			"	const highp vec4 position2 = vec4( 0.5,  0.5, 0.0, 0.0);\n"
389			"	const highp vec4 position3 = vec4( 0.7, -0.2, 0.0, 0.0);\n"
390			"	const highp vec4 position4 = vec4( 0.2,  0.2, 0.0, 0.0);\n"
391			"	const highp vec4 position5 = vec4( 0.4, -0.3, 0.0, 0.0);\n"
392			"\n";
393
394	for (int i = 0; i < emitCountA; ++i)
395		str <<	"	gl_Position = gl_in[0].gl_Position + position" << i << ";\n"
396				"	gl_PrimitiveID = gl_PrimitiveIDIn;\n"
397				"	v_frag_FragColor = v_geom_FragColor[0];\n"
398				"	EmitVertex();\n"
399				"\n";
400
401	for (int i = 0; i < endCountA; ++i)
402		str << "	EndPrimitive();\n";
403
404	for (int i = 0; i < emitCountB; ++i)
405		str <<	"	gl_Position = gl_in[0].gl_Position + position" << (emitCountA + i) << ";\n"
406				"	gl_PrimitiveID = gl_PrimitiveIDIn;\n"
407				"	v_frag_FragColor = v_geom_FragColor[0];\n"
408				"	EmitVertex();\n"
409				"\n";
410
411	for (int i = 0; i < endCountB; ++i)
412		str << "	EndPrimitive();\n";
413
414
415	str << "}\n";
416
417	return str.str();
418}
419
420class VertexVaryingShader : public sglr::ShaderProgram
421{
422public:
423												VertexVaryingShader		(int vertexOut, int geometryOut);
424
425	void										shadeVertices			(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
426	void										shadeFragments			(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
427	void										shadePrimitives			(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
428
429private:
430	static sglr::pdec::ShaderProgramDeclaration genProgramDeclaration	(int vertexOut, int geometryOut);
431
432	const int									m_vertexOut;
433	const int									m_geometryOut;
434};
435
436VertexVaryingShader::VertexVaryingShader (int vertexOut, int geometryOut)
437	: sglr::ShaderProgram	(genProgramDeclaration(vertexOut, geometryOut))
438	, m_vertexOut			(vertexOut)
439	, m_geometryOut			(geometryOut)
440{
441}
442
443void VertexVaryingShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
444{
445	// vertex shader is no-op
446	if (m_vertexOut == -1)
447		return;
448
449	for (int ndx = 0; ndx < numPackets; ++ndx)
450	{
451		const tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
452
453		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
454		packets[ndx]->pointSize = 1.0f;
455
456		switch (m_vertexOut)
457		{
458			case 0:
459				break;
460
461			case 1:
462				packets[ndx]->outputs[0] = color;
463				break;
464
465			case 2:
466				packets[ndx]->outputs[0] = color * 0.5f;
467				packets[ndx]->outputs[1] = color.swizzle(2,1,0,3) * 0.5f;
468				break;
469
470			default:
471				DE_ASSERT(DE_FALSE);
472		}
473	}
474}
475
476void VertexVaryingShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
477{
478	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
479	{
480		switch (m_geometryOut)
481		{
482			case 0:
483				for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
484					rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
485				break;
486
487			case 1:
488				for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
489					rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx));
490				break;
491
492			case 2:
493				for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
494					rr::writeFragmentOutput(context, packetNdx, fragNdx, 0,   rr::readTriangleVarying<float>(packets[packetNdx], context, 0, fragNdx)
495					                                                        + rr::readTriangleVarying<float>(packets[packetNdx], context, 1, fragNdx).swizzle(1, 0, 2, 3));
496				break;
497
498			default:
499				DE_ASSERT(DE_FALSE);
500		}
501	}
502}
503
504void VertexVaryingShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
505{
506	DE_UNREF(invocationID);
507
508	const tcu::Vec4 vertexOffset(-0.2f, -0.2f, 0, 0);
509
510	if (m_vertexOut == -1)
511	{
512		// vertex is a no-op
513		const tcu::Vec4 inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
514		rr::GenericVec4	outputs[2];
515
516		// output color
517		switch (m_geometryOut)
518		{
519			case 0:
520				break;
521
522			case 1:
523				outputs[0] = inputColor;
524				break;
525
526			case 2:
527				outputs[0] = inputColor * 0.5f;
528				outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
529				break;
530
531			default:
532				DE_ASSERT(DE_FALSE);
533		}
534
535		for (int ndx = 0; ndx < numPackets; ++ndx)
536		{
537			output.EmitVertex(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
538			output.EmitVertex(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
539			output.EmitVertex(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f) + vertexOffset, 1.0f, outputs, packets[ndx].primitiveIDIn);
540			output.EndPrimitive();
541		}
542	}
543	else
544	{
545		// vertex is not a no-op
546		for (int ndx = 0; ndx < numPackets; ++ndx)
547		{
548			for (int verticeNdx = 0; verticeNdx < verticesIn; ++verticeNdx)
549			{
550				tcu::Vec4		inputColor;
551				rr::GenericVec4	outputs[2];
552
553				// input color
554				switch (m_vertexOut)
555				{
556					case 0:
557						inputColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
558						break;
559
560					case 1:
561						inputColor = packets[ndx].vertices[verticeNdx]->outputs[0].get<float>();
562						break;
563
564					case 2:
565						inputColor = (packets[ndx].vertices[verticeNdx]->outputs[0].get<float>() * 0.5f)
566								   + (packets[ndx].vertices[verticeNdx]->outputs[1].get<float>().swizzle(2, 1, 0, 3) * 0.5f);
567						break;
568
569					default:
570						DE_ASSERT(DE_FALSE);
571				}
572
573				// output color
574				switch (m_geometryOut)
575				{
576					case 0:
577						break;
578
579					case 1:
580						outputs[0] = inputColor;
581						break;
582
583					case 2:
584						outputs[0] = inputColor * 0.5f;
585						outputs[1] = inputColor.swizzle(1, 0, 2, 3) * 0.5f;
586						break;
587
588					default:
589						DE_ASSERT(DE_FALSE);
590				}
591
592				output.EmitVertex(packets[ndx].vertices[verticeNdx]->position + vertexOffset, packets[ndx].vertices[verticeNdx]->pointSize, outputs, packets[ndx].primitiveIDIn);
593			}
594			output.EndPrimitive();
595		}
596	}
597}
598
599sglr::pdec::ShaderProgramDeclaration VertexVaryingShader::genProgramDeclaration	(int vertexOut, int geometryOut)
600{
601	sglr::pdec::ShaderProgramDeclaration	decl;
602	std::ostringstream						vertexSource;
603	std::ostringstream						fragmentSource;
604	std::ostringstream						geometrySource;
605
606	decl
607		<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
608		<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT);
609
610	for (int i = 0; i < vertexOut; ++i)
611		decl << sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT);
612	for (int i = 0; i < geometryOut; ++i)
613		decl << sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
614
615	decl
616		<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
617		<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_TRIANGLES, rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, 3);
618
619	// vertexSource
620
621	vertexSource << "#version 310 es\n"
622					"in highp vec4 a_position;\n"
623					"in highp vec4 a_color;\n";
624
625	// no-op case?
626	if (vertexOut == -1)
627	{
628		vertexSource << "void main (void)\n"
629						"{\n"
630						"}\n";
631	}
632	else
633	{
634		for (int i = 0; i < vertexOut; ++i)
635			vertexSource << "out highp vec4 v_geom_" << i << ";\n";
636
637		vertexSource << "void main (void)\n"
638						"{\n"
639						"\tgl_Position = a_position;\n"
640						"\tgl_PointSize = 1.0;\n";
641		switch (vertexOut)
642		{
643			case 0:
644				break;
645
646			case 1:
647				vertexSource << "\tv_geom_0 = a_color;\n";
648				break;
649
650			case 2:
651				vertexSource << "\tv_geom_0 = a_color * 0.5;\n";
652				vertexSource << "\tv_geom_1 = a_color.zyxw * 0.5;\n";
653				break;
654
655			default:
656				DE_ASSERT(DE_FALSE);
657		}
658		vertexSource << "}\n";
659	}
660
661	// fragmentSource
662
663	fragmentSource <<	"#version 310 es\n"
664						"layout(location = 0) out mediump vec4 fragColor;\n";
665
666	for (int i = 0; i < geometryOut; ++i)
667		fragmentSource << "in mediump vec4 v_frag_" << i << ";\n";
668
669	fragmentSource <<	"void main (void)\n"
670						"{\n";
671	switch (geometryOut)
672	{
673		case 0:
674			fragmentSource << "\tfragColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
675			break;
676
677		case 1:
678			fragmentSource << "\tfragColor = v_frag_0;\n";
679			break;
680
681		case 2:
682			fragmentSource << "\tfragColor = v_frag_0 + v_frag_1.yxzw;\n";
683			break;
684
685		default:
686			DE_ASSERT(DE_FALSE);
687	}
688	fragmentSource << "}\n";
689
690	// geometrySource
691
692	geometrySource <<	"#version 310 es\n"
693						"#extension GL_EXT_geometry_shader : require\n"
694						"layout(triangles) in;\n"
695						"layout(triangle_strip, max_vertices = 3) out;\n";
696
697	for (int i = 0; i < vertexOut; ++i)
698		geometrySource << "in highp vec4 v_geom_" << i << "[];\n";
699	for (int i = 0; i < geometryOut; ++i)
700		geometrySource << "out highp vec4 v_frag_" << i << ";\n";
701
702	geometrySource <<	"void main (void)\n"
703						"{\n"
704						"\thighp vec4 offset = vec4(-0.2, -0.2, 0.0, 0.0);\n"
705						"\thighp vec4 inputColor;\n\n";
706
707	for (int vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
708	{
709		if (vertexOut == -1)
710		{
711			// vertex is a no-op
712			geometrySource <<	"\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
713								"\tgl_Position = vec4(" << ((vertexNdx==0) ? ("0.0, 0.0") : ((vertexNdx==1) ? ("1.0, 0.0") : ("1.0, 1.0"))) << ", 0.0, 1.0) + offset;\n"
714								"\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
715		}
716		else
717		{
718			switch (vertexOut)
719			{
720				case 0:
721					geometrySource << "\tinputColor = vec4(1.0, 0.0, 0.0, 1.0);\n";
722					break;
723
724				case 1:
725					geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "];\n";
726					break;
727
728				case 2:
729					geometrySource << "\tinputColor = v_geom_0[" << vertexNdx << "] * 0.5 + v_geom_1[" << vertexNdx << "].zyxw * 0.5;\n";
730					break;
731
732				default:
733					DE_ASSERT(DE_FALSE);
734			}
735			geometrySource <<	"\tgl_Position = gl_in[" << vertexNdx << "].gl_Position + offset;\n"
736								"\tgl_PrimitiveID = gl_PrimitiveIDIn;\n";
737		}
738
739		switch (geometryOut)
740		{
741			case 0:
742				break;
743
744			case 1:
745				geometrySource << "\tv_frag_0 = inputColor;\n";
746				break;
747
748			case 2:
749				geometrySource << "\tv_frag_0 = inputColor * 0.5;\n";
750				geometrySource << "\tv_frag_1 = inputColor.yxzw * 0.5;\n";
751				break;
752
753			default:
754				DE_ASSERT(DE_FALSE);
755		}
756
757		geometrySource << "\tEmitVertex();\n\n";
758	}
759
760	geometrySource <<	"\tEndPrimitive();\n"
761						"}\n";
762
763	decl
764		<< sglr::pdec::VertexSource(vertexSource.str().c_str())
765		<< sglr::pdec::FragmentSource(fragmentSource.str().c_str())
766		<< sglr::pdec::GeometrySource(geometrySource.str().c_str());
767	return decl;
768}
769
770class OutputCountShader : public sglr::ShaderProgram
771{
772public:
773									OutputCountShader		(const OutputCountPatternSpec& spec);
774
775	void							shadeVertices			(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
776	void							shadeFragments			(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
777	void							shadePrimitives			(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
778
779private:
780	std::string						genGeometrySource		(const OutputCountPatternSpec& spec) const;
781	size_t							getPatternEmitCount		(const OutputCountPatternSpec& spec) const;
782
783	const int						m_patternLength;
784	const int						m_patternMaxEmitCount;
785	const OutputCountPatternSpec	m_spec;
786};
787
788OutputCountShader::OutputCountShader (const OutputCountPatternSpec& spec)
789	: sglr::ShaderProgram	(sglr::pdec::ShaderProgramDeclaration()
790							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
791							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
792							<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
793							<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
794							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
795							<< sglr::pdec::VertexSource(s_commonShaderSourceVertex)
796							<< sglr::pdec::FragmentSource(s_commonShaderSourceFragment)
797							<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS, rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP, getPatternEmitCount(spec))
798							<< sglr::pdec::GeometrySource(genGeometrySource(spec).c_str()))
799	, m_patternLength		((int)spec.pattern.size())
800	, m_patternMaxEmitCount	((int)getPatternEmitCount(spec))
801	, m_spec				(spec)
802{
803}
804
805void OutputCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
806{
807	for (int ndx = 0; ndx < numPackets; ++ndx)
808	{
809		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
810		packets[ndx]->pointSize = 1.0f;
811		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
812	}
813}
814
815void OutputCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
816{
817	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
818	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
819		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
820}
821
822void OutputCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
823{
824	DE_UNREF(verticesIn);
825	DE_UNREF(invocationID);
826
827	const float rowHeight	= 2.0f / (float)m_patternLength;
828	const float colWidth	= 2.0f / (float)m_patternMaxEmitCount;
829
830	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
831	{
832		// Create triangle strip at this point
833		const rr::VertexPacket*	vertex		= packets[packetNdx].vertices[0];
834		const int				emitCount	= m_spec.pattern[packets[packetNdx].primitiveIDIn];
835
836		for (int ndx = 0; ndx < emitCount / 2; ++ndx)
837		{
838			output.EmitVertex(vertex->position + tcu::Vec4(2 * ndx * colWidth, 0.0,       0.0, 0.0), vertex->pointSize, vertex->outputs, packets[packetNdx].primitiveIDIn);
839			output.EmitVertex(vertex->position + tcu::Vec4(2 * ndx * colWidth, rowHeight, 0.0, 0.0), vertex->pointSize, vertex->outputs, packets[packetNdx].primitiveIDIn);
840		}
841		output.EndPrimitive();
842	}
843}
844
845std::string	OutputCountShader::genGeometrySource (const OutputCountPatternSpec& spec) const
846{
847	std::ostringstream str;
848
849	// draw row with a triangle strip, always make rectangles
850	for (int ndx = 0; ndx < (int)spec.pattern.size(); ++ndx)
851		DE_ASSERT(spec.pattern[ndx] % 2 == 0);
852
853	str << "#version 310 es\n";
854	str << "#extension GL_EXT_geometry_shader : require\n";
855	str << "layout(points) in;\n";
856	str << "layout(triangle_strip, max_vertices = " << getPatternEmitCount(spec) << ") out;";
857	str << "\n";
858
859	str <<	"in highp vec4 v_geom_FragColor[];\n"
860			"out highp vec4 v_frag_FragColor;\n"
861			"\n"
862			"void main (void)\n"
863			"{\n"
864			"	const highp float rowHeight = 2.0 / float(" << spec.pattern.size() << ");\n"
865			"	const highp float colWidth = 2.0 / float(" << getPatternEmitCount(spec) << ");\n"
866			"\n";
867
868	str <<	"	highp int emitCount = ";
869	for (int ndx = 0; ndx < (int)spec.pattern.size() - 1; ++ndx)
870		str << "(gl_PrimitiveIDIn == " << ndx << ") ? (" << spec.pattern[ndx] << ") : (";
871	str <<	spec.pattern[(int)spec.pattern.size() - 1]
872		<<	((spec.pattern.size() == 1) ? ("") : (")"))
873		<<	";\n";
874
875	str <<	"	for (highp int ndx = 0; ndx < emitCount / 2; ndx++)\n"
876			"	{\n"
877			"		gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, 0.0, 0.0, 0.0);\n"
878			"		v_frag_FragColor = v_geom_FragColor[0];\n"
879			"		EmitVertex();\n"
880			"\n"
881			"		gl_Position = gl_in[0].gl_Position + vec4(float(ndx) * 2.0 * colWidth, rowHeight, 0.0, 0.0);\n"
882			"		v_frag_FragColor = v_geom_FragColor[0];\n"
883			"		EmitVertex();\n"
884			"	}\n"
885			"}\n";
886
887	return str.str();
888}
889
890size_t OutputCountShader::getPatternEmitCount (const OutputCountPatternSpec& spec) const
891{
892	return *std::max_element(spec.pattern.begin(), spec.pattern.end());
893}
894
895class BuiltinVariableShader : public sglr::ShaderProgram
896{
897public:
898	enum VariableTest
899	{
900		TEST_POINT_SIZE = 0,
901		TEST_PRIMITIVE_ID_IN,
902		TEST_PRIMITIVE_ID,
903
904		TEST_LAST
905	};
906
907						BuiltinVariableShader	(VariableTest test);
908
909	void				shadeVertices			(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
910	void				shadeFragments			(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
911	void				shadePrimitives			(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
912
913	static const char*	getTestAttributeName	(VariableTest test);
914
915private:
916	std::string			genGeometrySource		(VariableTest test) const;
917	std::string			genVertexSource			(VariableTest test) const;
918	std::string			genFragmentSource		(VariableTest test) const;
919
920	const VariableTest	m_test;
921};
922
923BuiltinVariableShader::BuiltinVariableShader (VariableTest test)
924	: sglr::ShaderProgram	(sglr::pdec::ShaderProgramDeclaration()
925							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
926							<< sglr::pdec::VertexAttribute(getTestAttributeName(test), rr::GENERICVECTYPE_FLOAT)
927							<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
928							<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
929							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
930							<< sglr::pdec::VertexSource(genVertexSource(test))
931							<< sglr::pdec::FragmentSource(genFragmentSource(test))
932							<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
933																	 ((test == TEST_POINT_SIZE) ? (rr::GEOMETRYSHADEROUTPUTTYPE_POINTS) : (rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP)),
934																	 ((test == TEST_POINT_SIZE) ? (1) : (3)))
935							<< sglr::pdec::GeometrySource(genGeometrySource(test).c_str()))
936	, m_test				(test)
937{
938}
939
940void BuiltinVariableShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
941{
942	for (int ndx = 0; ndx < numPackets; ++ndx)
943	{
944		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
945		packets[ndx]->pointSize = 1.0f;
946		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
947	}
948}
949
950void BuiltinVariableShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
951{
952	const tcu::Vec4 red			= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
953	const tcu::Vec4 green		= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
954	const tcu::Vec4 blue		= tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
955	const tcu::Vec4 yellow		= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
956	const tcu::Vec4 colors[4]	= { yellow, red, green, blue };
957
958	if (m_test == TEST_POINT_SIZE || m_test == TEST_PRIMITIVE_ID_IN)
959	{
960		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
961		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
962			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
963	}
964	else if (m_test == TEST_PRIMITIVE_ID)
965	{
966		const tcu::Vec4 color = colors[context.primitiveID % 4];
967
968		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
969		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
970			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
971	}
972	else
973		DE_ASSERT(DE_FALSE);
974}
975
976void BuiltinVariableShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
977{
978	DE_UNREF(verticesIn);
979	DE_UNREF(invocationID);
980
981	const tcu::Vec4 red			= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
982	const tcu::Vec4 green		= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
983	const tcu::Vec4 blue		= tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
984	const tcu::Vec4 yellow		= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
985	const tcu::Vec4 colors[4]	= { red, green, blue, yellow };
986
987	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
988	{
989		const rr::VertexPacket*	vertex = packets[packetNdx].vertices[0];
990
991		if (m_test == TEST_POINT_SIZE)
992		{
993			rr::GenericVec4	fragColor;
994			const float		pointSize = vertex->outputs[0].get<float>().x() + 1.0f;
995
996			fragColor = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
997			output.EmitVertex(vertex->position, pointSize, &fragColor, packets[packetNdx].primitiveIDIn);
998		}
999		else if (m_test == TEST_PRIMITIVE_ID_IN)
1000		{
1001			rr::GenericVec4	fragColor;
1002			fragColor = colors[packets[packetNdx].primitiveIDIn % 4];
1003
1004			output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1005			output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1006			output.EmitVertex(vertex->position + tcu::Vec4(0.0f,  0.05f, 0.0f, 0.0f), 1.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1007		}
1008		else if (m_test == TEST_PRIMITIVE_ID)
1009		{
1010			const int primitiveID = (int)deFloatFloor(vertex->outputs[0].get<float>().x()) + 3;
1011
1012			output.EmitVertex(vertex->position + tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
1013			output.EmitVertex(vertex->position - tcu::Vec4(0.05f, 0.0f,  0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
1014			output.EmitVertex(vertex->position + tcu::Vec4(0.0f,  0.05f, 0.0f, 0.0f), 1.0f, vertex->outputs, primitiveID);
1015		}
1016		else
1017			DE_ASSERT(DE_FALSE);
1018
1019		output.EndPrimitive();
1020	}
1021}
1022
1023const char* BuiltinVariableShader::getTestAttributeName (VariableTest test)
1024{
1025	switch (test)
1026	{
1027		case TEST_POINT_SIZE:			return "a_pointSize";
1028		case TEST_PRIMITIVE_ID_IN:		return "";
1029		case TEST_PRIMITIVE_ID:			return "a_primitiveID";
1030		default:
1031			DE_ASSERT(DE_FALSE);
1032			return "";
1033	}
1034}
1035
1036std::string BuiltinVariableShader::genGeometrySource (VariableTest test) const
1037{
1038	std::ostringstream buf;
1039
1040	buf <<	"#version 310 es\n"
1041			"#extension GL_EXT_geometry_shader : require\n";
1042
1043	if (test == TEST_POINT_SIZE)
1044		buf << "#extension GL_EXT_geometry_point_size : require\n";
1045
1046	buf << "layout(points) in;\n";
1047
1048	if (test == TEST_POINT_SIZE)
1049		buf << "layout(points, max_vertices = 1) out;\n";
1050	else
1051		buf << "layout(triangle_strip, max_vertices = 3) out;\n";
1052
1053	if (test == TEST_POINT_SIZE)
1054		buf << "in highp vec4 v_geom_pointSize[];\n";
1055	else if (test == TEST_PRIMITIVE_ID)
1056		buf << "in highp vec4 v_geom_primitiveID[];\n";
1057
1058	if (test != TEST_PRIMITIVE_ID)
1059		buf << "out highp vec4 v_frag_FragColor;\n";
1060
1061	buf <<	"\n"
1062			"void main (void)\n"
1063			"{\n";
1064
1065	if (test == TEST_POINT_SIZE)
1066	{
1067		buf <<	"	gl_Position = gl_in[0].gl_Position;\n"
1068				"	gl_PointSize = v_geom_pointSize[0].x + 1.0;\n"
1069				"	v_frag_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
1070				"	EmitVertex();\n";
1071	}
1072	else if (test == TEST_PRIMITIVE_ID_IN)
1073	{
1074		buf <<	"	const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1075				"	const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1076				"	const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1077				"	const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1078				"	const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
1079				"\n"
1080				"	gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
1081				"	v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1082				"	EmitVertex();\n"
1083				"\n"
1084				"	gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
1085				"	v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1086				"	EmitVertex();\n"
1087				"\n"
1088				"	gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
1089				"	v_frag_FragColor = colors[gl_PrimitiveIDIn % 4];\n"
1090				"	EmitVertex();\n";
1091	}
1092	else if (test == TEST_PRIMITIVE_ID)
1093	{
1094		buf <<	"	gl_Position = gl_in[0].gl_Position + vec4(0.05, 0.0, 0.0, 0.0);\n"
1095				"	gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1096				"	EmitVertex();\n"
1097				"\n"
1098				"	gl_Position = gl_in[0].gl_Position - vec4(0.05, 0.0, 0.0, 0.0);\n"
1099				"	gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1100				"	EmitVertex();\n"
1101				"\n"
1102				"	gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.05, 0.0, 0.0);\n"
1103				"	gl_PrimitiveID = int(floor(v_geom_primitiveID[0].x)) + 3;\n"
1104				"	EmitVertex();\n"
1105				"\n";
1106	}
1107	else
1108		DE_ASSERT(DE_FALSE);
1109
1110	buf << "}\n";
1111
1112	return buf.str();
1113}
1114
1115std::string BuiltinVariableShader::genVertexSource (VariableTest test) const
1116{
1117	std::ostringstream buf;
1118
1119	buf <<	"#version 310 es\n"
1120			"in highp vec4 a_position;\n";
1121
1122	if (test == TEST_POINT_SIZE)
1123		buf << "in highp vec4 a_pointSize;\n";
1124	else if (test == TEST_PRIMITIVE_ID)
1125		buf << "in highp vec4 a_primitiveID;\n";
1126
1127	if (test == TEST_POINT_SIZE)
1128		buf << "out highp vec4 v_geom_pointSize;\n";
1129	else if (test == TEST_PRIMITIVE_ID)
1130		buf << "out highp vec4 v_geom_primitiveID;\n";
1131
1132	buf <<	"void main (void)\n"
1133			"{\n"
1134			"	gl_Position = a_position;\n"
1135			"	gl_PointSize = 1.0;\n";
1136
1137	if (test == TEST_POINT_SIZE)
1138		buf << "	v_geom_pointSize = a_pointSize;\n";
1139	else if (test == TEST_PRIMITIVE_ID)
1140		buf << "	v_geom_primitiveID = a_primitiveID;\n";
1141
1142	buf <<	"}\n";
1143
1144	return buf.str();
1145}
1146
1147std::string BuiltinVariableShader::genFragmentSource (VariableTest test) const
1148{
1149	if (test == TEST_POINT_SIZE || test == TEST_PRIMITIVE_ID_IN)
1150		return s_commonShaderSourceFragment;
1151	else if (test == TEST_PRIMITIVE_ID)
1152	{
1153		return	"#version 310 es\n"
1154				"#extension GL_EXT_geometry_shader : require\n"
1155				"layout(location = 0) out mediump vec4 fragColor;\n"
1156				"void main (void)\n"
1157				"{\n"
1158				"	const mediump vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1159				"	const mediump vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1160				"	const mediump vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1161				"	const mediump vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1162				"	const mediump vec4 colors[4] = vec4[4](yellow, red, green, blue);\n"
1163				"	fragColor = colors[gl_PrimitiveID % 4];\n"
1164				"}\n";
1165	}
1166	else
1167	{
1168		DE_ASSERT(DE_FALSE);
1169		return DE_NULL;
1170	}
1171}
1172
1173class VaryingOutputCountShader : public sglr::ShaderProgram
1174{
1175public:
1176	enum VaryingSource
1177	{
1178		READ_ATTRIBUTE = 0,
1179		READ_UNIFORM,
1180		READ_TEXTURE,
1181
1182		READ_LAST
1183	};
1184
1185	enum
1186	{
1187		EMIT_COUNT_VERTEX_0 = 6,
1188		EMIT_COUNT_VERTEX_1 = 0,
1189		EMIT_COUNT_VERTEX_2 = -1,
1190		EMIT_COUNT_VERTEX_3 = 10,
1191	};
1192
1193								VaryingOutputCountShader	(VaryingSource source, int maxEmitCount, bool instanced);
1194
1195	void						shadeVertices				(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1196	void						shadeFragments				(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1197	void						shadePrimitives				(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
1198
1199	static const char*			getAttributeName			(VaryingSource test);
1200
1201private:
1202	static std::string			genGeometrySource			(VaryingSource test, int maxEmitCount, bool instanced);
1203	static std::string			genVertexSource				(VaryingSource test);
1204
1205	const VaryingSource			m_test;
1206	const sglr::UniformSlot&	m_sampler;
1207	const sglr::UniformSlot&	m_emitCount;
1208	const int					m_maxEmitCount;
1209	const bool					m_instanced;
1210};
1211
1212VaryingOutputCountShader::VaryingOutputCountShader (VaryingSource source, int maxEmitCount, bool instanced)
1213	: sglr::ShaderProgram	(sglr::pdec::ShaderProgramDeclaration()
1214							<< sglr::pdec::Uniform("u_sampler", glu::TYPE_SAMPLER_2D)
1215							<< sglr::pdec::Uniform("u_emitCount", glu::TYPE_INT_VEC4)
1216							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1217							<< sglr::pdec::VertexAttribute(getAttributeName(source), rr::GENERICVECTYPE_FLOAT)
1218							<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
1219							<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
1220							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1221							<< sglr::pdec::VertexSource(genVertexSource(source))
1222							<< sglr::pdec::FragmentSource(s_commonShaderSourceFragment)
1223							<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1224																	 rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
1225																	 maxEmitCount,
1226																	 (instanced) ? (4) : (1))
1227							<< sglr::pdec::GeometrySource(genGeometrySource(source, maxEmitCount, instanced).c_str()))
1228	, m_test				(source)
1229	, m_sampler				(getUniformByName("u_sampler"))
1230	, m_emitCount			(getUniformByName("u_emitCount"))
1231	, m_maxEmitCount		(maxEmitCount)
1232	, m_instanced			(instanced)
1233{
1234}
1235
1236void VaryingOutputCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1237{
1238	for (int ndx = 0; ndx < numPackets; ++ndx)
1239	{
1240		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1241		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1242	}
1243}
1244
1245void VaryingOutputCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1246{
1247	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1248	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1249		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
1250}
1251
1252void VaryingOutputCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
1253{
1254	DE_UNREF(verticesIn);
1255
1256	const tcu::Vec4 red			= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1257	const tcu::Vec4 green		= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1258	const tcu::Vec4 blue		= tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
1259	const tcu::Vec4 yellow		= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
1260	const tcu::Vec4 colors[4]	= { red, green, blue, yellow };
1261
1262	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1263	{
1264		const rr::VertexPacket*	vertex		= packets[packetNdx].vertices[0];
1265		int						emitCount	= 0;
1266		tcu::Vec4				color		= tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
1267
1268		if (m_test == READ_ATTRIBUTE)
1269		{
1270			emitCount = (int)vertex->outputs[0].get<float>()[(m_instanced) ? (invocationID) : (0)];
1271			color = tcu::Vec4((emitCount < 10) ? (0.0f) : (1.0f), (emitCount > 10) ? (0.0f) : (1.0f), 1.0f, 1.0f);
1272		}
1273		else if (m_test == READ_UNIFORM)
1274		{
1275			const int primitiveNdx = (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
1276
1277			DE_ASSERT(primitiveNdx >= 0);
1278			DE_ASSERT(primitiveNdx < 4);
1279
1280			emitCount = m_emitCount.value.i4[primitiveNdx];
1281			color = colors[primitiveNdx];
1282		}
1283		else if (m_test == READ_TEXTURE)
1284		{
1285			const int			primitiveNdx	= (m_instanced) ? (invocationID) : ((int)vertex->outputs[0].get<float>().x());
1286			const tcu::Vec2		texCoord		= tcu::Vec2(1.0f / 8.0f + primitiveNdx / 4.0f, 0.5f);
1287			const tcu::Vec4		texColor		= m_sampler.sampler.tex2D->sample(texCoord.x(), texCoord.y(), 0.0f);
1288
1289			DE_ASSERT(primitiveNdx >= 0);
1290			DE_ASSERT(primitiveNdx < 4);
1291
1292			color = colors[primitiveNdx];
1293			emitCount = 0;
1294
1295			if (texColor.x() > 0.0f)
1296				emitCount += (EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_0);
1297			if (texColor.y() > 0.0f)
1298				emitCount += (EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_1);
1299			if (texColor.z() > 0.0f)
1300				emitCount += (EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_2);
1301			if (texColor.w() > 0.0f)
1302				emitCount += (EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (EMIT_COUNT_VERTEX_3);
1303		}
1304		else
1305			DE_ASSERT(DE_FALSE);
1306
1307		for (int ndx = 0; ndx < (int)emitCount / 2; ++ndx)
1308		{
1309			const float		angle			= (float(ndx) + 0.5f) / float(emitCount / 2) * 3.142f;
1310			const tcu::Vec4 basePosition	= (m_instanced) ?
1311												(vertex->position + tcu::Vec4(deFloatCos(float(invocationID)), deFloatSin(float(invocationID)), 0.0f, 0.0f) * 0.5f) :
1312												(vertex->position);
1313			const tcu::Vec4	position0		= basePosition + tcu::Vec4(deFloatCos(angle),  deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
1314			const tcu::Vec4	position1		= basePosition + tcu::Vec4(deFloatCos(angle), -deFloatSin(angle), 0.0f, 0.0f) * 0.15f;
1315			rr::GenericVec4	fragColor;
1316
1317			fragColor = color;
1318
1319			output.EmitVertex(position0, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1320			output.EmitVertex(position1, 0.0f, &fragColor, packets[packetNdx].primitiveIDIn);
1321		}
1322
1323		output.EndPrimitive();
1324	}
1325}
1326
1327const char* VaryingOutputCountShader::getAttributeName (VaryingSource test)
1328{
1329	switch (test)
1330	{
1331		case READ_ATTRIBUTE:	return "a_emitCount";
1332		case READ_UNIFORM:		return "a_vertexNdx";
1333		case READ_TEXTURE:		return "a_vertexNdx";
1334		default:
1335			DE_ASSERT(DE_FALSE);
1336			return "";
1337	}
1338}
1339
1340std::string VaryingOutputCountShader::genGeometrySource (VaryingSource test, int maxEmitCount, bool instanced)
1341{
1342	std::ostringstream buf;
1343
1344	buf <<	"#version 310 es\n"
1345			"#extension GL_EXT_geometry_shader : require\n"
1346			"layout(points" << ((instanced) ? (",invocations=4") : ("")) << ") in;\n"
1347			"layout(triangle_strip, max_vertices = " << maxEmitCount << ") out;\n";
1348
1349	if (test == READ_ATTRIBUTE)
1350		buf <<	"in highp vec4 v_geom_emitCount[];\n";
1351	else if (test == READ_UNIFORM)
1352		buf <<	"in highp vec4 v_geom_vertexNdx[];\n"
1353				"uniform highp ivec4 u_emitCount;\n";
1354	else
1355		buf <<	"in highp vec4 v_geom_vertexNdx[];\n"
1356				"uniform highp sampler2D u_sampler;\n";
1357
1358	buf <<	"out highp vec4 v_frag_FragColor;\n"
1359			"\n"
1360			"void main (void)\n"
1361			"{\n";
1362
1363	// emit count
1364
1365	if (test == READ_ATTRIBUTE)
1366	{
1367		buf <<	"	highp vec4 attrEmitCounts = v_geom_emitCount[0];\n"
1368				"	mediump int emitCount = int(attrEmitCounts[" << ((instanced) ? ("gl_InvocationID") : ("0")) << "]);\n";
1369	}
1370	else if (test == READ_UNIFORM)
1371	{
1372		buf <<	"	mediump int primitiveNdx = " << ((instanced) ? ("gl_InvocationID") : ("int(v_geom_vertexNdx[0].x)")) << ";\n"
1373				"	mediump int emitCount = u_emitCount[primitiveNdx];\n";
1374	}
1375	else if (test == READ_TEXTURE)
1376	{
1377		buf <<	"	highp float primitiveNdx = " << ((instanced) ? ("float(gl_InvocationID)") : ("v_geom_vertexNdx[0].x")) << ";\n"
1378				"	highp vec2 texCoord = vec2(1.0 / 8.0 + primitiveNdx / 4.0, 0.5);\n"
1379				"	highp vec4 texColor = texture(u_sampler, texCoord);\n"
1380				"	mediump int emitCount = 0;\n"
1381				"	if (texColor.x > 0.0)\n"
1382				"		emitCount += " << ((EMIT_COUNT_VERTEX_0 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_0)) << ";\n"
1383				"	if (texColor.y > 0.0)\n"
1384				"		emitCount += " << ((EMIT_COUNT_VERTEX_1 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_1)) << ";\n"
1385				"	if (texColor.z > 0.0)\n"
1386				"		emitCount += " << ((EMIT_COUNT_VERTEX_2 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_2)) << ";\n"
1387				"	if (texColor.w > 0.0)\n"
1388				"		emitCount += " << ((EMIT_COUNT_VERTEX_3 == -1) ? (maxEmitCount) : (EMIT_COUNT_VERTEX_3)) << ";\n";
1389	}
1390	else
1391		DE_ASSERT(DE_FALSE);
1392
1393	// color
1394
1395	if (test == READ_ATTRIBUTE)
1396	{
1397		// We don't want color to be compile time constant
1398		buf <<	"	highp vec4 color = vec4((emitCount < 10) ? (0.0) : (1.0), (emitCount > 10) ? (0.0) : (1.0), 1.0, 1.0);\n";
1399	}
1400	else if (test == READ_UNIFORM || test == READ_TEXTURE)
1401	{
1402		buf <<	"\n"
1403				"	const highp vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
1404				"	const highp vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
1405				"	const highp vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
1406				"	const highp vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
1407				"	const highp vec4 colors[4] = vec4[4](red, green, blue, yellow);\n"
1408				"	highp vec4 color = colors[int(primitiveNdx)];\n";
1409	}
1410	else
1411		DE_ASSERT(DE_FALSE);
1412
1413	buf <<	"\n"
1414			"	highp vec4 basePos = " << ((instanced) ? ("gl_in[0].gl_Position + 0.5 * vec4(cos(float(gl_InvocationID)), sin(float(gl_InvocationID)), 0.0, 0.0)") : ("gl_in[0].gl_Position")) << ";\n"
1415			"	for (mediump int i = 0; i < emitCount / 2; i++)\n"
1416			"	{\n"
1417			"		highp float angle = (float(i) + 0.5) / float(emitCount / 2) * 3.142;\n"
1418			"		gl_Position = basePos + vec4(cos(angle),  sin(angle), 0.0, 0.0) * 0.15;\n"
1419			"		v_frag_FragColor = color;\n"
1420			"		EmitVertex();\n"
1421			"		gl_Position = basePos + vec4(cos(angle), -sin(angle), 0.0, 0.0) * 0.15;\n"
1422			"		v_frag_FragColor = color;\n"
1423			"		EmitVertex();\n"
1424			"	}"
1425			"}\n";
1426
1427	return buf.str();
1428}
1429
1430std::string VaryingOutputCountShader::genVertexSource (VaryingSource test)
1431{
1432	std::ostringstream buf;
1433
1434	buf <<	"#version 310 es\n"
1435			"in highp vec4 a_position;\n";
1436
1437	if (test == READ_ATTRIBUTE)
1438	{
1439		buf << "in highp vec4 a_emitCount;\n";
1440		buf << "out highp vec4 v_geom_emitCount;\n";
1441	}
1442	else if (test == READ_UNIFORM || test == READ_TEXTURE)
1443	{
1444		buf << "in highp vec4 a_vertexNdx;\n";
1445		buf << "out highp vec4 v_geom_vertexNdx;\n";
1446	}
1447
1448	buf <<	"void main (void)\n"
1449			"{\n"
1450			"	gl_Position = a_position;\n";
1451
1452	if (test == READ_ATTRIBUTE)
1453		buf << "	v_geom_emitCount = a_emitCount;\n";
1454	else if (test == READ_UNIFORM || test == READ_TEXTURE)
1455		buf << "	v_geom_vertexNdx = a_vertexNdx;\n";
1456
1457	buf <<	"}\n";
1458
1459	return buf.str();
1460}
1461
1462class InvocationCountShader : public sglr::ShaderProgram
1463{
1464public:
1465	enum OutputCase
1466	{
1467		CASE_FIXED_OUTPUT_COUNTS = 0,
1468		CASE_DIFFERENT_OUTPUT_COUNTS,
1469
1470		CASE_LAST
1471	};
1472
1473						InvocationCountShader		 (int numInvocations, OutputCase testCase);
1474
1475private:
1476	void				shadeVertices				(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1477	void				shadeFragments				(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1478	void				shadePrimitives				(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
1479
1480	static std::string	genGeometrySource			(int numInvocations, OutputCase testCase);
1481	static size_t		getNumVertices				(int numInvocations, OutputCase testCase);
1482
1483	const int			m_numInvocations;
1484	const OutputCase	m_testCase;
1485};
1486
1487InvocationCountShader::InvocationCountShader (int numInvocations, OutputCase testCase)
1488	: sglr::ShaderProgram	(sglr::pdec::ShaderProgramDeclaration()
1489							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1490							<< sglr::pdec::VertexAttribute("a_color", rr::GENERICVECTYPE_FLOAT)
1491							<< sglr::pdec::VertexToGeometryVarying(rr::GENERICVECTYPE_FLOAT)
1492							<< sglr::pdec::GeometryToFragmentVarying(rr::GENERICVECTYPE_FLOAT)
1493							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1494							<< sglr::pdec::VertexSource(s_commonShaderSourceVertex)
1495							<< sglr::pdec::FragmentSource(s_commonShaderSourceFragment)
1496							<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1497																	 rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
1498																	 getNumVertices(numInvocations, testCase),
1499																	 numInvocations)
1500							<< sglr::pdec::GeometrySource(genGeometrySource(numInvocations, testCase).c_str()))
1501	, m_numInvocations		(numInvocations)
1502	, m_testCase			(testCase)
1503{
1504}
1505
1506void InvocationCountShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1507{
1508	for (int ndx = 0; ndx < numPackets; ++ndx)
1509	{
1510		packets[ndx]->position = rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1511		packets[ndx]->outputs[0] = rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1512	}
1513}
1514
1515void InvocationCountShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1516{
1517	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1518	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1519		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx));
1520}
1521
1522void InvocationCountShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
1523{
1524	DE_UNREF(verticesIn);
1525
1526	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1527	{
1528		const float				l_angle		= float(invocationID) / float(m_numInvocations) * 5.5f;
1529		const float				l_radius	= 0.6f;
1530
1531		const rr::VertexPacket*	vertex		= packets[packetNdx].vertices[0];
1532
1533		if (m_testCase == CASE_FIXED_OUTPUT_COUNTS)
1534		{
1535			const tcu::Vec4			position0	= vertex->position + tcu::Vec4(deFloatCos(l_angle)      * (l_radius - 0.1f), deFloatSin(l_angle)      * (l_radius - 0.1f), 0.0f, 0.0f);
1536			const tcu::Vec4			position1	= vertex->position + tcu::Vec4(deFloatCos(l_angle+0.1f) * l_radius,          deFloatSin(l_angle+0.1f) * l_radius,          0.0f, 0.0f);
1537			const tcu::Vec4			position2	= vertex->position + tcu::Vec4(deFloatCos(l_angle-0.1f) * l_radius,          deFloatSin(l_angle-0.1f) * l_radius,          0.0f, 0.0f);
1538
1539			rr::GenericVec4			tipColor;
1540			rr::GenericVec4			baseColor;
1541
1542			tipColor  = tcu::Vec4(1.0, 1.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
1543			baseColor = tcu::Vec4(1.0, 0.0, 0.0, 1.0) * packets[packetNdx].vertices[0]->outputs[0].get<float>();
1544
1545			output.EmitVertex(position0, 0.0f, &tipColor, packets[packetNdx].primitiveIDIn);
1546			output.EmitVertex(position1, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
1547			output.EmitVertex(position2, 0.0f, &baseColor, packets[packetNdx].primitiveIDIn);
1548			output.EndPrimitive();
1549		}
1550		else if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
1551		{
1552			const tcu::Vec4 color			= tcu::Vec4(float(invocationID % 2), (((invocationID / 2) % 2) == 0) ? (1.0f) : (0.0f), 1.0f, 1.0f);
1553			const tcu::Vec4 basePosition	= vertex->position + tcu::Vec4(deFloatCos(l_angle) * l_radius, deFloatSin(l_angle) * l_radius, 0.0f, 0.0f);
1554			const int		numNgonVtx		= invocationID + 3;
1555
1556			rr::GenericVec4	outColor;
1557			outColor = color;
1558
1559			for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)
1560			{
1561				const float subAngle = (float(ndx) + 1.0f) / float(numNgonVtx) * 3.141f;
1562
1563				output.EmitVertex(basePosition + tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) *  0.1f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1564				output.EmitVertex(basePosition + tcu::Vec4(deFloatCos(subAngle) * 0.1f, deFloatSin(subAngle) * -0.1f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1565			}
1566
1567			if ((numNgonVtx % 2) == 1)
1568				output.EmitVertex(basePosition + tcu::Vec4(-0.1f, 0.0f, 0.0f, 0.0f), 0.0f, &outColor, packets[packetNdx].primitiveIDIn);
1569
1570			output.EndPrimitive();
1571		}
1572	}
1573}
1574
1575std::string InvocationCountShader::genGeometrySource (int numInvocations, OutputCase testCase)
1576{
1577	const int			maxVertices = (int)getNumVertices(numInvocations, testCase);
1578	std::ostringstream	buf;
1579
1580	buf	<<	"#version 310 es\n"
1581			"#extension GL_EXT_geometry_shader : require\n"
1582			"layout(points, invocations = " << numInvocations << ") in;\n"
1583			"layout(triangle_strip, max_vertices = " << maxVertices << ") out;\n"
1584			"\n"
1585			"in highp vec4 v_geom_FragColor[];\n"
1586			"out highp vec4 v_frag_FragColor;\n"
1587			"\n"
1588			"void main ()\n"
1589			"{\n"
1590			"	highp float l_angle = float(gl_InvocationID) / float(" << numInvocations << ") * 5.5;\n"
1591			"	highp float l_radius = 0.6;\n"
1592			"\n";
1593
1594	if (testCase == CASE_FIXED_OUTPUT_COUNTS)
1595	{
1596		buf <<	"	v_frag_FragColor = vec4(1.0, 1.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1597				"	gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle) * (l_radius - 0.1), sin(l_angle) * (l_radius - 0.1), 0.0, 0.0);\n"
1598				"	EmitVertex();\n"
1599				"\n"
1600				"	v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1601				"	gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle+0.1) * l_radius, sin(l_angle+0.1) * l_radius, 0.0, 0.0);\n"
1602				"	EmitVertex();\n"
1603				"\n"
1604				"	v_frag_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * v_geom_FragColor[0];\n"
1605				"	gl_Position = gl_in[0].gl_Position + vec4(cos(l_angle-0.1) * l_radius, sin(l_angle-0.1) * l_radius, 0.0, 0.0);\n"
1606				"	EmitVertex();\n";
1607	}
1608	else if (testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
1609	{
1610		buf <<	"	highp vec4 l_color = vec4(float(gl_InvocationID % 2), (((gl_InvocationID / 2) % 2) == 0) ? (1.0) : (0.0), 1.0, 1.0);\n"
1611				"	highp vec4 basePosition = gl_in[0].gl_Position + vec4(cos(l_angle) * l_radius, sin(l_angle) * l_radius, 0.0, 0.0);\n"
1612				"	mediump int numNgonVtx = gl_InvocationID + 3;\n"
1613				"\n"
1614				"	for (int ndx = 0; ndx + 1 < numNgonVtx; ndx += 2)\n"
1615				"	{\n"
1616				"		highp float sub_angle = (float(ndx) + 1.0) / float(numNgonVtx) * 3.141;\n"
1617				"\n"
1618				"		v_frag_FragColor = l_color;\n"
1619				"		gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * 0.1, 0.0, 0.0);\n"
1620				"		EmitVertex();\n"
1621				"\n"
1622				"		v_frag_FragColor = l_color;\n"
1623				"		gl_Position = basePosition + vec4(cos(sub_angle) * 0.1, sin(sub_angle) * -0.1, 0.0, 0.0);\n"
1624				"		EmitVertex();\n"
1625				"	}\n"
1626				"	if ((numNgonVtx % 2) == 1)\n"
1627				"	{\n"
1628				"		v_frag_FragColor = l_color;\n"
1629				"		gl_Position = basePosition + vec4(-0.1, 0.0, 0.0, 0.0);\n"
1630				"		EmitVertex();\n"
1631				"	}\n";
1632	}
1633	else
1634		DE_ASSERT(false);
1635
1636	buf <<	"}\n";
1637
1638	return buf.str();
1639}
1640
1641size_t InvocationCountShader::getNumVertices (int numInvocations, OutputCase testCase)
1642{
1643	switch (testCase)
1644	{
1645		case CASE_FIXED_OUTPUT_COUNTS:			return 3;
1646		case CASE_DIFFERENT_OUTPUT_COUNTS:		return (size_t)(2 + numInvocations);
1647		default:
1648			DE_ASSERT(false);
1649			return 0;
1650	}
1651}
1652
1653class InstancedExpansionShader : public sglr::ShaderProgram
1654{
1655public:
1656						InstancedExpansionShader	(int numInvocations);
1657
1658private:
1659	void				shadeVertices				(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1660	void				shadeFragments				(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1661	void				shadePrimitives				(rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const;
1662
1663	static std::string	genVertexSource				(void);
1664	static std::string	genFragmentSource			(void);
1665	static std::string	genGeometrySource			(int numInvocations);
1666
1667	const int			m_numInvocations;
1668};
1669
1670InstancedExpansionShader::InstancedExpansionShader (int numInvocations)
1671	: sglr::ShaderProgram	(sglr::pdec::ShaderProgramDeclaration()
1672							<< sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT)
1673							<< sglr::pdec::VertexAttribute("a_offset", rr::GENERICVECTYPE_FLOAT)
1674							<< sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT)
1675							<< sglr::pdec::VertexSource(genVertexSource())
1676							<< sglr::pdec::FragmentSource(genFragmentSource())
1677							<< sglr::pdec::GeometryShaderDeclaration(rr::GEOMETRYSHADERINPUTTYPE_POINTS,
1678																	 rr::GEOMETRYSHADEROUTPUTTYPE_TRIANGLE_STRIP,
1679																	 4,
1680																	 numInvocations)
1681							<< sglr::pdec::GeometrySource(genGeometrySource(numInvocations).c_str()))
1682	, m_numInvocations		(numInvocations)
1683{
1684}
1685
1686void InstancedExpansionShader::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1687{
1688	for (int ndx = 0; ndx < numPackets; ++ndx)
1689	{
1690		packets[ndx]->position =	rr::readVertexAttribFloat(inputs[0], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx) +
1691									rr::readVertexAttribFloat(inputs[1], packets[ndx]->instanceNdx, packets[ndx]->vertexNdx);
1692	}
1693}
1694
1695void InstancedExpansionShader::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1696{
1697	DE_UNREF(packets);
1698
1699	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1700	for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1701		rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
1702}
1703
1704void InstancedExpansionShader::shadePrimitives (rr::GeometryEmitter& output, int verticesIn, const rr::PrimitivePacket* packets, const int numPackets, int invocationID) const
1705{
1706	DE_UNREF(verticesIn);
1707
1708	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1709	{
1710		const rr::VertexPacket*	vertex			= packets[packetNdx].vertices[0];
1711		const tcu::Vec4			basePosition	= vertex->position;
1712		const float				phase			= float(invocationID) / float(m_numInvocations) * 6.3f;
1713		const tcu::Vec4			centerPosition	= basePosition + tcu::Vec4(deFloatCos(phase), deFloatSin(phase), 0.0f, 0.0f) * 0.1f;
1714
1715		output.EmitVertex(centerPosition + tcu::Vec4( 0.0f,  -0.1f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
1716		output.EmitVertex(centerPosition + tcu::Vec4(-0.05f,  0.0f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
1717		output.EmitVertex(centerPosition + tcu::Vec4( 0.05f,  0.0f, 0.0f, 0.0f), 0.0f, DE_NULL, packets[packetNdx].primitiveIDIn);
1718		output.EndPrimitive();
1719	}
1720}
1721
1722std::string InstancedExpansionShader::genVertexSource (void)
1723{
1724	return	"#version 310 es\n"
1725			"in highp vec4 a_position;\n"
1726			"in highp vec4 a_offset;\n"
1727			"void main (void)\n"
1728			"{\n"
1729			"	gl_Position = a_position + a_offset;\n"
1730			"}\n";
1731}
1732
1733std::string InstancedExpansionShader::genFragmentSource (void)
1734{
1735	return	"#version 310 es\n"
1736			"layout(location = 0) out mediump vec4 fragColor;\n"
1737			"void main (void)\n"
1738			"{\n"
1739			"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
1740			"}\n";
1741}
1742
1743std::string InstancedExpansionShader::genGeometrySource (int numInvocations)
1744{
1745	std::ostringstream buf;
1746
1747	buf <<	"#version 310 es\n"
1748			"#extension GL_EXT_geometry_shader : require\n"
1749			"layout(points,invocations=" << numInvocations << ") in;\n"
1750			"layout(triangle_strip, max_vertices = 3) out;\n"
1751			"\n"
1752			"void main (void)\n"
1753			"{\n"
1754			"	highp vec4 basePosition = gl_in[0].gl_Position;\n"
1755			"	highp float phase = float(gl_InvocationID) / float(" << numInvocations << ") * 6.3;\n"
1756			"	highp vec4 centerPosition = basePosition + 0.1 * vec4(cos(phase), sin(phase), 0.0, 0.0);\n"
1757			"\n"
1758			"	gl_Position = centerPosition + vec4( 0.00, -0.1, 0.0, 0.0);\n"
1759			"	EmitVertex();\n"
1760			"	gl_Position = centerPosition + vec4(-0.05,  0.0, 0.0, 0.0);\n"
1761			"	EmitVertex();\n"
1762			"	gl_Position = centerPosition + vec4( 0.05,  0.0, 0.0, 0.0);\n"
1763			"	EmitVertex();\n"
1764			"}\n";
1765
1766	return buf.str();
1767}
1768
1769class GeometryShaderRenderTest : public TestCase
1770{
1771public:
1772	enum Flag
1773	{
1774		FLAG_DRAW_INSTANCED		= 1,
1775		FLAG_USE_INDICES		= 2,
1776		FLAG_USE_RESTART_INDEX	= 4,
1777	};
1778
1779									GeometryShaderRenderTest 	(Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives, const char* dataAttributeName, int flags = 0);
1780	virtual							~GeometryShaderRenderTest	(void);
1781
1782	void							init						(void);
1783	void							deinit						(void);
1784
1785	IterateResult					iterate 					(void);
1786	bool							compare						(void);
1787
1788	virtual sglr::ShaderProgram&	getProgram					(void) = 0;
1789
1790protected:
1791	virtual void					genVertexAttribData			(void);
1792	void							renderWithContext			(sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dstSurface);
1793	virtual void					preRender					(sglr::Context& ctx, GLuint programID);
1794	virtual void					postRender					(sglr::Context& ctx, GLuint programID);
1795
1796	int								m_numDrawVertices;
1797	int								m_numDrawInstances;
1798	int								m_vertexAttrDivisor;
1799
1800	const GLenum					m_inputPrimitives;
1801	const GLenum					m_outputPrimitives;
1802	const char* const				m_dataAttributeName;
1803	const int						m_flags;
1804
1805	tcu::IVec2						m_viewportSize;
1806	int								m_interationCount;
1807
1808	tcu::Surface*					m_glResult;
1809	tcu::Surface*					m_refResult;
1810
1811	sglr::ReferenceContextBuffers*	m_refBuffers;
1812	sglr::ReferenceContext*			m_refContext;
1813	sglr::Context*					m_glContext;
1814
1815	std::vector<tcu::Vec4>			m_vertexPosData;
1816	std::vector<tcu::Vec4>			m_vertexAttrData;
1817	std::vector<deUint16>			m_indices;
1818};
1819
1820GeometryShaderRenderTest::GeometryShaderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives, const char* dataAttributeName, int flags)
1821	: TestCase				(context, name, desc)
1822	, m_numDrawVertices		(0)
1823	, m_numDrawInstances	(0)
1824	, m_vertexAttrDivisor	(0)
1825	, m_inputPrimitives		(inputPrimitives)
1826	, m_outputPrimitives	(outputPrimitives)
1827	, m_dataAttributeName	(dataAttributeName)
1828	, m_flags				(flags)
1829	, m_viewportSize		(TEST_CANVAS_SIZE, TEST_CANVAS_SIZE)
1830	, m_interationCount		(0)
1831	, m_glResult			(DE_NULL)
1832	, m_refResult			(DE_NULL)
1833	, m_refBuffers			(DE_NULL)
1834	, m_refContext			(DE_NULL)
1835	, m_glContext			(DE_NULL)
1836{
1837	// Disallow instanced drawElements
1838	DE_ASSERT(((m_flags & FLAG_DRAW_INSTANCED) == 0) || ((m_flags & FLAG_USE_INDICES) == 0));
1839	// Disallow restart without indices
1840	DE_ASSERT(!(((m_flags & FLAG_USE_RESTART_INDEX) != 0) && ((m_flags & FLAG_USE_INDICES) == 0)));
1841}
1842
1843GeometryShaderRenderTest::~GeometryShaderRenderTest (void)
1844{
1845	deinit();
1846}
1847
1848void GeometryShaderRenderTest::init (void)
1849{
1850	// requirements
1851	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
1852		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
1853
1854	// gen resources
1855	{
1856		sglr::ReferenceContextLimits limits;
1857
1858		m_glResult		= new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
1859		m_refResult		= new tcu::Surface(m_viewportSize.x(), m_viewportSize.y());
1860
1861		m_refBuffers	= new sglr::ReferenceContextBuffers(m_context.getRenderTarget().getPixelFormat(), m_context.getRenderTarget().getDepthBits(), 0, m_viewportSize.x(), m_viewportSize.y());
1862		m_refContext	= new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
1863		m_glContext		= new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, m_viewportSize.x(), m_viewportSize.y()));
1864	}
1865}
1866
1867void GeometryShaderRenderTest::deinit (void)
1868{
1869	delete m_glResult;
1870	delete m_refResult;
1871
1872	m_glResult = DE_NULL;
1873	m_refResult = DE_NULL;
1874
1875	delete m_refContext;
1876	delete m_glContext;
1877	delete m_refBuffers;
1878
1879	m_refBuffers = DE_NULL;
1880	m_refContext = DE_NULL;
1881	m_glContext = DE_NULL;
1882}
1883
1884tcu::TestCase::IterateResult GeometryShaderRenderTest::iterate (void)
1885{
1886	// init() must be called
1887	DE_ASSERT(m_glContext);
1888	DE_ASSERT(m_refContext);
1889
1890	const int iteration = m_interationCount++;
1891
1892	if (iteration == 0)
1893	{
1894		// Check requirements
1895		const int width	 = m_context.getRenderTarget().getWidth();
1896		const int height = m_context.getRenderTarget().getHeight();
1897
1898		if (width < m_viewportSize.x() || height < m_viewportSize.y())
1899			throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_viewportSize.x()) + "x" + de::toString(m_viewportSize.y()));
1900
1901		// Gen data
1902		genVertexAttribData();
1903
1904		return CONTINUE;
1905	}
1906	else if (iteration == 1)
1907	{
1908		// Render
1909		sglr::ShaderProgram& program = getProgram();
1910
1911		renderWithContext(*m_glContext, program, *m_glResult);
1912		renderWithContext(*m_refContext, program, *m_refResult);
1913
1914		return CONTINUE;
1915	}
1916	else
1917	{
1918		if (compare())
1919			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1920		else
1921			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
1922
1923		return STOP;
1924	}
1925}
1926
1927bool GeometryShaderRenderTest::compare (void)
1928{
1929	using tcu::TestLog;
1930
1931	if (m_context.getRenderTarget().getNumSamples() > 1)
1932	{
1933		return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", m_refResult->getAccess(), m_glResult->getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
1934	}
1935	else
1936	{
1937		tcu::Surface	errorMask				(m_viewportSize.x(), m_viewportSize.y());
1938		const tcu::RGBA	green					(0, 255, 0, 255);
1939		const tcu::RGBA	red						(255, 0, 0, 255);
1940		const int		colorComponentThreshold	= 20;
1941		bool			testResult				= true;
1942
1943		for (int x = 1; x + 1 < m_viewportSize.x(); ++x)
1944		for (int y = 1; y + 1 < m_viewportSize.y(); ++y)
1945		{
1946			bool found = false;
1947			const tcu::RGBA refcolor = m_refResult->getPixel(x, y);
1948
1949			// Got to find similar pixel near this pixel (3x3 kernel)
1950			for (int dx = -1; dx <= 1; ++dx)
1951			for (int dy = -1; dy <= 1; ++dy)
1952			{
1953				const tcu::RGBA		testColor	= m_glResult->getPixel(x + dx, y + dy);
1954				const tcu::IVec4	colDiff		= tcu::abs(testColor.toIVec() - refcolor.toIVec());
1955
1956				const int			maxColDiff	= de::max(de::max(colDiff.x(), colDiff.y()), colDiff.z()); // check RGB channels
1957
1958				if (maxColDiff <= colorComponentThreshold)
1959					found = true;
1960			}
1961
1962			if (!found)
1963				testResult = false;
1964
1965			errorMask.setPixel(x, y, (found) ? (green) : (red));
1966		}
1967
1968		if (testResult)
1969		{
1970			m_testCtx.getLog()	<< TestLog::ImageSet("Compare result", "Result of rendering")
1971								<< TestLog::Image("Result", "Result", *m_glResult)
1972								<< TestLog::EndImageSet;
1973			m_testCtx.getLog() << TestLog::Message << "Image compare ok." << TestLog::EndMessage;
1974		}
1975		else
1976		{
1977			m_testCtx.getLog()	<< TestLog::ImageSet("Compare result", "Result of rendering")
1978								<< TestLog::Image("Result",		"Result",		*m_glResult)
1979								<< TestLog::Image("Reference",	"Reference",	*m_refResult)
1980								<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
1981								<< TestLog::EndImageSet;
1982			m_testCtx.getLog() << TestLog::Message << "Image compare failed." << TestLog::EndMessage;
1983		}
1984
1985		return testResult;
1986	}
1987}
1988
1989void GeometryShaderRenderTest::genVertexAttribData (void)
1990{
1991	// Create 1 X 2 grid in triangle strip adjacent - order
1992	const float scale = 0.3f;
1993	const tcu::Vec4 offset(-0.5f, -0.2f, 0.0f, 1.0f);
1994
1995	m_vertexPosData.resize(12);
1996	m_vertexPosData[ 0] = tcu::Vec4( 0,  0, 0.0f, 0.0f) * scale + offset;
1997	m_vertexPosData[ 1] = tcu::Vec4(-1, -1, 0.0f, 0.0f) * scale + offset;
1998	m_vertexPosData[ 2] = tcu::Vec4( 0, -1, 0.0f, 0.0f) * scale + offset;
1999	m_vertexPosData[ 3] = tcu::Vec4( 1,  1, 0.0f, 0.0f) * scale + offset;
2000	m_vertexPosData[ 4] = tcu::Vec4( 1,  0, 0.0f, 0.0f) * scale + offset;
2001	m_vertexPosData[ 5] = tcu::Vec4( 0, -2, 0.0f, 0.0f) * scale + offset;
2002	m_vertexPosData[ 6] = tcu::Vec4( 1, -1, 0.0f, 0.0f) * scale + offset;
2003	m_vertexPosData[ 7] = tcu::Vec4( 2,  1, 0.0f, 0.0f) * scale + offset;
2004	m_vertexPosData[ 8] = tcu::Vec4( 2,  0, 0.0f, 0.0f) * scale + offset;
2005	m_vertexPosData[ 9] = tcu::Vec4( 1, -2, 0.0f, 0.0f) * scale + offset;
2006	m_vertexPosData[10] = tcu::Vec4( 2, -1, 0.0f, 0.0f) * scale + offset;
2007	m_vertexPosData[11] = tcu::Vec4( 3,  0, 0.0f, 0.0f) * scale + offset;
2008
2009	// Red and white
2010	m_vertexAttrData.resize(12);
2011	for (int i = 0; i < 12; ++i)
2012		m_vertexAttrData[i] = (i % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
2013
2014	m_numDrawVertices = 12;
2015}
2016
2017void GeometryShaderRenderTest::renderWithContext (sglr::Context& ctx, sglr::ShaderProgram& program, tcu::Surface& dstSurface)
2018{
2019#define CHECK_GL_CTX_ERRORS() glu::checkError(ctx.getError(), DE_NULL, __FILE__, __LINE__)
2020
2021	const GLuint	programId		= ctx.createProgram(&program);
2022	const GLint		attrPosLoc		= ctx.getAttribLocation(programId, "a_position");
2023	const GLint		attrColLoc		= ctx.getAttribLocation(programId, m_dataAttributeName);
2024	GLuint			vaoId			= 0;
2025	GLuint			vertexPosBuf	= 0;
2026	GLuint			vertexAttrBuf	= 0;
2027	GLuint			elementArrayBuf	= 0;
2028
2029	ctx.genVertexArrays(1, &vaoId);
2030	ctx.bindVertexArray(vaoId);
2031
2032	if (attrPosLoc != -1)
2033	{
2034		ctx.genBuffers(1, &vertexPosBuf);
2035		ctx.bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
2036		ctx.bufferData(GL_ARRAY_BUFFER, m_vertexPosData.size() * sizeof(tcu::Vec4), &m_vertexPosData[0], GL_STATIC_DRAW);
2037		ctx.vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2038		ctx.enableVertexAttribArray(attrPosLoc);
2039	}
2040
2041	if (attrColLoc != -1)
2042	{
2043		ctx.genBuffers(1, &vertexAttrBuf);
2044		ctx.bindBuffer(GL_ARRAY_BUFFER, vertexAttrBuf);
2045		ctx.bufferData(GL_ARRAY_BUFFER, m_vertexAttrData.size() * sizeof(tcu::Vec4), &m_vertexAttrData[0], GL_STATIC_DRAW);
2046		ctx.vertexAttribPointer(attrColLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2047		ctx.enableVertexAttribArray(attrColLoc);
2048
2049		if (m_vertexAttrDivisor)
2050			ctx.vertexAttribDivisor(attrColLoc, m_vertexAttrDivisor);
2051	}
2052
2053	if (m_flags & FLAG_USE_INDICES)
2054	{
2055		ctx.genBuffers(1, &elementArrayBuf);
2056		ctx.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementArrayBuf);
2057		ctx.bufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(deUint16), &m_indices[0], GL_STATIC_DRAW);
2058	}
2059
2060	ctx.clearColor(0, 0, 0, 1);
2061	ctx.clear(GL_COLOR_BUFFER_BIT);
2062
2063	ctx.viewport(0, 0, m_viewportSize.x(), m_viewportSize.y());
2064	CHECK_GL_CTX_ERRORS();
2065
2066	ctx.useProgram(programId);
2067	CHECK_GL_CTX_ERRORS();
2068
2069	preRender(ctx, programId);
2070	CHECK_GL_CTX_ERRORS();
2071
2072	if (m_flags & FLAG_USE_RESTART_INDEX)
2073	{
2074		ctx.enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2075		CHECK_GL_CTX_ERRORS();
2076	}
2077
2078	if (m_flags & FLAG_USE_INDICES)
2079		ctx.drawElements(m_inputPrimitives, m_numDrawVertices, GL_UNSIGNED_SHORT, DE_NULL);
2080	else if (m_flags & FLAG_DRAW_INSTANCED)
2081		ctx.drawArraysInstanced(m_inputPrimitives, 0, m_numDrawVertices, m_numDrawInstances);
2082	else
2083		ctx.drawArrays(m_inputPrimitives, 0, m_numDrawVertices);
2084
2085	CHECK_GL_CTX_ERRORS();
2086
2087	if (m_flags & FLAG_USE_RESTART_INDEX)
2088	{
2089		ctx.disable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2090		CHECK_GL_CTX_ERRORS();
2091	}
2092
2093	postRender(ctx, programId);
2094	CHECK_GL_CTX_ERRORS();
2095
2096	ctx.useProgram(0);
2097
2098	if (attrPosLoc != -1)
2099		ctx.disableVertexAttribArray(attrPosLoc);
2100	if (attrColLoc != -1)
2101		ctx.disableVertexAttribArray(attrColLoc);
2102
2103	if (vertexPosBuf)
2104		ctx.deleteBuffers(1, &vertexPosBuf);
2105	if (vertexAttrBuf)
2106		ctx.deleteBuffers(1, &vertexAttrBuf);
2107	if (elementArrayBuf)
2108		ctx.deleteBuffers(1, &elementArrayBuf);
2109
2110	ctx.deleteVertexArrays(1, &vaoId);
2111
2112	CHECK_GL_CTX_ERRORS();
2113
2114	ctx.finish();
2115	ctx.readPixels(dstSurface, 0, 0, m_viewportSize.x(), m_viewportSize.y());
2116
2117#undef CHECK_GL_CTX_ERRORS
2118}
2119
2120void GeometryShaderRenderTest::preRender (sglr::Context& ctx, GLuint programID)
2121{
2122	DE_UNREF(ctx);
2123	DE_UNREF(programID);
2124}
2125
2126void GeometryShaderRenderTest::postRender (sglr::Context& ctx, GLuint programID)
2127{
2128	DE_UNREF(ctx);
2129	DE_UNREF(programID);
2130}
2131
2132class GeometryExpanderRenderTest : public GeometryShaderRenderTest
2133{
2134public:
2135									GeometryExpanderRenderTest 	(Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives);
2136	virtual							~GeometryExpanderRenderTest	(void);
2137
2138	sglr::ShaderProgram&			getProgram					(void);
2139
2140private:
2141	VertexExpanderShader			m_program;
2142};
2143
2144GeometryExpanderRenderTest::GeometryExpanderRenderTest (Context& context, const char* name, const char* desc, GLenum inputPrimitives, GLenum outputPrimitives)
2145	: GeometryShaderRenderTest	(context, name, desc, inputPrimitives, outputPrimitives, "a_color")
2146	, m_program					(sglr::rr_util::mapGLGeometryShaderInputType(inputPrimitives), sglr::rr_util::mapGLGeometryShaderOutputType(outputPrimitives))
2147{
2148}
2149
2150GeometryExpanderRenderTest::~GeometryExpanderRenderTest (void)
2151{
2152}
2153
2154sglr::ShaderProgram& GeometryExpanderRenderTest::getProgram (void)
2155{
2156	return m_program;
2157}
2158
2159class EmitTest : public GeometryShaderRenderTest
2160{
2161public:
2162							EmitTest				(Context& context, const char* name, const char* desc, int emitCountA, int endCountA, int emitCountB, int endCountB, GLenum outputType);
2163
2164	sglr::ShaderProgram&	getProgram				(void);
2165private:
2166	void					genVertexAttribData		(void);
2167
2168	VertexEmitterShader		m_program;
2169};
2170
2171EmitTest::EmitTest (Context& context, const char* name, const char* desc, int emitCountA, int endCountA, int emitCountB, int endCountB, GLenum outputType)
2172	: GeometryShaderRenderTest	(context, name, desc, GL_POINTS, outputType, "a_color")
2173	, m_program					(emitCountA, endCountA, emitCountB, endCountB, sglr::rr_util::mapGLGeometryShaderOutputType(outputType))
2174{
2175}
2176
2177sglr::ShaderProgram& EmitTest::getProgram (void)
2178{
2179	return m_program;
2180}
2181
2182void EmitTest::genVertexAttribData (void)
2183{
2184	m_vertexPosData.resize(1);
2185	m_vertexPosData[0] = tcu::Vec4(0, 0, 0, 1);
2186
2187	m_vertexAttrData.resize(1);
2188	m_vertexAttrData[0] = tcu::Vec4(1, 1, 1, 1);
2189
2190	m_numDrawVertices = 1;
2191}
2192
2193class VaryingTest : public GeometryShaderRenderTest
2194{
2195public:
2196							VaryingTest				(Context& context, const char* name, const char* desc, int vertexOut, int geometryOut);
2197
2198	sglr::ShaderProgram&	getProgram				(void);
2199private:
2200	void					genVertexAttribData		(void);
2201
2202	VertexVaryingShader		m_program;
2203};
2204
2205VaryingTest::VaryingTest (Context& context, const char* name, const char* desc, int vertexOut, int geometryOut)
2206	: GeometryShaderRenderTest	(context, name, desc, GL_TRIANGLES, GL_TRIANGLE_STRIP, "a_color")
2207	, m_program					(vertexOut, geometryOut)
2208{
2209}
2210
2211sglr::ShaderProgram& VaryingTest::getProgram (void)
2212{
2213	return m_program;
2214}
2215
2216void VaryingTest::genVertexAttribData (void)
2217{
2218	m_vertexPosData.resize(3);
2219	m_vertexPosData[0] = tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f);
2220	m_vertexPosData[1] = tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f);
2221	m_vertexPosData[2] = tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f);
2222
2223	m_vertexAttrData.resize(3);
2224	m_vertexAttrData[0] = tcu::Vec4(0.7f, 0.4f, 0.6f, 1.0f);
2225	m_vertexAttrData[1] = tcu::Vec4(0.9f, 0.2f, 0.5f, 1.0f);
2226	m_vertexAttrData[2] = tcu::Vec4(0.1f, 0.8f, 0.3f, 1.0f);
2227
2228	m_numDrawVertices = 3;
2229}
2230
2231class TriangleStripAdjacencyVertexCountTest : public GeometryExpanderRenderTest
2232{
2233public:
2234				TriangleStripAdjacencyVertexCountTest	(Context& context, const char* name, const char* desc, int numInputVertices);
2235
2236private:
2237	void		genVertexAttribData						(void);
2238
2239	int			m_numInputVertices;
2240};
2241
2242TriangleStripAdjacencyVertexCountTest::TriangleStripAdjacencyVertexCountTest (Context& context, const char* name, const char* desc, int numInputVertices)
2243	: GeometryExpanderRenderTest	(context, name, desc, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLE_STRIP)
2244	, m_numInputVertices			(numInputVertices)
2245{
2246}
2247
2248void TriangleStripAdjacencyVertexCountTest::genVertexAttribData (void)
2249{
2250	this->GeometryShaderRenderTest::genVertexAttribData();
2251	m_numDrawVertices = m_numInputVertices;
2252}
2253
2254class NegativeDrawCase : public TestCase
2255{
2256public:
2257							NegativeDrawCase 	(Context& context, const char* name, const char* desc, GLenum inputType, GLenum inputPrimitives);
2258							~NegativeDrawCase	(void);
2259
2260	void					init				(void);
2261	void					deinit				(void);
2262
2263	IterateResult			iterate 			(void);
2264
2265private:
2266	sglr::Context*			m_ctx;
2267	VertexExpanderShader*	m_program;
2268	GLenum					m_inputType;
2269	GLenum					m_inputPrimitives;
2270};
2271
2272NegativeDrawCase::NegativeDrawCase (Context& context, const char* name, const char* desc, GLenum inputType, GLenum inputPrimitives)
2273	: TestCase			(context, name, desc)
2274	, m_ctx				(DE_NULL)
2275	, m_program			(DE_NULL)
2276	, m_inputType		(inputType)
2277	, m_inputPrimitives	(inputPrimitives)
2278{
2279}
2280
2281NegativeDrawCase::~NegativeDrawCase (void)
2282{
2283	deinit();
2284}
2285
2286void NegativeDrawCase::init (void)
2287{
2288	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2289		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
2290
2291	m_ctx		= new sglr::GLContext(m_context.getRenderContext(), m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, 1, 1));
2292	m_program	= new VertexExpanderShader(sglr::rr_util::mapGLGeometryShaderInputType(m_inputType), rr::GEOMETRYSHADEROUTPUTTYPE_POINTS);
2293}
2294
2295void NegativeDrawCase::deinit (void)
2296{
2297	delete m_ctx;
2298	delete m_program;
2299
2300	m_ctx = NULL;
2301	m_program = DE_NULL;
2302}
2303
2304NegativeDrawCase::IterateResult NegativeDrawCase::iterate (void)
2305{
2306	const GLuint	programId		= m_ctx->createProgram(m_program);
2307	const GLint		attrPosLoc		= m_ctx->getAttribLocation(programId, "a_position");
2308	const tcu::Vec4 vertexPosData	(0, 0, 0, 1);
2309
2310	GLuint vaoId		= 0;
2311	GLuint vertexPosBuf = 0;
2312	GLenum errorCode	= 0;
2313
2314	m_ctx->genVertexArrays(1, &vaoId);
2315	m_ctx->bindVertexArray(vaoId);
2316
2317	m_ctx->genBuffers(1, &vertexPosBuf);
2318	m_ctx->bindBuffer(GL_ARRAY_BUFFER, vertexPosBuf);
2319	m_ctx->bufferData(GL_ARRAY_BUFFER, sizeof(tcu::Vec4), vertexPosData.m_data, GL_STATIC_DRAW);
2320	m_ctx->vertexAttribPointer(attrPosLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
2321	m_ctx->enableVertexAttribArray(attrPosLoc);
2322
2323	m_ctx->clearColor(0, 0, 0, 1);
2324	m_ctx->clear(GL_COLOR_BUFFER_BIT);
2325
2326	m_ctx->viewport(0, 0, 1, 1);
2327
2328	m_ctx->useProgram(programId);
2329
2330	// no errors before
2331	glu::checkError(m_ctx->getError(), "", __FILE__, __LINE__);
2332
2333	m_ctx->drawArrays(m_inputPrimitives, 0, 1);
2334
2335	errorCode = m_ctx->getError();
2336	if (errorCode != GL_INVALID_OPERATION)
2337	{
2338		m_testCtx.getLog() << tcu::TestLog::Message << "Expected GL_INVALID_OPERATION, got " << glu::getErrorStr(errorCode) << tcu::TestLog::EndMessage;
2339		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got wrong error code");
2340	}
2341	else
2342	{
2343		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2344	}
2345
2346	m_ctx->useProgram(0);
2347
2348	m_ctx->disableVertexAttribArray(attrPosLoc);
2349	m_ctx->deleteBuffers(1, &vertexPosBuf);
2350
2351	m_ctx->deleteVertexArrays(1, &vaoId);
2352
2353	return STOP;
2354}
2355
2356class OutputCountCase : public GeometryShaderRenderTest
2357{
2358public:
2359									OutputCountCase			(Context& context, const char* name, const char* desc, const OutputCountPatternSpec&);
2360private:
2361	void							init					(void);
2362	void							deinit					(void);
2363
2364	sglr::ShaderProgram&			getProgram				(void);
2365	void							genVertexAttribData		(void);
2366
2367	const int						m_primitiveCount;
2368	OutputCountShader*				m_program;
2369	OutputCountPatternSpec			m_spec;
2370};
2371
2372OutputCountCase::OutputCountCase (Context& context, const char* name, const char* desc, const OutputCountPatternSpec& spec)
2373	: GeometryShaderRenderTest	(context, name, desc, GL_POINTS, GL_TRIANGLE_STRIP, "a_color")
2374	, m_primitiveCount			((int)spec.pattern.size())
2375	, m_program					(DE_NULL)
2376	, m_spec					(spec)
2377{
2378}
2379
2380void OutputCountCase::init (void)
2381{
2382	// Check requirements and adapt to them
2383	{
2384		const int	componentsPerVertex	= 4 + 4; // vec4 pos, vec4 color
2385		const int	testVertices		= *std::max_element(m_spec.pattern.begin(), m_spec.pattern.end());
2386		glw::GLint	maxVertices			= 0;
2387		glw::GLint	maxComponents		= 0;
2388
2389		// check the extension before querying anything
2390		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2391			throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
2392
2393		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxVertices);
2394		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
2395
2396		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_OUTPUT_VERTICES = " << maxVertices << tcu::TestLog::EndMessage;
2397		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << maxComponents << tcu::TestLog::EndMessage;
2398		m_testCtx.getLog() << tcu::TestLog::Message << "Components per vertex = " << componentsPerVertex << tcu::TestLog::EndMessage;
2399
2400		if (testVertices == -1)
2401		{
2402			// "max vertices"-case
2403			DE_ASSERT((int)m_spec.pattern.size() == 1);
2404			m_spec.pattern[0] = de::min(maxVertices, maxComponents / componentsPerVertex);
2405
2406			// make sure size is dividable by 2, as OutputShader requires
2407			m_spec.pattern[0] = m_spec.pattern[0] & ~0x00000001;
2408
2409			if (m_spec.pattern[0] == 0)
2410				throw tcu::InternalError("Pattern size is invalid.");
2411		}
2412		else
2413		{
2414			// normal case
2415			if (testVertices > maxVertices)
2416				throw tcu::NotSupportedError(de::toString(testVertices) + " output vertices required.");
2417			if (testVertices * componentsPerVertex > maxComponents)
2418				throw tcu::NotSupportedError(de::toString(testVertices * componentsPerVertex) + " output components required.");
2419		}
2420	}
2421
2422	// Log what the test tries to do
2423
2424	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << (int)m_spec.pattern.size() << " row(s).\nOne geometry shader invocation generates one row.\nRow sizes:" << tcu::TestLog::EndMessage;
2425	for (int ndx = 0; ndx < (int)m_spec.pattern.size(); ++ndx)
2426		m_testCtx.getLog() << tcu::TestLog::Message << "Row " << ndx << ": " << m_spec.pattern[ndx] << " vertices." << tcu::TestLog::EndMessage;
2427
2428	// Gen shader
2429	DE_ASSERT(!m_program);
2430	m_program = new OutputCountShader(m_spec);
2431
2432	// Case init
2433	GeometryShaderRenderTest::init();
2434}
2435
2436void OutputCountCase::deinit (void)
2437{
2438	if (m_program)
2439	{
2440		delete m_program;
2441		m_program = DE_NULL;
2442	}
2443
2444	GeometryShaderRenderTest::deinit();
2445}
2446
2447sglr::ShaderProgram& OutputCountCase::getProgram (void)
2448{
2449	return *m_program;
2450}
2451
2452void OutputCountCase::genVertexAttribData (void)
2453{
2454	m_vertexPosData.resize(m_primitiveCount);
2455	m_vertexAttrData.resize(m_primitiveCount);
2456
2457	for (int ndx = 0; ndx < m_primitiveCount; ++ndx)
2458	{
2459		m_vertexPosData[ndx] = tcu::Vec4(-1.0f, ((float)ndx) / m_primitiveCount * 2.0f - 1.0f, 0.0f, 1.0f);
2460		m_vertexAttrData[ndx] = (ndx % 2 == 0) ? tcu::Vec4(1, 1, 1, 1) : tcu::Vec4(1, 0, 0, 1);
2461	}
2462
2463	m_numDrawVertices = m_primitiveCount;
2464}
2465
2466class BuiltinVariableRenderTest : public GeometryShaderRenderTest
2467{
2468public:
2469												BuiltinVariableRenderTest	(Context& context, const char* name, const char* desc, BuiltinVariableShader::VariableTest test, int flags = 0);
2470
2471private:
2472	void										init						(void);
2473
2474	sglr::ShaderProgram&						getProgram					(void);
2475	void										genVertexAttribData			(void);
2476
2477	BuiltinVariableShader						m_program;
2478	const BuiltinVariableShader::VariableTest	m_test;
2479};
2480
2481BuiltinVariableRenderTest::BuiltinVariableRenderTest (Context& context, const char* name, const char* desc, BuiltinVariableShader::VariableTest test, int flags)
2482	: GeometryShaderRenderTest	(context, name, desc, GL_POINTS, GL_POINTS, BuiltinVariableShader::getTestAttributeName(test), flags)
2483	, m_program					(test)
2484	, m_test					(test)
2485{
2486}
2487
2488void BuiltinVariableRenderTest::init (void)
2489{
2490	// Requirements
2491	if (m_test == BuiltinVariableShader::TEST_POINT_SIZE)
2492	{
2493		const float requiredPointSize = 5.0f;
2494
2495		tcu::Vec2 range = tcu::Vec2(1.0f, 1.0f);
2496
2497		if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_point_size"))
2498			throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_point_size extension");
2499
2500		m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range.getPtr());
2501		if (range.y() < requiredPointSize)
2502			throw tcu::NotSupportedError("Test case requires point size " + de::toString(requiredPointSize));
2503	}
2504
2505	// Shader init
2506	GeometryShaderRenderTest::init();
2507}
2508
2509sglr::ShaderProgram& BuiltinVariableRenderTest::getProgram (void)
2510{
2511	return m_program;
2512}
2513
2514void BuiltinVariableRenderTest::genVertexAttribData (void)
2515{
2516	m_vertexPosData.resize(4);
2517	m_vertexPosData[0] = tcu::Vec4( 0.5f,  0.0f, 0.0f, 1.0f);
2518	m_vertexPosData[1] = tcu::Vec4( 0.0f,  0.5f, 0.0f, 1.0f);
2519	m_vertexPosData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 1.0f);
2520	m_vertexPosData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 1.0f);
2521
2522	m_vertexAttrData.resize(4);
2523	m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
2524	m_vertexAttrData[1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f);
2525	m_vertexAttrData[2] = tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f);
2526	m_vertexAttrData[3] = tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f);
2527
2528	// Only used by primitive ID restart test
2529	m_indices.resize(4);
2530	m_indices[0] = 3;
2531	m_indices[1] = 2;
2532	m_indices[2] = 0xFFFF; // restart
2533	m_indices[3] = 1;
2534
2535	m_numDrawVertices = 4;
2536}
2537
2538class LayeredRenderCase : public TestCase
2539{
2540public:
2541	enum LayeredRenderTargetType
2542	{
2543		TARGET_CUBE = 0,
2544		TARGET_3D,
2545		TARGET_1D_ARRAY,
2546		TARGET_2D_ARRAY,
2547		TARGET_2D_MS_ARRAY,
2548
2549		TARGET_LAST
2550	};
2551	enum TestType
2552	{
2553		TEST_DEFAULT_LAYER,						// !< draw to default layer
2554		TEST_SINGLE_LAYER,						// !< draw to single layer
2555		TEST_ALL_LAYERS,						// !< draw all layers
2556		TEST_DIFFERENT_LAYERS,					// !< draw different content to different layers
2557		TEST_INVOCATION_PER_LAYER,				// !< draw to all layers, one invocation per layer
2558		TEST_MULTIPLE_LAYERS_PER_INVOCATION,	// !< draw to all layers, multiple invocations write to multiple layers
2559		TEST_LAYER_ID,							// !< draw to all layers, verify gl_Layer fragment input
2560		TEST_LAYER_PROVOKING_VERTEX,			// !< draw primitive with vertices in different layers, check which layer it was drawn to
2561
2562		TEST_LAST
2563	};
2564										LayeredRenderCase			(Context& context, const char* name, const char* desc, LayeredRenderTargetType target, TestType test);
2565										~LayeredRenderCase			(void);
2566
2567	void								init						(void);
2568	void								deinit						(void);
2569	IterateResult						iterate						(void);
2570
2571private:
2572	void								initTexture					(void);
2573	void								initFbo						(void);
2574	void								initRenderShader			(void);
2575	void								initSamplerShader			(void);
2576
2577	std::string							genFragmentSource			(void) const;
2578	std::string							genGeometrySource			(void) const;
2579	std::string							genSamplerFragmentSource	(void) const;
2580
2581	void								renderToTexture				(void);
2582	void								sampleTextureLayer			(tcu::Surface& dst, int layer);
2583	bool								verifyLayerContent			(const tcu::Surface& layer, int layerNdx);
2584	bool								verifyImageSingleColoredRow (const tcu::Surface& layer, float rowWidthRatio, const tcu::Vec4& color, bool logging = true);
2585	bool								verifyEmptyImage			(const tcu::Surface& layer, bool logging = true);
2586	bool								verifyProvokingVertexLayers	(const tcu::Surface& layer0, const tcu::Surface& layer1);
2587
2588	static int							getTargetLayers				(LayeredRenderTargetType target);
2589	static glw::GLenum					getTargetTextureTarget		(LayeredRenderTargetType target);
2590	static tcu::IVec3					getTargetDimensions			(LayeredRenderTargetType target);
2591	static tcu::IVec2					getResolveDimensions		(LayeredRenderTargetType target);
2592
2593	const LayeredRenderTargetType		m_target;
2594	const TestType						m_test;
2595	const int							m_numLayers;
2596	const int							m_targetLayer;
2597	const tcu::IVec2					m_resolveDimensions;
2598
2599	int									m_iteration;
2600	bool								m_allLayersOk;
2601
2602	glw::GLuint							m_texture;
2603	glw::GLuint							m_fbo;
2604	glu::ShaderProgram*					m_renderShader;
2605	glu::ShaderProgram*					m_samplerShader;
2606
2607	glw::GLint							m_samplerSamplerLoc;
2608	glw::GLint							m_samplerLayerLoc;
2609
2610	glw::GLenum							m_provokingVertex;
2611};
2612
2613LayeredRenderCase::LayeredRenderCase (Context& context, const char* name, const char* desc, LayeredRenderTargetType target, TestType test)
2614	: TestCase				(context, name, desc)
2615	, m_target				(target)
2616	, m_test				(test)
2617	, m_numLayers			(getTargetLayers(target))
2618	, m_targetLayer			(m_numLayers / 2)
2619	, m_resolveDimensions	(getResolveDimensions(target))
2620	, m_iteration			(0)
2621	, m_allLayersOk			(true)
2622	, m_texture				(0)
2623	, m_fbo					(0)
2624	, m_renderShader		(DE_NULL)
2625	, m_samplerShader		(DE_NULL)
2626	, m_samplerSamplerLoc	(-1)
2627	, m_samplerLayerLoc		(-1)
2628	, m_provokingVertex		(0)
2629{
2630}
2631
2632LayeredRenderCase::~LayeredRenderCase (void)
2633{
2634	deinit();
2635}
2636
2637void LayeredRenderCase::init (void)
2638{
2639	// Requirements
2640
2641	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
2642		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
2643
2644	if (m_target == TARGET_2D_MS_ARRAY && !m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
2645		throw tcu::NotSupportedError("Test requires OES_texture_storage_multisample_2d_array extension");
2646
2647	if (m_context.getRenderTarget().getWidth() < m_resolveDimensions.x() || m_context.getRenderTarget().getHeight() < m_resolveDimensions.y())
2648		throw tcu::NotSupportedError("Render target size must be at least " + de::toString(m_resolveDimensions.x()) + "x" + de::toString(m_resolveDimensions.y()));
2649
2650	// log what the test tries to do
2651
2652	if (m_test == TEST_DEFAULT_LAYER)
2653		m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to the default layer." << tcu::TestLog::EndMessage;
2654	else if (m_test == TEST_SINGLE_LAYER)
2655		m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to a single layer." << tcu::TestLog::EndMessage;
2656	else if (m_test == TEST_ALL_LAYERS)
2657		m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to all layers." << tcu::TestLog::EndMessage;
2658	else if (m_test == TEST_DIFFERENT_LAYERS)
2659		m_testCtx.getLog() << tcu::TestLog::Message << "Outputting different number of vertices to each layer." << tcu::TestLog::EndMessage;
2660	else if (m_test == TEST_INVOCATION_PER_LAYER)
2661		m_testCtx.getLog() << tcu::TestLog::Message << "Using a different invocation to output to each layer." << tcu::TestLog::EndMessage;
2662	else if (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
2663		m_testCtx.getLog() << tcu::TestLog::Message << "Outputting to each layer from multiple invocations." << tcu::TestLog::EndMessage;
2664	else if (m_test == TEST_LAYER_ID)
2665		m_testCtx.getLog() << tcu::TestLog::Message << "Using gl_Layer in fragment shader." << tcu::TestLog::EndMessage;
2666	else if (m_test == TEST_LAYER_PROVOKING_VERTEX)
2667		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying LAYER_PROVOKING_VERTEX." << tcu::TestLog::EndMessage;
2668	else
2669		DE_ASSERT(false);
2670
2671	// init resources
2672
2673	initTexture();
2674	initFbo();
2675	initRenderShader();
2676	initSamplerShader();
2677}
2678
2679void LayeredRenderCase::deinit (void)
2680{
2681	if (m_texture)
2682	{
2683		m_context.getRenderContext().getFunctions().deleteTextures(1, &m_texture);
2684		m_texture = 0;
2685	}
2686
2687	if (m_fbo)
2688	{
2689		m_context.getRenderContext().getFunctions().deleteFramebuffers(1, &m_fbo);
2690		m_fbo = 0;
2691	}
2692
2693	delete m_renderShader;
2694	delete m_samplerShader;
2695
2696	m_renderShader = DE_NULL;
2697	m_samplerShader = DE_NULL;
2698}
2699
2700LayeredRenderCase::IterateResult LayeredRenderCase::iterate (void)
2701{
2702	++m_iteration;
2703
2704	if (m_iteration == 1)
2705	{
2706		if (m_test == TEST_LAYER_PROVOKING_VERTEX)
2707		{
2708			// which layer the implementation claims to render to
2709
2710			gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint> state;
2711
2712			m_context.getRenderContext().getFunctions().getIntegerv(GL_LAYER_PROVOKING_VERTEX, &state);
2713			GLU_EXPECT_NO_ERROR(m_context.getRenderContext().getFunctions().getError(), "getInteger(GL_LAYER_PROVOKING_VERTEX)");
2714
2715			if (!state.verifyValidity(m_testCtx))
2716				return STOP;
2717
2718			m_testCtx.getLog() << tcu::TestLog::Message << "GL_LAYER_PROVOKING_VERTEX = " << glu::getProvokingVertexStr(state) << tcu::TestLog::EndMessage;
2719
2720			if (state != GL_FIRST_VERTEX_CONVENTION &&
2721				state != GL_LAST_VERTEX_CONVENTION &&
2722				state != GL_UNDEFINED_VERTEX)
2723			{
2724				m_testCtx.getLog() << tcu::TestLog::Message << "getInteger(GL_LAYER_PROVOKING_VERTEX) returned illegal value. Got " << state << tcu::TestLog::EndMessage;
2725				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected provoking vertex value");
2726				return STOP;
2727			}
2728
2729			m_provokingVertex = (glw::GLenum)state;
2730		}
2731
2732		// render to texture
2733		{
2734			const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderToTexture", "Render to layered texture");
2735
2736			// render to layered texture with the geometry shader
2737			renderToTexture();
2738		}
2739
2740		return CONTINUE;
2741	}
2742	else if (m_test == TEST_LAYER_PROVOKING_VERTEX && m_provokingVertex == GL_UNDEFINED_VERTEX)
2743	{
2744		// Verification requires information from another layers, layers not independent
2745		{
2746			const tcu::ScopedLogSection	section		(m_testCtx.getLog(), "VerifyLayers", "Verify layers 0 and 1");
2747			tcu::Surface				layer0		(m_resolveDimensions.x(), m_resolveDimensions.y());
2748			tcu::Surface				layer1		(m_resolveDimensions.x(), m_resolveDimensions.y());
2749
2750			// sample layer to frame buffer
2751			sampleTextureLayer(layer0, 0);
2752			sampleTextureLayer(layer1, 1);
2753
2754			m_allLayersOk &= verifyProvokingVertexLayers(layer0, layer1);
2755		}
2756
2757		// Other layers empty
2758		for (int layerNdx = 2; layerNdx < m_numLayers; ++layerNdx)
2759		{
2760			const tcu::ScopedLogSection	section		(m_testCtx.getLog(), "VerifyLayer", "Verify layer " + de::toString(layerNdx));
2761			tcu::Surface				layer		(m_resolveDimensions.x(), m_resolveDimensions.y());
2762
2763			// sample layer to frame buffer
2764			sampleTextureLayer(layer, layerNdx);
2765
2766			// verify
2767			m_allLayersOk &= verifyEmptyImage(layer);
2768		}
2769	}
2770	else
2771	{
2772		// Layers independent
2773
2774		const int					layerNdx	= m_iteration - 2;
2775		const tcu::ScopedLogSection	section		(m_testCtx.getLog(), "VerifyLayer", "Verify layer " + de::toString(layerNdx));
2776		tcu::Surface				layer		(m_resolveDimensions.x(), m_resolveDimensions.y());
2777
2778		// sample layer to frame buffer
2779		sampleTextureLayer(layer, layerNdx);
2780
2781		// verify
2782		m_allLayersOk &= verifyLayerContent(layer, layerNdx);
2783
2784		if (layerNdx < m_numLayers-1)
2785			return CONTINUE;
2786	}
2787
2788	// last iteration
2789	if (m_allLayersOk)
2790		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2791	else
2792		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Detected invalid layer content");
2793
2794	return STOP;
2795}
2796
2797void LayeredRenderCase::initTexture (void)
2798{
2799	DE_ASSERT(!m_texture);
2800
2801	const glw::Functions&		gl				= m_context.getRenderContext().getFunctions();
2802	const tcu::IVec3			texSize			= getTargetDimensions(m_target);
2803	const tcu::TextureFormat	texFormat		= glu::mapGLInternalFormat(GL_RGBA8);
2804	const glu::TransferFormat	transferFormat	= glu::getTransferFormat(texFormat);
2805
2806	gl.genTextures(1, &m_texture);
2807	GLU_EXPECT_NO_ERROR(gl.getError(), "gen texture");
2808
2809	switch (m_target)
2810	{
2811		case TARGET_CUBE:
2812			m_testCtx.getLog() << tcu::TestLog::Message << "Creating cubemap texture, size = " << texSize.x() << "x" << texSize.y() << tcu::TestLog::EndMessage;
2813			gl.bindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
2814			gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2815			gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2816			gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2817			gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2818			gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2819			gl.texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2820			break;
2821
2822		case TARGET_3D:
2823			m_testCtx.getLog() << tcu::TestLog::Message << "Creating 3d texture, size = " << texSize.x() << "x" << texSize.y() << "x" << texSize.z() << tcu::TestLog::EndMessage;
2824			gl.bindTexture(GL_TEXTURE_3D, m_texture);
2825			gl.texImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2826			break;
2827
2828		case TARGET_1D_ARRAY:
2829			m_testCtx.getLog() << tcu::TestLog::Message << "Creating 1d texture array, size = " << texSize.x() << ", layers = " << texSize.y() << tcu::TestLog::EndMessage;
2830			gl.bindTexture(GL_TEXTURE_1D_ARRAY, m_texture);
2831			gl.texImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA8, texSize.x(), texSize.y(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2832			break;
2833
2834		case TARGET_2D_ARRAY:
2835			m_testCtx.getLog() << tcu::TestLog::Message << "Creating 2d texture array, size = " << texSize.x() << "x" << texSize.y() << ", layers = " << texSize.z() << tcu::TestLog::EndMessage;
2836			gl.bindTexture(GL_TEXTURE_2D_ARRAY, m_texture);
2837			gl.texImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), 0, transferFormat.format, transferFormat.dataType, DE_NULL);
2838			break;
2839
2840		case TARGET_2D_MS_ARRAY:
2841		{
2842			const int numSamples = 2;
2843
2844			int maxSamples = 0;
2845			gl.getIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &maxSamples);
2846
2847			m_testCtx.getLog() << tcu::TestLog::Message << "Creating 2d multisample texture array, size = " << texSize.x() << "x" << texSize.y() << ", layers = " << texSize.z() << ", samples = " << numSamples << tcu::TestLog::EndMessage;
2848
2849			if (numSamples > maxSamples)
2850				throw tcu::NotSupportedError("Test requires " + de::toString(numSamples) + " color texture samples." );
2851
2852			gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, m_texture);
2853			gl.texStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, numSamples, GL_RGBA8, texSize.x(), texSize.y(), texSize.z(), GL_TRUE);
2854			break;
2855		}
2856
2857		default:
2858			DE_ASSERT(DE_FALSE);
2859	}
2860	GLU_EXPECT_NO_ERROR(gl.getError(), "tex image");
2861
2862	// Multisample textures don't use filters
2863	if (getTargetTextureTarget(m_target) != GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
2864	{
2865		gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2866		gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2867		gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_S, GL_REPEAT);
2868		gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_T, GL_REPEAT);
2869		gl.texParameteri(getTargetTextureTarget(m_target), GL_TEXTURE_WRAP_R, GL_REPEAT);
2870		GLU_EXPECT_NO_ERROR(gl.getError(), "tex filter");
2871	}
2872}
2873
2874void LayeredRenderCase::initFbo (void)
2875{
2876	DE_ASSERT(!m_fbo);
2877
2878	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
2879
2880	m_testCtx.getLog() << tcu::TestLog::Message << "Creating FBO" << tcu::TestLog::EndMessage;
2881
2882	gl.genFramebuffers(1, &m_fbo);
2883	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
2884	gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
2885	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
2886
2887	GLU_EXPECT_NO_ERROR(gl.getError(), "setup fbo");
2888}
2889
2890void LayeredRenderCase::initRenderShader (void)
2891{
2892	const tcu::ScopedLogSection section(m_testCtx.getLog(), "RenderToTextureShader", "Create layered rendering shader program");
2893
2894	static const char* const positionVertex =	"#version 310 es\n"
2895												"void main (void)\n"
2896												"{\n"
2897												"	gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
2898												"}\n";
2899
2900	m_renderShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(positionVertex) << glu::FragmentSource(genFragmentSource()) << glu::GeometrySource(genGeometrySource()));
2901	m_testCtx.getLog() << *m_renderShader;
2902
2903	if (!m_renderShader->isOk())
2904		throw tcu::TestError("failed to build render shader");
2905}
2906
2907void LayeredRenderCase::initSamplerShader (void)
2908{
2909	const tcu::ScopedLogSection section(m_testCtx.getLog(), "TextureSamplerShader", "Create shader sampler program");
2910
2911	static const char* const positionVertex =	"#version 310 es\n"
2912												"in highp vec4 a_position;\n"
2913												"void main (void)\n"
2914												"{\n"
2915												"	gl_Position = a_position;\n"
2916												"}\n";
2917
2918	m_samplerShader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2919																			<< glu::VertexSource(positionVertex)
2920																			<< glu::FragmentSource(genSamplerFragmentSource()));
2921
2922	m_testCtx.getLog() << *m_samplerShader;
2923
2924	if (!m_samplerShader->isOk())
2925		throw tcu::TestError("failed to build sampler shader");
2926
2927	m_samplerSamplerLoc = m_context.getRenderContext().getFunctions().getUniformLocation(m_samplerShader->getProgram(), "u_sampler");
2928	if (m_samplerSamplerLoc == -1)
2929		throw tcu::TestError("u_sampler uniform location = -1");
2930
2931	m_samplerLayerLoc = m_context.getRenderContext().getFunctions().getUniformLocation(m_samplerShader->getProgram(), "u_layer");
2932	if (m_samplerLayerLoc == -1)
2933		throw tcu::TestError("u_layer uniform location = -1");
2934}
2935
2936std::string LayeredRenderCase::genFragmentSource (void) const
2937{
2938	static const char* const fragmentLayerIdShader =	"#version 310 es\n"
2939														"#extension GL_EXT_geometry_shader : require\n"
2940														"layout(location = 0) out mediump vec4 fragColor;\n"
2941														"void main (void)\n"
2942														"{\n"
2943														"	fragColor = vec4(((gl_Layer % 2) == 1) ? 1.0 : 0.5,\n"
2944														"	                 (((gl_Layer / 2) % 2) == 1) ? 1.0 : 0.5,\n"
2945														"	                 (gl_Layer == 0) ? 1.0 : 0.0,\n"
2946														"	                 1.0);\n"
2947														"}\n";
2948
2949	if (m_test != TEST_LAYER_ID)
2950		return std::string(s_commonShaderSourceFragment);
2951	else
2952		return std::string(fragmentLayerIdShader);
2953}
2954
2955std::string LayeredRenderCase::genGeometrySource (void) const
2956{
2957	// TEST_DIFFERENT_LAYERS:				draw 0 quad to first layer, 1 to second, etc.
2958	// TEST_ALL_LAYERS:						draw 1 quad to all layers
2959	// TEST_MULTIPLE_LAYERS_PER_INVOCATION:	draw 1 triangle to "current layer" and 1 triangle to another layer
2960	// else:								draw 1 quad to some single layer
2961	const int			maxVertices =		(m_test == TEST_DIFFERENT_LAYERS) ? ((2 + m_numLayers-1) * m_numLayers) :
2962											(m_test == TEST_ALL_LAYERS || m_test == TEST_LAYER_ID) ? (m_numLayers * 4) :
2963											(m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION) ? (6) :
2964											(m_test == TEST_LAYER_PROVOKING_VERTEX) ? (6) :
2965											(4);
2966	std::ostringstream	buf;
2967
2968	buf <<	"#version 310 es\n"
2969			"#extension GL_EXT_geometry_shader : require\n";
2970
2971	if (m_test == TEST_INVOCATION_PER_LAYER || m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
2972		buf << "layout(points, invocations=" << m_numLayers << ") in;\n";
2973	else
2974		buf << "layout(points) in;\n";
2975
2976	buf <<	"layout(triangle_strip, max_vertices = " << maxVertices << ") out;\n"
2977			"out highp vec4 v_frag_FragColor;\n"
2978			"\n"
2979			"void main (void)\n"
2980			"{\n";
2981
2982	if (m_test == TEST_DEFAULT_LAYER)
2983	{
2984		buf <<	"	const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
2985				"	gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
2986				"	v_frag_FragColor = white;\n"
2987				"	EmitVertex();\n\n"
2988				"	gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
2989				"	v_frag_FragColor = white;\n"
2990				"	EmitVertex();\n\n"
2991				"	gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
2992				"	v_frag_FragColor = white;\n"
2993				"	EmitVertex();\n\n"
2994				"	gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
2995				"	v_frag_FragColor = white;\n"
2996				"	EmitVertex();\n";
2997	}
2998	else if (m_test == TEST_SINGLE_LAYER)
2999	{
3000		buf <<	"	const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3001				"	gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3002				"	gl_Layer = " << m_targetLayer << ";\n"
3003				"	v_frag_FragColor = white;\n"
3004				"	EmitVertex();\n\n"
3005				"	gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3006				"	gl_Layer = " << m_targetLayer << ";\n"
3007				"	v_frag_FragColor = white;\n"
3008				"	EmitVertex();\n\n"
3009				"	gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3010				"	gl_Layer = " << m_targetLayer << ";\n"
3011				"	v_frag_FragColor = white;\n"
3012				"	EmitVertex();\n\n"
3013				"	gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3014				"	gl_Layer = " << m_targetLayer << ";\n"
3015				"	v_frag_FragColor = white;\n"
3016				"	EmitVertex();\n";
3017	}
3018	else if (m_test == TEST_ALL_LAYERS || m_test == TEST_LAYER_ID)
3019	{
3020		DE_ASSERT(m_numLayers <= 6);
3021
3022		buf <<	"	const highp vec4 white   = vec4(1.0, 1.0, 1.0, 1.0);\n"
3023				"	const highp vec4 red     = vec4(1.0, 0.0, 0.0, 1.0);\n"
3024				"	const highp vec4 green   = vec4(0.0, 1.0, 0.0, 1.0);\n"
3025				"	const highp vec4 blue    = vec4(0.0, 0.0, 1.0, 1.0);\n"
3026				"	const highp vec4 yellow  = vec4(1.0, 1.0, 0.0, 1.0);\n"
3027				"	const highp vec4 magenta = vec4(1.0, 0.0, 1.0, 1.0);\n"
3028				"	const highp vec4 colors[6] = vec4[6](white, red, green, blue, yellow, magenta);\n\n"
3029				"	for (mediump int layerNdx = 0; layerNdx < " << m_numLayers << "; ++layerNdx)\n"
3030				"	{\n"
3031				"		gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3032				"		gl_Layer = layerNdx;\n"
3033				"		v_frag_FragColor = colors[layerNdx];\n"
3034				"		EmitVertex();\n\n"
3035				"		gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3036				"		gl_Layer = layerNdx;\n"
3037				"		v_frag_FragColor = colors[layerNdx];\n"
3038				"		EmitVertex();\n\n"
3039				"		gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3040				"		gl_Layer = layerNdx;\n"
3041				"		v_frag_FragColor = colors[layerNdx];\n"
3042				"		EmitVertex();\n\n"
3043				"		gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3044				"		gl_Layer = layerNdx;\n"
3045				"		v_frag_FragColor = colors[layerNdx];\n"
3046				"		EmitVertex();\n"
3047				"		EndPrimitive();\n"
3048				"	}\n";
3049	}
3050	else if (m_test == TEST_DIFFERENT_LAYERS)
3051	{
3052		DE_ASSERT(m_numLayers <= 6);
3053
3054		buf <<	"	const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3055				"	for (mediump int layerNdx = 0; layerNdx < " << m_numLayers << "; ++layerNdx)\n"
3056				"	{\n"
3057				"		for (mediump int colNdx = 0; colNdx <= layerNdx; ++colNdx)\n"
3058				"		{\n"
3059				"			highp float posX = float(colNdx) / float(" << m_numLayers << ") * 2.0 - 1.0;\n\n"
3060				"			gl_Position = vec4(posX,  1.0, 0.0, 1.0);\n"
3061				"			gl_Layer = layerNdx;\n"
3062				"			v_frag_FragColor = white;\n"
3063				"			EmitVertex();\n\n"
3064				"			gl_Position = vec4(posX, -1.0, 0.0, 1.0);\n"
3065				"			gl_Layer = layerNdx;\n"
3066				"			v_frag_FragColor = white;\n"
3067				"			EmitVertex();\n"
3068				"		}\n"
3069				"		EndPrimitive();\n"
3070				"	}\n";
3071	}
3072	else if (m_test == TEST_INVOCATION_PER_LAYER)
3073	{
3074		buf <<	"	const highp vec4 white   = vec4(1.0, 1.0, 1.0, 1.0);\n"
3075				"	const highp vec4 red     = vec4(1.0, 0.0, 0.0, 1.0);\n"
3076				"	const highp vec4 green   = vec4(0.0, 1.0, 0.0, 1.0);\n"
3077				"	const highp vec4 blue    = vec4(0.0, 0.0, 1.0, 1.0);\n"
3078				"	const highp vec4 yellow  = vec4(1.0, 1.0, 0.0, 1.0);\n"
3079				"	const highp vec4 magenta = vec4(1.0, 0.0, 1.0, 1.0);\n"
3080				"	const highp vec4 colors[6] = vec4[6](white, red, green, blue, yellow, magenta);\n"
3081				"\n"
3082				"	gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3083				"	gl_Layer = gl_InvocationID;\n"
3084				"	v_frag_FragColor = colors[gl_InvocationID];\n"
3085				"	EmitVertex();\n\n"
3086				"	gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3087				"	gl_Layer = gl_InvocationID;\n"
3088				"	v_frag_FragColor = colors[gl_InvocationID];\n"
3089				"	EmitVertex();\n\n"
3090				"	gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3091				"	gl_Layer = gl_InvocationID;\n"
3092				"	v_frag_FragColor = colors[gl_InvocationID];\n"
3093				"	EmitVertex();\n\n"
3094				"	gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3095				"	gl_Layer = gl_InvocationID;\n"
3096				"	v_frag_FragColor = colors[gl_InvocationID];\n"
3097				"	EmitVertex();\n"
3098				"	EndPrimitive();\n";
3099	}
3100	else if (m_test == TEST_MULTIPLE_LAYERS_PER_INVOCATION)
3101	{
3102		buf <<	"	const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n"
3103				"\n"
3104				"	mediump int layerA = gl_InvocationID;\n"
3105				"	mediump int layerB = (gl_InvocationID + 1) % " << m_numLayers << ";\n"
3106				"	highp float aEnd = float(layerA) / float(" << m_numLayers << ") * 2.0 - 1.0;\n"
3107				"	highp float bEnd = float(layerB) / float(" << m_numLayers << ") * 2.0 - 1.0;\n"
3108				"\n"
3109				"	gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3110				"	gl_Layer = layerA;\n"
3111				"	v_frag_FragColor = white;\n"
3112				"	EmitVertex();\n\n"
3113				"	gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3114				"	gl_Layer = layerA;\n"
3115				"	v_frag_FragColor = white;\n"
3116				"	EmitVertex();\n\n"
3117				"	gl_Position = vec4(aEnd, -1.0, 0.0, 1.0);\n"
3118				"	gl_Layer = layerA;\n"
3119				"	v_frag_FragColor = white;\n"
3120				"	EmitVertex();\n\n"
3121				"	EndPrimitive();\n"
3122				"\n"
3123				"	gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3124				"	gl_Layer = layerB;\n"
3125				"	v_frag_FragColor = white;\n"
3126				"	EmitVertex();\n\n"
3127				"	gl_Position = vec4(bEnd,  1.0, 0.0, 1.0);\n"
3128				"	gl_Layer = layerB;\n"
3129				"	v_frag_FragColor = white;\n"
3130				"	EmitVertex();\n\n"
3131				"	gl_Position = vec4(bEnd, -1.0, 0.0, 1.0);\n"
3132				"	gl_Layer = layerB;\n"
3133				"	v_frag_FragColor = white;\n"
3134				"	EmitVertex();\n\n"
3135				"	EndPrimitive();\n";
3136	}
3137	else if (m_test == TEST_LAYER_PROVOKING_VERTEX)
3138	{
3139		buf <<	"	const highp vec4 white = vec4(1.0, 1.0, 1.0, 1.0);\n\n"
3140				"	gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
3141				"	gl_Layer = 0;\n"
3142				"	v_frag_FragColor = white;\n"
3143				"	EmitVertex();\n\n"
3144				"	gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3145				"	gl_Layer = 1;\n"
3146				"	v_frag_FragColor = white;\n"
3147				"	EmitVertex();\n\n"
3148				"	gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3149				"	gl_Layer = 1;\n"
3150				"	v_frag_FragColor = white;\n"
3151				"	EmitVertex();\n\n"
3152				"	EndPrimitive();\n\n"
3153				"	gl_Position = vec4(-1.0,  1.0, 0.0, 1.0);\n"
3154				"	gl_Layer = 0;\n"
3155				"	v_frag_FragColor = white;\n"
3156				"	EmitVertex();\n\n"
3157				"	gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n"
3158				"	gl_Layer = 1;\n"
3159				"	v_frag_FragColor = white;\n"
3160				"	EmitVertex();\n\n"
3161				"	gl_Position = vec4( 0.0,  1.0, 0.0, 1.0);\n"
3162				"	gl_Layer = 1;\n"
3163				"	v_frag_FragColor = white;\n"
3164				"	EmitVertex();\n";
3165	}
3166	else
3167		DE_ASSERT(DE_FALSE);
3168
3169	buf <<	"}\n";
3170
3171	return buf.str();
3172}
3173
3174std::string LayeredRenderCase::genSamplerFragmentSource (void) const
3175{
3176	std::ostringstream buf;
3177
3178	buf << "#version 310 es\n";
3179	if (m_target == TARGET_2D_MS_ARRAY)
3180		buf << "#extension GL_OES_texture_storage_multisample_2d_array : require\n";
3181	buf << "layout(location = 0) out mediump vec4 fragColor;\n";
3182
3183	switch (m_target)
3184	{
3185		case TARGET_CUBE:			buf << "uniform highp samplerCube u_sampler;\n";		break;
3186		case TARGET_3D:				buf << "uniform highp sampler3D u_sampler;\n";			break;
3187		case TARGET_2D_ARRAY:		buf << "uniform highp sampler2DArray u_sampler;\n";		break;
3188		case TARGET_1D_ARRAY:		buf << "uniform highp sampler1DArray u_sampler;\n";		break;
3189		case TARGET_2D_MS_ARRAY:	buf << "uniform highp sampler2DMSArray u_sampler;\n";	break;
3190		default:
3191			DE_ASSERT(DE_FALSE);
3192	}
3193
3194	buf <<	"uniform highp int u_layer;\n"
3195			"void main (void)\n"
3196			"{\n";
3197
3198	switch (m_target)
3199	{
3200		case TARGET_CUBE:
3201			buf <<	"	highp vec2 facepos = 2.0 * gl_FragCoord.xy / vec2(ivec2(" << m_resolveDimensions.x() << ", " << m_resolveDimensions.y() << ")) - vec2(1.0, 1.0);\n"
3202					"	if (u_layer == 0)\n"
3203					"		fragColor = textureLod(u_sampler, vec3(1.0, -facepos.y, -facepos.x), 0.0);\n"
3204					"	else if (u_layer == 1)\n"
3205					"		fragColor = textureLod(u_sampler, vec3(-1.0, -facepos.y, facepos.x), 0.0);\n"
3206					"	else if (u_layer == 2)\n"
3207					"		fragColor = textureLod(u_sampler, vec3(facepos.x, 1.0, facepos.y), 0.0);\n"
3208					"	else if (u_layer == 3)\n"
3209					"		fragColor = textureLod(u_sampler, vec3(facepos.x, -1.0, -facepos.y), 0.0);\n"
3210					"	else if (u_layer == 4)\n"
3211					"		fragColor = textureLod(u_sampler, vec3(facepos.x, -facepos.y, 1.0), 0.0);\n"
3212					"	else if (u_layer == 5)\n"
3213					"		fragColor = textureLod(u_sampler, vec3(-facepos.x, -facepos.y, -1.0), 0.0);\n"
3214					"	else\n"
3215					"		fragColor = vec4(1.0, 0.0, 1.0, 1.0);\n";
3216			break;
3217
3218		case TARGET_3D:
3219		case TARGET_2D_ARRAY:
3220		case TARGET_2D_MS_ARRAY:
3221			buf <<	"	highp ivec2 screenpos = ivec2(floor(gl_FragCoord.xy));\n"
3222					"	fragColor = texelFetch(u_sampler, ivec3(screenpos, u_layer), 0);\n";
3223			break;
3224
3225		case TARGET_1D_ARRAY:
3226			buf <<	"	highp ivec2 screenpos = ivec2(floor(gl_FragCoord.xy));\n"
3227					"	fragColor = texelFetch(u_sampler, ivec2(screenpos.x, u_layer), 0);\n";
3228			break;
3229
3230		default:
3231			DE_ASSERT(DE_FALSE);
3232	}
3233	buf <<	"}\n";
3234	return buf.str();
3235}
3236
3237void LayeredRenderCase::renderToTexture (void)
3238{
3239	const tcu::IVec3		texSize		= getTargetDimensions(m_target);
3240	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
3241	glu::VertexArray		vao			(m_context.getRenderContext());
3242
3243	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering to texture" << tcu::TestLog::EndMessage;
3244
3245	gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3246	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3247	gl.clear(GL_COLOR_BUFFER_BIT);
3248	gl.viewport(0, 0, texSize.x(), texSize.y());
3249	gl.clear(GL_COLOR_BUFFER_BIT);
3250
3251	gl.bindVertexArray(*vao);
3252	gl.useProgram(m_renderShader->getProgram());
3253	gl.drawArrays(GL_POINTS, 0, 1);
3254	gl.useProgram(0);
3255	gl.bindVertexArray(0);
3256	gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
3257
3258	GLU_EXPECT_NO_ERROR(gl.getError(), "render");
3259}
3260
3261void LayeredRenderCase::sampleTextureLayer (tcu::Surface& dst, int layer)
3262{
3263	DE_ASSERT(dst.getWidth() == m_resolveDimensions.x());
3264	DE_ASSERT(dst.getHeight() == m_resolveDimensions.y());
3265
3266	static const tcu::Vec4 fullscreenQuad[4] =
3267	{
3268		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
3269		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
3270		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
3271		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
3272	};
3273
3274	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
3275	const int				positionLoc	= gl.getAttribLocation(m_samplerShader->getProgram(), "a_position");
3276	glu::VertexArray		vao			(m_context.getRenderContext());
3277	glu::Buffer				buf			(m_context.getRenderContext());
3278
3279	m_testCtx.getLog() << tcu::TestLog::Message << "Sampling from texture layer " << layer << tcu::TestLog::EndMessage;
3280
3281	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3282	gl.clear(GL_COLOR_BUFFER_BIT);
3283	gl.viewport(0, 0, m_resolveDimensions.x(), m_resolveDimensions.y());
3284	GLU_EXPECT_NO_ERROR(gl.getError(), "clear");
3285
3286	gl.bindBuffer(GL_ARRAY_BUFFER, *buf);
3287	gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
3288	GLU_EXPECT_NO_ERROR(gl.getError(), "buf");
3289
3290	gl.bindVertexArray(*vao);
3291	gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
3292	gl.enableVertexAttribArray(positionLoc);
3293	GLU_EXPECT_NO_ERROR(gl.getError(), "setup attribs");
3294
3295	gl.activeTexture(GL_TEXTURE0);
3296	gl.bindTexture(getTargetTextureTarget(m_target), m_texture);
3297	GLU_EXPECT_NO_ERROR(gl.getError(), "bind texture");
3298
3299	gl.useProgram(m_samplerShader->getProgram());
3300	gl.uniform1i(m_samplerLayerLoc, layer);
3301	gl.uniform1i(m_samplerSamplerLoc, 0);
3302	GLU_EXPECT_NO_ERROR(gl.getError(), "setup program");
3303
3304	gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
3305	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
3306
3307	gl.useProgram(0);
3308	gl.bindVertexArray(0);
3309	GLU_EXPECT_NO_ERROR(gl.getError(), "clean");
3310
3311	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.getAccess());
3312}
3313
3314bool LayeredRenderCase::verifyLayerContent (const tcu::Surface& layer, int layerNdx)
3315{
3316	const tcu::Vec4 white   = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
3317	const tcu::Vec4 red     = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
3318	const tcu::Vec4 green   = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
3319	const tcu::Vec4 blue    = tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
3320	const tcu::Vec4 yellow  = tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
3321	const tcu::Vec4 magenta = tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f);
3322	const tcu::Vec4 colors[6] = { white, red, green, blue, yellow, magenta };
3323
3324	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying layer contents" << tcu::TestLog::EndMessage;
3325
3326	switch (m_test)
3327	{
3328		case TEST_DEFAULT_LAYER:
3329			if (layerNdx == 0)
3330				return verifyImageSingleColoredRow(layer, 0.5f, white);
3331			else
3332				return verifyEmptyImage(layer);
3333
3334		case TEST_SINGLE_LAYER:
3335			if (layerNdx == m_targetLayer)
3336				return verifyImageSingleColoredRow(layer, 0.5f, white);
3337			else
3338				return verifyEmptyImage(layer);
3339
3340		case TEST_ALL_LAYERS:
3341		case TEST_INVOCATION_PER_LAYER:
3342			return verifyImageSingleColoredRow(layer, 0.5f, colors[layerNdx]);
3343
3344		case TEST_DIFFERENT_LAYERS:
3345		case TEST_MULTIPLE_LAYERS_PER_INVOCATION:
3346			if (layerNdx == 0)
3347				return verifyEmptyImage(layer);
3348			else
3349				return verifyImageSingleColoredRow(layer, layerNdx / (float)m_numLayers, white);
3350
3351		case TEST_LAYER_ID:
3352		{
3353			const tcu::Vec4 layerColor((layerNdx % 2 == 1) ? (1.0f) : (0.5f),
3354									   ((layerNdx/2) % 2 == 1) ? (1.0f) : (0.5f),
3355									   (layerNdx == 0) ? (1.0f) : (0.0f),
3356									   1.0f);
3357			return verifyImageSingleColoredRow(layer, 0.5f, layerColor);
3358		}
3359
3360		case TEST_LAYER_PROVOKING_VERTEX:
3361			if (m_provokingVertex == GL_FIRST_VERTEX_CONVENTION)
3362			{
3363				if (layerNdx == 0)
3364					return verifyImageSingleColoredRow(layer, 0.5f, white);
3365				else
3366					return verifyEmptyImage(layer);
3367			}
3368			else if (m_provokingVertex == GL_LAST_VERTEX_CONVENTION)
3369			{
3370				if (layerNdx == 1)
3371					return verifyImageSingleColoredRow(layer, 0.5f, white);
3372				else
3373					return verifyEmptyImage(layer);
3374			}
3375			else
3376			{
3377				DE_ASSERT(false);
3378				return false;
3379			}
3380
3381		default:
3382			DE_ASSERT(DE_FALSE);
3383			return false;
3384	};
3385}
3386
3387bool LayeredRenderCase::verifyImageSingleColoredRow (const tcu::Surface& layer, float rowWidthRatio, const tcu::Vec4& barColor, bool logging)
3388{
3389	DE_ASSERT(rowWidthRatio > 0.0f);
3390
3391	const int		barLength			= (int)(rowWidthRatio*layer.getWidth());
3392	const int		barLengthThreshold	= 1;
3393	tcu::Surface	errorMask			(layer.getWidth(), layer.getHeight());
3394	bool			allPixelsOk			= true;
3395
3396	if (logging)
3397		m_testCtx.getLog() << tcu::TestLog::Message << "Expecting all pixels with distance less or equal to (about) " << barLength << " pixels from left border to be of color " << barColor.swizzle(0,1,2) << "." << tcu::TestLog::EndMessage;
3398
3399	tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toIVec());
3400
3401	for (int y = 0; y < layer.getHeight(); ++y)
3402	for (int x = 0; x < layer.getWidth(); ++x)
3403	{
3404		const tcu::RGBA color		= layer.getPixel(x, y);
3405		const tcu::RGBA refColor	= tcu::RGBA(barColor);
3406		const int		threshold	= 8;
3407		const bool		isBlack		= color.getRed() <= threshold || color.getGreen() <= threshold || color.getBlue() <= threshold;
3408		const bool		isColor		= tcu::allEqual(tcu::lessThan(tcu::abs(color.toIVec().swizzle(0, 1, 2) - refColor.toIVec().swizzle(0, 1, 2)), tcu::IVec3(threshold, threshold, threshold)), tcu::BVec3(true, true, true));
3409
3410		bool			isOk;
3411
3412		if (x <= barLength - barLengthThreshold)
3413			isOk = isColor;
3414		else if (x >= barLength + barLengthThreshold)
3415			isOk = isBlack;
3416		else
3417			isOk = isColor || isBlack;
3418
3419		allPixelsOk &= isOk;
3420
3421		if (!isOk)
3422			errorMask.setPixel(x, y, tcu::RGBA::red);
3423	}
3424
3425	if (allPixelsOk)
3426	{
3427		if (logging)
3428			m_testCtx.getLog()	<< tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage
3429								<< tcu::TestLog::ImageSet("LayerContent", "Layer content")
3430								<< tcu::TestLog::Image("Layer", "Layer", layer)
3431								<< tcu::TestLog::EndImageSet;
3432		return true;
3433	}
3434	else
3435	{
3436		if (logging)
3437			m_testCtx.getLog()	<< tcu::TestLog::Message << "Image verification failed. Got unexpected pixels." << tcu::TestLog::EndMessage
3438								<< tcu::TestLog::ImageSet("LayerContent", "Layer content")
3439								<< tcu::TestLog::Image("Layer",		"Layer",	layer)
3440								<< tcu::TestLog::Image("ErrorMask",	"Errors",	errorMask)
3441								<< tcu::TestLog::EndImageSet;
3442		return false;
3443	}
3444
3445	if (logging)
3446		m_testCtx.getLog() << tcu::TestLog::Image("LayerContent", "Layer content", layer);
3447
3448	return allPixelsOk;
3449}
3450
3451bool LayeredRenderCase::verifyEmptyImage (const tcu::Surface& layer, bool logging)
3452{
3453	// Expect black
3454	if (logging)
3455		m_testCtx.getLog() << tcu::TestLog::Message << "Expecting empty image" << tcu::TestLog::EndMessage;
3456
3457	for (int y = 0; y < layer.getHeight(); ++y)
3458	for (int x = 0; x < layer.getWidth(); ++x)
3459	{
3460		const tcu::RGBA color		= layer.getPixel(x, y);
3461		const int		threshold	= 8;
3462		const bool		isBlack		= color.getRed() <= threshold || color.getGreen() <= threshold || color.getBlue() <= threshold;
3463
3464		if (!isBlack)
3465		{
3466			if (logging)
3467				m_testCtx.getLog()	<< tcu::TestLog::Message
3468									<< "Found (at least) one bad pixel at " << x << "," << y << ". Pixel color is not background color."
3469									<< tcu::TestLog::EndMessage
3470									<< tcu::TestLog::ImageSet("LayerContent", "Layer content")
3471									<< tcu::TestLog::Image("Layer", "Layer", layer)
3472									<< tcu::TestLog::EndImageSet;
3473			return false;
3474		}
3475	}
3476
3477	if (logging)
3478		m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage;
3479
3480	return true;
3481}
3482
3483bool LayeredRenderCase::verifyProvokingVertexLayers (const tcu::Surface& layer0, const tcu::Surface& layer1)
3484{
3485	const bool		layer0Empty		= verifyEmptyImage(layer0, false);
3486	const bool		layer1Empty		= verifyEmptyImage(layer1, false);
3487	bool			error			= false;
3488
3489	// Both images could contain something if the quad triangles get assigned to different layers
3490	m_testCtx.getLog() << tcu::TestLog::Message << "Expecting non-empty layers, or non-empty layer." << tcu::TestLog::EndMessage;
3491
3492	if (layer0Empty == true && layer1Empty == true)
3493	{
3494		m_testCtx.getLog() << tcu::TestLog::Message << "Got empty images." << tcu::TestLog::EndMessage;
3495		error = true;
3496	}
3497
3498	// log images always
3499	m_testCtx.getLog()
3500		<< tcu::TestLog::ImageSet("LayerContent", "Layer content")
3501		<< tcu::TestLog::Image("Layer", "Layer0", layer0)
3502		<< tcu::TestLog::Image("Layer", "Layer1", layer1)
3503		<< tcu::TestLog::EndImageSet;
3504
3505	if (error)
3506		m_testCtx.getLog() << tcu::TestLog::Message << "Image verification failed." << tcu::TestLog::EndMessage;
3507	else
3508		m_testCtx.getLog() << tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage;
3509
3510	return !error;
3511}
3512
3513int LayeredRenderCase::getTargetLayers (LayeredRenderTargetType target)
3514{
3515	switch (target)
3516	{
3517		case TARGET_CUBE:			return 6;
3518		case TARGET_3D:				return 4;
3519		case TARGET_1D_ARRAY:		return 4;
3520		case TARGET_2D_ARRAY:		return 4;
3521		case TARGET_2D_MS_ARRAY:	return 2;
3522		default:
3523			DE_ASSERT(DE_FALSE);
3524			return 0;
3525	}
3526}
3527
3528glw::GLenum LayeredRenderCase::getTargetTextureTarget (LayeredRenderTargetType target)
3529{
3530	switch (target)
3531	{
3532		case TARGET_CUBE:			return GL_TEXTURE_CUBE_MAP;
3533		case TARGET_3D:				return GL_TEXTURE_3D;
3534		case TARGET_1D_ARRAY:		return GL_TEXTURE_1D_ARRAY;
3535		case TARGET_2D_ARRAY:		return GL_TEXTURE_2D_ARRAY;
3536		case TARGET_2D_MS_ARRAY:	return GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
3537		default:
3538			DE_ASSERT(DE_FALSE);
3539			return 0;
3540	}
3541}
3542
3543tcu::IVec3 LayeredRenderCase::getTargetDimensions (LayeredRenderTargetType target)
3544{
3545	switch (target)
3546	{
3547		case TARGET_CUBE:			return tcu::IVec3(64, 64, 0);
3548		case TARGET_3D:				return tcu::IVec3(64, 64, 4);
3549		case TARGET_1D_ARRAY:		return tcu::IVec3(64, 4, 0);
3550		case TARGET_2D_ARRAY:		return tcu::IVec3(64, 64, 4);
3551		case TARGET_2D_MS_ARRAY:	return tcu::IVec3(64, 64, 2);
3552		default:
3553			DE_ASSERT(DE_FALSE);
3554			return tcu::IVec3(0, 0, 0);
3555	}
3556}
3557
3558tcu::IVec2 LayeredRenderCase::getResolveDimensions (LayeredRenderTargetType target)
3559{
3560	switch (target)
3561	{
3562		case TARGET_CUBE:			return tcu::IVec2(64, 64);
3563		case TARGET_3D:				return tcu::IVec2(64, 64);
3564		case TARGET_1D_ARRAY:		return tcu::IVec2(64, 1);
3565		case TARGET_2D_ARRAY:		return tcu::IVec2(64, 64);
3566		case TARGET_2D_MS_ARRAY:	return tcu::IVec2(64, 64);
3567		default:
3568			DE_ASSERT(DE_FALSE);
3569			return tcu::IVec2(0, 0);
3570	}
3571}
3572
3573class VaryingOutputCountCase : public GeometryShaderRenderTest
3574{
3575public:
3576	enum ShaderInstancingMode
3577	{
3578		MODE_WITHOUT_INSTANCING = 0,
3579		MODE_WITH_INSTANCING,
3580
3581		MODE_LAST
3582	};
3583													VaryingOutputCountCase			(Context& context, const char* name, const char* desc, VaryingOutputCountShader::VaryingSource test, ShaderInstancingMode mode);
3584private:
3585	void											init							(void);
3586	void											deinit							(void);
3587	void											preRender						(sglr::Context& ctx, GLuint programID);
3588
3589	sglr::ShaderProgram&							getProgram						(void);
3590	void											genVertexAttribData				(void);
3591	void											genVertexDataWithoutInstancing	(void);
3592	void											genVertexDataWithInstancing		(void);
3593
3594	VaryingOutputCountShader*						m_program;
3595	const VaryingOutputCountShader::VaryingSource	m_test;
3596	const ShaderInstancingMode						m_mode;
3597	int												m_maxEmitCount;
3598};
3599
3600VaryingOutputCountCase::VaryingOutputCountCase (Context& context, const char* name, const char* desc, VaryingOutputCountShader::VaryingSource test, ShaderInstancingMode mode)
3601	: GeometryShaderRenderTest	(context, name, desc, GL_POINTS, GL_TRIANGLE_STRIP, VaryingOutputCountShader::getAttributeName(test))
3602	, m_program					(DE_NULL)
3603	, m_test					(test)
3604	, m_mode					(mode)
3605	, m_maxEmitCount			(0)
3606{
3607	DE_ASSERT(mode < MODE_LAST);
3608}
3609
3610void VaryingOutputCountCase::init (void)
3611{
3612	// Check requirements
3613
3614	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
3615		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
3616
3617	if (m_test == VaryingOutputCountShader::READ_TEXTURE)
3618	{
3619		glw::GLint maxTextures = 0;
3620
3621		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &maxTextures);
3622
3623		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = " << maxTextures << tcu::TestLog::EndMessage;
3624
3625		if (maxTextures < 1)
3626			throw tcu::NotSupportedError("Geometry shader texture units required");
3627	}
3628
3629	// Get max emit count
3630	{
3631		const int	componentsPerVertex	= 4 + 4; // vec4 pos, vec4 color
3632		glw::GLint	maxVertices			= 0;
3633		glw::GLint	maxComponents		= 0;
3634
3635		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &maxVertices);
3636		m_context.getRenderContext().getFunctions().getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
3637
3638		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_OUTPUT_VERTICES = " << maxVertices << tcu::TestLog::EndMessage;
3639		m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << maxComponents << tcu::TestLog::EndMessage;
3640		m_testCtx.getLog() << tcu::TestLog::Message << "Components per vertex = " << componentsPerVertex << tcu::TestLog::EndMessage;
3641
3642		if (maxVertices < 256)
3643			throw tcu::TestError("MAX_GEOMETRY_OUTPUT_VERTICES was less than minimum required (256)");
3644		if (maxComponents < 1024)
3645			throw tcu::TestError("MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS was less than minimum required (1024)");
3646
3647		m_maxEmitCount = de::min(maxVertices, maxComponents / componentsPerVertex);
3648	}
3649
3650	// Log what the test tries to do
3651
3652	m_testCtx.getLog()
3653		<< tcu::TestLog::Message
3654		<< "Rendering 4 n-gons with n = "
3655		<< ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0)) << ", "
3656		<< ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1)) << ", "
3657		<< ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2)) << ", and "
3658		<< ((VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3)) << ".\n"
3659		<< "N is supplied to the geomery shader with "
3660		<< ((m_test == VaryingOutputCountShader::READ_ATTRIBUTE) ? ("attribute") : (m_test == VaryingOutputCountShader::READ_UNIFORM) ? ("uniform") : ("texture"))
3661		<< tcu::TestLog::EndMessage;
3662
3663	// Gen shader
3664	{
3665		const bool instanced = (m_mode == MODE_WITH_INSTANCING);
3666
3667		DE_ASSERT(!m_program);
3668		m_program = new VaryingOutputCountShader(m_test, m_maxEmitCount, instanced);
3669	}
3670
3671	// Case init
3672	GeometryShaderRenderTest::init();
3673}
3674
3675void VaryingOutputCountCase::deinit (void)
3676{
3677	if (m_program)
3678	{
3679		delete m_program;
3680		m_program = DE_NULL;
3681	}
3682
3683	GeometryShaderRenderTest::deinit();
3684}
3685
3686void VaryingOutputCountCase::preRender (sglr::Context& ctx, GLuint programID)
3687{
3688	if (m_test == VaryingOutputCountShader::READ_UNIFORM)
3689	{
3690		const int		location		= ctx.getUniformLocation(programID, "u_emitCount");
3691		const deInt32	emitCount[4]	= { 6, 0, m_maxEmitCount, 10 };
3692
3693		if (location == -1)
3694			throw tcu::TestError("uniform location of u_emitCount was -1.");
3695
3696		ctx.uniform4iv(location, 1, emitCount);
3697	}
3698	else if (m_test == VaryingOutputCountShader::READ_TEXTURE)
3699	{
3700		const deUint8 data[4*4] =
3701		{
3702			255,   0,   0,   0,
3703			  0, 255,   0,   0,
3704			  0,   0, 255,   0,
3705			  0,   0,   0, 255,
3706		};
3707		const int	location	= ctx.getUniformLocation(programID, "u_sampler");
3708		GLuint		texID		= 0;
3709
3710		if (location == -1)
3711			throw tcu::TestError("uniform location of u_sampler was -1.");
3712		ctx.uniform1i(location, 0);
3713
3714		// \note we don't need to explicitly delete the texture, the sglr context will delete it
3715		ctx.genTextures(1, &texID);
3716		ctx.bindTexture(GL_TEXTURE_2D, texID);
3717		ctx.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
3718		ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3719		ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3720	}
3721}
3722
3723sglr::ShaderProgram& VaryingOutputCountCase::getProgram (void)
3724{
3725	return *m_program;
3726}
3727
3728void VaryingOutputCountCase::genVertexAttribData (void)
3729{
3730	if (m_mode == MODE_WITHOUT_INSTANCING)
3731		genVertexDataWithoutInstancing();
3732	else if (m_mode == MODE_WITH_INSTANCING)
3733		genVertexDataWithInstancing();
3734	else
3735		DE_ASSERT(false);
3736}
3737
3738void VaryingOutputCountCase::genVertexDataWithoutInstancing (void)
3739{
3740	m_numDrawVertices = 4;
3741
3742	m_vertexPosData.resize(4);
3743	m_vertexAttrData.resize(4);
3744
3745	m_vertexPosData[0] = tcu::Vec4( 0.5f,  0.0f, 0.0f, 1.0f);
3746	m_vertexPosData[1] = tcu::Vec4( 0.0f,  0.5f, 0.0f, 1.0f);
3747	m_vertexPosData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 1.0f);
3748	m_vertexPosData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 1.0f);
3749
3750	if (m_test == VaryingOutputCountShader::READ_ATTRIBUTE)
3751	{
3752		m_vertexAttrData[0] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_0)), 0.0f, 0.0f, 0.0f);
3753		m_vertexAttrData[1] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_1)), 0.0f, 0.0f, 0.0f);
3754		m_vertexAttrData[2] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_2)), 0.0f, 0.0f, 0.0f);
3755		m_vertexAttrData[3] = tcu::Vec4(((VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ? ((float)m_maxEmitCount) : ((float)VaryingOutputCountShader::EMIT_COUNT_VERTEX_3)), 0.0f, 0.0f, 0.0f);
3756	}
3757	else
3758	{
3759		m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
3760		m_vertexAttrData[1] = tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f);
3761		m_vertexAttrData[2] = tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f);
3762		m_vertexAttrData[3] = tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f);
3763	}
3764}
3765
3766void VaryingOutputCountCase::genVertexDataWithInstancing (void)
3767{
3768	m_numDrawVertices = 1;
3769
3770	m_vertexPosData.resize(1);
3771	m_vertexAttrData.resize(1);
3772
3773	m_vertexPosData[0] = tcu::Vec4(0.0f,  0.0f, 0.0f, 1.0f);
3774
3775	if (m_test == VaryingOutputCountShader::READ_ATTRIBUTE)
3776	{
3777		const int emitCounts[] =
3778		{
3779			(VaryingOutputCountShader::EMIT_COUNT_VERTEX_0 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_0),
3780			(VaryingOutputCountShader::EMIT_COUNT_VERTEX_1 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_1),
3781			(VaryingOutputCountShader::EMIT_COUNT_VERTEX_2 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_2),
3782			(VaryingOutputCountShader::EMIT_COUNT_VERTEX_3 == -1) ? (m_maxEmitCount) : (VaryingOutputCountShader::EMIT_COUNT_VERTEX_3),
3783		};
3784
3785		m_vertexAttrData[0] = tcu::Vec4((float)emitCounts[0], (float)emitCounts[1], (float)emitCounts[2], (float)emitCounts[3]);
3786	}
3787	else
3788	{
3789		// not used
3790		m_vertexAttrData[0] = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
3791	}
3792}
3793
3794class GeometryProgramQueryCase : public TestCase
3795{
3796public:
3797	struct ProgramCase
3798	{
3799		const char*	description;
3800		const char*	header;
3801		int			value;
3802	};
3803
3804						GeometryProgramQueryCase			(Context& context, const char* name, const char* description, glw::GLenum target);
3805
3806	void				init								(void);
3807	IterateResult		iterate								(void);
3808
3809private:
3810	void				expectProgramValue					(deUint32 program, int value);
3811	void				expectQueryError					(deUint32 program);
3812
3813	const glw::GLenum	m_target;
3814
3815protected:
3816	std::vector<ProgramCase> m_cases;
3817};
3818
3819GeometryProgramQueryCase::GeometryProgramQueryCase (Context& context, const char* name, const char* description, glw::GLenum target)
3820	: TestCase	(context, name, description)
3821	, m_target	(target)
3822{
3823}
3824
3825void GeometryProgramQueryCase::init (void)
3826{
3827	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
3828		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
3829}
3830
3831GeometryProgramQueryCase::IterateResult GeometryProgramQueryCase::iterate (void)
3832{
3833	static const char* const s_vertexSource =			"#version 310 es\n"
3834														"void main ()\n"
3835														"{\n"
3836														"	gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
3837														"}\n";
3838	static const char* const s_fragmentSource =			"#version 310 es\n"
3839														"layout(location = 0) out mediump vec4 fragColor;\n"
3840														"void main ()\n"
3841														"{\n"
3842														"	fragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
3843														"}\n";
3844	static const char* const s_geometryBody =			"void main ()\n"
3845														"{\n"
3846														"	gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
3847														"	EmitVertex();\n"
3848														"}\n";
3849
3850	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3851
3852	// default cases
3853	for (int ndx = 0; ndx < (int)m_cases.size(); ++ndx)
3854	{
3855		const tcu::ScopedLogSection section			(m_testCtx.getLog(), "Case", m_cases[ndx].description);
3856		const std::string			geometrySource	= m_cases[ndx].header + std::string(s_geometryBody);
3857		const glu::ShaderProgram	program			(m_context.getRenderContext(),
3858													glu::ProgramSources()
3859														<< glu::VertexSource(s_vertexSource)
3860														<< glu::FragmentSource(s_fragmentSource)
3861														<< glu::GeometrySource(geometrySource));
3862
3863		m_testCtx.getLog() << program;
3864		expectProgramValue(program.getProgram(), m_cases[ndx].value);
3865	}
3866
3867	// no geometry shader -case (INVALID OP)
3868	{
3869		const tcu::ScopedLogSection section			(m_testCtx.getLog(), "NoGeometryShader", "No geometry shader");
3870		const glu::ShaderProgram	program			(m_context.getRenderContext(),
3871													glu::ProgramSources()
3872														<< glu::VertexSource(s_vertexSource)
3873														<< glu::FragmentSource(s_fragmentSource));
3874
3875		m_testCtx.getLog() << program;
3876		expectQueryError(program.getProgram());
3877	}
3878
3879	// not linked -case (INVALID OP)
3880	{
3881		const tcu::ScopedLogSection section			(m_testCtx.getLog(), "NotLinkedProgram", "Shader program not linked");
3882		const std::string			geometrySource	= "#version 310 es\n"
3883													  "#extension GL_EXT_geometry_shader : require\n"
3884													  "layout (triangles) in;\n"
3885													  "layout (points, max_vertices = 3) out;\n"
3886													  + std::string(s_geometryBody);
3887
3888
3889		glu::Shader					vertexShader	(m_context.getRenderContext(), glu::SHADERTYPE_VERTEX);
3890		glu::Shader					fragmentShader	(m_context.getRenderContext(), glu::SHADERTYPE_FRAGMENT);
3891		glu::Shader					geometryShader	(m_context.getRenderContext(), glu::SHADERTYPE_GEOMETRY);
3892		glu::Program				program			(m_context.getRenderContext());
3893
3894		const char* const			geometrySourceArray[1] = { geometrySource.c_str() };
3895
3896		vertexShader.setSources(1, &s_vertexSource, DE_NULL);
3897		fragmentShader.setSources(1, &s_fragmentSource, DE_NULL);
3898		geometryShader.setSources(1, geometrySourceArray, DE_NULL);
3899
3900		vertexShader.compile();
3901		fragmentShader.compile();
3902		geometryShader.compile();
3903
3904		if (!vertexShader.getCompileStatus()   ||
3905			!fragmentShader.getCompileStatus() ||
3906			!geometryShader.getCompileStatus())
3907			throw tcu::TestError("Failed to compile shader");
3908
3909		program.attachShader(vertexShader.getShader());
3910		program.attachShader(fragmentShader.getShader());
3911		program.attachShader(geometryShader.getShader());
3912
3913		m_testCtx.getLog() << tcu::TestLog::Message << "Creating a program with geometry shader, but not linking it" << tcu::TestLog::EndMessage;
3914
3915		expectQueryError(program.getProgram());
3916	}
3917
3918	return STOP;
3919}
3920
3921void GeometryProgramQueryCase::expectProgramValue (deUint32 program, int value)
3922{
3923	const glw::Functions&										gl		= m_context.getRenderContext().getFunctions();
3924	gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint>	state;
3925
3926	gl.getProgramiv(program, m_target, &state);
3927	GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv");
3928
3929	m_testCtx.getLog() << tcu::TestLog::Message << glu::getProgramParamStr(m_target) << " = " << state << tcu::TestLog::EndMessage;
3930
3931	if (state != value)
3932	{
3933		m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected " << value << ", got " << state << tcu::TestLog::EndMessage;
3934
3935		// don't overwrite error
3936		if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
3937			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got invalid value");
3938	}
3939}
3940
3941void GeometryProgramQueryCase::expectQueryError (deUint32 program)
3942{
3943	const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
3944	glw::GLint				dummy;
3945	glw::GLenum				errorCode;
3946
3947	m_testCtx.getLog() << tcu::TestLog::Message << "Querying " << glu::getProgramParamStr(m_target) << ", expecting INVALID_OPERATION" << tcu::TestLog::EndMessage;
3948	gl.getProgramiv(program, m_target, &dummy);
3949
3950	errorCode = gl.getError();
3951
3952	if (errorCode != GL_INVALID_OPERATION)
3953	{
3954		m_testCtx.getLog() << tcu::TestLog::Message << "// ERROR: Expected INVALID_OPERATION, got " << glu::getErrorStr(errorCode) << tcu::TestLog::EndMessage;
3955
3956		// don't overwrite error
3957		if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
3958			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected error code");
3959	}
3960}
3961
3962class GeometryShaderInvocationsQueryCase : public GeometryProgramQueryCase
3963{
3964public:
3965	GeometryShaderInvocationsQueryCase(Context& context, const char* name, const char* description);
3966};
3967
3968GeometryShaderInvocationsQueryCase::GeometryShaderInvocationsQueryCase(Context& context, const char* name, const char* description)
3969	: GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_SHADER_INVOCATIONS)
3970{
3971	// 2 normal cases
3972	m_cases.resize(2);
3973
3974	m_cases[0].description	= "Default value";
3975	m_cases[0].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (triangles) in;\nlayout (points, max_vertices = 3) out;\n";
3976	m_cases[0].value		= 1;
3977
3978	m_cases[1].description	= "Value declared";
3979	m_cases[1].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (triangles, invocations=2) in;\nlayout (points, max_vertices = 3) out;\n";
3980	m_cases[1].value		= 2;
3981}
3982
3983class GeometryShaderVerticesQueryCase : public GeometryProgramQueryCase
3984{
3985public:
3986	GeometryShaderVerticesQueryCase(Context& context, const char* name, const char* description);
3987};
3988
3989GeometryShaderVerticesQueryCase::GeometryShaderVerticesQueryCase(Context& context, const char* name, const char* description)
3990	: GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_VERTICES_OUT_EXT)
3991{
3992	m_cases.resize(1);
3993
3994	m_cases[0].description	= "max_vertices = 1";
3995	m_cases[0].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (triangles) in;\nlayout (points, max_vertices = 1) out;\n";
3996	m_cases[0].value		= 1;
3997}
3998
3999class GeometryShaderInputQueryCase : public GeometryProgramQueryCase
4000{
4001public:
4002	GeometryShaderInputQueryCase(Context& context, const char* name, const char* description);
4003};
4004
4005GeometryShaderInputQueryCase::GeometryShaderInputQueryCase(Context& context, const char* name, const char* description)
4006	: GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_INPUT_TYPE_EXT)
4007{
4008	m_cases.resize(3);
4009
4010	m_cases[0].description	= "Triangles";
4011	m_cases[0].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (triangles) in;\nlayout (points, max_vertices = 3) out;\n";
4012	m_cases[0].value		= GL_TRIANGLES;
4013
4014	m_cases[1].description	= "Lines";
4015	m_cases[1].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (lines) in;\nlayout (points, max_vertices = 3) out;\n";
4016	m_cases[1].value		= GL_LINES;
4017
4018	m_cases[2].description	= "Points";
4019	m_cases[2].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (points) in;\nlayout (points, max_vertices = 3) out;\n";
4020	m_cases[2].value		= GL_POINTS;
4021}
4022
4023class GeometryShaderOutputQueryCase : public GeometryProgramQueryCase
4024{
4025public:
4026	GeometryShaderOutputQueryCase(Context& context, const char* name, const char* description);
4027};
4028
4029GeometryShaderOutputQueryCase::GeometryShaderOutputQueryCase(Context& context, const char* name, const char* description)
4030	: GeometryProgramQueryCase(context, name, description, GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT)
4031{
4032	m_cases.resize(3);
4033
4034	m_cases[0].description	= "Triangle strip";
4035	m_cases[0].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (triangles) in;\nlayout (triangle_strip, max_vertices = 3) out;\n";
4036	m_cases[0].value		= GL_TRIANGLE_STRIP;
4037
4038	m_cases[1].description	= "Lines";
4039	m_cases[1].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (triangles) in;\nlayout (line_strip, max_vertices = 3) out;\n";
4040	m_cases[1].value		= GL_LINE_STRIP;
4041
4042	m_cases[2].description	= "Points";
4043	m_cases[2].header		= "#version 310 es\n#extension GL_EXT_geometry_shader : require\nlayout (triangles) in;\nlayout (points, max_vertices = 3) out;\n";
4044	m_cases[2].value		= GL_POINTS;
4045}
4046
4047class ImplementationLimitCase : public TestCase
4048{
4049public:
4050						ImplementationLimitCase	(Context& context, const char* name, const char* description, glw::GLenum target, int minValue);
4051
4052	void				init					(void);
4053	IterateResult		iterate					(void);
4054
4055	const glw::GLenum	m_target;
4056	const int			m_minValue;
4057};
4058
4059ImplementationLimitCase::ImplementationLimitCase (Context& context, const char* name, const char* description, glw::GLenum target, int minValue)
4060	: TestCase		(context, name, description)
4061	, m_target		(target)
4062	, m_minValue	(minValue)
4063{
4064}
4065
4066void ImplementationLimitCase::init (void)
4067{
4068	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4069		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
4070}
4071
4072ImplementationLimitCase::IterateResult ImplementationLimitCase::iterate (void)
4073{
4074	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4075	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
4076
4077	gl.enableLogging(true);
4078	verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER);
4079
4080	{
4081		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
4082		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_BOOLEAN);
4083		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER64);
4084		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_FLOAT);
4085	}
4086
4087	result.setTestContextResult(m_testCtx);
4088	return STOP;
4089}
4090
4091class LayerProvokingVertexQueryCase : public TestCase
4092{
4093public:
4094					LayerProvokingVertexQueryCase	(Context& context, const char* name, const char* description);
4095
4096	void			init							(void);
4097	IterateResult	iterate							(void);
4098};
4099
4100LayerProvokingVertexQueryCase::LayerProvokingVertexQueryCase(Context& context, const char* name, const char* description)
4101	: TestCase(context, name, description)
4102{
4103}
4104
4105void LayerProvokingVertexQueryCase::init (void)
4106{
4107	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4108		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
4109}
4110
4111LayerProvokingVertexQueryCase::IterateResult LayerProvokingVertexQueryCase::iterate (void)
4112{
4113	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4114	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
4115	QueriedState			state;
4116
4117	gl.enableLogging(true);
4118	queryState(result, gl, QUERY_INTEGER, GL_LAYER_PROVOKING_VERTEX, state);
4119
4120	if (!state.isUndefined())
4121	{
4122		m_testCtx.getLog() << tcu::TestLog::Message << "LAYER_PROVOKING_VERTEX = " << glu::getProvokingVertexStr(state.getIntAccess()) << tcu::TestLog::EndMessage;
4123
4124		if (state.getIntAccess() != GL_FIRST_VERTEX_CONVENTION &&
4125			state.getIntAccess() != GL_LAST_VERTEX_CONVENTION &&
4126			state.getIntAccess() != GL_UNDEFINED_VERTEX)
4127		{
4128			m_testCtx.getLog()
4129				<< tcu::TestLog::Message
4130				<< "getInteger(GL_LAYER_PROVOKING_VERTEX) returned illegal value. Got "
4131				<< state.getIntAccess() << "\n"
4132				<< "Expected any of {FIRST_VERTEX_CONVENTION, LAST_VERTEX_CONVENTION, UNDEFINED_VERTEX}."
4133				<< tcu::TestLog::EndMessage;
4134
4135			result.fail("got unexpected provoking vertex value");
4136		}
4137
4138		{
4139			const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
4140			verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_BOOLEAN);
4141			verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_INTEGER64);
4142			verifyStateInteger(result, gl, GL_LAYER_PROVOKING_VERTEX, state.getIntAccess(), QUERY_FLOAT);
4143		}
4144	}
4145
4146	result.setTestContextResult(m_testCtx);
4147	return STOP;
4148}
4149
4150class GeometryInvocationCase : public GeometryShaderRenderTest
4151{
4152public:
4153	enum OutputCase
4154	{
4155		CASE_FIXED_OUTPUT_COUNTS = 0,
4156		CASE_DIFFERENT_OUTPUT_COUNTS,
4157
4158		CASE_LAST
4159	};
4160
4161								GeometryInvocationCase	(Context& context, const char* name, const char* description, int numInvocations, OutputCase testCase);
4162								~GeometryInvocationCase	(void);
4163
4164	void						init					(void);
4165	void						deinit					(void);
4166
4167private:
4168	sglr::ShaderProgram&		getProgram				(void);
4169	void						genVertexAttribData		(void);
4170
4171	static InvocationCountShader::OutputCase mapToShaderCaseType (OutputCase testCase);
4172
4173	const OutputCase			m_testCase;
4174	int							m_numInvocations;
4175	InvocationCountShader*		m_program;
4176};
4177
4178GeometryInvocationCase::GeometryInvocationCase (Context& context, const char* name, const char* description, int numInvocations, OutputCase testCase)
4179	: GeometryShaderRenderTest	(context, name, description, GL_POINTS, GL_TRIANGLE_STRIP, "a_color")
4180	, m_testCase				(testCase)
4181	, m_numInvocations			(numInvocations)
4182	, m_program					(DE_NULL)
4183{
4184	DE_ASSERT(m_testCase < CASE_LAST);
4185}
4186
4187GeometryInvocationCase::~GeometryInvocationCase	(void)
4188{
4189	deinit();
4190}
4191
4192void GeometryInvocationCase::init (void)
4193{
4194	const glw::Functions&	gl								= m_context.getRenderContext().getFunctions();
4195	int						maxGeometryShaderInvocations	= 0;
4196	int						maxComponents					= 0;
4197
4198	// requirements
4199
4200	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4201		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
4202
4203	gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &maxGeometryShaderInvocations);
4204	GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS)");
4205
4206	gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &maxComponents);
4207	GLU_EXPECT_NO_ERROR(gl.getError(), "getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS)");
4208
4209	m_testCtx.getLog() << tcu::TestLog::Message << "GL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << maxGeometryShaderInvocations << tcu::TestLog::EndMessage;
4210
4211	// set target num invocations
4212
4213	if (m_numInvocations == -1)
4214		m_numInvocations = maxGeometryShaderInvocations;
4215	else if (maxGeometryShaderInvocations < m_numInvocations)
4216		throw tcu::NotSupportedError("Test requires larger GL_MAX_GEOMETRY_SHADER_INVOCATIONS");
4217
4218	if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
4219	{
4220		const int maxEmitCount	= m_numInvocations + 2;
4221		const int numComponents	= 8; // pos + color
4222		if (maxEmitCount * numComponents > maxComponents)
4223			throw tcu::NotSupportedError("Test requires larger GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS");
4224	}
4225
4226	// Log what the test tries to do
4227
4228	if (m_testCase == CASE_FIXED_OUTPUT_COUNTS)
4229	{
4230		m_testCtx.getLog()
4231			<< tcu::TestLog::Message
4232			<< "Rendering triangles in a partial circle formation with a geometry shader. Each triangle is generated by a separate invocation.\n"
4233			<< "Drawing 2 points, each generating " << m_numInvocations << " triangles."
4234			<< tcu::TestLog::EndMessage;
4235	}
4236	else if (m_testCase == CASE_DIFFERENT_OUTPUT_COUNTS)
4237	{
4238		m_testCtx.getLog()
4239			<< tcu::TestLog::Message
4240			<< "Rendering n-gons in a partial circle formation with a geometry shader. Each n-gon is generated by a separate invocation.\n"
4241			<< "Drawing 2 points, each generating " << m_numInvocations << " n-gons."
4242			<< tcu::TestLog::EndMessage;
4243	}
4244	else
4245		DE_ASSERT(false);
4246
4247	// resources
4248
4249	m_program = new InvocationCountShader(m_numInvocations, mapToShaderCaseType(m_testCase));
4250
4251	GeometryShaderRenderTest::init();
4252}
4253
4254void GeometryInvocationCase::deinit (void)
4255{
4256	if (m_program)
4257	{
4258		delete m_program;
4259		m_program = DE_NULL;
4260	}
4261
4262	GeometryShaderRenderTest::deinit();
4263}
4264
4265sglr::ShaderProgram& GeometryInvocationCase::getProgram (void)
4266{
4267	return *m_program;
4268}
4269
4270void GeometryInvocationCase::genVertexAttribData (void)
4271{
4272	m_vertexPosData.resize(2);
4273	m_vertexPosData[0] = tcu::Vec4(0.0f,-0.3f, 0.0f, 1.0f);
4274	m_vertexPosData[1] = tcu::Vec4(0.2f, 0.3f, 0.0f, 1.0f);
4275
4276	m_vertexAttrData.resize(2);
4277	m_vertexAttrData[0] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
4278	m_vertexAttrData[1] = tcu::Vec4(0.8f, 0.8f, 0.8f, 1.0f);
4279	m_numDrawVertices = 2;
4280}
4281
4282InvocationCountShader::OutputCase GeometryInvocationCase::mapToShaderCaseType (OutputCase testCase)
4283{
4284	switch (testCase)
4285	{
4286		case CASE_FIXED_OUTPUT_COUNTS:			return InvocationCountShader::CASE_FIXED_OUTPUT_COUNTS;
4287		case CASE_DIFFERENT_OUTPUT_COUNTS:		return InvocationCountShader::CASE_DIFFERENT_OUTPUT_COUNTS;
4288		default:
4289			DE_ASSERT(false);
4290			return InvocationCountShader::CASE_LAST;
4291	}
4292}
4293
4294class DrawInstancedGeometryInstancedCase : public GeometryShaderRenderTest
4295{
4296public:
4297								DrawInstancedGeometryInstancedCase	(Context& context, const char* name, const char* description, int numInstances, int numInvocations);
4298								~DrawInstancedGeometryInstancedCase	(void);
4299
4300private:
4301	void						init								(void);
4302	sglr::ShaderProgram&		getProgram							(void);
4303	void						genVertexAttribData					(void);
4304
4305	const int					m_numInstances;
4306	const int					m_numInvocations;
4307	InstancedExpansionShader	m_program;
4308};
4309
4310DrawInstancedGeometryInstancedCase::DrawInstancedGeometryInstancedCase (Context& context, const char* name, const char* description, int numInstances, int numInvocations)
4311	: GeometryShaderRenderTest	(context, name, description, GL_POINTS, GL_TRIANGLE_STRIP, "a_offset", FLAG_DRAW_INSTANCED)
4312	, m_numInstances			(numInstances)
4313	, m_numInvocations			(numInvocations)
4314	, m_program					(numInvocations)
4315{
4316}
4317
4318DrawInstancedGeometryInstancedCase::~DrawInstancedGeometryInstancedCase (void)
4319{
4320}
4321
4322void DrawInstancedGeometryInstancedCase::init (void)
4323{
4324	m_testCtx.getLog()
4325		<< tcu::TestLog::Message
4326		<< "Rendering a single point with " << m_numInstances << " instances. "
4327		<< "Each geometry shader is invoked " << m_numInvocations << " times for each primitive. "
4328		<< tcu::TestLog::EndMessage;
4329
4330	GeometryShaderRenderTest::init();
4331}
4332
4333sglr::ShaderProgram& DrawInstancedGeometryInstancedCase::getProgram (void)
4334{
4335	return m_program;
4336}
4337
4338void DrawInstancedGeometryInstancedCase::genVertexAttribData (void)
4339{
4340	m_numDrawVertices = 1;
4341	m_numDrawInstances = m_numInstances;
4342	m_vertexAttrDivisor = 1;
4343
4344	m_vertexPosData.resize(1);
4345	m_vertexAttrData.resize(8);
4346
4347	m_vertexPosData[0] = tcu::Vec4( 0.0f,  0.0f, 0.0f, 1.0f);
4348
4349	m_vertexAttrData[0] = tcu::Vec4( 0.5f,  0.0f, 0.0f, 0.0f);
4350	m_vertexAttrData[1] = tcu::Vec4( 0.0f,  0.5f, 0.0f, 0.0f);
4351	m_vertexAttrData[2] = tcu::Vec4(-0.7f, -0.1f, 0.0f, 0.0f);
4352	m_vertexAttrData[3] = tcu::Vec4(-0.1f, -0.7f, 0.0f, 0.0f);
4353	m_vertexAttrData[4] = tcu::Vec4(-0.8f, -0.7f, 0.0f, 0.0f);
4354	m_vertexAttrData[5] = tcu::Vec4(-0.9f,  0.6f, 0.0f, 0.0f);
4355	m_vertexAttrData[6] = tcu::Vec4(-0.8f,  0.3f, 0.0f, 0.0f);
4356	m_vertexAttrData[7] = tcu::Vec4(-0.1f,  0.1f, 0.0f, 0.0f);
4357
4358	DE_ASSERT(m_numInstances <= (int)m_vertexAttrData.size());
4359}
4360
4361class GeometryProgramLimitCase : public TestCase
4362{
4363public:
4364						GeometryProgramLimitCase	(Context& context, const char* name, const char* description, glw::GLenum apiName, const std::string& glslName, int limit);
4365
4366private:
4367	void				init						(void);
4368	IterateResult		iterate						(void);
4369
4370	const glw::GLenum	m_apiName;
4371	const std::string	m_glslName;
4372	const int			m_limit;
4373};
4374
4375GeometryProgramLimitCase::GeometryProgramLimitCase (Context& context, const char* name, const char* description, glw::GLenum apiName, const std::string& glslName, int limit)
4376	: TestCase		(context, name, description)
4377	, m_apiName		(apiName)
4378	, m_glslName	(glslName)
4379	, m_limit		(limit)
4380{
4381}
4382
4383void GeometryProgramLimitCase::init (void)
4384{
4385	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4386		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
4387}
4388
4389GeometryProgramLimitCase::IterateResult GeometryProgramLimitCase::iterate (void)
4390{
4391	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
4392	int						limit;
4393
4394	// query limit
4395	{
4396		gls::StateQueryUtil::StateQueryMemoryWriteGuard<glw::GLint>	state;
4397		glu::CallLogWrapper											gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4398
4399		gl.enableLogging(true);
4400		gl.glGetIntegerv(m_apiName, &state);
4401		GLU_EXPECT_NO_ERROR(gl.glGetError(), "getIntegerv()");
4402
4403		m_testCtx.getLog() << tcu::TestLog::Message << glu::getGettableStateStr(m_apiName) << " = " << state << tcu::TestLog::EndMessage;
4404
4405		if (!state.verifyValidity(result))
4406		{
4407			result.setTestContextResult(m_testCtx);
4408			return STOP;
4409		}
4410
4411		if (state < m_limit)
4412		{
4413			result.fail("Minimum value = " + de::toString(m_limit) + ", got " + de::toString(state.get()));
4414			result.setTestContextResult(m_testCtx);
4415			return STOP;
4416		}
4417
4418		limit = state;
4419
4420		// verify other getters
4421		{
4422			const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
4423			verifyStateInteger(result, gl, m_apiName, limit, QUERY_BOOLEAN);
4424			verifyStateInteger(result, gl, m_apiName, limit, QUERY_INTEGER64);
4425			verifyStateInteger(result, gl, m_apiName, limit, QUERY_FLOAT);
4426		}
4427	}
4428
4429	// verify limit is the same in GLSL
4430	{
4431		static const char* const vertexSource =		"#version 310 es\n"
4432													"void main ()\n"
4433													"{\n"
4434													"	gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
4435													"}\n";
4436		static const char* const fragmentSource =	"#version 310 es\n"
4437													"layout(location = 0) out mediump vec4 fragColor;\n"
4438													"void main ()\n"
4439													"{\n"
4440													"	fragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
4441													"}\n";
4442		const std::string geometrySource =			"#version 310 es\n"
4443													"#extension GL_EXT_geometry_shader : require\n"
4444													"layout(points) in;\n"
4445													"layout(points, max_vertices = 1) out;\n"
4446													"void main ()\n"
4447													"{\n"
4448													"	// Building the shader will fail if the constant value is not the expected\n"
4449													"	const mediump int cArraySize = (gl_" + m_glslName + " == " + de::toString(limit) + ") ? (1) : (-1);\n"
4450													"	float[cArraySize] fArray;\n"
4451													"	fArray[0] = 0.0f;\n"
4452													"	gl_Position = vec4(0.0, 0.0, 0.0, fArray[0]);\n"
4453													"	EmitVertex();\n"
4454													"}\n";
4455
4456		const de::UniquePtr<glu::ShaderProgram> program(new glu::ShaderProgram(m_context.getRenderContext(),
4457																			   glu::ProgramSources()
4458																				<< glu::VertexSource(vertexSource)
4459																				<< glu::FragmentSource(fragmentSource)
4460																				<< glu::GeometrySource(geometrySource)));
4461
4462		m_testCtx.getLog() << tcu::TestLog::Message << "Building a test shader to verify GLSL constant " << m_glslName << " value." << tcu::TestLog::EndMessage;
4463		m_testCtx.getLog() << *program;
4464
4465		if (!program->isOk())
4466		{
4467			// compile failed, assume static assert failed
4468			result.fail("Shader build failed");
4469			result.setTestContextResult(m_testCtx);
4470			return STOP;
4471		}
4472
4473		m_testCtx.getLog() << tcu::TestLog::Message << "Build ok" << tcu::TestLog::EndMessage;
4474	}
4475
4476	result.setTestContextResult(m_testCtx);
4477	return STOP;
4478}
4479
4480class PrimitivesGeneratedQueryCase : public TestCase
4481{
4482public:
4483	enum QueryTest
4484	{
4485		TEST_NO_GEOMETRY			= 0,
4486		TEST_NO_AMPLIFICATION,
4487		TEST_AMPLIFICATION,
4488		TEST_PARTIAL_PRIMITIVES,
4489		TEST_INSTANCED,
4490
4491		TEST_LAST
4492	};
4493
4494						PrimitivesGeneratedQueryCase	(Context& context, const char* name, const char* description, QueryTest test);
4495						~PrimitivesGeneratedQueryCase	(void);
4496
4497private:
4498	void				init							(void);
4499	void				deinit							(void);
4500	IterateResult		iterate							(void);
4501
4502	glu::ShaderProgram*	genProgram						(void);
4503
4504	const QueryTest		m_test;
4505	glu::ShaderProgram*	m_program;
4506};
4507
4508PrimitivesGeneratedQueryCase::PrimitivesGeneratedQueryCase (Context& context, const char* name, const char* description, QueryTest test)
4509	: TestCase	(context, name, description)
4510	, m_test	(test)
4511	, m_program	(DE_NULL)
4512{
4513	DE_ASSERT(m_test < TEST_LAST);
4514}
4515
4516PrimitivesGeneratedQueryCase::~PrimitivesGeneratedQueryCase (void)
4517{
4518	deinit();
4519}
4520
4521void PrimitivesGeneratedQueryCase::init (void)
4522{
4523	// requirements
4524
4525	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4526		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
4527
4528	// log what test tries to do
4529
4530	if (m_test == TEST_NO_GEOMETRY)
4531		m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering without a geometry shader." << tcu::TestLog::EndMessage;
4532	else if (m_test == TEST_NO_AMPLIFICATION)
4533		m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a non-amplifying geometry shader." << tcu::TestLog::EndMessage;
4534	else if (m_test == TEST_AMPLIFICATION)
4535		m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a (3x) amplifying geometry shader." << tcu::TestLog::EndMessage;
4536	else if (m_test == TEST_PARTIAL_PRIMITIVES)
4537		m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a geometry shader that emits also partial primitives." << tcu::TestLog::EndMessage;
4538	else if (m_test == TEST_INSTANCED)
4539		m_testCtx.getLog() << tcu::TestLog::Message << "Querying PRIMITIVES_GENERATED while rendering with a instanced geometry shader." << tcu::TestLog::EndMessage;
4540	else
4541		DE_ASSERT(false);
4542
4543	// resources
4544
4545	m_program = genProgram();
4546	m_testCtx.getLog() << *m_program;
4547
4548	if (!m_program->isOk())
4549		throw tcu::TestError("could not build program");
4550}
4551
4552void PrimitivesGeneratedQueryCase::deinit (void)
4553{
4554	delete m_program;
4555	m_program = DE_NULL;
4556}
4557
4558PrimitivesGeneratedQueryCase::IterateResult PrimitivesGeneratedQueryCase::iterate (void)
4559{
4560	glw::GLuint primitivesGenerated = 0xDEBADBAD;
4561
4562	m_testCtx.getLog()
4563		<< tcu::TestLog::Message
4564		<< "Drawing 8 points, setting a_one for each to value (1.0, 1.0, 1.0, 1.0)"
4565		<< tcu::TestLog::EndMessage;
4566
4567	{
4568		static const tcu::Vec4 vertexData[8*2] =
4569		{
4570			tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4571			tcu::Vec4(0.1f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4572			tcu::Vec4(0.2f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4573			tcu::Vec4(0.3f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4574			tcu::Vec4(0.4f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4575			tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4576			tcu::Vec4(0.6f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4577			tcu::Vec4(0.7f, 0.0f, 0.0f, 1.0f),	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
4578		};
4579
4580		const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
4581		const glu::VertexArray	vao					(m_context.getRenderContext());
4582		const glu::Buffer		buffer				(m_context.getRenderContext());
4583		const glu::Query		query				(m_context.getRenderContext());
4584		const int				positionLocation	= gl.getAttribLocation(m_program->getProgram(), "a_position");
4585		const int				oneLocation			= gl.getAttribLocation(m_program->getProgram(), "a_one");
4586
4587		gl.bindVertexArray(*vao);
4588
4589		gl.bindBuffer(GL_ARRAY_BUFFER, *buffer);
4590		gl.bufferData(GL_ARRAY_BUFFER, (int)sizeof(vertexData), vertexData, GL_STATIC_DRAW);
4591
4592		gl.vertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(tcu::Vec4), DE_NULL);
4593		gl.enableVertexAttribArray(positionLocation);
4594
4595		if (oneLocation != -1)
4596		{
4597			gl.vertexAttribPointer(oneLocation, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(tcu::Vec4), (const tcu::Vec4*)DE_NULL + 1);
4598			gl.enableVertexAttribArray(oneLocation);
4599		}
4600
4601		gl.useProgram(m_program->getProgram());
4602
4603		GLU_EXPECT_NO_ERROR(gl.getError(), "setup render");
4604
4605		gl.beginQuery(GL_PRIMITIVES_GENERATED, *query);
4606		gl.drawArrays(GL_POINTS, 0, 8);
4607		gl.endQuery(GL_PRIMITIVES_GENERATED);
4608
4609		GLU_EXPECT_NO_ERROR(gl.getError(), "render and query");
4610
4611		gl.getQueryObjectuiv(*query, GL_QUERY_RESULT, &primitivesGenerated);
4612		GLU_EXPECT_NO_ERROR(gl.getError(), "get query result");
4613	}
4614
4615	m_testCtx.getLog()
4616		<< tcu::TestLog::Message
4617		<< "GL_PRIMITIVES_GENERATED = " << primitivesGenerated
4618		<< tcu::TestLog::EndMessage;
4619
4620	{
4621		const deUint32 expectedGenerated = (m_test == TEST_AMPLIFICATION) ? (3*8) : (m_test == TEST_INSTANCED) ? (8*(3+1)) : (8);
4622
4623		if (expectedGenerated == primitivesGenerated)
4624			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4625		else
4626		{
4627			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got wrong result for GL_PRIMITIVES_GENERATED");
4628			m_testCtx.getLog()
4629				<< tcu::TestLog::Message
4630				<< "Got unexpected result for GL_PRIMITIVES_GENERATED. Expected " << expectedGenerated << ", got " << primitivesGenerated
4631				<< tcu::TestLog::EndMessage;
4632		}
4633	}
4634
4635	return STOP;
4636}
4637
4638glu::ShaderProgram* PrimitivesGeneratedQueryCase::genProgram (void)
4639{
4640	static const char* const vertexSource =		"#version 310 es\n"
4641												"in highp vec4 a_position;\n"
4642												"in highp vec4 a_one;\n"
4643												"out highp vec4 v_one;\n"
4644												"void main (void)\n"
4645												"{\n"
4646												"	gl_Position = a_position;\n"
4647												"	v_one = a_one;\n"
4648												"}\n";
4649	static const char* const fragmentSource =	"#version 310 es\n"
4650												"layout(location = 0) out mediump vec4 fragColor;\n"
4651												"void main (void)\n"
4652												"{\n"
4653												"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
4654												"}\n";
4655	std::ostringstream geometrySource;
4656	glu::ProgramSources sources;
4657
4658	if (m_test != TEST_NO_GEOMETRY)
4659	{
4660		geometrySource <<	"#version 310 es\n"
4661							"#extension GL_EXT_geometry_shader : require\n"
4662							"layout(points" << ((m_test == TEST_INSTANCED) ? (", invocations = 3") : ("")) << ") in;\n"
4663							"layout(triangle_strip, max_vertices = 7) out;\n"
4664							"in highp vec4 v_one[];\n"
4665							"void main (void)\n"
4666							"{\n"
4667							"	// always taken\n"
4668							"	if (v_one[0].x != 0.0)\n"
4669							"	{\n"
4670							"		gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4671							"		EmitVertex();\n"
4672							"		gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4673							"		EmitVertex();\n"
4674							"		gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4675							"		EmitVertex();\n"
4676							"		EndPrimitive();\n"
4677							"	}\n";
4678
4679		if (m_test == TEST_AMPLIFICATION)
4680		{
4681			geometrySource <<	"\n"
4682								"	// always taken\n"
4683								"	if (v_one[0].y != 0.0)\n"
4684								"	{\n"
4685								"		gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4686								"		EmitVertex();\n"
4687								"		gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4688								"		EmitVertex();\n"
4689								"		gl_Position = gl_in[0].gl_Position - vec4(0.0, 0.1, 0.0, 0.0);\n"
4690								"		EmitVertex();\n"
4691								"		gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4692								"		EmitVertex();\n"
4693								"	}\n";
4694		}
4695		else if (m_test == TEST_PARTIAL_PRIMITIVES)
4696		{
4697			geometrySource <<	"\n"
4698								"	// always taken\n"
4699								"	if (v_one[0].y != 0.0)\n"
4700								"	{\n"
4701								"		gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4702								"		EmitVertex();\n"
4703								"		gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4704								"		EmitVertex();\n"
4705								"\n"
4706								"		// never taken\n"
4707								"		if (v_one[0].z < 0.0)\n"
4708								"		{\n"
4709								"			gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4710								"			EmitVertex();\n"
4711								"		}\n"
4712								"	}\n";
4713		}
4714		else if (m_test == TEST_INSTANCED)
4715		{
4716			geometrySource <<	"\n"
4717								"	// taken once\n"
4718								"	if (v_one[0].y > float(gl_InvocationID) + 0.5)\n"
4719								"	{\n"
4720								"		gl_Position = gl_in[0].gl_Position + vec4(0.0, 0.1, 0.0, 0.0);\n"
4721								"		EmitVertex();\n"
4722								"		gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);\n"
4723								"		EmitVertex();\n"
4724								"		gl_Position = gl_in[0].gl_Position - vec4(0.1, 0.0, 0.0, 0.0);\n"
4725								"		EmitVertex();\n"
4726								"	}\n";
4727		}
4728
4729		geometrySource <<	"}\n";
4730	}
4731
4732	sources << glu::VertexSource(vertexSource);
4733	sources << glu::FragmentSource(fragmentSource);
4734
4735	if (!geometrySource.str().empty())
4736		sources << glu::GeometrySource(geometrySource.str());
4737
4738	return new glu::ShaderProgram(m_context.getRenderContext(), sources);
4739}
4740
4741class PrimitivesGeneratedQueryObjectQueryCase : public TestCase
4742{
4743public:
4744					PrimitivesGeneratedQueryObjectQueryCase	(Context& context, const char* name, const char* description);
4745
4746	void			init									(void);
4747	IterateResult	iterate									(void);
4748};
4749
4750PrimitivesGeneratedQueryObjectQueryCase::PrimitivesGeneratedQueryObjectQueryCase (Context& context, const char* name, const char* description)
4751	: TestCase(context, name, description)
4752{
4753}
4754
4755void PrimitivesGeneratedQueryObjectQueryCase::init (void)
4756{
4757	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4758		throw tcu::NotSupportedError("Geometry shader tests require GL_EXT_geometry_shader extension");
4759}
4760
4761PrimitivesGeneratedQueryObjectQueryCase::IterateResult PrimitivesGeneratedQueryObjectQueryCase::iterate (void)
4762{
4763	glu::CallLogWrapper 	gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4764	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
4765
4766	gl.enableLogging(true);
4767
4768	{
4769		glw::GLuint query = 0;
4770
4771		verifyStateQueryInteger(result, gl, GL_PRIMITIVES_GENERATED, GL_CURRENT_QUERY, 0, QUERY_QUERY);
4772
4773		gl.glGenQueries(1, &query);
4774		GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGenQueries");
4775
4776		gl.glBeginQuery(GL_PRIMITIVES_GENERATED, query);
4777		GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "beginQuery");
4778
4779		verifyStateQueryInteger(result, gl, GL_PRIMITIVES_GENERATED, GL_CURRENT_QUERY, (int)query, QUERY_QUERY);
4780
4781		gl.glEndQuery(GL_PRIMITIVES_GENERATED);
4782		GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "endQuery");
4783	}
4784
4785	result.setTestContextResult(m_testCtx);
4786	return STOP;
4787}
4788
4789class GeometryShaderFeartureTestCase : public TestCase
4790{
4791public:
4792					GeometryShaderFeartureTestCase	(Context& context, const char* name, const char* description);
4793
4794	void			init							(void);
4795};
4796
4797GeometryShaderFeartureTestCase::GeometryShaderFeartureTestCase (Context& context, const char* name, const char* description)
4798	: TestCase(context, name, description)
4799{
4800}
4801
4802void GeometryShaderFeartureTestCase::init (void)
4803{
4804	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
4805		throw tcu::NotSupportedError("test requires GL_EXT_geometry_shader extension");
4806}
4807
4808class FramebufferDefaultLayersCase : public GeometryShaderFeartureTestCase
4809{
4810public:
4811					FramebufferDefaultLayersCase	(Context& context, const char* name, const char* description);
4812	IterateResult	iterate							(void);
4813};
4814
4815FramebufferDefaultLayersCase::FramebufferDefaultLayersCase (Context& context, const char* name, const char* description)
4816	: GeometryShaderFeartureTestCase(context, name, description)
4817{
4818}
4819
4820FramebufferDefaultLayersCase::IterateResult FramebufferDefaultLayersCase::iterate (void)
4821{
4822	glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4823
4824	gl.enableLogging(true);
4825
4826	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4827
4828	{
4829		const tcu::ScopedLogSection section			(m_testCtx.getLog(), "Default", "Default value");
4830		const glu::Framebuffer		fbo				(m_context.getRenderContext());
4831		glw::GLint					defaultLayers	= -1;
4832
4833		gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
4834		gl.glGetFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, &defaultLayers);
4835		GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
4836
4837		m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_DEFAULT_LAYERS = " << defaultLayers << tcu::TestLog::EndMessage;
4838
4839		if (defaultLayers != 0)
4840		{
4841			m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected 0, got " << defaultLayers << tcu::TestLog::EndMessage;
4842			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
4843		}
4844	}
4845
4846	{
4847		const tcu::ScopedLogSection section			(m_testCtx.getLog(), "SetTo12", "Set default layers to 12");
4848		const glu::Framebuffer		fbo				(m_context.getRenderContext());
4849		glw::GLint					defaultLayers	= -1;
4850
4851		gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
4852		gl.glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, 12);
4853		gl.glGetFramebufferParameteriv(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, &defaultLayers);
4854		GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
4855
4856		m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_DEFAULT_LAYERS = " << defaultLayers << tcu::TestLog::EndMessage;
4857
4858		if (defaultLayers != 12)
4859		{
4860			m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected 12, got " << defaultLayers << tcu::TestLog::EndMessage;
4861			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
4862		}
4863	}
4864
4865	return STOP;
4866}
4867
4868class FramebufferAttachmentLayeredCase : public GeometryShaderFeartureTestCase
4869{
4870public:
4871					FramebufferAttachmentLayeredCase	(Context& context, const char* name, const char* description);
4872	IterateResult	iterate								(void);
4873};
4874
4875FramebufferAttachmentLayeredCase::FramebufferAttachmentLayeredCase (Context& context, const char* name, const char* description)
4876	: GeometryShaderFeartureTestCase(context, name, description)
4877{
4878}
4879
4880FramebufferAttachmentLayeredCase::IterateResult FramebufferAttachmentLayeredCase::iterate (void)
4881{
4882	enum CaseType
4883	{
4884		TEXTURE_3D,
4885		TEXTURE_2D_ARRAY,
4886		TEXTURE_CUBE,
4887		TEXTURE_2D_MS_ARRAY,
4888		TEXTURE_3D_LAYER,
4889		TEXTURE_2D_ARRAY_LAYER,
4890	};
4891
4892	static const struct TextureType
4893	{
4894		const char*	name;
4895		const char*	description;
4896		bool		layered;
4897		CaseType	type;
4898	} textureTypes[] =
4899	{
4900		{ "3D",				"3D texture",			true,	TEXTURE_3D				},
4901		{ "2DArray",		"2D array",				true,	TEXTURE_2D_ARRAY		},
4902		{ "Cube",			"Cube map",				true,	TEXTURE_CUBE			},
4903		{ "2DMSArray",		"2D multisample array",	true,	TEXTURE_2D_MS_ARRAY		},
4904		{ "3DLayer",		"3D texture layer ",	false,	TEXTURE_3D_LAYER		},
4905		{ "2DArrayLayer",	"2D array layer ",		false,	TEXTURE_2D_ARRAY_LAYER	},
4906	};
4907
4908	glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
4909	gl.enableLogging(true);
4910
4911	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4912
4913	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(textureTypes); ++ndx)
4914	{
4915		const tcu::ScopedLogSection section			(m_testCtx.getLog(), textureTypes[ndx].name, textureTypes[ndx].description);
4916		const glu::Framebuffer		fbo				(m_context.getRenderContext());
4917		const glu::Texture			texture			(m_context.getRenderContext());
4918		glw::GLint					layered			= -1;
4919
4920		gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
4921
4922		if (textureTypes[ndx].type == TEXTURE_3D || textureTypes[ndx].type == TEXTURE_3D_LAYER)
4923		{
4924			gl.glBindTexture(GL_TEXTURE_3D, *texture);
4925			gl.glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
4926			gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4927			gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4928
4929			if (textureTypes[ndx].type == TEXTURE_3D)
4930				gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
4931			else
4932				gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0, 2);
4933		}
4934		else if (textureTypes[ndx].type == TEXTURE_2D_ARRAY || textureTypes[ndx].type == TEXTURE_2D_ARRAY_LAYER)
4935		{
4936			gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture);
4937			gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
4938			gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4939			gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4940
4941			if (textureTypes[ndx].type == TEXTURE_2D_ARRAY)
4942				gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
4943			else
4944				gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0, 3);
4945		}
4946		else if (textureTypes[ndx].type == TEXTURE_CUBE)
4947		{
4948			gl.glBindTexture(GL_TEXTURE_CUBE_MAP, *texture);
4949			for (int face = 0; face < 6; ++face)
4950				gl.glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA8, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
4951			gl.glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4952			gl.glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4953			gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
4954		}
4955		else if (textureTypes[ndx].type == TEXTURE_2D_MS_ARRAY)
4956		{
4957			// check extension
4958			if (!m_context.getContextInfo().isExtensionSupported("GL_OES_texture_storage_multisample_2d_array"))
4959			{
4960				m_testCtx.getLog() << tcu::TestLog::Message << "GL_OES_texture_storage_multisample_2d_array not supported, skipping." << tcu::TestLog::EndMessage;
4961				continue;
4962			}
4963
4964			gl.glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, *texture);
4965			gl.glTexStorage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 1, GL_RGBA8, 32, 32, 32, GL_FALSE);
4966			gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture, 0);
4967		}
4968
4969		GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup attachment");
4970
4971		gl.glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_LAYERED, &layered);
4972		GLU_EXPECT_NO_ERROR(gl.glGetError(), "getFramebufferParameteriv");
4973
4974		m_testCtx.getLog() << tcu::TestLog::Message << "GL_FRAMEBUFFER_ATTACHMENT_LAYERED = " << glu::getBooleanStr(layered) << tcu::TestLog::EndMessage;
4975
4976		if (layered != GL_TRUE && layered != GL_FALSE)
4977		{
4978			m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected boolean, got " << layered << tcu::TestLog::EndMessage;
4979			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid boolean");
4980		}
4981		else if ((layered == GL_TRUE) != textureTypes[ndx].layered)
4982		{
4983			m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected " << ((textureTypes[ndx].layered) ? ("GL_TRUE") : ("GL_FALSE")) << ", got " << glu::getBooleanStr(layered) << tcu::TestLog::EndMessage;
4984			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
4985		}
4986	}
4987
4988	return STOP;
4989}
4990
4991class FramebufferIncompleteLayereTargetsCase : public GeometryShaderFeartureTestCase
4992{
4993public:
4994					FramebufferIncompleteLayereTargetsCase	(Context& context, const char* name, const char* description);
4995	IterateResult	iterate									(void);
4996};
4997
4998FramebufferIncompleteLayereTargetsCase::FramebufferIncompleteLayereTargetsCase (Context& context, const char* name, const char* description)
4999	: GeometryShaderFeartureTestCase(context, name, description)
5000{
5001}
5002
5003FramebufferIncompleteLayereTargetsCase::IterateResult FramebufferIncompleteLayereTargetsCase::iterate (void)
5004{
5005	glu::CallLogWrapper gl(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5006	gl.enableLogging(true);
5007
5008	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5009
5010	{
5011		const tcu::ScopedLogSection section			(m_testCtx.getLog(), "LayerAndNonLayer", "Layered and non-layered");
5012		const glu::Framebuffer		fbo				(m_context.getRenderContext());
5013		const glu::Texture			texture0		(m_context.getRenderContext());
5014		const glu::Texture			texture1		(m_context.getRenderContext());
5015
5016		glw::GLint					fboStatus;
5017
5018		gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture0);
5019		gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5020		gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5021		gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5022
5023		gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture1);
5024		gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5025		gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5026		gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5027
5028		gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5029		gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture0, 0);
5030		gl.glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, *texture1, 0, 0);
5031
5032		GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup fbo");
5033
5034		fboStatus = gl.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
5035		m_testCtx.getLog() << tcu::TestLog::Message << "Framebuffer status: " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5036
5037		if (fboStatus != GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
5038		{
5039			m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS, got " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5040			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5041		}
5042	}
5043
5044	{
5045		const tcu::ScopedLogSection section			(m_testCtx.getLog(), "DifferentTarget", "Different target");
5046		const glu::Framebuffer		fbo				(m_context.getRenderContext());
5047		const glu::Texture			texture0		(m_context.getRenderContext());
5048		const glu::Texture			texture1		(m_context.getRenderContext());
5049
5050		glw::GLint					fboStatus;
5051
5052		gl.glBindTexture(GL_TEXTURE_2D_ARRAY, *texture0);
5053		gl.glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5054		gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5055		gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5056
5057		gl.glBindTexture(GL_TEXTURE_3D, *texture1);
5058		gl.glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, 32, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL);
5059		gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5060		gl.glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5061
5062		gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *fbo);
5063		gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *texture0, 0);
5064		gl.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, *texture1, 0);
5065
5066		GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup fbo");
5067
5068		fboStatus = gl.glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
5069		m_testCtx.getLog() << tcu::TestLog::Message << "Framebuffer status: " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5070
5071		if (fboStatus != GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS)
5072		{
5073			m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS, got " << glu::getFramebufferStatusStr(fboStatus) << tcu::TestLog::EndMessage;
5074			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "invalid layer count");
5075		}
5076	}
5077
5078	return STOP;
5079}
5080
5081class ReferencedByGeometryShaderCase : public GeometryShaderFeartureTestCase
5082{
5083public:
5084					ReferencedByGeometryShaderCase	(Context& context, const char* name, const char* description);
5085	IterateResult	iterate							(void);
5086};
5087
5088ReferencedByGeometryShaderCase::ReferencedByGeometryShaderCase (Context& context, const char* name, const char* description)
5089	: GeometryShaderFeartureTestCase(context, name, description)
5090{
5091}
5092
5093ReferencedByGeometryShaderCase::IterateResult ReferencedByGeometryShaderCase::iterate (void)
5094{
5095	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5096
5097	{
5098		static const char* const vertexSource =		"#version 310 es\n"
5099													"uniform highp vec4 u_position;\n"
5100													"void main (void)\n"
5101													"{\n"
5102													"	gl_Position = u_position;\n"
5103													"}\n";
5104		static const char* const fragmentSource =	"#version 310 es\n"
5105													"layout(location = 0) out mediump vec4 fragColor;\n"
5106													"void main (void)\n"
5107													"{\n"
5108													"	fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
5109													"}\n";
5110		static const char* const geometrySource =	"#version 310 es\n"
5111													"#extension GL_EXT_geometry_shader : require\n"
5112													"layout(points) in;\n"
5113													"layout(points, max_vertices=1) out;\n"
5114													"uniform highp vec4 u_offset;\n"
5115													"void main (void)\n"
5116													"{\n"
5117													"	gl_Position = gl_in[0].gl_Position + u_offset;\n"
5118													"	EmitVertex();\n"
5119													"}\n";
5120
5121		const glu::ShaderProgram program(m_context.getRenderContext(), glu::ProgramSources()
5122																		<< glu::VertexSource(vertexSource)
5123																		<< glu::FragmentSource(fragmentSource)
5124																		<< glu::GeometrySource(geometrySource));
5125		m_testCtx.getLog() << program;
5126
5127		{
5128			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "UnreferencedUniform", "Unreferenced uniform u_position");
5129			glu::CallLogWrapper			gl			(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5130			const deUint32				props[1]	= { GL_REFERENCED_BY_GEOMETRY_SHADER };
5131			deUint32					resourcePos;
5132			glw::GLsizei				length		= 0;
5133			glw::GLint					referenced	= 0;
5134
5135			gl.enableLogging(true);
5136
5137			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_position");
5138			m_testCtx.getLog() << tcu::TestLog::Message << "u_position resource index: " << resourcePos << tcu::TestLog::EndMessage;
5139
5140			gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
5141			m_testCtx.getLog() << tcu::TestLog::Message << "Query GL_REFERENCED_BY_GEOMETRY_SHADER, got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced) << tcu::TestLog::EndMessage;
5142
5143			GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
5144
5145			if (length == 0 || referenced != GL_FALSE)
5146			{
5147				m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_FALSE." << tcu::TestLog::EndMessage;
5148				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected value");
5149			}
5150		}
5151
5152		{
5153			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "ReferencedUniform", "Referenced uniform u_offset");
5154			glu::CallLogWrapper			gl			(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5155			const deUint32				props[1]	= { GL_REFERENCED_BY_GEOMETRY_SHADER };
5156			deUint32					resourcePos;
5157			glw::GLsizei				length		= 0;
5158			glw::GLint					referenced	= 0;
5159
5160			gl.enableLogging(true);
5161
5162			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_offset");
5163			m_testCtx.getLog() << tcu::TestLog::Message << "u_offset resource index: " << resourcePos << tcu::TestLog::EndMessage;
5164
5165			gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
5166			m_testCtx.getLog() << tcu::TestLog::Message << "Query GL_REFERENCED_BY_GEOMETRY_SHADER, got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced) << tcu::TestLog::EndMessage;
5167
5168			GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
5169
5170			if (length == 0 || referenced != GL_TRUE)
5171			{
5172				m_testCtx.getLog() << tcu::TestLog::Message << "Error, expected GL_TRUE." << tcu::TestLog::EndMessage;
5173				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "got unexpected value");
5174			}
5175		}
5176	}
5177
5178	return STOP;
5179}
5180
5181class CombinedGeometryUniformLimitCase : public GeometryShaderFeartureTestCase
5182{
5183public:
5184						CombinedGeometryUniformLimitCase	(Context& context, const char* name, const char* desc);
5185private:
5186	IterateResult		iterate								(void);
5187};
5188
5189CombinedGeometryUniformLimitCase::CombinedGeometryUniformLimitCase (Context& context, const char* name, const char* desc)
5190	: GeometryShaderFeartureTestCase(context, name, desc)
5191{
5192}
5193
5194CombinedGeometryUniformLimitCase::IterateResult CombinedGeometryUniformLimitCase::iterate (void)
5195{
5196	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
5197	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
5198
5199	gl.enableLogging(true);
5200
5201	m_testCtx.getLog()	<< tcu::TestLog::Message
5202						<< "The minimum value of MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS is MAX_GEOMETRY_UNIFORM_BLOCKS x MAX_UNIFORM_BLOCK_SIZE / 4 + MAX_GEOMETRY_UNIFORM_COMPONENTS"
5203						<< tcu::TestLog::EndMessage;
5204
5205	StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlocks;
5206	gl.glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_BLOCKS, &maxUniformBlocks);
5207	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5208
5209	StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlockSize;
5210	gl.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
5211	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5212
5213	StateQueryMemoryWriteGuard<glw::GLint> maxUniformComponents;
5214	gl.glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, &maxUniformComponents);
5215	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
5216
5217	if (maxUniformBlocks.verifyValidity(result) && maxUniformBlockSize.verifyValidity(result) && maxUniformComponents.verifyValidity(result))
5218	{
5219		const int limit = ((int)maxUniformBlocks) * ((int)maxUniformBlockSize) / 4 + (int)maxUniformComponents;
5220		verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_INTEGER);
5221
5222		{
5223			const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
5224			verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_BOOLEAN);
5225			verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_INTEGER64);
5226			verifyStateIntegerMin(result, gl, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, limit, QUERY_FLOAT);
5227		}
5228	}
5229
5230	result.setTestContextResult(m_testCtx);
5231	return STOP;
5232}
5233
5234class VertexFeedbackCase : public TestCase
5235{
5236public:
5237	enum DrawMethod
5238	{
5239		METHOD_DRAW_ARRAYS = 0,
5240		METHOD_DRAW_ARRAYS_INSTANCED,
5241		METHOD_DRAW_ARRAYS_INDIRECT,
5242		METHOD_DRAW_ELEMENTS,
5243		METHOD_DRAW_ELEMENTS_INSTANCED,
5244		METHOD_DRAW_ELEMENTS_INDIRECT,
5245
5246		METHOD_LAST
5247	};
5248	enum PrimitiveType
5249	{
5250		PRIMITIVE_LINE_LOOP = 0,
5251		PRIMITIVE_LINE_STRIP,
5252		PRIMITIVE_TRIANGLE_STRIP,
5253		PRIMITIVE_TRIANGLE_FAN,
5254		PRIMITIVE_POINTS,
5255
5256		PRIMITIVE_LAST
5257	};
5258
5259						VertexFeedbackCase	(Context& context, const char* name, const char* description, DrawMethod method, PrimitiveType output);
5260						~VertexFeedbackCase	(void);
5261private:
5262	void				init				(void);
5263	void				deinit				(void);
5264	IterateResult		iterate				(void);
5265
5266	glu::ShaderProgram*	genProgram			(void);
5267	deUint32			getOutputPrimitive	(void);
5268	deUint32			getBasePrimitive	(void);
5269
5270	const DrawMethod	m_method;
5271	const PrimitiveType	m_output;
5272
5273	deUint32			m_elementBuf;
5274	deUint32			m_arrayBuf;
5275	deUint32			m_offsetBuf;
5276	deUint32			m_feedbackBuf;
5277	deUint32			m_indirectBuffer;
5278	glu::ShaderProgram*	m_program;
5279	glu::VertexArray*	m_vao;
5280};
5281
5282VertexFeedbackCase::VertexFeedbackCase (Context& context, const char* name, const char* description, DrawMethod method, PrimitiveType output)
5283	: TestCase			(context, name, description)
5284	, m_method			(method)
5285	, m_output			(output)
5286	, m_elementBuf		(0)
5287	, m_arrayBuf		(0)
5288	, m_offsetBuf		(0)
5289	, m_feedbackBuf		(0)
5290	, m_indirectBuffer	(0)
5291	, m_program			(DE_NULL)
5292	, m_vao				(DE_NULL)
5293{
5294	DE_ASSERT(method < METHOD_LAST);
5295	DE_ASSERT(output < PRIMITIVE_LAST);
5296}
5297
5298VertexFeedbackCase::~VertexFeedbackCase (void)
5299{
5300	deinit();
5301}
5302
5303void VertexFeedbackCase::init (void)
5304{
5305	// requirements
5306
5307	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
5308		throw tcu::NotSupportedError("test requires GL_EXT_geometry_shader extension");
5309
5310	// log what test tries to do
5311
5312	m_testCtx.getLog()
5313		<< tcu::TestLog::Message
5314		<< "Testing GL_EXT_geometry_shader transform feedback relaxations.\n"
5315		<< "Capturing vertex shader varying, no geometry shader. Invoke with:"
5316		<< tcu::TestLog::EndMessage;
5317
5318	switch (m_method)
5319	{
5320		case METHOD_DRAW_ARRAYS:				m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArrays"			<< tcu::TestLog::EndMessage;	break;
5321		case METHOD_DRAW_ARRAYS_INSTANCED:		m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArraysInstanced"	<< tcu::TestLog::EndMessage;	break;
5322		case METHOD_DRAW_ARRAYS_INDIRECT:		m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawArraysIndirect"	<< tcu::TestLog::EndMessage;	break;
5323		case METHOD_DRAW_ELEMENTS:				m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElements"			<< tcu::TestLog::EndMessage;	break;
5324		case METHOD_DRAW_ELEMENTS_INSTANCED:	m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElementsInstanced" << tcu::TestLog::EndMessage;	break;
5325		case METHOD_DRAW_ELEMENTS_INDIRECT:		m_testCtx.getLog() << tcu::TestLog::Message << "Draw method: drawElementsIndirect"	<< tcu::TestLog::EndMessage;	break;
5326		default:
5327			DE_ASSERT(false);
5328	}
5329	switch (m_output)
5330	{
5331		case PRIMITIVE_LINE_LOOP:				m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: line loop"			<< tcu::TestLog::EndMessage;	break;
5332		case PRIMITIVE_LINE_STRIP:				m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: line strip"			<< tcu::TestLog::EndMessage;	break;
5333		case PRIMITIVE_TRIANGLE_STRIP:			m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: triangle strip"		<< tcu::TestLog::EndMessage;	break;
5334		case PRIMITIVE_TRIANGLE_FAN:			m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: triangle fan"		<< tcu::TestLog::EndMessage;	break;
5335		case PRIMITIVE_POINTS:					m_testCtx.getLog() << tcu::TestLog::Message << "Draw primitive: points"				<< tcu::TestLog::EndMessage;	break;
5336		default:
5337			DE_ASSERT(false);
5338	}
5339
5340	// resources
5341
5342	{
5343		static const deUint16 elementData[] =
5344		{
5345			0, 1, 2, 3,
5346		};
5347		static const tcu::Vec4 arrayData[] =
5348		{
5349			tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5350			tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f),
5351			tcu::Vec4(2.0f, 0.0f, 0.0f, 0.0f),
5352			tcu::Vec4(3.0f, 0.0f, 0.0f, 0.0f),
5353		};
5354		static const tcu::Vec4 offsetData[] =
5355		{
5356			tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5357			tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5358			tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5359			tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
5360		};
5361
5362		const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
5363		const int				feedbackSize	= 8 * sizeof(float[4]);
5364
5365		m_vao = new glu::VertexArray(m_context.getRenderContext());
5366		gl.bindVertexArray(**m_vao);
5367		GLU_EXPECT_NO_ERROR(gl.getError(), "set up vao");
5368
5369		gl.genBuffers(1, &m_elementBuf);
5370		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
5371		gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), &elementData[0], GL_STATIC_DRAW);
5372		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5373
5374		gl.genBuffers(1, &m_arrayBuf);
5375		gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5376		gl.bufferData(GL_ARRAY_BUFFER, sizeof(arrayData), &arrayData[0], GL_STATIC_DRAW);
5377		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5378
5379		gl.genBuffers(1, &m_offsetBuf);
5380		gl.bindBuffer(GL_ARRAY_BUFFER, m_offsetBuf);
5381		gl.bufferData(GL_ARRAY_BUFFER, sizeof(offsetData), &offsetData[0], GL_STATIC_DRAW);
5382		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5383
5384		gl.genBuffers(1, &m_feedbackBuf);
5385		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuf);
5386		gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, feedbackSize, DE_NULL, GL_DYNAMIC_COPY);
5387		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5388
5389		m_program = genProgram();
5390
5391		if (!m_program->isOk())
5392		{
5393			m_testCtx.getLog() << *m_program;
5394			throw tcu::TestError("could not build program");
5395		}
5396	}
5397}
5398
5399void VertexFeedbackCase::deinit (void)
5400{
5401	if (m_elementBuf)
5402	{
5403		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuf);
5404		m_elementBuf = 0;
5405	}
5406
5407	if (m_arrayBuf)
5408	{
5409		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
5410		m_arrayBuf = 0;
5411	}
5412
5413	if (m_offsetBuf)
5414	{
5415		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_offsetBuf);
5416		m_offsetBuf = 0;
5417	}
5418
5419	if (m_feedbackBuf)
5420	{
5421		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuf);
5422		m_feedbackBuf = 0;
5423	}
5424
5425	if (m_indirectBuffer)
5426	{
5427		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_indirectBuffer);
5428		m_indirectBuffer = 0;
5429	}
5430
5431	delete m_program;
5432	m_program = DE_NULL;
5433
5434	delete m_vao;
5435	m_vao = DE_NULL;
5436}
5437
5438VertexFeedbackCase::IterateResult VertexFeedbackCase::iterate (void)
5439{
5440	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
5441	const deUint32			outputPrimitive	= getOutputPrimitive();
5442	const deUint32			basePrimitive	= getBasePrimitive();
5443
5444	const int				posLocation		= gl.getAttribLocation(m_program->getProgram(), "a_position");
5445	const int				offsetLocation	= gl.getAttribLocation(m_program->getProgram(), "a_offset");
5446
5447	if (posLocation == -1)
5448		throw tcu::TestError("a_position location was -1");
5449	if (offsetLocation == -1)
5450		throw tcu::TestError("a_offset location was -1");
5451
5452	gl.useProgram(m_program->getProgram());
5453
5454	gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5455	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
5456	gl.enableVertexAttribArray(posLocation);
5457
5458	gl.bindBuffer(GL_ARRAY_BUFFER, m_offsetBuf);
5459	gl.vertexAttribPointer(offsetLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
5460	gl.enableVertexAttribArray(offsetLocation);
5461
5462	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuf);
5463	GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffer base");
5464
5465	m_testCtx.getLog() << tcu::TestLog::Message << "Calling BeginTransformFeedback(" << glu::getPrimitiveTypeStr(basePrimitive) << ")" << tcu::TestLog::EndMessage;
5466	gl.beginTransformFeedback(basePrimitive);
5467	GLU_EXPECT_NO_ERROR(gl.getError(), "beginTransformFeedback");
5468
5469	switch (m_method)
5470	{
5471		case METHOD_DRAW_ARRAYS:
5472		{
5473			m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawArrays(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5474			gl.drawArrays(outputPrimitive, 0, 4);
5475			break;
5476		}
5477
5478		case METHOD_DRAW_ARRAYS_INSTANCED:
5479		{
5480			m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawArraysInstanced(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5481			gl.vertexAttribDivisor(offsetLocation, 2);
5482			gl.drawArraysInstanced(outputPrimitive, 0, 3, 2);
5483			break;
5484		}
5485
5486		case METHOD_DRAW_ELEMENTS:
5487		{
5488			m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElements(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5489			gl.drawElements(outputPrimitive, 4, GL_UNSIGNED_SHORT, DE_NULL);
5490			break;
5491		}
5492
5493		case METHOD_DRAW_ELEMENTS_INSTANCED:
5494		{
5495			m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsInstanced(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5496			gl.drawElementsInstanced(outputPrimitive, 3, GL_UNSIGNED_SHORT, DE_NULL, 2);
5497			break;
5498		}
5499
5500		case METHOD_DRAW_ARRAYS_INDIRECT:
5501		{
5502			struct DrawArraysIndirectCommand
5503			{
5504				deUint32 count;
5505				deUint32 instanceCount;
5506				deUint32 first;
5507				deUint32 reservedMustBeZero;
5508			} params;
5509
5510			DE_STATIC_ASSERT(sizeof(DrawArraysIndirectCommand) == sizeof(deUint32[4]));
5511
5512			params.count = 4;
5513			params.instanceCount = 1;
5514			params.first = 0;
5515			params.reservedMustBeZero = 0;
5516
5517			gl.genBuffers(1, &m_indirectBuffer);
5518			gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
5519			gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(params), &params, GL_STATIC_DRAW);
5520
5521			m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsIndirect(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5522			gl.drawArraysIndirect(outputPrimitive, DE_NULL);
5523			break;
5524		}
5525
5526		case METHOD_DRAW_ELEMENTS_INDIRECT:
5527		{
5528			struct DrawElementsIndirectCommand
5529			{
5530				deUint32	count;
5531				deUint32	instanceCount;
5532				deUint32	firstIndex;
5533				deInt32		baseVertex;
5534				deUint32	reservedMustBeZero;
5535			} params;
5536
5537			DE_STATIC_ASSERT(sizeof(DrawElementsIndirectCommand) == sizeof(deUint32[5]));
5538
5539			params.count = 4;
5540			params.instanceCount = 1;
5541			params.firstIndex = 0;
5542			params.baseVertex = 0;
5543			params.reservedMustBeZero = 0;
5544
5545			gl.genBuffers(1, &m_indirectBuffer);
5546			gl.bindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
5547			gl.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(params), &params, GL_STATIC_DRAW);
5548
5549			m_testCtx.getLog() << tcu::TestLog::Message << "Calling DrawElementsIndirect(" << glu::getPrimitiveTypeStr(outputPrimitive) << ", ...)" << tcu::TestLog::EndMessage;
5550			gl.drawElementsIndirect(outputPrimitive, GL_UNSIGNED_SHORT, DE_NULL);
5551			break;
5552		}
5553
5554		default:
5555			DE_ASSERT(false);
5556	}
5557	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
5558
5559	gl.endTransformFeedback();
5560	GLU_EXPECT_NO_ERROR(gl.getError(), "endTransformFeedback");
5561
5562	m_testCtx.getLog() << tcu::TestLog::Message << "No errors." << tcu::TestLog::EndMessage;
5563	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5564
5565	return STOP;
5566}
5567
5568glu::ShaderProgram* VertexFeedbackCase::genProgram (void)
5569{
5570	static const char* const vertexSource =		"#version 310 es\n"
5571												"in highp vec4 a_position;\n"
5572												"in highp vec4 a_offset;\n"
5573												"out highp vec4 tf_value;\n"
5574												"void main (void)\n"
5575												"{\n"
5576												"	gl_Position = a_position;\n"
5577												"	tf_value = a_position + a_offset;\n"
5578												"}\n";
5579	static const char* const fragmentSource =	"#version 310 es\n"
5580												"layout(location = 0) out mediump vec4 fragColor;\n"
5581												"void main (void)\n"
5582												"{\n"
5583												"	fragColor = vec4(1.0);\n"
5584												"}\n";
5585
5586	return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5587																<< glu::VertexSource(vertexSource)
5588																<< glu::FragmentSource(fragmentSource)
5589																<< glu::TransformFeedbackVarying("tf_value")
5590																<< glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
5591}
5592
5593deUint32 VertexFeedbackCase::getOutputPrimitive (void)
5594{
5595	switch(m_output)
5596	{
5597		case PRIMITIVE_LINE_LOOP:		return GL_LINE_LOOP;
5598		case PRIMITIVE_LINE_STRIP:		return GL_LINE_STRIP;
5599		case PRIMITIVE_TRIANGLE_STRIP:	return GL_TRIANGLE_STRIP;
5600		case PRIMITIVE_TRIANGLE_FAN:	return GL_TRIANGLE_FAN;
5601		case PRIMITIVE_POINTS:			return GL_POINTS;
5602		default:
5603			DE_ASSERT(false);
5604			return 0;
5605	}
5606}
5607
5608deUint32 VertexFeedbackCase::getBasePrimitive (void)
5609{
5610	switch(m_output)
5611	{
5612		case PRIMITIVE_LINE_LOOP:		return GL_LINES;
5613		case PRIMITIVE_LINE_STRIP:		return GL_LINES;
5614		case PRIMITIVE_TRIANGLE_STRIP:	return GL_TRIANGLES;
5615		case PRIMITIVE_TRIANGLE_FAN:	return GL_TRIANGLES;
5616		case PRIMITIVE_POINTS:			return GL_POINTS;
5617		default:
5618			DE_ASSERT(false);
5619			return 0;
5620	}
5621}
5622
5623class VertexFeedbackOverflowCase : public TestCase
5624{
5625public:
5626	enum Method
5627	{
5628		METHOD_DRAW_ARRAYS = 0,
5629		METHOD_DRAW_ELEMENTS,
5630	};
5631
5632						VertexFeedbackOverflowCase	(Context& context, const char* name, const char* description, Method method);
5633						~VertexFeedbackOverflowCase	(void);
5634
5635private:
5636	void				init						(void);
5637	void				deinit						(void);
5638	IterateResult		iterate						(void);
5639	glu::ShaderProgram*	genProgram					(void);
5640
5641	const Method		m_method;
5642
5643	deUint32			m_elementBuf;
5644	deUint32			m_arrayBuf;
5645	deUint32			m_feedbackBuf;
5646	glu::ShaderProgram*	m_program;
5647	glu::VertexArray*	m_vao;
5648};
5649
5650VertexFeedbackOverflowCase::VertexFeedbackOverflowCase (Context& context, const char* name, const char* description, Method method)
5651	: TestCase		(context, name, description)
5652	, m_method		(method)
5653	, m_elementBuf	(0)
5654	, m_arrayBuf	(0)
5655	, m_feedbackBuf	(0)
5656	, m_program		(DE_NULL)
5657	, m_vao			(DE_NULL)
5658{
5659}
5660
5661VertexFeedbackOverflowCase::~VertexFeedbackOverflowCase (void)
5662{
5663	deinit();
5664}
5665
5666void VertexFeedbackOverflowCase::init (void)
5667{
5668	// requirements
5669
5670	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
5671		throw tcu::NotSupportedError("test requires GL_EXT_geometry_shader extension");
5672
5673	// log what test tries to do
5674
5675	m_testCtx.getLog()
5676		<< tcu::TestLog::Message
5677		<< "Testing GL_EXT_geometry_shader transform feedback overflow behavior.\n"
5678		<< "Capturing vertex shader varying, rendering 2 triangles. Allocating feedback buffer for 5 vertices."
5679		<< tcu::TestLog::EndMessage;
5680
5681	// resources
5682
5683	{
5684		static const deUint16	elementData[] =
5685		{
5686			0, 1, 2,
5687			0, 1, 2,
5688		};
5689		static const tcu::Vec4	arrayData[] =
5690		{
5691			tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5692			tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5693			tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5694			tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),
5695		};
5696
5697		const glw::Functions&	gl			= m_context.getRenderContext().getFunctions();
5698
5699		m_vao = new glu::VertexArray(m_context.getRenderContext());
5700		gl.bindVertexArray(**m_vao);
5701		GLU_EXPECT_NO_ERROR(gl.getError(), "set up vao");
5702
5703		if (m_method == METHOD_DRAW_ELEMENTS)
5704		{
5705			gl.genBuffers(1, &m_elementBuf);
5706			gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
5707			gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elementData), &elementData[0], GL_STATIC_DRAW);
5708			GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5709		}
5710
5711		gl.genBuffers(1, &m_arrayBuf);
5712		gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5713		gl.bufferData(GL_ARRAY_BUFFER, sizeof(arrayData), &arrayData[0], GL_STATIC_DRAW);
5714		GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5715
5716		{
5717			const int					feedbackCount			= 5 * 4; // 5x vec4
5718			const std::vector<float>	initialBufferContents	(feedbackCount, -1.0f);
5719
5720			m_testCtx.getLog() << tcu::TestLog::Message << "Filling feeback buffer with dummy value (-1.0)." << tcu::TestLog::EndMessage;
5721
5722			gl.genBuffers(1, &m_feedbackBuf);
5723			gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, m_feedbackBuf);
5724			gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, (int)(sizeof(float) * initialBufferContents.size()), &initialBufferContents[0], GL_DYNAMIC_COPY);
5725			GLU_EXPECT_NO_ERROR(gl.getError(), "gen buf");
5726		}
5727
5728		m_program = genProgram();
5729
5730		if (!m_program->isOk())
5731		{
5732			m_testCtx.getLog() << *m_program;
5733			throw tcu::TestError("could not build program");
5734		}
5735	}
5736}
5737
5738void VertexFeedbackOverflowCase::deinit (void)
5739{
5740	if (m_elementBuf)
5741	{
5742		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_elementBuf);
5743		m_elementBuf = 0;
5744	}
5745
5746	if (m_arrayBuf)
5747	{
5748		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
5749		m_arrayBuf = 0;
5750	}
5751
5752	if (m_feedbackBuf)
5753	{
5754		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_feedbackBuf);
5755		m_feedbackBuf = 0;
5756	}
5757
5758	delete m_program;
5759	m_program = DE_NULL;
5760
5761	delete m_vao;
5762	m_vao = DE_NULL;
5763}
5764
5765VertexFeedbackOverflowCase::IterateResult VertexFeedbackOverflowCase::iterate (void)
5766{
5767	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
5768	const int				posLocation		= gl.getAttribLocation(m_program->getProgram(), "a_position");
5769
5770	if (posLocation == -1)
5771		throw tcu::TestError("a_position location was -1");
5772
5773	gl.useProgram(m_program->getProgram());
5774
5775	gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
5776	gl.vertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
5777	gl.enableVertexAttribArray(posLocation);
5778
5779	if (m_method == METHOD_DRAW_ELEMENTS)
5780	{
5781		gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBuf);
5782		GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffers");
5783	}
5784
5785	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_feedbackBuf);
5786	GLU_EXPECT_NO_ERROR(gl.getError(), "bind buffer base");
5787
5788	m_testCtx.getLog() << tcu::TestLog::Message << "Capturing 2 triangles." << tcu::TestLog::EndMessage;
5789
5790	gl.beginTransformFeedback(GL_TRIANGLES);
5791
5792	if (m_method == METHOD_DRAW_ELEMENTS)
5793		gl.drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, DE_NULL);
5794	else if (m_method == METHOD_DRAW_ARRAYS)
5795		gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
5796	else
5797		DE_ASSERT(false);
5798
5799	gl.endTransformFeedback();
5800	GLU_EXPECT_NO_ERROR(gl.getError(), "capture");
5801
5802	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying final triangle was not partially written to the feedback buffer." << tcu::TestLog::EndMessage;
5803
5804	{
5805		const void*				ptr		= gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float[4]) * 5, GL_MAP_READ_BIT);
5806		std::vector<float>		feedback;
5807		bool					error	= false;
5808
5809		GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange");
5810		if (!ptr)
5811			throw tcu::TestError("mapBufferRange returned null");
5812
5813		feedback.resize(5*4);
5814		deMemcpy(&feedback[0], ptr, sizeof(float[4]) * 5);
5815
5816		if (gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER) != GL_TRUE)
5817			throw tcu::TestError("unmapBuffer returned false");
5818
5819		// Verify vertices 0 - 2
5820		for (int vertex = 0; vertex < 3; ++vertex)
5821		{
5822			for (int component = 0; component < 4; ++component)
5823			{
5824				if (feedback[vertex*4 + component] != 1.0f)
5825				{
5826					m_testCtx.getLog()
5827						<< tcu::TestLog::Message
5828						<< "Feedback buffer vertex " << vertex << ", component " << component << ": unexpected value, expected 1.0, got " << feedback[vertex*4 + component]
5829						<< tcu::TestLog::EndMessage;
5830					error = true;
5831				}
5832			}
5833		}
5834
5835		// Verify vertices 3 - 4
5836		for (int vertex = 3; vertex < 5; ++vertex)
5837		{
5838			for (int component = 0; component < 4; ++component)
5839			{
5840				if (feedback[vertex*4 + component] != -1.0f)
5841				{
5842					m_testCtx.getLog()
5843						<< tcu::TestLog::Message
5844						<< "Feedback buffer vertex " << vertex << ", component " << component << ": unexpected value, expected -1.0, got " << feedback[vertex*4 + component]
5845						<< tcu::TestLog::EndMessage;
5846					error = true;
5847				}
5848			}
5849		}
5850
5851		if (error)
5852			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Feedback result validation failed");
5853		else
5854			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5855	}
5856
5857	return STOP;
5858}
5859
5860glu::ShaderProgram* VertexFeedbackOverflowCase::genProgram (void)
5861{
5862	static const char* const vertexSource =		"#version 310 es\n"
5863												"in highp vec4 a_position;\n"
5864												"void main (void)\n"
5865												"{\n"
5866												"	gl_Position = a_position;\n"
5867												"}\n";
5868	static const char* const fragmentSource =	"#version 310 es\n"
5869												"layout(location = 0) out mediump vec4 fragColor;\n"
5870												"void main (void)\n"
5871												"{\n"
5872												"	fragColor = vec4(1.0);\n"
5873												"}\n";
5874
5875	return new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5876																<< glu::VertexSource(vertexSource)
5877																<< glu::FragmentSource(fragmentSource)
5878																<< glu::TransformFeedbackVarying("gl_Position")
5879																<< glu::TransformFeedbackMode(GL_INTERLEAVED_ATTRIBS));
5880}
5881
5882} // anonymous
5883
5884GeometryShaderTests::GeometryShaderTests (Context& context)
5885	: TestCaseGroup(context, "geometry_shading", "Geometry shader tests")
5886{
5887}
5888
5889GeometryShaderTests::~GeometryShaderTests (void)
5890{
5891}
5892
5893void GeometryShaderTests::init (void)
5894{
5895	struct PrimitiveTestSpec
5896	{
5897		deUint32	primitiveType;
5898		const char* name;
5899		deUint32	outputType;
5900	};
5901
5902	struct EmitTestSpec
5903	{
5904		deUint32	outputType;
5905		int			emitCountA;		//!< primitive A emit count
5906		int			endCountA;		//!< primitive A end count
5907		int			emitCountB;		//!<
5908		int			endCountB;		//!<
5909		const char* name;
5910	};
5911
5912	static const struct LayeredTarget
5913	{
5914		LayeredRenderCase::LayeredRenderTargetType	target;
5915		const char*									name;
5916		const char*									desc;
5917	} layerTargets[] =
5918	{
5919		{ LayeredRenderCase::TARGET_CUBE,			"cubemap",				"cubemap"						},
5920		{ LayeredRenderCase::TARGET_3D,				"3d",					"3D texture"					},
5921		{ LayeredRenderCase::TARGET_2D_ARRAY,		"2d_array",				"2D array texture"				},
5922		{ LayeredRenderCase::TARGET_2D_MS_ARRAY,	"2d_multisample_array",	"2D multisample array texture"	},
5923	};
5924
5925	tcu::TestCaseGroup* const queryGroup				= new tcu::TestCaseGroup(m_testCtx, "query", "Query tests.");
5926	tcu::TestCaseGroup* const basicGroup				= new tcu::TestCaseGroup(m_testCtx, "basic", "Basic tests.");
5927	tcu::TestCaseGroup* const inputPrimitiveGroup		= new tcu::TestCaseGroup(m_testCtx, "input", "Different input primitives.");
5928	tcu::TestCaseGroup* const conversionPrimitiveGroup	= new tcu::TestCaseGroup(m_testCtx, "conversion", "Different input and output primitives.");
5929	tcu::TestCaseGroup* const emitGroup					= new tcu::TestCaseGroup(m_testCtx, "emit", "Different emit counts.");
5930	tcu::TestCaseGroup* const varyingGroup				= new tcu::TestCaseGroup(m_testCtx, "varying", "Test varyings.");
5931	tcu::TestCaseGroup* const layeredGroup				= new tcu::TestCaseGroup(m_testCtx, "layered", "Layered rendering.");
5932	tcu::TestCaseGroup* const instancedGroup			= new tcu::TestCaseGroup(m_testCtx, "instanced", "Instanced rendering.");
5933	tcu::TestCaseGroup* const negativeGroup				= new tcu::TestCaseGroup(m_testCtx, "negative", "Negative tests.");
5934	tcu::TestCaseGroup* const feedbackGroup				= new tcu::TestCaseGroup(m_testCtx, "vertex_transform_feedback", "Transform feedback.");
5935
5936	this->addChild(queryGroup);
5937	this->addChild(basicGroup);
5938	this->addChild(inputPrimitiveGroup);
5939	this->addChild(conversionPrimitiveGroup);
5940	this->addChild(emitGroup);
5941	this->addChild(varyingGroup);
5942	this->addChild(layeredGroup);
5943	this->addChild(instancedGroup);
5944	this->addChild(negativeGroup);
5945	this->addChild(feedbackGroup);
5946
5947	// query test
5948	{
5949		// limits with a corresponding glsl constant
5950		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_input_components",				"", GL_MAX_GEOMETRY_INPUT_COMPONENTS,				"MaxGeometryInputComponents",		64));
5951		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_output_components",				"", GL_MAX_GEOMETRY_OUTPUT_COMPONENTS,				"MaxGeometryOutputComponents",		128));
5952		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_image_uniforms",					"", GL_MAX_GEOMETRY_IMAGE_UNIFORMS,					"MaxGeometryImageUniforms",			0));
5953		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_texture_image_units",			"", GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS,			"MaxGeometryTextureImageUnits",		16));
5954		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_output_vertices",				"", GL_MAX_GEOMETRY_OUTPUT_VERTICES,				"MaxGeometryOutputVertices",		256));
5955		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_total_output_components",		"", GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS,		"MaxGeometryTotalOutputComponents",	1024));
5956		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_uniform_components",				"", GL_MAX_GEOMETRY_UNIFORM_COMPONENTS,				"MaxGeometryUniformComponents",		1024));
5957		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_atomic_counters",				"", GL_MAX_GEOMETRY_ATOMIC_COUNTERS,				"MaxGeometryAtomicCounters",		0));
5958		queryGroup->addChild(new GeometryProgramLimitCase(m_context, "max_geometry_atomic_counter_buffers",			"", GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,			"MaxGeometryAtomicCounterBuffers",	0));
5959
5960		// program queries
5961		queryGroup->addChild(new GeometryShaderVerticesQueryCase	(m_context, "geometry_linked_vertices_out",	"GL_GEOMETRY_LINKED_VERTICES_OUT"));
5962		queryGroup->addChild(new GeometryShaderInputQueryCase		(m_context, "geometry_linked_input_type",	"GL_GEOMETRY_LINKED_INPUT_TYPE"));
5963		queryGroup->addChild(new GeometryShaderOutputQueryCase		(m_context, "geometry_linked_output_type",	"GL_GEOMETRY_LINKED_OUTPUT_TYPE"));
5964		queryGroup->addChild(new GeometryShaderInvocationsQueryCase	(m_context, "geometry_shader_invocations",	"GL_GEOMETRY_SHADER_INVOCATIONS"));
5965
5966		// limits
5967		queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_shader_invocations",		"", GL_MAX_GEOMETRY_SHADER_INVOCATIONS,		32));
5968		queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_uniform_blocks",			"", GL_MAX_GEOMETRY_UNIFORM_BLOCKS,			12));
5969		queryGroup->addChild(new ImplementationLimitCase(m_context, "max_geometry_shader_storage_blocks",	"", GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS,	0));
5970
5971		// layer_provoking_vertex_ext
5972		queryGroup->addChild(new LayerProvokingVertexQueryCase(m_context, "layer_provoking_vertex", "GL_LAYER_PROVOKING_VERTEX"));
5973
5974		// primitives_generated
5975		queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_no_geometry",		"PRIMITIVES_GENERATED query with no geometry shader",								PrimitivesGeneratedQueryCase::TEST_NO_GEOMETRY));
5976		queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_no_amplification",	"PRIMITIVES_GENERATED query with non amplifying geometry shader",					PrimitivesGeneratedQueryCase::TEST_NO_AMPLIFICATION));
5977		queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_amplification",		"PRIMITIVES_GENERATED query with amplifying geometry shader",						PrimitivesGeneratedQueryCase::TEST_AMPLIFICATION));
5978		queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_partial_primitives", "PRIMITIVES_GENERATED query with geometry shader emitting partial primitives",		PrimitivesGeneratedQueryCase::TEST_PARTIAL_PRIMITIVES));
5979		queryGroup->addChild(new PrimitivesGeneratedQueryCase(m_context, "primitives_generated_instanced",			"PRIMITIVES_GENERATED query with instanced geometry shader",						PrimitivesGeneratedQueryCase::TEST_INSTANCED));
5980
5981		queryGroup->addChild(new PrimitivesGeneratedQueryObjectQueryCase(m_context, "primitives_generated", "Query bound PRIMITIVES_GENERATED query"));
5982
5983		// fbo
5984		queryGroup->addChild(new ImplementationLimitCase				(m_context, "max_framebuffer_layers",				"", GL_MAX_FRAMEBUFFER_LAYERS,	256));
5985		queryGroup->addChild(new FramebufferDefaultLayersCase			(m_context, "framebuffer_default_layers",			""));
5986		queryGroup->addChild(new FramebufferAttachmentLayeredCase		(m_context, "framebuffer_attachment_layered",		""));
5987		queryGroup->addChild(new FramebufferIncompleteLayereTargetsCase	(m_context, "framebuffer_incomplete_layer_targets",	""));
5988
5989		// resource query
5990		queryGroup->addChild(new ReferencedByGeometryShaderCase			(m_context, "referenced_by_geometry_shader",	""));
5991
5992		// combined limits
5993		queryGroup->addChild(new CombinedGeometryUniformLimitCase		(m_context, "max_combined_geometry_uniform_components", "MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS"));
5994	}
5995
5996	// basic tests
5997	{
5998		basicGroup->addChild(new OutputCountCase			(m_context,	"output_10",				"Output 10 vertices",								OutputCountPatternSpec(10)));
5999		basicGroup->addChild(new OutputCountCase			(m_context,	"output_128",				"Output 128 vertices",								OutputCountPatternSpec(128)));
6000		basicGroup->addChild(new OutputCountCase			(m_context,	"output_256",				"Output 256 vertices",								OutputCountPatternSpec(256)));
6001		basicGroup->addChild(new OutputCountCase			(m_context,	"output_max",				"Output max vertices",								OutputCountPatternSpec(-1)));
6002		basicGroup->addChild(new OutputCountCase			(m_context,	"output_10_and_100",		"Output 10 and 100 vertices in two invocations",	OutputCountPatternSpec(10, 100)));
6003		basicGroup->addChild(new OutputCountCase			(m_context,	"output_100_and_10",		"Output 100 and 10 vertices in two invocations",	OutputCountPatternSpec(100, 10)));
6004		basicGroup->addChild(new OutputCountCase			(m_context,	"output_0_and_128",			"Output 0 and 128 vertices in two invocations",		OutputCountPatternSpec(0, 128)));
6005		basicGroup->addChild(new OutputCountCase			(m_context,	"output_128_and_0",			"Output 128 and 0 vertices in two invocations",		OutputCountPatternSpec(128, 0)));
6006
6007		basicGroup->addChild(new VaryingOutputCountCase		(m_context,	"output_vary_by_attribute",	"Output varying number of vertices",				VaryingOutputCountShader::READ_ATTRIBUTE,	VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6008		basicGroup->addChild(new VaryingOutputCountCase		(m_context,	"output_vary_by_uniform",	"Output varying number of vertices",				VaryingOutputCountShader::READ_UNIFORM,		VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6009		basicGroup->addChild(new VaryingOutputCountCase		(m_context,	"output_vary_by_texture",	"Output varying number of vertices",				VaryingOutputCountShader::READ_TEXTURE,		VaryingOutputCountCase::MODE_WITHOUT_INSTANCING));
6010
6011		basicGroup->addChild(new BuiltinVariableRenderTest	(m_context,	"point_size",				"test gl_PointSize",								BuiltinVariableShader::TEST_POINT_SIZE));
6012		basicGroup->addChild(new BuiltinVariableRenderTest	(m_context,	"primitive_id_in",			"test gl_PrimitiveIDIn",							BuiltinVariableShader::TEST_PRIMITIVE_ID_IN));
6013		basicGroup->addChild(new BuiltinVariableRenderTest	(m_context,	"primitive_id_in_restarted","test gl_PrimitiveIDIn with primitive restart",		BuiltinVariableShader::TEST_PRIMITIVE_ID_IN, GeometryShaderRenderTest::FLAG_USE_RESTART_INDEX | GeometryShaderRenderTest::FLAG_USE_INDICES));
6014		basicGroup->addChild(new BuiltinVariableRenderTest	(m_context,	"primitive_id",				"test gl_PrimitiveID",								BuiltinVariableShader::TEST_PRIMITIVE_ID));
6015	}
6016
6017	// input primitives
6018	{
6019		static const PrimitiveTestSpec inputPrimitives[] =
6020		{
6021			{ GL_POINTS,					"points",					GL_POINTS			},
6022			{ GL_LINES,						"lines",					GL_LINE_STRIP		},
6023			{ GL_LINE_LOOP,					"line_loop",				GL_LINE_STRIP		},
6024			{ GL_LINE_STRIP,				"line_strip",				GL_LINE_STRIP		},
6025			{ GL_TRIANGLES,					"triangles",				GL_TRIANGLE_STRIP	},
6026			{ GL_TRIANGLE_STRIP,			"triangle_strip",			GL_TRIANGLE_STRIP	},
6027			{ GL_TRIANGLE_FAN,				"triangle_fan",				GL_TRIANGLE_STRIP	},
6028			{ GL_LINES_ADJACENCY,			"lines_adjacency",			GL_LINE_STRIP		},
6029			{ GL_LINE_STRIP_ADJACENCY,		"line_strip_adjacency",		GL_LINE_STRIP		},
6030			{ GL_TRIANGLES_ADJACENCY,		"triangles_adjacency",		GL_TRIANGLE_STRIP	}
6031		};
6032
6033		tcu::TestCaseGroup* const basicPrimitiveGroup		= new tcu::TestCaseGroup(m_testCtx, "basic_primitive",			"Different input and output primitives.");
6034		tcu::TestCaseGroup* const triStripAdjacencyGroup	= new tcu::TestCaseGroup(m_testCtx, "triangle_strip_adjacency",	"Different triangle_strip_adjacency vertex counts.");
6035
6036		// more basic types
6037		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(inputPrimitives); ++ndx)
6038			basicPrimitiveGroup->addChild(new GeometryExpanderRenderTest(m_context, inputPrimitives[ndx].name, inputPrimitives[ndx].name, inputPrimitives[ndx].primitiveType, inputPrimitives[ndx].outputType));
6039
6040		// triangle strip adjacency with different vtx counts
6041		for (int vtxCount = 0; vtxCount <= 12; ++vtxCount)
6042		{
6043			const std::string name = "vertex_count_" + de::toString(vtxCount);
6044			const std::string desc = "Vertex count is " + de::toString(vtxCount);
6045
6046			triStripAdjacencyGroup->addChild(new TriangleStripAdjacencyVertexCountTest(m_context, name.c_str(), desc.c_str(), vtxCount));
6047		}
6048
6049		inputPrimitiveGroup->addChild(basicPrimitiveGroup);
6050		inputPrimitiveGroup->addChild(triStripAdjacencyGroup);
6051	}
6052
6053	// different type conversions
6054	{
6055		static const PrimitiveTestSpec conversionPrimitives[] =
6056		{
6057			{ GL_TRIANGLES,		"triangles_to_points",	GL_POINTS			},
6058			{ GL_LINES,			"lines_to_points",		GL_POINTS			},
6059			{ GL_POINTS,		"points_to_lines",		GL_LINE_STRIP		},
6060			{ GL_TRIANGLES,		"triangles_to_lines",	GL_LINE_STRIP		},
6061			{ GL_POINTS,		"points_to_triangles",	GL_TRIANGLE_STRIP	},
6062			{ GL_LINES,			"lines_to_triangles",	GL_TRIANGLE_STRIP	}
6063		};
6064
6065		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(conversionPrimitives); ++ndx)
6066			conversionPrimitiveGroup->addChild(new GeometryExpanderRenderTest(m_context, conversionPrimitives[ndx].name, conversionPrimitives[ndx].name, conversionPrimitives[ndx].primitiveType, conversionPrimitives[ndx].outputType));
6067	}
6068
6069	// emit different amounts
6070	{
6071		static const EmitTestSpec emitTests[] =
6072		{
6073			{ GL_POINTS,			 0,		0,	0,	0,	"points"			},
6074			{ GL_POINTS,			 0,		1,	0,	0,	"points"			},
6075			{ GL_POINTS,			 1,		1,	0,	0,	"points"			},
6076			{ GL_POINTS,			 0,		2,	0,	0,	"points"			},
6077			{ GL_POINTS,			 1,		2,	0,	0,	"points"			},
6078			{ GL_LINE_STRIP,		 0,		0,	0,	0,	"line_strip"		},
6079			{ GL_LINE_STRIP,		 0,		1,	0,	0,	"line_strip"		},
6080			{ GL_LINE_STRIP,		 1,		1,	0,	0,	"line_strip"		},
6081			{ GL_LINE_STRIP,		 2,		1,	0,	0,	"line_strip"		},
6082			{ GL_LINE_STRIP,		 0,		2,	0,	0,	"line_strip"		},
6083			{ GL_LINE_STRIP,		 1,		2,	0,	0,	"line_strip"		},
6084			{ GL_LINE_STRIP,		 2,		2,	0,	0,	"line_strip"		},
6085			{ GL_LINE_STRIP,		 2,		2,	2,	0,	"line_strip"		},
6086			{ GL_TRIANGLE_STRIP,	 0,		0,	0,	0,	"triangle_strip"	},
6087			{ GL_TRIANGLE_STRIP,	 0,		1,	0,	0,	"triangle_strip"	},
6088			{ GL_TRIANGLE_STRIP,	 1,		1,	0,	0,	"triangle_strip"	},
6089			{ GL_TRIANGLE_STRIP,	 2,		1,	0,	0,	"triangle_strip"	},
6090			{ GL_TRIANGLE_STRIP,	 3,		1,	0,	0,	"triangle_strip"	},
6091			{ GL_TRIANGLE_STRIP,	 0,		2,	0,	0,	"triangle_strip"	},
6092			{ GL_TRIANGLE_STRIP,	 1,		2,	0,	0,	"triangle_strip"	},
6093			{ GL_TRIANGLE_STRIP,	 2,		2,	0,	0,	"triangle_strip"	},
6094			{ GL_TRIANGLE_STRIP,	 3,		2,	0,	0,	"triangle_strip"	},
6095			{ GL_TRIANGLE_STRIP,	 3,		2,	3,	0,	"triangle_strip"	},
6096		};
6097
6098		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(emitTests); ++ndx)
6099		{
6100			std::string name = std::string(emitTests[ndx].name) + "_emit_" + de::toString(emitTests[ndx].emitCountA) + "_end_" + de::toString(emitTests[ndx].endCountA);
6101			std::string desc = std::string(emitTests[ndx].name) + " output, emit " + de::toString(emitTests[ndx].emitCountA) + " vertices, call EndPrimitive " + de::toString(emitTests[ndx].endCountA) + " times";
6102
6103			if (emitTests[ndx].emitCountB)
6104			{
6105				name += "_emit_" + de::toString(emitTests[ndx].emitCountB) + "_end_" + de::toString(emitTests[ndx].endCountB);
6106				desc += ", emit " + de::toString(emitTests[ndx].emitCountB) + " vertices, call EndPrimitive " + de::toString(emitTests[ndx].endCountB) + " times";
6107			}
6108
6109			emitGroup->addChild(new EmitTest(m_context, name.c_str(), desc.c_str(), emitTests[ndx].emitCountA, emitTests[ndx].endCountA, emitTests[ndx].emitCountB, emitTests[ndx].endCountB, emitTests[ndx].outputType));
6110		}
6111	}
6112
6113	// varying
6114	{
6115		struct VaryingTestSpec
6116		{
6117			int			vertexOutputs;
6118			int			geometryOutputs;
6119			const char*	name;
6120			const char*	desc;
6121		};
6122
6123		static const VaryingTestSpec varyingTests[] =
6124		{
6125			{ -1, 1, "vertex_no_op_geometry_out_1", "vertex_no_op_geometry_out_1" },
6126			{  0, 1, "vertex_out_0_geometry_out_1", "vertex_out_0_geometry_out_1" },
6127			{  0, 2, "vertex_out_0_geometry_out_2", "vertex_out_0_geometry_out_2" },
6128			{  1, 0, "vertex_out_1_geometry_out_0", "vertex_out_1_geometry_out_0" },
6129			{  1, 2, "vertex_out_1_geometry_out_2", "vertex_out_1_geometry_out_2" },
6130		};
6131
6132		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(varyingTests); ++ndx)
6133			varyingGroup->addChild(new VaryingTest(m_context, varyingTests[ndx].name, varyingTests[ndx].desc, varyingTests[ndx].vertexOutputs, varyingTests[ndx].geometryOutputs));
6134	}
6135
6136	// layered
6137	{
6138		static const struct TestType
6139		{
6140			LayeredRenderCase::TestType	test;
6141			const char*					testPrefix;
6142			const char*					descPrefix;
6143		} tests[] =
6144		{
6145			{ LayeredRenderCase::TEST_DEFAULT_LAYER,			"render_with_default_layer_",	"Render to all layers of "					},
6146			{ LayeredRenderCase::TEST_SINGLE_LAYER,				"render_to_one_",				"Render to one layer of "					},
6147			{ LayeredRenderCase::TEST_ALL_LAYERS,				"render_to_all_",				"Render to all layers of "					},
6148			{ LayeredRenderCase::TEST_DIFFERENT_LAYERS,			"render_different_to_",			"Render different data to different layers"	},
6149			{ LayeredRenderCase::TEST_LAYER_ID,					"fragment_layer_",				"Read gl_Layer in fragment shader"			},
6150			{ LayeredRenderCase::TEST_LAYER_PROVOKING_VERTEX,	"layer_provoking_vertex_",		"Verify LAYER_PROVOKING_VERTEX"				},
6151		};
6152
6153		for (int testNdx = 0; testNdx < DE_LENGTH_OF_ARRAY(tests); ++testNdx)
6154		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6155		{
6156			const std::string name = std::string(tests[testNdx].testPrefix) + layerTargets[targetNdx].name;
6157			const std::string desc = std::string(tests[testNdx].descPrefix) + layerTargets[targetNdx].desc;
6158
6159			layeredGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(), layerTargets[targetNdx].target, tests[testNdx].test));
6160		}
6161	}
6162
6163	// instanced
6164	{
6165		static const struct InvocationCase
6166		{
6167			const char* name;
6168			int			numInvocations;
6169		} invocationCases[] =
6170		{
6171			{ "1",		1  },
6172			{ "2",		2  },
6173			{ "8",		8  },
6174			{ "32",		32 },
6175			{ "max",	-1 },
6176		};
6177		static const int numDrawInstances[] = { 2, 4, 8 };
6178		static const int numDrawInvocations[] = { 2, 8 };
6179
6180		// same amount of content to all invocations
6181		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(invocationCases); ++ndx)
6182			instancedGroup->addChild(new GeometryInvocationCase(m_context,
6183																(std::string("geometry_") + invocationCases[ndx].name + "_invocations").c_str(),
6184																(std::string("Geometry shader with ") + invocationCases[ndx].name + " invocation(s)").c_str(),
6185																invocationCases[ndx].numInvocations,
6186																GeometryInvocationCase::CASE_FIXED_OUTPUT_COUNTS));
6187
6188		// different amount of content to each invocation
6189		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(invocationCases); ++ndx)
6190			if (invocationCases[ndx].numInvocations != 1)
6191				instancedGroup->addChild(new GeometryInvocationCase(m_context,
6192																	(std::string("geometry_output_different_") + invocationCases[ndx].name + "_invocations").c_str(),
6193																	"Geometry shader invocation(s) with different emit counts",
6194																	invocationCases[ndx].numInvocations,
6195																	GeometryInvocationCase::CASE_DIFFERENT_OUTPUT_COUNTS));
6196
6197		// invocation per layer
6198		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6199		{
6200			const std::string name = std::string("invocation_per_layer_") + layerTargets[targetNdx].name;
6201			const std::string desc = std::string("Render to multiple layers with multiple invocations, one invocation per layer, target ") + layerTargets[targetNdx].desc;
6202
6203			instancedGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(), layerTargets[targetNdx].target, LayeredRenderCase::TEST_INVOCATION_PER_LAYER));
6204		}
6205
6206		// multiple layers per invocation
6207		for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(layerTargets); ++targetNdx)
6208		{
6209			const std::string name = std::string("multiple_layers_per_invocation_") + layerTargets[targetNdx].name;
6210			const std::string desc = std::string("Render to multiple layers with multiple invocations, multiple layers per invocation, target ") + layerTargets[targetNdx].desc;
6211
6212			instancedGroup->addChild(new LayeredRenderCase(m_context, name.c_str(), desc.c_str(), layerTargets[targetNdx].target, LayeredRenderCase::TEST_MULTIPLE_LAYERS_PER_INVOCATION));
6213		}
6214
6215		// different invocation output counts depending on {uniform, attrib, texture}
6216		instancedGroup->addChild(new VaryingOutputCountCase(m_context,	"invocation_output_vary_by_attribute",	"Output varying number of vertices", VaryingOutputCountShader::READ_ATTRIBUTE,	VaryingOutputCountCase::MODE_WITH_INSTANCING));
6217		instancedGroup->addChild(new VaryingOutputCountCase(m_context,	"invocation_output_vary_by_uniform",	"Output varying number of vertices", VaryingOutputCountShader::READ_UNIFORM,	VaryingOutputCountCase::MODE_WITH_INSTANCING));
6218		instancedGroup->addChild(new VaryingOutputCountCase(m_context,	"invocation_output_vary_by_texture",	"Output varying number of vertices", VaryingOutputCountShader::READ_TEXTURE,	VaryingOutputCountCase::MODE_WITH_INSTANCING));
6219
6220		// with drawInstanced
6221		for (int instanceNdx = 0; instanceNdx < DE_LENGTH_OF_ARRAY(numDrawInstances); ++instanceNdx)
6222		for (int invocationNdx = 0; invocationNdx < DE_LENGTH_OF_ARRAY(numDrawInvocations); ++invocationNdx)
6223		{
6224			const std::string name = std::string("draw_") + de::toString(numDrawInstances[instanceNdx]) + "_instances_geometry_" + de::toString(numDrawInvocations[invocationNdx]) + "_invocations";
6225			const std::string desc = std::string("Draw ") + de::toString(numDrawInstances[instanceNdx]) + " instances, with " + de::toString(numDrawInvocations[invocationNdx]) + " geometry shader invocations.";
6226
6227			instancedGroup->addChild(new DrawInstancedGeometryInstancedCase(m_context, name.c_str(), desc.c_str(), numDrawInstances[instanceNdx], numDrawInvocations[invocationNdx]));
6228		}
6229	}
6230
6231	// negative (wrong types)
6232	{
6233		struct PrimitiveToInputTypeConversion
6234		{
6235			GLenum inputType;
6236			GLenum primitiveType;
6237		};
6238
6239		static const PrimitiveToInputTypeConversion legalConversions[] =
6240		{
6241			{ GL_POINTS,				GL_POINTS					},
6242			{ GL_LINES,					GL_LINES					},
6243			{ GL_LINES,					GL_LINE_LOOP				},
6244			{ GL_LINES,					GL_LINE_STRIP				},
6245			{ GL_LINES_ADJACENCY,		GL_LINES_ADJACENCY			},
6246			{ GL_LINES_ADJACENCY,		GL_LINE_STRIP_ADJACENCY		},
6247			{ GL_TRIANGLES,				GL_TRIANGLES				},
6248			{ GL_TRIANGLES,				GL_TRIANGLE_STRIP			},
6249			{ GL_TRIANGLES,				GL_TRIANGLE_FAN				},
6250			{ GL_TRIANGLES_ADJACENCY,	GL_TRIANGLES_ADJACENCY		},
6251			{ GL_TRIANGLES_ADJACENCY,	GL_TRIANGLE_STRIP_ADJACENCY	},
6252		};
6253
6254		static const GLenum inputTypes[] =
6255		{
6256			GL_POINTS,
6257			GL_LINES,
6258			GL_LINES_ADJACENCY,
6259			GL_TRIANGLES,
6260			GL_TRIANGLES_ADJACENCY
6261		};
6262
6263		static const GLenum primitiveTypes[] =
6264		{
6265			GL_POINTS,
6266			GL_LINES,
6267			GL_LINE_LOOP,
6268			GL_LINE_STRIP,
6269			GL_LINES_ADJACENCY,
6270			GL_LINE_STRIP_ADJACENCY,
6271			GL_TRIANGLES,
6272			GL_TRIANGLE_STRIP,
6273			GL_TRIANGLE_FAN,
6274			GL_TRIANGLES_ADJACENCY,
6275			GL_TRIANGLE_STRIP_ADJACENCY
6276		};
6277
6278		for (int inputTypeNdx = 0; inputTypeNdx < DE_LENGTH_OF_ARRAY(inputTypes); ++inputTypeNdx)
6279		for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
6280		{
6281			const GLenum		inputType		= inputTypes[inputTypeNdx];
6282			const GLenum		primitiveType	= primitiveTypes[primitiveTypeNdx];
6283			const std::string	name			= std::string("type_") + inputTypeToGLString(sglr::rr_util::mapGLGeometryShaderInputType(inputType)) + "_primitive_" + primitiveTypeToString(primitiveType);
6284			const std::string	desc			= std::string("Shader input type ") + inputTypeToGLString(sglr::rr_util::mapGLGeometryShaderInputType(inputType)) + ", draw primitive type " + primitiveTypeToString(primitiveType);
6285
6286			bool isLegal = false;
6287
6288			for (int legalNdx = 0; legalNdx < DE_LENGTH_OF_ARRAY(legalConversions); ++legalNdx)
6289				if (legalConversions[legalNdx].inputType == inputType && legalConversions[legalNdx].primitiveType == primitiveType)
6290					isLegal = true;
6291
6292			// only illegal
6293			if (!isLegal)
6294				negativeGroup->addChild(new NegativeDrawCase(m_context, name.c_str(), desc.c_str(), inputType, primitiveType));
6295		}
6296	}
6297
6298	// vertex transform feedback
6299	{
6300		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_line_loop",				"Capture line loop lines",									VertexFeedbackCase::METHOD_DRAW_ARRAYS,				VertexFeedbackCase::PRIMITIVE_LINE_LOOP));
6301		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_line_strip",				"Capture line strip lines",									VertexFeedbackCase::METHOD_DRAW_ARRAYS,				VertexFeedbackCase::PRIMITIVE_LINE_STRIP));
6302		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_triangle_strip",			"Capture triangle strip triangles",							VertexFeedbackCase::METHOD_DRAW_ARRAYS,				VertexFeedbackCase::PRIMITIVE_TRIANGLE_STRIP));
6303		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_triangle_fan",			"Capture triangle fan triangles",							VertexFeedbackCase::METHOD_DRAW_ARRAYS,				VertexFeedbackCase::PRIMITIVE_TRIANGLE_FAN));
6304		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_arrays",				"Capture primitives generated with drawArrays",				VertexFeedbackCase::METHOD_DRAW_ARRAYS,				VertexFeedbackCase::PRIMITIVE_POINTS));
6305		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_arrays_instanced",	"Capture primitives generated with drawArraysInstanced",	VertexFeedbackCase::METHOD_DRAW_ARRAYS_INSTANCED,	VertexFeedbackCase::PRIMITIVE_POINTS));
6306		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_arrays_indirect",	"Capture primitives generated with drawArraysIndirect",		VertexFeedbackCase::METHOD_DRAW_ARRAYS_INDIRECT,	VertexFeedbackCase::PRIMITIVE_POINTS));
6307		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements",			"Capture primitives generated with drawElements",			VertexFeedbackCase::METHOD_DRAW_ELEMENTS,			VertexFeedbackCase::PRIMITIVE_POINTS));
6308		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements_instanced",	"Capture primitives generated with drawElementsInstanced",	VertexFeedbackCase::METHOD_DRAW_ELEMENTS_INSTANCED,	VertexFeedbackCase::PRIMITIVE_POINTS));
6309		feedbackGroup->addChild(new VertexFeedbackCase(m_context, "capture_vertex_draw_elements_indirect",	"Capture primitives generated with drawElementsIndirect",	VertexFeedbackCase::METHOD_DRAW_ELEMENTS_INDIRECT,	VertexFeedbackCase::PRIMITIVE_POINTS));
6310
6311		feedbackGroup->addChild(new VertexFeedbackOverflowCase(m_context, "capture_vertex_draw_arrays_overflow_single_buffer",		"Capture triangles to too small a buffer", VertexFeedbackOverflowCase::METHOD_DRAW_ARRAYS));
6312		feedbackGroup->addChild(new VertexFeedbackOverflowCase(m_context, "capture_vertex_draw_elements_overflow_single_buffer",	"Capture triangles to too small a buffer", VertexFeedbackOverflowCase::METHOD_DRAW_ELEMENTS));
6313	}
6314}
6315
6316} // Functional
6317} // gles31
6318} // deqp
6319