es31sTessellationGeometryInteractionTests.cpp revision 3c827367444ee418f129b2c238299f49d3264554
1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Tessellation and geometry shader interaction stress tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es31sTessellationGeometryInteractionTests.hpp"
25
26#include "tcuTestLog.hpp"
27#include "tcuRenderTarget.hpp"
28#include "tcuSurface.hpp"
29#include "tcuTextureUtil.hpp"
30#include "gluRenderContext.hpp"
31#include "gluShaderProgram.hpp"
32#include "gluContextInfo.hpp"
33#include "gluObjectWrapper.hpp"
34#include "gluPixelTransfer.hpp"
35#include "glwFunctions.hpp"
36#include "glwEnums.hpp"
37#include "deStringUtil.hpp"
38#include "deUniquePtr.hpp"
39
40#include <sstream>
41
42namespace deqp
43{
44namespace gles31
45{
46namespace Stress
47{
48namespace
49{
50
51class AllowedRenderFailureException : public std::runtime_error
52{
53public:
54	AllowedRenderFailureException (const char* message) : std::runtime_error(message) { }
55};
56
57class GridRenderCase : public TestCase
58{
59public:
60	enum Flags
61	{
62		FLAG_TESSELLATION_MAX_SPEC						= 0x0001,
63		FLAG_TESSELLATION_MAX_IMPLEMENTATION			= 0x0002,
64		FLAG_GEOMETRY_MAX_SPEC							= 0x0004,
65		FLAG_GEOMETRY_MAX_IMPLEMENTATION				= 0x0008,
66		FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC				= 0x0010,
67		FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION	= 0x0020,
68	};
69
70						GridRenderCase					(Context& context, const char* name, const char* description, int flags);
71						~GridRenderCase					(void);
72
73private:
74	void				init							(void);
75	void				deinit							(void);
76	IterateResult		iterate							(void);
77
78	void				renderTo						(std::vector<tcu::Surface>& dst);
79	bool				verifyResultLayer				(int layerNdx, const tcu::Surface& dst);
80
81	const char*			getVertexSource					(void);
82	const char*			getFragmentSource				(void);
83	std::string			getTessellationControlSource	(int tessLevel);
84	std::string			getTessellationEvaluationSource	(int tessLevel);
85	std::string			getGeometryShaderSource			(int numPrimitives, int numInstances);
86
87	enum
88	{
89		RENDER_SIZE = 256
90	};
91
92	const int			m_flags;
93
94	glu::ShaderProgram*	m_program;
95	int					m_numLayers;
96};
97
98GridRenderCase::GridRenderCase (Context& context, const char* name, const char* description, int flags)
99	: TestCase		(context, name, description)
100	, m_flags		(flags)
101	, m_program		(DE_NULL)
102	, m_numLayers	(1)
103{
104	DE_ASSERT(((m_flags & FLAG_TESSELLATION_MAX_SPEC) == 0)			|| ((m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION) == 0));
105	DE_ASSERT(((m_flags & FLAG_GEOMETRY_MAX_SPEC) == 0)				|| ((m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION) == 0));
106	DE_ASSERT(((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC) == 0)	|| ((m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION) == 0));
107}
108
109GridRenderCase::~GridRenderCase (void)
110{
111	deinit();
112}
113
114void GridRenderCase::init (void)
115{
116	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
117
118	// Requirements
119
120	if (!m_context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader") ||
121		!m_context.getContextInfo().isExtensionSupported("GL_EXT_geometry_shader"))
122		throw tcu::NotSupportedError("Test requires GL_EXT_tessellation_shader and GL_EXT_geometry_shader extensions");
123
124	if (m_context.getRenderTarget().getWidth() < RENDER_SIZE ||
125		m_context.getRenderTarget().getHeight() < RENDER_SIZE)
126		throw tcu::NotSupportedError("Test requires " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE) + " or larger render target.");
127
128	// Log
129
130	m_testCtx.getLog()
131		<< tcu::TestLog::Message
132		<< "Testing tessellation and geometry shaders that output a large number of primitives.\n"
133		<< getDescription()
134		<< tcu::TestLog::EndMessage;
135
136	// Gen program
137	{
138		glu::ProgramSources	sources;
139		int					tessGenLevel = -1;
140
141		sources	<< glu::VertexSource(getVertexSource())
142				<< glu::FragmentSource(getFragmentSource());
143
144		// Tessellation limits
145		{
146			if (m_flags & FLAG_TESSELLATION_MAX_IMPLEMENTATION)
147			{
148				gl.getIntegerv(GL_MAX_TESS_GEN_LEVEL, &tessGenLevel);
149				GLU_EXPECT_NO_ERROR(gl.getError(), "query tessellation limits");
150			}
151			else if (m_flags & FLAG_TESSELLATION_MAX_SPEC)
152			{
153				tessGenLevel = 64;
154			}
155			else
156			{
157				tessGenLevel = 5;
158			}
159
160			m_testCtx.getLog()
161					<< tcu::TestLog::Message
162					<< "Tessellation level: " << tessGenLevel << ", mode = quad.\n"
163					<< "\tEach input patch produces " << (tessGenLevel*tessGenLevel) << " (" << (tessGenLevel*tessGenLevel*2) << " triangles)\n"
164					<< tcu::TestLog::EndMessage;
165
166			sources << glu::TessellationControlSource(getTessellationControlSource(tessGenLevel))
167					<< glu::TessellationEvaluationSource(getTessellationEvaluationSource(tessGenLevel));
168		}
169
170		// Geometry limits
171		{
172			int		geometryOutputComponents		= -1;
173			int		geometryOutputVertices			= -1;
174			int		geometryTotalOutputComponents	= -1;
175			int		geometryShaderInvocations		= -1;
176			bool	logGeometryLimits				= false;
177			bool	logInvocationLimits				= false;
178
179			if (m_flags & FLAG_GEOMETRY_MAX_IMPLEMENTATION)
180			{
181				m_testCtx.getLog() << tcu::TestLog::Message << "Using implementation maximum geometry shader output limits." << tcu::TestLog::EndMessage;
182
183				gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &geometryOutputComponents);
184				gl.getIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &geometryOutputVertices);
185				gl.getIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &geometryTotalOutputComponents);
186				GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry limits");
187
188				logGeometryLimits = true;
189			}
190			else if (m_flags & FLAG_GEOMETRY_MAX_SPEC)
191			{
192				m_testCtx.getLog() << tcu::TestLog::Message << "Using geometry shader extension minimum maximum output limits." << tcu::TestLog::EndMessage;
193
194				geometryOutputComponents = 128;
195				geometryOutputVertices = 256;
196				geometryTotalOutputComponents = 1024;
197				logGeometryLimits = true;
198			}
199			else
200			{
201				geometryOutputComponents = 128;
202				geometryOutputVertices = 16;
203				geometryTotalOutputComponents = 1024;
204			}
205
206			if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION)
207			{
208				gl.getIntegerv(GL_MAX_GEOMETRY_SHADER_INVOCATIONS, &geometryShaderInvocations);
209				GLU_EXPECT_NO_ERROR(gl.getError(), "query geometry invocation limits");
210
211				logInvocationLimits = true;
212			}
213			else if (m_flags & FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC)
214			{
215				geometryShaderInvocations = 32;
216				logInvocationLimits = true;
217			}
218			else
219			{
220				geometryShaderInvocations = 4;
221			}
222
223			if (logGeometryLimits || logInvocationLimits)
224			{
225				tcu::MessageBuilder msg(&m_testCtx.getLog());
226
227				msg << "Geometry shader, targeting following limits:\n";
228
229				if (logGeometryLimits)
230					msg	<< "\tGL_MAX_GEOMETRY_OUTPUT_COMPONENTS = " << geometryOutputComponents << "\n"
231						<< "\tGL_MAX_GEOMETRY_OUTPUT_VERTICES = " << geometryOutputVertices << "\n"
232						<< "\tGL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = " << geometryTotalOutputComponents << "\n";
233
234				if (logInvocationLimits)
235					msg << "\tGL_MAX_GEOMETRY_SHADER_INVOCATIONS = " << geometryShaderInvocations;
236
237				msg << tcu::TestLog::EndMessage;
238			}
239
240
241			{
242				const int	numComponentsPerVertex		= 8; // vec4 pos, vec4 color
243
244				// If FLAG_GEOMETRY_SEPARATE_PRIMITIVES is not set, geometry shader fills a rectangle area in slices.
245				// Each slice is a triangle strip and is generated by a single shader invocation.
246				// One slice with 4 segment ends (nodes) and 3 segments:
247				//    .__.__.__.
248				//    |\ |\ |\ |
249				//    |_\|_\|_\|
250
251				const int	numSliceNodesComponentLimit			= geometryTotalOutputComponents / (2 * numComponentsPerVertex);			// each node 2 vertices
252				const int	numSliceNodesOutputLimit			= geometryOutputVertices / 2;											// each node 2 vertices
253				const int	numSliceNodes						= de::min(numSliceNodesComponentLimit, numSliceNodesOutputLimit);
254
255				const int	numVerticesPerInvocation			= numSliceNodes * 2;
256				const int	numPrimitivesPerInvocation			= (numSliceNodes - 1) * 2;
257
258				const int	geometryVerticesPerPrimitive		= numVerticesPerInvocation * geometryShaderInvocations;
259				const int	geometryPrimitivesOutPerPrimitive	= numPrimitivesPerInvocation * geometryShaderInvocations;
260
261				m_testCtx.getLog()
262					<< tcu::TestLog::Message
263					<< "Geometry shader:\n"
264					<< "\tTotal output vertex count per invocation: " << (numVerticesPerInvocation) << "\n"
265					<< "\tTotal output primitive count per invocation: " << (numPrimitivesPerInvocation) << "\n"
266					<< "\tNumber of invocations per primitive: " << geometryShaderInvocations << "\n"
267					<< "\tTotal output vertex count per input primitive: " << (geometryVerticesPerPrimitive) << "\n"
268					<< "\tTotal output primitive count per input primitive: " << (geometryPrimitivesOutPerPrimitive) << "\n"
269					<< tcu::TestLog::EndMessage;
270
271				sources	<< glu::GeometrySource(getGeometryShaderSource(numPrimitivesPerInvocation, geometryShaderInvocations));
272
273				m_testCtx.getLog()
274					<< tcu::TestLog::Message
275					<< "Program:\n"
276					<< "\tTotal program output vertices count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryVerticesPerPrimitive) << "\n"
277					<< "\tTotal program output primitive count per input patch: " << (tessGenLevel*tessGenLevel*2 * geometryPrimitivesOutPerPrimitive) << "\n"
278					<< tcu::TestLog::EndMessage;
279			}
280		}
281
282		m_program = new glu::ShaderProgram(m_context.getRenderContext(), sources);
283		m_testCtx.getLog() << *m_program;
284		if (!m_program->isOk())
285			throw tcu::TestError("failed to build program");
286	}
287}
288
289void GridRenderCase::deinit (void)
290{
291	delete m_program;
292	m_program = DE_NULL;
293}
294
295GridRenderCase::IterateResult GridRenderCase::iterate (void)
296{
297	std::vector<tcu::Surface>	renderedLayers	(m_numLayers);
298	bool						allLayersOk		= true;
299
300	for (int ndx = 0; ndx < m_numLayers; ++ndx)
301		renderedLayers[ndx].setSize(RENDER_SIZE, RENDER_SIZE);
302
303	m_testCtx.getLog() << tcu::TestLog::Message << "Rendering single point at the origin. Expecting yellow and green colored grid-like image. (High-frequency grid may appear unicolored)." << tcu::TestLog::EndMessage;
304
305	try
306	{
307		renderTo(renderedLayers);
308	}
309	catch (const AllowedRenderFailureException& ex)
310	{
311		// Got accepted failure
312		m_testCtx.getLog()
313			<< tcu::TestLog::Message
314			<< "Could not render, reason: " << ex.what() << "\n"
315			<< "Failure is allowed."
316			<< tcu::TestLog::EndMessage;
317
318		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
319		return STOP;
320	}
321
322	for (int ndx = 0; ndx < m_numLayers; ++ndx)
323		allLayersOk &= verifyResultLayer(ndx, renderedLayers[ndx]);
324
325	if (allLayersOk)
326		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
327	else
328		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
329	return STOP;
330}
331
332void GridRenderCase::renderTo (std::vector<tcu::Surface>& dst)
333{
334	const glw::Functions&			gl					= m_context.getRenderContext().getFunctions();
335	const int						positionLocation	= gl.getAttribLocation(m_program->getProgram(), "a_position");
336	const glu::VertexArray			vao					(m_context.getRenderContext());
337
338	if (positionLocation == -1)
339		throw tcu::TestError("Attribute a_position location was -1");
340
341	gl.viewport(0, 0, dst.front().getWidth(), dst.front().getHeight());
342	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
343	GLU_EXPECT_NO_ERROR(gl.getError(), "viewport");
344
345	gl.bindVertexArray(*vao);
346	GLU_EXPECT_NO_ERROR(gl.getError(), "bind vao");
347
348	gl.useProgram(m_program->getProgram());
349	GLU_EXPECT_NO_ERROR(gl.getError(), "use program");
350
351	gl.patchParameteri(GL_PATCH_VERTICES, 1);
352	GLU_EXPECT_NO_ERROR(gl.getError(), "set patch param");
353
354	gl.vertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
355
356	// clear viewport
357	gl.clear(GL_COLOR_BUFFER_BIT);
358
359	// draw
360	{
361		glw::GLenum glerror;
362
363		gl.drawArrays(GL_PATCHES, 0, 1);
364
365		// allow always OOM
366		glerror = gl.getError();
367		if (glerror == GL_OUT_OF_MEMORY)
368			throw AllowedRenderFailureException("got GL_OUT_OF_MEMORY while drawing");
369
370		GLU_EXPECT_NO_ERROR(glerror, "draw patches");
371	}
372
373	// Read layers
374
375	glu::readPixels(m_context.getRenderContext(), 0, 0, dst.front().getAccess());
376	GLU_EXPECT_NO_ERROR(gl.getError(), "read pixels");
377}
378
379bool GridRenderCase::verifyResultLayer (int layerNdx, const tcu::Surface& image)
380{
381	tcu::Surface	errorMask	(image.getWidth(), image.getHeight());
382	bool			foundError	= false;
383
384	tcu::clear(errorMask.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
385
386	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output layer " << layerNdx  << tcu::TestLog::EndMessage;
387
388	for (int y = 0; y < image.getHeight(); ++y)
389	for (int x = 0; x < image.getWidth(); ++x)
390	{
391		const int		threshold	= 8;
392		const tcu::RGBA	color		= image.getPixel(x, y);
393
394		// Color must be a linear combination of green and yellow
395		if (color.getGreen() < 255 - threshold || color.getBlue() > threshold)
396		{
397			errorMask.setPixel(x, y, tcu::RGBA::red);
398			foundError = true;
399		}
400	}
401
402	if (!foundError)
403	{
404		m_testCtx.getLog()
405			<< tcu::TestLog::Message << "Image valid." << tcu::TestLog::EndMessage
406			<< tcu::TestLog::ImageSet("ImageVerification", "Image verification")
407			<< tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
408			<< tcu::TestLog::EndImageSet;
409		return true;
410	}
411	else
412	{
413		m_testCtx.getLog()
414			<< tcu::TestLog::Message << "Image verification failed, found invalid pixels." << tcu::TestLog::EndMessage
415			<< tcu::TestLog::ImageSet("ImageVerification", "Image verification")
416			<< tcu::TestLog::Image("Result", "Rendered result", image.getAccess())
417			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask.getAccess())
418			<< tcu::TestLog::EndImageSet;
419		return false;
420	}
421}
422
423const char* GridRenderCase::getVertexSource (void)
424{
425	return	"#version 310 es\n"
426			"in highp vec4 a_position;\n"
427			"void main (void)\n"
428			"{\n"
429			"	gl_Position = a_position;\n"
430			"}\n";
431}
432
433const char* GridRenderCase::getFragmentSource (void)
434{
435	return	"#version 310 es\n"
436			"flat in mediump vec4 v_color;\n"
437			"layout(location = 0) out mediump vec4 fragColor;\n"
438			"void main (void)\n"
439			"{\n"
440			"	fragColor = v_color;\n"
441			"}\n";
442}
443
444std::string GridRenderCase::getTessellationControlSource (int tessLevel)
445{
446	std::ostringstream buf;
447
448	buf <<	"#version 310 es\n"
449			"#extension GL_EXT_tessellation_shader : require\n"
450			"layout(vertices=1) out;\n"
451			"\n"
452			"void main()\n"
453			"{\n"
454			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
455			"	gl_TessLevelOuter[0] = " << tessLevel << ".0;\n"
456			"	gl_TessLevelOuter[1] = " << tessLevel << ".0;\n"
457			"	gl_TessLevelOuter[2] = " << tessLevel << ".0;\n"
458			"	gl_TessLevelOuter[3] = " << tessLevel << ".0;\n"
459			"	gl_TessLevelInner[0] = " << tessLevel << ".0;\n"
460			"	gl_TessLevelInner[1] = " << tessLevel << ".0;\n"
461			"}\n";
462
463	return buf.str();
464}
465
466std::string GridRenderCase::getTessellationEvaluationSource (int tessLevel)
467{
468	std::ostringstream buf;
469
470	buf <<	"#version 310 es\n"
471			"#extension GL_EXT_tessellation_shader : require\n"
472			"layout(quads) in;\n"
473			"\n"
474			"out mediump ivec2 v_tessellationGridPosition;\n"
475			"\n"
476			"void main (void)\n"
477			"{\n"
478			"	// Fill the whole viewport\n"
479			"	gl_Position = vec4(gl_TessCoord.x * 2.0 - 1.0, gl_TessCoord.y * 2.0 - 1.0, 0.0, 1.0);\n"
480			"	// Calculate position in tessellation grid\n"
481			"	v_tessellationGridPosition = ivec2(round(gl_TessCoord.xy * float(" << tessLevel << ")));\n"
482			"}\n";
483
484	return buf.str();
485}
486
487std::string GridRenderCase::getGeometryShaderSource (int numPrimitives, int numInstances)
488{
489	std::ostringstream buf;
490
491	buf	<<	"#version 310 es\n"
492			"#extension GL_EXT_geometry_shader : require\n"
493			"layout(triangles, invocations=" << numInstances << ") in;\n"
494			"layout(triangle_strip, max_vertices=" << (numPrimitives + 2) << ") out;\n"
495			"\n"
496			"in mediump ivec2 v_tessellationGridPosition[];\n"
497			"flat out highp vec4 v_color;\n"
498			"\n"
499			"void main ()\n"
500			"{\n"
501			"	const float equalThreshold = 0.001;\n"
502			"	const float gapOffset = 0.0001; // subdivision performed by the geometry shader might produce gaps. Fill potential gaps by enlarging the output slice a little.\n"
503			"\n"
504			"	// Input triangle is generated from an axis-aligned rectangle by splitting it in half\n"
505			"	// Original rectangle can be found by finding the bounding AABB of the triangle\n"
506			"	vec4 aabb = vec4(min(gl_in[0].gl_Position.x, min(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
507			"	                 min(gl_in[0].gl_Position.y, min(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)),\n"
508			"	                 max(gl_in[0].gl_Position.x, max(gl_in[1].gl_Position.x, gl_in[2].gl_Position.x)),\n"
509			"	                 max(gl_in[0].gl_Position.y, max(gl_in[1].gl_Position.y, gl_in[2].gl_Position.y)));\n"
510			"\n"
511			"	// Location in tessellation grid\n"
512			"	ivec2 gridPosition = ivec2(min(v_tessellationGridPosition[0], min(v_tessellationGridPosition[1], v_tessellationGridPosition[2])));\n"
513			"\n"
514			"	// Which triangle of the two that split the grid cell\n"
515			"	int numVerticesOnBottomEdge = 0;\n"
516			"	for (int ndx = 0; ndx < 3; ++ndx)\n"
517			"		if (abs(gl_in[ndx].gl_Position.y - aabb.w) < equalThreshold)\n"
518			"			++numVerticesOnBottomEdge;\n"
519			"	bool isBottomTriangle = numVerticesOnBottomEdge == 2;\n"
520			"\n"
521			"	// Fill the input area with slices\n"
522			"	// Upper triangle produces slices only to the upper half of the quad and vice-versa\n"
523			"	float triangleOffset = (isBottomTriangle) ? ((aabb.w + aabb.y) / 2.0) : (aabb.y);\n"
524			"	// Each slice is a invocation\n"
525			"	float sliceHeight = (aabb.w - aabb.y) / float(2 * " << numInstances << ");\n"
526			"	float invocationOffset = float(gl_InvocationID) * sliceHeight;\n"
527			"\n"
528			"	vec4 outputSliceArea;\n"
529			"	outputSliceArea.x = aabb.x - gapOffset;\n"
530			"	outputSliceArea.y = triangleOffset + invocationOffset - gapOffset;\n"
531			"	outputSliceArea.z = aabb.z + gapOffset;\n"
532			"	outputSliceArea.w = triangleOffset + invocationOffset + sliceHeight + gapOffset;\n""\n"
533			"	// Draw slice\n"
534			"	for (int ndx = 0; ndx < " << ((numPrimitives+2)/2) << "; ++ndx)\n"
535			"	{\n"
536			"		vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
537			"		vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
538			"		vec4 outputColor = (((gl_InvocationID + ndx) % 2) == 0) ? (green) : (yellow);\n"
539			"		float xpos = mix(outputSliceArea.x, outputSliceArea.z, float(ndx) / float(" << (numPrimitives/2) << "));\n"
540			"\n"
541			"		gl_Position = vec4(xpos, outputSliceArea.y, 0.0, 1.0);\n"
542			"		v_color = outputColor;\n"
543			"		EmitVertex();\n"
544			"\n"
545			"		gl_Position = vec4(xpos, outputSliceArea.w, 0.0, 1.0);\n"
546			"		v_color = outputColor;\n"
547			"		EmitVertex();\n"
548			"	}\n"
549			"}\n";
550
551	return buf.str();
552}
553
554} // anonymous
555
556TessellationGeometryInteractionTests::TessellationGeometryInteractionTests (Context& context)
557	: TestCaseGroup(context, "tessellation_geometry_interaction", "Tessellation and geometry shader interaction stress tests")
558{
559}
560
561TessellationGeometryInteractionTests::~TessellationGeometryInteractionTests (void)
562{
563}
564
565void TessellationGeometryInteractionTests::init (void)
566{
567	tcu::TestCaseGroup* const multilimitGroup = new tcu::TestCaseGroup(m_testCtx, "render_multiple_limits", "Various render tests");
568
569	addChild(multilimitGroup);
570
571	// .render_multiple_limits
572	{
573		static const struct LimitCaseDef
574		{
575			const char*	name;
576			const char*	desc;
577			int			flags;
578		} cases[] =
579		{
580			// Test multiple limits at the same time
581
582			{
583				"output_required_max_tessellation_max_geometry",
584				"Minimum maximum tessellation level and geometry shader output vertices",
585				GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_MAX_SPEC
586			},
587			{
588				"output_implementation_max_tessellation_max_geometry",
589				"Maximum tessellation level and geometry shader output vertices supported by the implementation",
590				GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION
591			},
592			{
593				"output_required_max_tessellation_max_invocations",
594				"Minimum maximum tessellation level and geometry shader invocations",
595				GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
596			},
597			{
598				"output_implementation_max_tessellation_max_invocations",
599				"Maximum tessellation level and geometry shader invocations supported by the implementation",
600				GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
601			},
602			{
603				"output_required_max_geometry_max_invocations",
604				"Minimum maximum geometry shader output vertices and invocations",
605				GridRenderCase::FLAG_GEOMETRY_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
606			},
607			{
608				"output_implementation_max_geometry_max_invocations",
609				"Maximum geometry shader output vertices and invocations invocations supported by the implementation",
610				GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
611			},
612
613			// Test all limits simultaneously
614			{
615				"output_max_required",
616				"Output minimum maximum number of vertices",
617				GridRenderCase::FLAG_TESSELLATION_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_MAX_SPEC | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_SPEC
618			},
619			{
620				"output_max_implementation",
621				"Output maximum number of vertices supported by the implementation",
622				GridRenderCase::FLAG_TESSELLATION_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_MAX_IMPLEMENTATION | GridRenderCase::FLAG_GEOMETRY_INVOCATIONS_MAX_IMPLEMENTATION
623			},
624		};
625
626		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(cases); ++ndx)
627			multilimitGroup->addChild(new GridRenderCase(m_context, cases[ndx].name, cases[ndx].desc, cases[ndx].flags));
628	}
629}
630
631} // Stress
632} // gles31
633} // deqp
634