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