1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2014 The Android Open Source Project
6 * Copyright (c) 2016 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Tessellation Invariance Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktTessellationInvarianceTests.hpp"
26#include "vktTestCaseUtil.hpp"
27#include "vktTessellationUtil.hpp"
28
29#include "tcuTestLog.hpp"
30#include "tcuVectorUtil.hpp"
31
32#include "vkDefs.hpp"
33#include "vkQueryUtil.hpp"
34#include "vkBuilderUtil.hpp"
35#include "vkImageUtil.hpp"
36#include "vkTypeUtil.hpp"
37
38#include "deUniquePtr.hpp"
39#include "deStringUtil.hpp"
40#include "deRandom.hpp"
41
42#include <string>
43#include <vector>
44#include <set>
45
46namespace vkt
47{
48namespace tessellation
49{
50
51using namespace vk;
52
53namespace
54{
55
56enum Constants
57{
58	NUM_TESS_LEVELS = 6,  // two inner and four outer levels
59};
60
61enum WindingUsage
62{
63	WINDING_USAGE_CCW = 0,
64	WINDING_USAGE_CW,
65	WINDING_USAGE_VARY,
66
67	WINDING_USAGE_LAST,
68};
69
70inline WindingUsage getWindingUsage (const Winding winding)
71{
72	const WindingUsage usage = winding == WINDING_CCW ? WINDING_USAGE_CCW :
73							   winding == WINDING_CW  ? WINDING_USAGE_CW  : WINDING_USAGE_LAST;
74	DE_ASSERT(usage !=  WINDING_USAGE_LAST);
75	return usage;
76}
77
78std::vector<Winding> getWindingCases (const WindingUsage windingUsage)
79{
80	std::vector<Winding> cases;
81	switch (windingUsage)
82	{
83		case WINDING_USAGE_CCW:
84			cases.push_back(WINDING_CCW);
85			break;
86		case WINDING_USAGE_CW:
87			cases.push_back(WINDING_CW);
88			break;
89		case WINDING_USAGE_VARY:
90			cases.push_back(WINDING_CCW);
91			cases.push_back(WINDING_CW);
92			break;
93		default:
94			DE_ASSERT(false);
95			break;
96	}
97	return cases;
98}
99
100enum PointModeUsage
101{
102	POINT_MODE_USAGE_DONT_USE = 0,
103	POINT_MODE_USAGE_USE,
104	POINT_MODE_USAGE_VARY,
105
106	POINT_MODE_USAGE_LAST,
107};
108
109inline PointModeUsage getPointModeUsage (const bool usePointMode)
110{
111	return usePointMode ? POINT_MODE_USAGE_USE : POINT_MODE_USAGE_DONT_USE;
112}
113
114std::vector<bool> getUsePointModeCases (const PointModeUsage pointModeUsage)
115{
116	std::vector<bool> cases;
117	switch (pointModeUsage)
118	{
119		case POINT_MODE_USAGE_DONT_USE:
120			cases.push_back(false);
121			break;
122		case POINT_MODE_USAGE_USE:
123			cases.push_back(true);
124			break;
125		case POINT_MODE_USAGE_VARY:
126			cases.push_back(false);
127			cases.push_back(true);
128			break;
129		default:
130			DE_ASSERT(false);
131			break;
132	}
133	return cases;
134}
135
136//! Data captured in the shader per output primitive (in geometry stage).
137struct PerPrimitive
138{
139	deInt32		patchPrimitiveID;	//!< gl_PrimitiveID in tessellation evaluation shader
140	deInt32		primitiveID;		//!< ID of an output primitive in geometry shader (user-defined)
141
142	deInt32		unused_padding[2];
143
144	tcu::Vec4	tessCoord[3];		//!< 3 coords for triangles/quads, 2 for isolines, 1 for point mode. Vec4 due to alignment.
145};
146
147typedef std::vector<PerPrimitive> PerPrimitiveVec;
148
149inline bool byPatchPrimitiveID (const PerPrimitive& a, const PerPrimitive& b)
150{
151	return a.patchPrimitiveID < b.patchPrimitiveID;
152}
153
154inline std::string getProgramName (const std::string& baseName, const Winding winding, const bool usePointMode)
155{
156	std::ostringstream str;
157	str << baseName << "_" << getWindingShaderName(winding) << (usePointMode ? "_point_mode" : "");
158	return str.str();
159}
160
161inline std::string getProgramName (const std::string& baseName, const bool usePointMode)
162{
163	std::ostringstream str;
164	str << baseName << (usePointMode ? "_point_mode" : "");
165	return str.str();
166}
167
168inline std::string getProgramDescription (const Winding winding, const bool usePointMode)
169{
170	std::ostringstream str;
171	str << "winding mode " << getWindingShaderName(winding) << ", " << (usePointMode ? "" : "don't ") << "use point mode";
172	return str.str();
173};
174
175template <typename T, int N>
176std::vector<T> arrayToVector (const T (&arr)[N])
177{
178	return std::vector<T>(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
179}
180
181template <typename T, int N>
182T arrayMax (const T (&arr)[N])
183{
184	return *std::max_element(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
185}
186
187template <int Size>
188inline tcu::Vector<bool, Size> singleTrueMask (int index)
189{
190	DE_ASSERT(de::inBounds(index, 0, Size));
191	tcu::Vector<bool, Size> result;
192	result[index] = true;
193	return result;
194}
195
196template <typename ContainerT, typename T>
197inline bool contains (const ContainerT& c, const T& key)
198{
199	return c.find(key) != c.end();
200}
201
202template <typename SeqT, int Size, typename Pred>
203class LexCompare
204{
205public:
206	LexCompare (void) : m_pred(Pred()) {}
207
208	bool operator() (const SeqT& a, const SeqT& b) const
209	{
210		for (int i = 0; i < Size; ++i)
211		{
212			if (m_pred(a[i], b[i]))
213				return true;
214			if (m_pred(b[i], a[i]))
215				return false;
216		}
217		return false;
218	}
219
220private:
221	Pred m_pred;
222};
223
224template <int Size>
225class VecLexLessThan : public LexCompare<tcu::Vector<float, Size>, Size, std::less<float> >
226{
227};
228
229//! Add default programs for invariance tests.
230//! Creates multiple shader programs for combinations of winding and point mode.
231//! mirrorCoords - special mode where some tessellation coordinates are mirrored in tessellation evaluation shader.
232//!                This is used by symmetric outer edge test.
233void addDefaultPrograms (vk::SourceCollections&  programCollection,
234						 const TessPrimitiveType primitiveType,
235						 const SpacingMode       spacingMode,
236						 const WindingUsage      windingUsage,
237						 const PointModeUsage    pointModeUsage,
238						 const bool				 mirrorCoords = false)
239{
240	// Vertex shader
241	{
242		std::ostringstream src;
243		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
244			<< "\n"
245			<< "layout(location = 0) in  highp float in_v_attr;\n"
246			<< "layout(location = 0) out highp float in_tc_attr;\n"
247			<< "\n"
248			<< "void main (void)\n"
249			<< "{\n"
250			<< "    in_tc_attr = in_v_attr;\n"
251			<< "}\n";
252
253		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
254	}
255
256	// Tessellation control shader
257	{
258		std::ostringstream src;
259		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
260			<< "#extension GL_EXT_tessellation_shader : require\n"
261			<< "\n"
262			<< "layout(vertices = 1) out;\n"
263			<< "\n"
264			<< "layout(location = 0) in highp float in_tc_attr[];\n"
265			<< "\n"
266			<< "void main (void)\n"
267			<< "{\n"
268			<< "    gl_TessLevelInner[0] = in_tc_attr[0];\n"
269			<< "    gl_TessLevelInner[1] = in_tc_attr[1];\n"
270			<< "\n"
271			<< "    gl_TessLevelOuter[0] = in_tc_attr[2];\n"
272			<< "    gl_TessLevelOuter[1] = in_tc_attr[3];\n"
273			<< "    gl_TessLevelOuter[2] = in_tc_attr[4];\n"
274			<< "    gl_TessLevelOuter[3] = in_tc_attr[5];\n"
275			<< "}\n";
276
277		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
278	}
279
280	const std::string perVertexInterfaceBlock = \
281		"VertexData {\n"					// no in/out qualifier
282		"    vec4 in_gs_tessCoord;\n"		// w component is used by mirroring test
283		"    int  in_gs_primitiveID;\n"
284		"}";								// no newline nor semicolon
285
286	// Alternative tess coordinates handling code
287	std::ostringstream tessEvalCoordSrc;
288	if (mirrorCoords)
289		switch (primitiveType)
290		{
291			case TESSPRIMITIVETYPE_TRIANGLES:
292				tessEvalCoordSrc << "    float x = gl_TessCoord.x;\n"
293								 << "    float y = gl_TessCoord.y;\n"
294								 << "    float z = gl_TessCoord.z;\n"
295								 << "\n"
296								 << "    // Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
297								 << "    ib_out.in_gs_tessCoord   = z == 0.0 && x > 0.5 && x != 1.0 ? vec4(1.0-x,  1.0-y,    0.0, 1.0)\n"
298								 << "                             : y == 0.0 && z > 0.5 && z != 1.0 ? vec4(1.0-x,    0.0,  1.0-z, 1.0)\n"
299								 << "                             : x == 0.0 && y > 0.5 && y != 1.0 ? vec4(  0.0,  1.0-y,  1.0-z, 1.0)\n"
300								 << "                             : vec4(x, y, z, 0.0);\n";
301				break;
302			case TESSPRIMITIVETYPE_QUADS:
303				tessEvalCoordSrc << "    float x = gl_TessCoord.x;\n"
304								 << "    float y = gl_TessCoord.y;\n"
305								 << "\n"
306								 << "    // Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
307								 << "    ib_out.in_gs_tessCoord   = (x == 0.0 || x == 1.0) && y > 0.5 && y != 1.0 ? vec4(    x, 1.0-y, 0.0, 1.0)\n"
308								 << "                             : (y == 0.0 || y == 1.0) && x > 0.5 && x != 1.0 ? vec4(1.0-x,     y, 0.0, 1.0)\n"
309								 << "                             : vec4(x, y, 0.0, 0.0);\n";
310				break;
311			case TESSPRIMITIVETYPE_ISOLINES:
312				tessEvalCoordSrc << "    float x = gl_TessCoord.x;\n"
313								 << "    float y = gl_TessCoord.y;\n"
314								 << "\n"
315								 << "    // Mirror one half of each outer edge onto the other half\n"
316								 << "    ib_out.in_gs_tessCoord   = (x == 0.0 || x == 1.0) && y > 0.5 ? vec4(x, 1.0-y, 0.0, 1.0)\n"
317								 << "                             : vec4(x, y, 0.0, 0.0);\n";
318				break;
319			default:
320				DE_ASSERT(false);
321				return;
322		}
323	else
324		tessEvalCoordSrc << "    ib_out.in_gs_tessCoord   = vec4(gl_TessCoord, 0.0);\n";
325
326	const std::vector<Winding> windingCases      = getWindingCases(windingUsage);
327	const std::vector<bool>    usePointModeCases = getUsePointModeCases(pointModeUsage);
328
329	for (std::vector<Winding>::const_iterator windingIter = windingCases.begin(); windingIter != windingCases.end(); ++windingIter)
330	for (std::vector<bool>::const_iterator usePointModeIter = usePointModeCases.begin(); usePointModeIter != usePointModeCases.end(); ++usePointModeIter)
331	{
332		// Tessellation evaluation shader
333		{
334			std::ostringstream src;
335			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
336				<< "#extension GL_EXT_tessellation_shader : require\n"
337				<< "\n"
338				<< "layout(" << getTessPrimitiveTypeShaderName(primitiveType) << ", "
339							 << getSpacingModeShaderName(spacingMode) << ", "
340							 << getWindingShaderName(*windingIter)
341							 << (*usePointModeIter ? ", point_mode" : "") << ") in;\n"
342				<< "\n"
343				<< "layout(location = 0) out " << perVertexInterfaceBlock << " ib_out;\n"
344				<< "\n"
345				<< "void main (void)\n"
346				<< "{\n"
347				<< tessEvalCoordSrc.str()
348				<< "    ib_out.in_gs_primitiveID = gl_PrimitiveID;\n"
349				<< "}\n";
350
351			programCollection.glslSources.add(getProgramName("tese", *windingIter, *usePointModeIter)) << glu::TessellationEvaluationSource(src.str());
352		}
353	}  // for windingNdx, usePointModeNdx
354
355	// Geometry shader: data is captured here.
356	{
357		for (std::vector<bool>::const_iterator usePointModeIter = usePointModeCases.begin(); usePointModeIter != usePointModeCases.end(); ++usePointModeIter)
358		{
359			const int numVertices = numVerticesPerPrimitive(primitiveType, *usePointModeIter);  // Primitives that the tessellated patch comprises of.
360
361			std::ostringstream src;
362			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
363				<< "#extension GL_EXT_geometry_shader : require\n"
364				<< "\n"
365				<< "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(primitiveType, *usePointModeIter) << ") in;\n"
366				<< "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(primitiveType, *usePointModeIter) << ", max_vertices = " << numVertices << ") out;\n"
367				<< "\n"
368				<< "layout(location = 0) in " << perVertexInterfaceBlock << " ib_in[];\n"
369				<< "\n"
370				<< "struct PerPrimitive {\n"
371				<< "    int  patchPrimitiveID;\n"
372				<< "    int  primitiveID;\n"
373				<< "    vec4 tessCoord[3];\n"
374				<< "};\n"
375				<< "\n"
376				<< "layout(set = 0, binding = 0, std430) coherent restrict buffer Output {\n"
377				<< "    int          numPrimitives;\n"
378				<< "    PerPrimitive primitive[];\n"
379				<< "} sb_out;\n"
380				<< "\n"
381				<< "void main (void)\n"
382				<< "{\n"
383				<< "    int index = atomicAdd(sb_out.numPrimitives, 1);\n"
384				<< "    sb_out.primitive[index].patchPrimitiveID = ib_in[0].in_gs_primitiveID;\n"
385				<< "    sb_out.primitive[index].primitiveID      = index;\n";
386			for (int i = 0; i < numVertices; ++i)
387				src << "    sb_out.primitive[index].tessCoord[" << i << "]     = ib_in[" << i << "].in_gs_tessCoord;\n";
388			for (int i = 0; i < numVertices; ++i)
389				src << "\n"
390					<< "    gl_Position = vec4(0.0);\n"
391					<< "    EmitVertex();\n";
392			src << "}\n";
393
394			programCollection.glslSources.add(getProgramName("geom", *usePointModeIter)) << glu::GeometrySource(src.str());
395		}
396	}
397}
398
399//! A description of an outer edge of a triangle, quad or isolines.
400//! An outer edge can be described by the index of a u/v/w coordinate
401//! and the coordinate's value along that edge.
402struct OuterEdgeDescription
403{
404	int		constantCoordinateIndex;
405	float	constantCoordinateValueChoices[2];
406	int		numConstantCoordinateValueChoices;
407
408	OuterEdgeDescription (const int i, const float c0)					: constantCoordinateIndex(i), numConstantCoordinateValueChoices(1) { constantCoordinateValueChoices[0] = c0; }
409	OuterEdgeDescription (const int i, const float c0, const float c1)	: constantCoordinateIndex(i), numConstantCoordinateValueChoices(2) { constantCoordinateValueChoices[0] = c0; constantCoordinateValueChoices[1] = c1; }
410
411	std::string description (void) const
412	{
413		static const char* const	coordinateNames[] = { "u", "v", "w" };
414		std::string					result;
415		for (int i = 0; i < numConstantCoordinateValueChoices; ++i)
416			result += std::string() + (i > 0 ? " or " : "") + coordinateNames[constantCoordinateIndex] + "=" + de::toString(constantCoordinateValueChoices[i]);
417		return result;
418	}
419
420	bool contains (const tcu::Vec3& v) const
421	{
422		for (int i = 0; i < numConstantCoordinateValueChoices; ++i)
423			if (v[constantCoordinateIndex] == constantCoordinateValueChoices[i])
424				return true;
425		return false;
426	}
427};
428
429std::vector<OuterEdgeDescription> outerEdgeDescriptions (const TessPrimitiveType primType)
430{
431	static const OuterEdgeDescription triangleOuterEdgeDescriptions[3] =
432	{
433		OuterEdgeDescription(0, 0.0f),
434		OuterEdgeDescription(1, 0.0f),
435		OuterEdgeDescription(2, 0.0f)
436	};
437
438	static const OuterEdgeDescription quadOuterEdgeDescriptions[4] =
439	{
440		OuterEdgeDescription(0, 0.0f),
441		OuterEdgeDescription(1, 0.0f),
442		OuterEdgeDescription(0, 1.0f),
443		OuterEdgeDescription(1, 1.0f)
444	};
445
446	static const OuterEdgeDescription isolinesOuterEdgeDescriptions[1] =
447	{
448		OuterEdgeDescription(0, 0.0f, 1.0f),
449	};
450
451	switch (primType)
452	{
453		case TESSPRIMITIVETYPE_TRIANGLES:	return arrayToVector(triangleOuterEdgeDescriptions);
454		case TESSPRIMITIVETYPE_QUADS:		return arrayToVector(quadOuterEdgeDescriptions);
455		case TESSPRIMITIVETYPE_ISOLINES:	return arrayToVector(isolinesOuterEdgeDescriptions);
456
457		default:
458			DE_ASSERT(false);
459			return std::vector<OuterEdgeDescription>();
460	}
461}
462
463namespace InvariantOuterEdge
464{
465
466struct CaseDefinition
467{
468	TessPrimitiveType	primitiveType;
469	SpacingMode			spacingMode;
470	Winding				winding;
471	bool				usePointMode;
472};
473
474typedef std::set<tcu::Vec3, VecLexLessThan<3> > Vec3Set;
475
476std::vector<float> generateRandomPatchTessLevels (const int numPatches, const int constantOuterLevelIndex, const float constantOuterLevel, de::Random& rnd)
477{
478	std::vector<float> tessLevels(numPatches*NUM_TESS_LEVELS);
479
480	for (int patchNdx = 0; patchNdx < numPatches; ++patchNdx)
481	{
482		float* const inner = &tessLevels[patchNdx*NUM_TESS_LEVELS + 0];
483		float* const outer = &tessLevels[patchNdx*NUM_TESS_LEVELS + 2];
484
485		for (int j = 0; j < 2; ++j)
486			inner[j] = rnd.getFloat(1.0f, 62.0f);
487		for (int j = 0; j < 4; ++j)
488			outer[j] = j == constantOuterLevelIndex ? constantOuterLevel : rnd.getFloat(1.0f, 62.0f);
489	}
490
491	return tessLevels;
492}
493
494std::vector<float> generatePatchTessLevels (const int numPatches, const int constantOuterLevelIndex, const float constantOuterLevel)
495{
496	de::Random rnd(123);
497	return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
498}
499
500int multiplePatchReferencePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* levels, int numPatches)
501{
502	int result = 0;
503	for (int patchNdx = 0; patchNdx < numPatches; ++patchNdx)
504		result += referencePrimitiveCount(primitiveType, spacingMode, usePointMode, &levels[NUM_TESS_LEVELS*patchNdx + 0], &levels[NUM_TESS_LEVELS*patchNdx + 2]);
505	return result;
506}
507
508template<std::size_t N>
509int computeMaxPrimitiveCount (const int numPatchesToDraw, const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float (&singleOuterEdgeLevels)[N])
510{
511	const int                outerEdgeIndex  = 0; // outer-edge index doesn't affect vertex count
512	const std::vector<float> patchTessLevels = generatePatchTessLevels(numPatchesToDraw, outerEdgeIndex, arrayMax(singleOuterEdgeLevels));
513	return multiplePatchReferencePrimitiveCount(primitiveType, spacingMode, usePointMode, &patchTessLevels[0], numPatchesToDraw);
514}
515
516void logOuterTessellationLevel (tcu::TestLog& log, const float tessLevel, const OuterEdgeDescription& edgeDesc)
517{
518	log << tcu::TestLog::Message
519		<< "Testing with outer tessellation level " << tessLevel << " for the " << edgeDesc.description() << " edge, and with various levels for other edges, and with all programs"
520		<< tcu::TestLog::EndMessage;
521}
522
523void logPrimitiveCountError (tcu::TestLog& log, const int numPatchesToDraw, int numPrimitives, const int refNumPrimitives, const std::vector<float>& patchTessLevels)
524{
525	log << tcu::TestLog::Message
526		<< "Failure: the number of generated primitives is " << numPrimitives << ", expected at least " << refNumPrimitives
527		<< tcu::TestLog::EndMessage;
528
529	if (numPatchesToDraw == 1)
530		log << tcu::TestLog::Message
531			<< "Note: rendered one patch; tessellation levels are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
532			<< containerStr(patchTessLevels, NUM_TESS_LEVELS)
533			<< tcu::TestLog::EndMessage;
534	else
535		log << tcu::TestLog::Message
536			<< "Note: rendered " << numPatchesToDraw << " patches in one draw call; "
537			<< "tessellation levels for each patch are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
538			<< containerStr(patchTessLevels, NUM_TESS_LEVELS)
539			<< tcu::TestLog::EndMessage;
540}
541
542class BaseTestInstance : public TestInstance
543{
544public:
545	struct DrawResult
546	{
547		bool			success;
548		int				refNumPrimitives;
549		int				numPrimitiveVertices;
550		deInt32			numPrimitives;
551		PerPrimitiveVec	primitives;
552	};
553
554											BaseTestInstance		(Context& context, const CaseDefinition caseDef, const int numPatchesToDraw);
555	DrawResult								draw					(const deUint32 vertexCount, const std::vector<float>& patchTessLevels, const Winding winding, const bool usePointMode);
556	void									uploadVertexAttributes	(const std::vector<float>& vertexData);
557
558protected:
559	static const float						m_singleOuterEdgeLevels[];
560
561	const CaseDefinition					m_caseDef;
562	const int								m_numPatchesToDraw;
563	const VkFormat							m_vertexFormat;
564	const deUint32							m_vertexStride;
565	const std::vector<OuterEdgeDescription>	m_edgeDescriptions;
566	const int								m_maxNumPrimitivesInDrawCall;
567	const VkDeviceSize						m_vertexDataSizeBytes;
568	const Buffer							m_vertexBuffer;
569	const int								m_resultBufferPrimitiveDataOffset;
570	const VkDeviceSize						m_resultBufferSizeBytes;
571	const Buffer							m_resultBuffer;
572	Unique<VkDescriptorSetLayout>			m_descriptorSetLayout;
573	Unique<VkDescriptorPool>				m_descriptorPool;
574	Unique<VkDescriptorSet>					m_descriptorSet;
575	Unique<VkRenderPass>					m_renderPass;
576	Unique<VkFramebuffer>					m_framebuffer;
577	Unique<VkPipelineLayout>				m_pipelineLayout;
578	Unique<VkCommandPool>					m_cmdPool;
579	Unique<VkCommandBuffer>					m_cmdBuffer;
580};
581
582const float BaseTestInstance::m_singleOuterEdgeLevels[] = { 1.0f, 1.2f, 1.9f, 2.3f, 2.8f, 3.3f, 3.8f, 10.2f, 1.6f, 24.4f, 24.7f, 63.0f };
583
584BaseTestInstance::BaseTestInstance (Context& context, const CaseDefinition caseDef, const int numPatchesToDraw)
585	: TestInstance							(context)
586	, m_caseDef								(caseDef)
587	, m_numPatchesToDraw					(numPatchesToDraw)
588	, m_vertexFormat						(VK_FORMAT_R32_SFLOAT)
589	, m_vertexStride						(tcu::getPixelSize(mapVkFormat(m_vertexFormat)))
590	, m_edgeDescriptions					(outerEdgeDescriptions(m_caseDef.primitiveType))
591	, m_maxNumPrimitivesInDrawCall			(computeMaxPrimitiveCount(m_numPatchesToDraw, caseDef.primitiveType, caseDef.spacingMode, caseDef.usePointMode, m_singleOuterEdgeLevels))
592	, m_vertexDataSizeBytes					(NUM_TESS_LEVELS * m_numPatchesToDraw * m_vertexStride)
593	, m_vertexBuffer						(m_context.getDeviceInterface(), m_context.getDevice(), m_context.getDefaultAllocator(),
594											makeBufferCreateInfo(m_vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible)
595	, m_resultBufferPrimitiveDataOffset		((int)sizeof(deInt32) * 4)
596	, m_resultBufferSizeBytes				(m_resultBufferPrimitiveDataOffset + m_maxNumPrimitivesInDrawCall * sizeof(PerPrimitive))
597	, m_resultBuffer						(m_context.getDeviceInterface(), m_context.getDevice(), m_context.getDefaultAllocator(),
598											makeBufferCreateInfo(m_resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible)
599	, m_descriptorSetLayout					(DescriptorSetLayoutBuilder()
600											.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_GEOMETRY_BIT)
601											.build(m_context.getDeviceInterface(), m_context.getDevice()))
602	, m_descriptorPool						(DescriptorPoolBuilder()
603											.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
604											.build(m_context.getDeviceInterface(), m_context.getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u))
605	, m_descriptorSet						(makeDescriptorSet(m_context.getDeviceInterface(), m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout))
606	, m_renderPass							(makeRenderPassWithoutAttachments (m_context.getDeviceInterface(), m_context.getDevice()))
607	, m_framebuffer							(makeFramebufferWithoutAttachments(m_context.getDeviceInterface(), m_context.getDevice(), *m_renderPass))
608	, m_pipelineLayout						(makePipelineLayout               (m_context.getDeviceInterface(), m_context.getDevice(), *m_descriptorSetLayout))
609	, m_cmdPool								(makeCommandPool                  (m_context.getDeviceInterface(), m_context.getDevice(), m_context.getUniversalQueueFamilyIndex()))
610	, m_cmdBuffer							(makeCommandBuffer                (m_context.getDeviceInterface(), m_context.getDevice(), *m_cmdPool))
611{
612	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(),
613					FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
614
615	const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(m_resultBuffer.get(), 0ull, m_resultBufferSizeBytes);
616
617	DescriptorSetUpdateBuilder()
618		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
619		.update(m_context.getDeviceInterface(), m_context.getDevice());
620}
621
622//! patchTessLevels are tessellation levels for all drawn patches.
623BaseTestInstance::DrawResult BaseTestInstance::draw (const deUint32 vertexCount, const std::vector<float>& patchTessLevels, const Winding winding, const bool usePointMode)
624{
625	const DeviceInterface&	vk		= m_context.getDeviceInterface();
626	const VkDevice			device	= m_context.getDevice();
627	const VkQueue			queue	= m_context.getUniversalQueue();
628
629	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
630		.setPatchControlPoints        (NUM_TESS_LEVELS)
631		.setVertexInputSingleAttribute(m_vertexFormat, m_vertexStride)
632		.setShader                    (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					m_context.getBinaryCollection().get("vert"), DE_NULL)
633		.setShader                    (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	m_context.getBinaryCollection().get("tesc"), DE_NULL)
634		.setShader                    (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get(getProgramName("tese", winding, usePointMode)), DE_NULL)
635		.setShader                    (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,                m_context.getBinaryCollection().get(getProgramName("geom", usePointMode)), DE_NULL)
636		.build                        (vk, device, *m_pipelineLayout, *m_renderPass));
637
638	{
639		const Allocation& alloc = m_resultBuffer.getAllocation();
640		deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(m_resultBufferSizeBytes));
641		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), m_resultBufferSizeBytes);
642	}
643
644	beginCommandBuffer(vk, *m_cmdBuffer);
645	beginRenderPassWithRasterizationDisabled(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer);
646
647	vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
648	vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
649	{
650		const VkDeviceSize vertexBufferOffset = 0ull;
651		vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
652	}
653
654	vk.cmdDraw(*m_cmdBuffer, vertexCount, 1u, 0u, 0u);
655	endRenderPass(vk, *m_cmdBuffer);
656
657	{
658		const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
659			VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *m_resultBuffer, 0ull, m_resultBufferSizeBytes);
660
661		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
662			0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
663	}
664
665	endCommandBuffer(vk, *m_cmdBuffer);
666	submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
667
668	// Read back and check results
669
670	const Allocation& resultAlloc = m_resultBuffer.getAllocation();
671	invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_resultBufferSizeBytes);
672
673	DrawResult result;
674	result.success				= true;
675	result.refNumPrimitives     = multiplePatchReferencePrimitiveCount(m_caseDef.primitiveType, m_caseDef.spacingMode, usePointMode, &patchTessLevels[0], m_numPatchesToDraw);
676	result.numPrimitiveVertices = numVerticesPerPrimitive(m_caseDef.primitiveType, usePointMode);
677	result.numPrimitives        = *static_cast<deInt32*>(resultAlloc.getHostPtr());
678	result.primitives           = sorted(readInterleavedData<PerPrimitive>(result.numPrimitives, resultAlloc.getHostPtr(), m_resultBufferPrimitiveDataOffset, sizeof(PerPrimitive)),
679										 byPatchPrimitiveID);
680
681	// If this fails then we didn't read all vertices from shader and test must be changed to allow more.
682	DE_ASSERT(result.numPrimitives <= m_maxNumPrimitivesInDrawCall);
683
684	tcu::TestLog& log = m_context.getTestContext().getLog();
685	if (result.numPrimitives != result.refNumPrimitives)
686	{
687		logPrimitiveCountError(log, m_numPatchesToDraw, result.numPrimitives, result.refNumPrimitives, patchTessLevels);
688		result.success = false;
689	}
690	return result;
691}
692
693void BaseTestInstance::uploadVertexAttributes (const std::vector<float>& vertexData)
694{
695	const DeviceInterface&	vk		= m_context.getDeviceInterface();
696	const VkDevice			device	= m_context.getDevice();
697
698	const Allocation& alloc = m_vertexBuffer.getAllocation();
699	deMemcpy(alloc.getHostPtr(), &vertexData[0], sizeInBytes(vertexData));
700	flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeInBytes(vertexData));
701}
702
703/*--------------------------------------------------------------------*//*!
704 * \brief Test invariance rule #2
705 *
706 * Test that the set of vertices along an outer edge of a quad or triangle
707 * only depends on that edge's tessellation level, and spacing.
708 *
709 * For each (outer) edge in the quad or triangle, draw multiple patches
710 * with identical tessellation levels for that outer edge but with
711 * different values for the other outer edges; compare, among the
712 * primitives, the vertices generated for that outer edge. Repeat with
713 * different programs, using different winding etc. settings. Compare
714 * the edge's vertices between different programs.
715 *//*--------------------------------------------------------------------*/
716class OuterEdgeDivisionTestInstance : public BaseTestInstance
717{
718public:
719						OuterEdgeDivisionTestInstance	(Context& context, const CaseDefinition caseDef) : BaseTestInstance (context, caseDef, 10) {}
720	tcu::TestStatus		iterate							(void);
721};
722
723tcu::TestStatus OuterEdgeDivisionTestInstance::iterate (void)
724{
725	for (int outerEdgeIndex = 0; outerEdgeIndex < static_cast<int>(m_edgeDescriptions.size()); ++outerEdgeIndex)
726	for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(m_singleOuterEdgeLevels); ++outerEdgeLevelCaseNdx)
727	{
728		const OuterEdgeDescription& edgeDesc        = m_edgeDescriptions[outerEdgeIndex];
729		const std::vector<float>    patchTessLevels = generatePatchTessLevels(m_numPatchesToDraw, outerEdgeIndex, m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
730
731		Vec3Set firstOuterEdgeVertices; // Vertices of the outer edge of the first patch of the first program's draw call; used for comparison with other patches.
732
733		uploadVertexAttributes(patchTessLevels);
734		logOuterTessellationLevel(m_context.getTestContext().getLog(), m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx], edgeDesc);
735
736		for (int windingNdx = 0; windingNdx < WINDING_LAST; ++windingNdx)
737		for (int usePointModeNdx = 0; usePointModeNdx <= 1; ++usePointModeNdx)
738		{
739			const Winding winding	     = static_cast<Winding>(windingNdx);
740			const bool	  usePointMode   = (usePointModeNdx != 0);
741			const bool    isFirstProgram = (windingNdx == 0 && usePointModeNdx == 0);
742
743			const DrawResult result = draw(static_cast<deUint32>(patchTessLevels.size()), patchTessLevels, winding, usePointMode);
744
745			if (!result.success)
746				return tcu::TestStatus::fail("Invalid set of vertices");
747
748			// Check the vertices of each patch.
749
750			int primitiveNdx = 0;
751			for (int patchNdx = 0; patchNdx < m_numPatchesToDraw; ++patchNdx)
752			{
753				DE_ASSERT(primitiveNdx < result.numPrimitives);
754
755				const float* const	innerLevels	= &patchTessLevels[NUM_TESS_LEVELS*patchNdx + 0];
756				const float* const	outerLevels	= &patchTessLevels[NUM_TESS_LEVELS*patchNdx + 2];
757
758				Vec3Set outerEdgeVertices;
759
760				// We're interested in just the vertices on the current outer edge.
761				for (; primitiveNdx < result.numPrimitives && result.primitives[primitiveNdx].patchPrimitiveID == patchNdx; ++primitiveNdx)
762				for (int i = 0; i < result.numPrimitiveVertices; ++i)
763				{
764					const tcu::Vec3& coord = result.primitives[primitiveNdx].tessCoord[i].swizzle(0, 1, 2);
765					if (edgeDesc.contains(coord))
766						outerEdgeVertices.insert(coord);
767				}
768
769				// Compare the vertices to those of the first patch (unless this is the first patch).
770
771				if (isFirstProgram && patchNdx == 0)
772					firstOuterEdgeVertices = outerEdgeVertices;
773				else if (firstOuterEdgeVertices != outerEdgeVertices)
774				{
775					tcu::TestLog& log = m_context.getTestContext().getLog();
776
777					log << tcu::TestLog::Message
778						<< "Failure: vertices generated for the edge differ between the following cases:\n"
779						<< "  - case A: " << getProgramDescription((Winding)0, (bool)0) << ", tessellation levels: "
780						<< getTessellationLevelsString(&patchTessLevels[0], &patchTessLevels[2]) << "\n"
781						<< "  - case B: " << getProgramDescription(winding, usePointMode) << ", tessellation levels: "
782						<< getTessellationLevelsString(innerLevels, outerLevels)
783						<< tcu::TestLog::EndMessage;
784
785					log << tcu::TestLog::Message
786						<< "Note: resulting vertices for the edge for the cases were:\n"
787						<< "  - case A: " << containerStr(firstOuterEdgeVertices, 5, 14) << "\n"
788						<< "  - case B: " << containerStr(outerEdgeVertices, 5, 14)
789						<< tcu::TestLog::EndMessage;
790
791					return tcu::TestStatus::fail("Invalid set of vertices");
792				}
793			}
794			DE_ASSERT(primitiveNdx == result.numPrimitives);
795		} // for windingNdx, usePointModeNdx
796	} // for outerEdgeIndex, outerEdgeLevelCaseNdx
797
798	return tcu::TestStatus::pass("OK");
799}
800
801/*--------------------------------------------------------------------*//*!
802 * \brief Test invariance rule #4
803 *
804 * Test that the vertices on an outer edge don't depend on which of the
805 * edges it is, other than with respect to component order.
806 *//*--------------------------------------------------------------------*/
807class OuterEdgeIndexIndependenceTestInstance : public BaseTestInstance
808{
809public:
810						OuterEdgeIndexIndependenceTestInstance	(Context& context, const CaseDefinition caseDef) : BaseTestInstance (context, caseDef, 1) {}
811	tcu::TestStatus		iterate									(void);
812};
813
814tcu::TestStatus OuterEdgeIndexIndependenceTestInstance::iterate (void)
815{
816	for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(m_singleOuterEdgeLevels); ++outerEdgeLevelCaseNdx)
817	{
818		Vec3Set firstEdgeVertices;
819
820		for (int outerEdgeIndex = 0; outerEdgeIndex < static_cast<int>(m_edgeDescriptions.size()); ++outerEdgeIndex)
821		{
822			const OuterEdgeDescription& edgeDesc        = m_edgeDescriptions[outerEdgeIndex];
823			const std::vector<float>    patchTessLevels = generatePatchTessLevels(m_numPatchesToDraw, outerEdgeIndex, m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
824
825			uploadVertexAttributes(patchTessLevels);
826			logOuterTessellationLevel(m_context.getTestContext().getLog(), m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx], edgeDesc);
827			const DrawResult result = draw(static_cast<deUint32>(patchTessLevels.size()), patchTessLevels, m_caseDef.winding, m_caseDef.usePointMode);
828
829			// Verify case result
830
831			if (!result.success)
832				return tcu::TestStatus::fail("Invalid set of vertices");
833
834			Vec3Set currentEdgeVertices;
835
836			// Get the vertices on the current outer edge.
837			for (int primitiveNdx = 0; primitiveNdx < result.numPrimitives; ++primitiveNdx)
838			for (int i = 0; i < result.numPrimitiveVertices; ++i)
839			{
840				const tcu::Vec3& coord = result.primitives[primitiveNdx].tessCoord[i].swizzle(0, 1, 2);
841				if (edgeDesc.contains(coord))
842				{
843					// Swizzle components to match the order of the first edge.
844					if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
845						currentEdgeVertices.insert(outerEdgeIndex == 0 ? coord :
846												   outerEdgeIndex == 1 ? coord.swizzle(1, 0, 2) :
847												   outerEdgeIndex == 2 ? coord.swizzle(2, 1, 0) : tcu::Vec3(-1.0f));
848					else if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
849						currentEdgeVertices.insert(tcu::Vec3(outerEdgeIndex == 0 ? coord.y() :
850															 outerEdgeIndex == 1 ? coord.x() :
851															 outerEdgeIndex == 2 ? coord.y() :
852															 outerEdgeIndex == 3 ? coord.x() : -1.0f,
853															 0.0f, 0.0f));
854					else
855						DE_ASSERT(false);
856				}
857			}
858
859			if (outerEdgeIndex == 0)
860				firstEdgeVertices = currentEdgeVertices;
861			else
862			{
863				// Compare vertices of this edge to those of the first edge.
864				if (currentEdgeVertices != firstEdgeVertices)
865				{
866					const char* const swizzleDesc =
867						m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? (outerEdgeIndex == 1 ? "(y, x, z)" :
868																				  outerEdgeIndex == 2 ? "(z, y, x)" : DE_NULL) :
869						m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ? (outerEdgeIndex == 1 ? "(x, 0)" :
870																			  outerEdgeIndex == 2 ? "(y, 0)" :
871																			  outerEdgeIndex == 3 ? "(x, 0)" : DE_NULL)
872						: DE_NULL;
873
874					tcu::TestLog& log = m_context.getTestContext().getLog();
875					log << tcu::TestLog::Message
876						<< "Failure: the set of vertices on the " << edgeDesc.description() << " edge"
877						<< " doesn't match the set of vertices on the " << m_edgeDescriptions[0].description() << " edge"
878						<< tcu::TestLog::EndMessage;
879
880					log << tcu::TestLog::Message
881						<< "Note: set of vertices on " << edgeDesc.description() << " edge, components swizzled like " << swizzleDesc
882						<< " to match component order on first edge:\n" << containerStr(currentEdgeVertices, 5)
883						<< "\non " << m_edgeDescriptions[0].description() << " edge:\n" << containerStr(firstEdgeVertices, 5)
884						<< tcu::TestLog::EndMessage;
885
886					return tcu::TestStatus::fail("Invalid set of vertices");
887				}
888			}
889		}
890	}
891	return tcu::TestStatus::pass("OK");
892}
893
894/*--------------------------------------------------------------------*//*!
895 * \brief Test invariance rule #3
896 *
897 * Test that the vertices along an outer edge are placed symmetrically.
898 *
899 * Draw multiple patches with different tessellation levels and different
900 * point_mode, winding etc. Before outputting tesscoords from shader, mirror
901 * the vertices in the TES such that every vertex on an outer edge -
902 * except the possible middle vertex - should be duplicated in the output.
903 * Check that appropriate duplicates exist.
904 *//*--------------------------------------------------------------------*/
905class SymmetricOuterEdgeTestInstance : public BaseTestInstance
906{
907public:
908						SymmetricOuterEdgeTestInstance	(Context& context, const CaseDefinition caseDef) : BaseTestInstance (context, caseDef, 1) {}
909	tcu::TestStatus		iterate							(void);
910};
911
912tcu::TestStatus SymmetricOuterEdgeTestInstance::iterate (void)
913{
914	for (int outerEdgeIndex = 0; outerEdgeIndex < static_cast<int>(m_edgeDescriptions.size()); ++outerEdgeIndex)
915	for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(m_singleOuterEdgeLevels); ++outerEdgeLevelCaseNdx)
916	{
917		const OuterEdgeDescription& edgeDesc        = m_edgeDescriptions[outerEdgeIndex];
918		const std::vector<float>    patchTessLevels = generatePatchTessLevels(m_numPatchesToDraw, outerEdgeIndex, m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
919
920		uploadVertexAttributes(patchTessLevels);
921		logOuterTessellationLevel(m_context.getTestContext().getLog(), m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx], edgeDesc);
922		const DrawResult result = draw(static_cast<deUint32>(patchTessLevels.size()), patchTessLevels, m_caseDef.winding, m_caseDef.usePointMode);
923
924		// Verify case result
925
926		if (!result.success)
927			return tcu::TestStatus::fail("Invalid set of vertices");
928
929		Vec3Set nonMirroredEdgeVertices;
930		Vec3Set mirroredEdgeVertices;
931
932		// Get the vertices on the current outer edge.
933		for (int primitiveNdx = 0; primitiveNdx < result.numPrimitives; ++primitiveNdx)
934		for (int i = 0; i < result.numPrimitiveVertices; ++i)
935		{
936			const tcu::Vec3& coord = result.primitives[primitiveNdx].tessCoord[i].swizzle(0, 1, 2);
937			if (edgeDesc.contains(coord))
938			{
939				// Ignore the middle vertex of the outer edge, as it's exactly at the mirroring point;
940				// for isolines, also ignore (0, 0) and (1, 0) because there's no mirrored counterpart for them.
941				if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES &&
942					coord == tcu::select(tcu::Vec3(0.0f), tcu::Vec3(0.5f), singleTrueMask<3>(edgeDesc.constantCoordinateIndex)))
943					continue;
944				if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS &&
945					coord.swizzle(0,1) == tcu::select(tcu::Vec2(edgeDesc.constantCoordinateValueChoices[0]), tcu::Vec2(0.5f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex)))
946					continue;
947				if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_ISOLINES &&
948					(coord == tcu::Vec3(0.0f, 0.5f, 0.0f) || coord == tcu::Vec3(1.0f, 0.5f, 0.0f) || coord == tcu::Vec3(0.0f, 0.0f, 0.0f) || coord == tcu::Vec3(1.0f, 0.0f, 0.0f)))
949					continue;
950
951				const bool isMirrored = result.primitives[primitiveNdx].tessCoord[i].w() > 0.5f;
952				if (isMirrored)
953					mirroredEdgeVertices.insert(coord);
954				else
955					nonMirroredEdgeVertices.insert(coord);
956			}
957		}
958
959		if (m_caseDef.primitiveType != TESSPRIMITIVETYPE_ISOLINES)
960		{
961			// Check that both endpoints are present. Note that endpoints aren't mirrored by the shader, since they belong to more than one edge.
962
963			tcu::Vec3 endpointA;
964			tcu::Vec3 endpointB;
965
966			if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
967			{
968				endpointA = tcu::select(tcu::Vec3(1.0f), tcu::Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 1) % 3));
969				endpointB = tcu::select(tcu::Vec3(1.0f), tcu::Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 2) % 3));
970			}
971			else if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
972			{
973				endpointA.xy() = tcu::select(tcu::Vec2(edgeDesc.constantCoordinateValueChoices[0]), tcu::Vec2(0.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
974				endpointB.xy() = tcu::select(tcu::Vec2(edgeDesc.constantCoordinateValueChoices[0]), tcu::Vec2(1.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
975			}
976			else
977				DE_ASSERT(false);
978
979			if (!contains(nonMirroredEdgeVertices, endpointA) ||
980				!contains(nonMirroredEdgeVertices, endpointB))
981			{
982				m_context.getTestContext().getLog()
983					<< tcu::TestLog::Message << "Failure: edge doesn't contain both endpoints, " << endpointA << " and " << endpointB << tcu::TestLog::EndMessage
984					<< tcu::TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
985											 << "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << tcu::TestLog::EndMessage;
986
987				return tcu::TestStatus::fail("Invalid set of vertices");
988			}
989			nonMirroredEdgeVertices.erase(endpointA);
990			nonMirroredEdgeVertices.erase(endpointB);
991		}
992
993		if (nonMirroredEdgeVertices != mirroredEdgeVertices)
994		{
995			m_context.getTestContext().getLog()
996				<< tcu::TestLog::Message << "Failure: the set of mirrored edges isn't equal to the set of non-mirrored edges (ignoring endpoints and possible middle)" << tcu::TestLog::EndMessage
997				<< tcu::TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
998										 << "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << tcu::TestLog::EndMessage;
999
1000			return tcu::TestStatus::fail("Invalid set of vertices");
1001		}
1002	}
1003	return tcu::TestStatus::pass("OK");
1004}
1005
1006class OuterEdgeDivisionTest : public TestCase
1007{
1008public:
1009	OuterEdgeDivisionTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const CaseDefinition caseDef)
1010		: TestCase	(testCtx, name, description)
1011		, m_caseDef	(caseDef)
1012	{
1013	}
1014
1015	void initPrograms (vk::SourceCollections& programCollection) const
1016	{
1017		addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, WINDING_USAGE_VARY, POINT_MODE_USAGE_VARY);
1018	}
1019
1020	TestInstance* createInstance (Context& context) const
1021	{
1022		return new OuterEdgeDivisionTestInstance(context, m_caseDef);
1023	};
1024
1025private:
1026	const CaseDefinition m_caseDef;
1027};
1028
1029class OuterEdgeIndexIndependenceTest : public TestCase
1030{
1031public:
1032	OuterEdgeIndexIndependenceTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const CaseDefinition caseDef)
1033		: TestCase	(testCtx, name, description)
1034		, m_caseDef	(caseDef)
1035	{
1036		DE_ASSERT(m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
1037	}
1038
1039	void initPrograms (vk::SourceCollections& programCollection) const
1040	{
1041		addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, getWindingUsage(m_caseDef.winding), getPointModeUsage(m_caseDef.usePointMode));
1042	}
1043
1044	TestInstance* createInstance (Context& context) const
1045	{
1046		return new OuterEdgeIndexIndependenceTestInstance(context, m_caseDef);
1047	};
1048
1049private:
1050	const CaseDefinition m_caseDef;
1051};
1052
1053class SymmetricOuterEdgeTest : public TestCase
1054{
1055public:
1056	SymmetricOuterEdgeTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const CaseDefinition caseDef)
1057		: TestCase	(testCtx, name, description)
1058		, m_caseDef	(caseDef)
1059	{
1060	}
1061
1062	void initPrograms (vk::SourceCollections& programCollection) const
1063	{
1064		const bool mirrorCoords = true;
1065		addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, getWindingUsage(m_caseDef.winding), getPointModeUsage(m_caseDef.usePointMode), mirrorCoords);
1066	}
1067
1068	TestInstance* createInstance (Context& context) const
1069	{
1070		return new SymmetricOuterEdgeTestInstance(context, m_caseDef);
1071	};
1072
1073private:
1074	const CaseDefinition m_caseDef;
1075};
1076
1077tcu::TestCase* makeOuterEdgeDivisionTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
1078{
1079	const CaseDefinition caseDef = { primitiveType, spacingMode, WINDING_LAST, false };  // winding is ignored by this test
1080	return new OuterEdgeDivisionTest(testCtx, name, description, caseDef);
1081}
1082
1083tcu::TestCase* makeOuterEdgeIndexIndependenceTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const Winding winding, const bool usePointMode)
1084{
1085	const CaseDefinition caseDef = { primitiveType, spacingMode, winding, usePointMode };
1086	return new OuterEdgeIndexIndependenceTest(testCtx, name, description, caseDef);
1087}
1088
1089tcu::TestCase* makeSymmetricOuterEdgeTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const Winding winding, const bool usePointMode)
1090{
1091	const CaseDefinition caseDef = { primitiveType, spacingMode, winding, usePointMode };
1092	return new SymmetricOuterEdgeTest(testCtx, name, description, caseDef);
1093}
1094
1095} // InvariantOuterEdge ns
1096
1097namespace PrimitiveSetInvariance
1098{
1099
1100enum CaseType
1101{
1102	CASETYPE_INVARIANT_PRIMITIVE_SET,
1103	CASETYPE_INVARIANT_TRIANGLE_SET,
1104	CASETYPE_INVARIANT_OUTER_TRIANGLE_SET,
1105	CASETYPE_INVARIANT_INNER_TRIANGLE_SET,
1106};
1107
1108struct CaseDefinition
1109{
1110	CaseType				caseType;
1111	TessPrimitiveType		primitiveType;
1112	SpacingMode				spacingMode;
1113	WindingUsage			windingUsage;
1114	bool					usePointMode;
1115};
1116
1117struct LevelCase
1118{
1119	std::vector<TessLevels>	levels;
1120	int						mem; //!< Subclass-defined arbitrary piece of data, for type of the levelcase, if needed.
1121
1122	LevelCase (const TessLevels& lev) : levels(std::vector<TessLevels>(1, lev)), mem(0) {}
1123	LevelCase (void) : mem(0) {}
1124};
1125
1126typedef tcu::Vector<tcu::Vec3, 3> Triangle;
1127
1128inline Triangle makeTriangle (const PerPrimitive& primitive)
1129{
1130	return Triangle(primitive.tessCoord[0].swizzle(0, 1, 2),
1131					primitive.tessCoord[1].swizzle(0, 1, 2),
1132					primitive.tessCoord[2].swizzle(0, 1, 2));
1133}
1134
1135//! Compare triangle sets, ignoring triangle order and vertex order within triangle, and possibly exclude some triangles too.
1136template <typename IsTriangleRelevantT>
1137bool compareTriangleSets (const PerPrimitiveVec&		primitivesA,
1138						  const PerPrimitiveVec&		primitivesB,
1139						  tcu::TestLog&					log,
1140						  const IsTriangleRelevantT&	isTriangleRelevant,
1141						  const char*					ignoredTriangleDescription = DE_NULL)
1142{
1143	typedef LexCompare<Triangle, 3, VecLexLessThan<3> >		TriangleLexLessThan;
1144	typedef std::set<Triangle, TriangleLexLessThan>			TriangleSet;
1145
1146	const int		numTrianglesA = static_cast<int>(primitivesA.size());
1147	const int		numTrianglesB = static_cast<int>(primitivesB.size());
1148	TriangleSet		trianglesA;
1149	TriangleSet		trianglesB;
1150
1151	for (int aOrB = 0; aOrB < 2; ++aOrB)
1152	{
1153		const PerPrimitiveVec& primitives	= aOrB == 0 ? primitivesA	: primitivesB;
1154		const int			   numTriangles	= aOrB == 0 ? numTrianglesA	: numTrianglesB;
1155		TriangleSet&		   triangles	= aOrB == 0 ? trianglesA	: trianglesB;
1156
1157		for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
1158		{
1159			Triangle triangle = makeTriangle(primitives[triNdx]);
1160
1161			if (isTriangleRelevant(triangle.getPtr()))
1162			{
1163				std::sort(triangle.getPtr(), triangle.getPtr()+3, VecLexLessThan<3>());
1164				triangles.insert(triangle);
1165			}
1166		}
1167	}
1168	{
1169		TriangleSet::const_iterator aIt = trianglesA.begin();
1170		TriangleSet::const_iterator bIt = trianglesB.begin();
1171
1172		while (aIt != trianglesA.end() || bIt != trianglesB.end())
1173		{
1174			const bool aEnd = aIt == trianglesA.end();
1175			const bool bEnd = bIt == trianglesB.end();
1176
1177			if (aEnd || bEnd || *aIt != *bIt)
1178			{
1179				log << tcu::TestLog::Message << "Failure: triangle sets in two cases are not equal (when ignoring triangle and vertex order"
1180					<< (ignoredTriangleDescription == DE_NULL ? "" : std::string() + ", and " + ignoredTriangleDescription) << ")" << tcu::TestLog::EndMessage;
1181
1182				if (!aEnd && (bEnd || TriangleLexLessThan()(*aIt, *bIt)))
1183					log << tcu::TestLog::Message << "Note: e.g. triangle " << *aIt << " exists for first case but not for second" << tcu::TestLog::EndMessage;
1184				else
1185					log << tcu::TestLog::Message << "Note: e.g. triangle " << *bIt << " exists for second case but not for first" << tcu::TestLog::EndMessage;
1186
1187				return false;
1188			}
1189
1190			++aIt;
1191			++bIt;
1192		}
1193
1194		return true;
1195	}
1196}
1197
1198template <typename ArgT, bool res>
1199struct ConstantUnaryPredicate
1200{
1201	bool operator() (const ArgT&) const { return res; }
1202};
1203
1204bool compareTriangleSets (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, tcu::TestLog& log)
1205{
1206	return compareTriangleSets(primitivesA, primitivesB, log, ConstantUnaryPredicate<const tcu::Vec3*, true>());
1207}
1208
1209//! Compare two sets of primitives. Order of primitives in each set is undefined, but within each primitive
1210//! vertex order and coordinates are expected to match exactly.
1211bool comparePrimitivesExact (const PerPrimitive* const primitivesA, const PerPrimitive* const primitivesB, const int numPrimitivesPerPatch)
1212{
1213	int ndxB = 0;
1214	for (int ndxA = 0; ndxA < numPrimitivesPerPatch; ++ndxA)
1215	{
1216		const tcu::Vec4 (&coordsA)[3] = primitivesA[ndxA].tessCoord;
1217		bool match = false;
1218
1219		// Actually both sets are usually somewhat sorted, so don't reset ndxB after each match. Instead, continue from the next index.
1220		for (int i = 0; i < numPrimitivesPerPatch; ++i)
1221		{
1222			const tcu::Vec4 (&coordsB)[3] = primitivesB[ndxB].tessCoord;
1223			ndxB = (ndxB + 1) % numPrimitivesPerPatch;
1224
1225			if (coordsA[0] == coordsB[0] && coordsA[1] == coordsB[1] && coordsA[2] == coordsB[2])
1226			{
1227				match = true;
1228				break;
1229			}
1230		}
1231
1232		if (!match)
1233			return false;
1234	}
1235	return true;
1236}
1237
1238/*--------------------------------------------------------------------*//*!
1239 * \brief Base class for testing invariance of entire primitive set
1240 *
1241 * Draws two patches with identical tessellation levels and compares the
1242 * results. Repeats the same with other programs that are only different
1243 * in irrelevant ways; compares the results between these two programs.
1244 * Also potentially compares to results produced by different tessellation
1245 * levels (see e.g. invariance rule #6).
1246 * Furthermore, repeats the above with multiple different tessellation
1247 * value sets.
1248 *
1249 * The manner of primitive set comparison is defined by subclass. E.g.
1250 * case for invariance rule #1 tests that same vertices come out, in same
1251 * order; rule #5 only requires that the same triangles are output, but
1252 * not necessarily in the same order.
1253 *//*--------------------------------------------------------------------*/
1254class InvarianceTestCase : public TestCase
1255{
1256public:
1257									InvarianceTestCase			(tcu::TestContext& context, const std::string& name, const std::string& description, const CaseDefinition& caseDef)
1258										: TestCase	(context, name, description)
1259										, m_caseDef	(caseDef) {}
1260
1261	virtual							~InvarianceTestCase			(void) {}
1262
1263	void							initPrograms				(SourceCollections& programCollection) const;
1264	TestInstance*					createInstance				(Context& context) const;
1265
1266private:
1267	const CaseDefinition			m_caseDef;
1268};
1269
1270void InvarianceTestCase::initPrograms (SourceCollections& programCollection) const
1271{
1272	addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, m_caseDef.windingUsage, getPointModeUsage(m_caseDef.usePointMode));
1273}
1274
1275class InvarianceTestInstance : public TestInstance
1276{
1277public:
1278									InvarianceTestInstance		(Context& context, const CaseDefinition& caseDef) : TestInstance(context), m_caseDef(caseDef) {}
1279	virtual							~InvarianceTestInstance		(void) {}
1280
1281	tcu::TestStatus					iterate						(void);
1282
1283protected:
1284	virtual std::vector<LevelCase>	genTessLevelCases			(void) const;
1285	virtual bool					compare						(const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int levelCaseMem) const = 0;
1286
1287	const CaseDefinition			m_caseDef;
1288};
1289
1290std::vector<LevelCase> InvarianceTestInstance::genTessLevelCases (void) const
1291{
1292	static const TessLevels basicTessLevelCases[] =
1293	{
1294		{ { 1.0f,	1.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
1295		{ { 63.0f,	24.0f	},	{ 15.0f,	42.0f,	10.0f,	12.0f	} },
1296		{ { 3.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
1297		{ { 4.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
1298		{ { 2.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
1299		{ { 5.0f,	6.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
1300		{ { 1.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
1301		{ { 5.0f,	1.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
1302		{ { 5.2f,	1.6f	},	{ 2.9f,		3.4f,	1.5f,	4.1f	} }
1303	};
1304
1305	std::vector<LevelCase> result;
1306	for (int i = 0; i < DE_LENGTH_OF_ARRAY(basicTessLevelCases); ++i)
1307		result.push_back(LevelCase(basicTessLevelCases[i]));
1308
1309	{
1310		de::Random rnd(123);
1311		for (int i = 0; i < 10; ++i)
1312		{
1313			TessLevels levels;
1314			for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.inner); ++j)
1315				levels.inner[j] = rnd.getFloat(1.0f, 16.0f);
1316			for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.outer); ++j)
1317				levels.outer[j] = rnd.getFloat(1.0f, 16.0f);
1318			result.push_back(LevelCase(levels));
1319		}
1320	}
1321
1322	return result;
1323}
1324
1325tcu::TestStatus InvarianceTestInstance::iterate (void)
1326{
1327	requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(),
1328					FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
1329
1330	const DeviceInterface&	vk					= m_context.getDeviceInterface();
1331	const VkDevice			device				= m_context.getDevice();
1332	const VkQueue			queue				= m_context.getUniversalQueue();
1333	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1334	Allocator&				allocator			= m_context.getDefaultAllocator();
1335
1336	const std::vector<LevelCase>	tessLevelCases				= genTessLevelCases();
1337	const int						numPatchesPerDrawCall		= 2;
1338	int								maxNumPrimitivesPerPatch	= 0;  // computed below
1339	std::vector<std::vector<int> >	primitiveCounts;
1340
1341	for (int caseNdx = 0; caseNdx < static_cast<int>(tessLevelCases.size()); ++caseNdx)
1342	{
1343		primitiveCounts.push_back(std::vector<int>());
1344		for (int levelNdx = 0; levelNdx < static_cast<int>(tessLevelCases[caseNdx].levels.size()); ++levelNdx)
1345		{
1346			const int primitiveCount = referencePrimitiveCount(m_caseDef.primitiveType, m_caseDef.spacingMode, m_caseDef.usePointMode,
1347															   &tessLevelCases[caseNdx].levels[levelNdx].inner[0], &tessLevelCases[caseNdx].levels[levelNdx].outer[0]);
1348			primitiveCounts.back().push_back(primitiveCount);
1349			maxNumPrimitivesPerPatch = de::max(maxNumPrimitivesPerPatch, primitiveCount);
1350		}
1351	}
1352
1353	// Vertex input attributes buffer: to pass tessellation levels
1354
1355	const VkFormat     vertexFormat        = VK_FORMAT_R32_SFLOAT;
1356	const deUint32     vertexStride        = tcu::getPixelSize(mapVkFormat(vertexFormat));
1357	const VkDeviceSize vertexDataSizeBytes = NUM_TESS_LEVELS * numPatchesPerDrawCall * vertexStride;
1358	const Buffer       vertexBuffer        (vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
1359
1360	// Output buffer: number of primitives and an array of PerPrimitive structures
1361
1362	const int		   resultBufferMaxVertices		= numPatchesPerDrawCall * maxNumPrimitivesPerPatch * numVerticesPerPrimitive(m_caseDef.primitiveType, m_caseDef.usePointMode);
1363	const int		   resultBufferTessCoordsOffset = (int)sizeof(deInt32) * 4;
1364	const VkDeviceSize resultBufferSizeBytes        = resultBufferTessCoordsOffset + resultBufferMaxVertices * sizeof(PerPrimitive);
1365	const Buffer       resultBuffer                 (vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
1366
1367	// Descriptors
1368
1369	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
1370		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_GEOMETRY_BIT)
1371		.build(vk, device));
1372
1373	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
1374		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1375		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1376
1377	const Unique<VkDescriptorSet> descriptorSet    (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1378	const VkDescriptorBufferInfo  resultBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
1379
1380	DescriptorSetUpdateBuilder()
1381		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
1382		.update(vk, device);
1383
1384	const Unique<VkRenderPass>     renderPass    (makeRenderPassWithoutAttachments (vk, device));
1385	const Unique<VkFramebuffer>    framebuffer   (makeFramebufferWithoutAttachments(vk, device, *renderPass));
1386	const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout               (vk, device, *descriptorSetLayout));
1387	const Unique<VkCommandPool>    cmdPool       (makeCommandPool                  (vk, device, queueFamilyIndex));
1388	const Unique<VkCommandBuffer>  cmdBuffer     (makeCommandBuffer                (vk, device, *cmdPool));
1389
1390	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < static_cast<int>(tessLevelCases.size()); ++tessLevelCaseNdx)
1391	{
1392		const LevelCase& levelCase = tessLevelCases[tessLevelCaseNdx];
1393		PerPrimitiveVec  firstPrim;
1394
1395		{
1396			tcu::TestLog& log = m_context.getTestContext().getLog();
1397			std::ostringstream tessLevelsStr;
1398
1399			for (int i = 0; i < static_cast<int>(levelCase.levels.size()); ++i)
1400				tessLevelsStr << (levelCase.levels.size() > 1u ? "\n" : "") << getTessellationLevelsString(levelCase.levels[i], m_caseDef.primitiveType);
1401
1402			log << tcu::TestLog::Message << "Tessellation level sets: " << tessLevelsStr.str() << tcu::TestLog::EndMessage;
1403		}
1404
1405		for (int subTessLevelCaseNdx = 0; subTessLevelCaseNdx < static_cast<int>(levelCase.levels.size()); ++subTessLevelCaseNdx)
1406		{
1407			const TessLevels& tessLevels = levelCase.levels[subTessLevelCaseNdx];
1408			{
1409				TessLevels data[2];
1410				data[0] = tessLevels;
1411				data[1] = tessLevels;
1412
1413				const Allocation& alloc = vertexBuffer.getAllocation();
1414				deMemcpy(alloc.getHostPtr(), data, sizeof(data));
1415				flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(data));
1416			}
1417
1418			int programNdx = 0;
1419			const std::vector<Winding> windingCases = getWindingCases(m_caseDef.windingUsage);
1420			for (std::vector<Winding>::const_iterator windingIter = windingCases.begin(); windingIter != windingCases.end(); ++windingIter)
1421			{
1422				const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
1423					.setPatchControlPoints        (NUM_TESS_LEVELS)
1424					.setVertexInputSingleAttribute(vertexFormat, vertexStride)
1425					.setShader                    (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					m_context.getBinaryCollection().get("vert"), DE_NULL)
1426					.setShader                    (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	m_context.getBinaryCollection().get("tesc"), DE_NULL)
1427					.setShader                    (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get(getProgramName("tese", *windingIter, m_caseDef.usePointMode)), DE_NULL)
1428					.setShader                    (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,                m_context.getBinaryCollection().get(getProgramName("geom", m_caseDef.usePointMode)), DE_NULL)
1429					.build                        (vk, device, *pipelineLayout, *renderPass));
1430
1431				{
1432					const Allocation& alloc = resultBuffer.getAllocation();
1433					deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(resultBufferSizeBytes));
1434					flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), resultBufferSizeBytes);
1435				}
1436
1437				beginCommandBuffer(vk, *cmdBuffer);
1438				beginRenderPassWithRasterizationDisabled(vk, *cmdBuffer, *renderPass, *framebuffer);
1439
1440				vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1441				vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1442				{
1443					const VkDeviceSize vertexBufferOffset = 0ull;
1444					vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1445				}
1446
1447				vk.cmdDraw(*cmdBuffer, numPatchesPerDrawCall * NUM_TESS_LEVELS, 1u, 0u, 0u);
1448				endRenderPass(vk, *cmdBuffer);
1449
1450				{
1451					const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
1452						VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes);
1453
1454					vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1455						0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
1456				}
1457
1458				endCommandBuffer(vk, *cmdBuffer);
1459				submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1460
1461				// Verify case result
1462				{
1463					const Allocation& resultAlloc = resultBuffer.getAllocation();
1464					invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSizeBytes);
1465
1466					const int				refNumPrimitives     = numPatchesPerDrawCall * primitiveCounts[tessLevelCaseNdx][subTessLevelCaseNdx];
1467					const int				numPrimitiveVertices = numVerticesPerPrimitive(m_caseDef.primitiveType, m_caseDef.usePointMode);
1468					const deInt32			numPrimitives        = *static_cast<deInt32*>(resultAlloc.getHostPtr());
1469					const PerPrimitiveVec	primitives           = sorted(readInterleavedData<PerPrimitive>(numPrimitives, resultAlloc.getHostPtr(), resultBufferTessCoordsOffset, sizeof(PerPrimitive)),
1470																		  byPatchPrimitiveID);
1471
1472					// If this fails then we didn't read all vertices from shader and test must be changed to allow more.
1473					DE_ASSERT(numPrimitiveVertices * numPrimitives <= resultBufferMaxVertices);
1474					DE_UNREF(numPrimitiveVertices);
1475
1476					tcu::TestLog& log = m_context.getTestContext().getLog();
1477
1478					if (numPrimitives != refNumPrimitives)
1479					{
1480						log << tcu::TestLog::Message << "Failure: got " << numPrimitives << " primitives, but expected " << refNumPrimitives << tcu::TestLog::EndMessage;
1481
1482						return tcu::TestStatus::fail("Invalid set of primitives");
1483					}
1484
1485					const int					half  = static_cast<int>(primitives.size() / 2);
1486					const PerPrimitiveVec		prim0 = PerPrimitiveVec(primitives.begin(), primitives.begin() + half);
1487					const PerPrimitive* const	prim1 = &primitives[half];
1488
1489					if (!comparePrimitivesExact(&prim0[0], prim1, half))
1490					{
1491							log << tcu::TestLog::Message << "Failure: tessellation coordinates differ between two primitives drawn in one draw call" << tcu::TestLog::EndMessage
1492								<< tcu::TestLog::Message << "Note: tessellation levels for both primitives were: " << getTessellationLevelsString(tessLevels, m_caseDef.primitiveType) << tcu::TestLog::EndMessage;
1493
1494							return tcu::TestStatus::fail("Invalid set of primitives");
1495					}
1496
1497					if (programNdx == 0 && subTessLevelCaseNdx == 0)
1498						firstPrim = prim0;
1499					else
1500					{
1501						const bool compareOk = compare(firstPrim, prim0, levelCase.mem);
1502						if (!compareOk)
1503						{
1504							log << tcu::TestLog::Message
1505								<< "Note: comparison of tessellation coordinates failed; comparison was made between following cases:\n"
1506								<< "  - case A: program 0, tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx].levels[0], m_caseDef.primitiveType) << "\n"
1507								<< "  - case B: program " << programNdx << ", tessellation levels: " << getTessellationLevelsString(tessLevels, m_caseDef.primitiveType)
1508								<< tcu::TestLog::EndMessage;
1509
1510							return tcu::TestStatus::fail("Invalid set of primitives");
1511						}
1512					}
1513				}
1514				++programNdx;
1515			}
1516		}
1517	}
1518	return tcu::TestStatus::pass("OK");
1519}
1520
1521/*--------------------------------------------------------------------*//*!
1522 * \brief Test invariance rule #1
1523 *
1524 * Test that the sequence of primitives input to the TES only depends on
1525 * the tessellation levels, tessellation mode, spacing mode, winding, and
1526 * point mode.
1527 *//*--------------------------------------------------------------------*/
1528class InvariantPrimitiveSetTestInstance : public InvarianceTestInstance
1529{
1530public:
1531	InvariantPrimitiveSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1532
1533protected:
1534	bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int) const
1535	{
1536		if (!comparePrimitivesExact(&primitivesA[0], &primitivesB[0], static_cast<int>(primitivesA.size())))
1537		{
1538			m_context.getTestContext().getLog()
1539				<< tcu::TestLog::Message << "Failure: tessellation coordinates differ between two programs" << tcu::TestLog::EndMessage;
1540
1541			return false;
1542		}
1543		return true;
1544	}
1545};
1546
1547/*--------------------------------------------------------------------*//*!
1548 * \brief Test invariance rule #5
1549 *
1550 * Test that the set of triangles input to the TES only depends on the
1551 * tessellation levels, tessellation mode and spacing mode. Specifically,
1552 * winding doesn't change the set of triangles, though it can change the
1553 * order in which they are input to TES, and can (and will) change the
1554 * vertex order within a triangle.
1555 *//*--------------------------------------------------------------------*/
1556class InvariantTriangleSetTestInstance : public InvarianceTestInstance
1557{
1558public:
1559	InvariantTriangleSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1560
1561protected:
1562	bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int) const
1563	{
1564		return compareTriangleSets(primitivesA, primitivesB, m_context.getTestContext().getLog());
1565	}
1566};
1567
1568/*--------------------------------------------------------------------*//*!
1569 * \brief Test invariance rule #6
1570 *
1571 * Test that the set of inner triangles input to the TES only depends on
1572 * the inner tessellation levels, tessellation mode and spacing mode.
1573 *//*--------------------------------------------------------------------*/
1574class InvariantInnerTriangleSetTestInstance : public InvarianceTestInstance
1575{
1576public:
1577	InvariantInnerTriangleSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1578
1579protected:
1580	std::vector<LevelCase> genTessLevelCases (void) const
1581	{
1582		const int						numSubCases		= 4;
1583		const std::vector<LevelCase>	baseResults		= InvarianceTestInstance::genTessLevelCases();
1584		std::vector<LevelCase>			result;
1585		de::Random						rnd				(123);
1586
1587		// Generate variants with different values for irrelevant levels.
1588		for (int baseNdx = 0; baseNdx < static_cast<int>(baseResults.size()); ++baseNdx)
1589		{
1590			const TessLevels&	base	= baseResults[baseNdx].levels[0];
1591			TessLevels			levels	= base;
1592			LevelCase			levelCase;
1593
1594			for (int subNdx = 0; subNdx < numSubCases; ++subNdx)
1595			{
1596				levelCase.levels.push_back(levels);
1597
1598				for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); ++i)
1599					levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
1600				if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1601					levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
1602			}
1603
1604			result.push_back(levelCase);
1605		}
1606
1607		return result;
1608	}
1609
1610	struct IsInnerTriangleTriangle
1611	{
1612		bool operator() (const tcu::Vec3* vertices) const
1613		{
1614			for (int v = 0; v < 3; ++v)
1615				for (int c = 0; c < 3; ++c)
1616					if (vertices[v][c] == 0.0f)
1617						return false;
1618			return true;
1619		}
1620	};
1621
1622	struct IsInnerQuadTriangle
1623	{
1624		bool operator() (const tcu::Vec3* vertices) const
1625		{
1626			for (int v = 0; v < 3; ++v)
1627				for (int c = 0; c < 2; ++c)
1628					if (vertices[v][c] == 0.0f || vertices[v][c] == 1.0f)
1629						return false;
1630			return true;
1631		}
1632	};
1633
1634	bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int) const
1635	{
1636		if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1637			return compareTriangleSets(primitivesA, primitivesB, m_context.getTestContext().getLog(), IsInnerTriangleTriangle(), "outer triangles");
1638		else if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
1639			return compareTriangleSets(primitivesA, primitivesB, m_context.getTestContext().getLog(), IsInnerQuadTriangle(), "outer triangles");
1640		else
1641		{
1642			DE_ASSERT(false);
1643			return false;
1644		}
1645	}
1646};
1647
1648/*--------------------------------------------------------------------*//*!
1649 * \brief Test invariance rule #7
1650 *
1651 * Test that the set of outer triangles input to the TES only depends on
1652 * tessellation mode, spacing mode and the inner and outer tessellation
1653 * levels corresponding to the inner and outer edges relevant to that
1654 * triangle.
1655 *//*--------------------------------------------------------------------*/
1656class InvariantOuterTriangleSetTestInstance : public InvarianceTestInstance
1657{
1658public:
1659	InvariantOuterTriangleSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1660
1661protected:
1662	std::vector<LevelCase> genTessLevelCases (void) const
1663	{
1664		const int						numSubCasesPerEdge	= 4;
1665		const int						numEdges			= m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES	? 3
1666															: m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS		? 4 : 0;
1667		const std::vector<LevelCase>	baseResult			= InvarianceTestInstance::genTessLevelCases();
1668		std::vector<LevelCase>			result;
1669		de::Random						rnd					(123);
1670
1671		// Generate variants with different values for irrelevant levels.
1672		for (int baseNdx = 0; baseNdx < static_cast<int>(baseResult.size()); ++baseNdx)
1673		{
1674			const TessLevels& base = baseResult[baseNdx].levels[0];
1675			if (base.inner[0] == 1.0f || (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS && base.inner[1] == 1.0f))
1676				continue;
1677
1678			for (int edgeNdx = 0; edgeNdx < numEdges; ++edgeNdx)
1679			{
1680				TessLevels	levels = base;
1681				LevelCase	levelCase;
1682				levelCase.mem = edgeNdx;
1683
1684				for (int subCaseNdx = 0; subCaseNdx < numSubCasesPerEdge; ++subCaseNdx)
1685				{
1686					levelCase.levels.push_back(levels);
1687
1688					for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); ++i)
1689					{
1690						if (i != edgeNdx)
1691							levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
1692					}
1693
1694					if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1695						levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
1696				}
1697
1698				result.push_back(levelCase);
1699			}
1700		}
1701
1702		return result;
1703	}
1704
1705	class IsTriangleTriangleOnOuterEdge
1706	{
1707	public:
1708		IsTriangleTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
1709		bool operator() (const tcu::Vec3* vertices) const
1710		{
1711			bool touchesAppropriateEdge = false;
1712			for (int v = 0; v < 3; ++v)
1713				if (vertices[v][m_edgeNdx] == 0.0f)
1714					touchesAppropriateEdge = true;
1715
1716			if (touchesAppropriateEdge)
1717			{
1718				const tcu::Vec3 avg = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
1719				return avg[m_edgeNdx] < avg[(m_edgeNdx+1)%3] &&
1720					   avg[m_edgeNdx] < avg[(m_edgeNdx+2)%3];
1721			}
1722			return false;
1723		}
1724
1725	private:
1726		const int m_edgeNdx;
1727	};
1728
1729	class IsQuadTriangleOnOuterEdge
1730	{
1731	public:
1732		IsQuadTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
1733
1734		bool onEdge (const tcu::Vec3& v) const
1735		{
1736			return v[m_edgeNdx%2] == (m_edgeNdx <= 1 ? 0.0f : 1.0f);
1737		}
1738
1739		static inline bool onAnyEdge (const tcu::Vec3& v)
1740		{
1741			return v[0] == 0.0f || v[0] == 1.0f || v[1] == 0.0f || v[1] == 1.0f;
1742		}
1743
1744		bool operator() (const tcu::Vec3* vertices) const
1745		{
1746			for (int v = 0; v < 3; ++v)
1747			{
1748				const tcu::Vec3& a = vertices[v];
1749				const tcu::Vec3& b = vertices[(v+1)%3];
1750				const tcu::Vec3& c = vertices[(v+2)%3];
1751				if (onEdge(a) && onEdge(b))
1752					return true;
1753				if (onEdge(c) && !onAnyEdge(a) && !onAnyEdge(b) && a[m_edgeNdx%2] == b[m_edgeNdx%2])
1754					return true;
1755			}
1756
1757			return false;
1758		}
1759
1760	private:
1761		const int m_edgeNdx;
1762	};
1763
1764	bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int outerEdgeNdx) const
1765	{
1766		if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1767		{
1768			return compareTriangleSets(primitivesA, primitivesB, m_context.getTestContext().getLog(),
1769									   IsTriangleTriangleOnOuterEdge(outerEdgeNdx),
1770									   ("inner triangles, and outer triangles corresponding to other edge than edge "
1771										+ outerEdgeDescriptions(m_caseDef.primitiveType)[outerEdgeNdx].description()).c_str());
1772		}
1773		else if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
1774		{
1775			return compareTriangleSets(primitivesA, primitivesB, m_context.getTestContext().getLog(),
1776									   IsQuadTriangleOnOuterEdge(outerEdgeNdx),
1777									   ("inner triangles, and outer triangles corresponding to other edge than edge "
1778										+ outerEdgeDescriptions(m_caseDef.primitiveType)[outerEdgeNdx].description()).c_str());
1779		}
1780		else
1781			DE_ASSERT(false);
1782
1783		return true;
1784	}
1785};
1786
1787TestInstance* InvarianceTestCase::createInstance (Context& context) const
1788{
1789	switch (m_caseDef.caseType)
1790	{
1791		case CASETYPE_INVARIANT_PRIMITIVE_SET:			return new InvariantPrimitiveSetTestInstance    (context, m_caseDef);
1792		case CASETYPE_INVARIANT_TRIANGLE_SET:			return new InvariantTriangleSetTestInstance     (context, m_caseDef);
1793		case CASETYPE_INVARIANT_OUTER_TRIANGLE_SET:		return new InvariantOuterTriangleSetTestInstance(context, m_caseDef);
1794		case CASETYPE_INVARIANT_INNER_TRIANGLE_SET:		return new InvariantInnerTriangleSetTestInstance(context, m_caseDef);
1795		default:
1796			DE_ASSERT(false);
1797			return DE_NULL;
1798	}
1799}
1800
1801TestCase* makeInvariantPrimitiveSetTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const Winding winding, const bool usePointMode)
1802{
1803	const CaseDefinition caseDef = { CASETYPE_INVARIANT_PRIMITIVE_SET, primitiveType, spacingMode, getWindingUsage(winding), usePointMode };
1804	return new InvarianceTestCase(testCtx, name, description, caseDef);
1805}
1806
1807TestCase* makeInvariantTriangleSetTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
1808{
1809	DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
1810	const CaseDefinition caseDef = { CASETYPE_INVARIANT_TRIANGLE_SET, primitiveType, spacingMode, WINDING_USAGE_VARY, false };
1811	return new InvarianceTestCase(testCtx, name, description, caseDef);
1812}
1813
1814TestCase* makeInvariantInnerTriangleSetTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
1815{
1816	DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
1817	const CaseDefinition caseDef = { CASETYPE_INVARIANT_INNER_TRIANGLE_SET, primitiveType, spacingMode, WINDING_USAGE_VARY, false };
1818	return new InvarianceTestCase(testCtx, name, description, caseDef);
1819}
1820
1821TestCase* makeInvariantOuterTriangleSetTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
1822{
1823	DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
1824	const CaseDefinition caseDef = { CASETYPE_INVARIANT_OUTER_TRIANGLE_SET, primitiveType, spacingMode, WINDING_USAGE_VARY, false };
1825	return new InvarianceTestCase(testCtx, name, description, caseDef);
1826}
1827
1828} // PrimitiveSetInvariance ns
1829
1830namespace TessCoordComponent
1831{
1832
1833enum CaseType
1834{
1835	CASETYPE_TESS_COORD_RANGE = 0,		//!< Test that all (relevant) components of tess coord are in [0,1].
1836	CASETYPE_ONE_MINUS_TESS_COORD,		//!< Test that for every (relevant) component c of a tess coord, 1.0-c is exact.
1837
1838	CASETYPE_LAST
1839};
1840
1841struct CaseDefinition
1842{
1843	CaseType			caseType;
1844	TessPrimitiveType	primitiveType;
1845	SpacingMode			spacingMode;
1846	Winding				winding;
1847	bool				usePointMode;
1848};
1849
1850std::vector<TessLevels> genTessLevelCases (const int numCases)
1851{
1852	de::Random				rnd(123);
1853	std::vector<TessLevels>	result;
1854
1855	for (int i = 0; i < numCases; ++i)
1856	{
1857		TessLevels levels;
1858		levels.inner[0] = rnd.getFloat(1.0f, 63.0f);
1859		levels.inner[1] = rnd.getFloat(1.0f, 63.0f);
1860		levels.outer[0] = rnd.getFloat(1.0f, 63.0f);
1861		levels.outer[1] = rnd.getFloat(1.0f, 63.0f);
1862		levels.outer[2] = rnd.getFloat(1.0f, 63.0f);
1863		levels.outer[3] = rnd.getFloat(1.0f, 63.0f);
1864		result.push_back(levels);
1865	}
1866
1867	return result;
1868}
1869
1870typedef bool (*CompareFunc)(tcu::TestLog& log, const float value);
1871
1872bool compareTessCoordRange (tcu::TestLog& log, const float value)
1873{
1874	if (!de::inRange(value, 0.0f, 1.0f))
1875	{
1876		log << tcu::TestLog::Message << "Failure: tess coord component isn't in range [0,1]" << tcu::TestLog::EndMessage;
1877		return false;
1878	}
1879	return true;
1880}
1881
1882bool compareOneMinusTessCoord (tcu::TestLog& log, const float value)
1883{
1884	if (value != 1.0f)
1885	{
1886		log << tcu::TestLog::Message << "Failure: comp + (1.0-comp) doesn't equal 1.0 for some component of tessellation coordinate" << tcu::TestLog::EndMessage;
1887		return false;
1888	}
1889	return true;
1890}
1891
1892void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
1893{
1894	// Vertex shader
1895	{
1896		std::ostringstream src;
1897		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
1898			<< "\n"
1899			<< "layout(location = 0) in  highp float in_v_attr;\n"
1900			<< "layout(location = 0) out highp float in_tc_attr;\n"
1901			<< "\n"
1902			<< "void main (void)\n"
1903			<< "{\n"
1904			<< "    in_tc_attr = in_v_attr;\n"
1905			<< "}\n";
1906
1907		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1908	}
1909
1910	// Tessellation control shader
1911	{
1912		std::ostringstream src;
1913		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
1914			<< "#extension GL_EXT_tessellation_shader : require\n"
1915			<< "\n"
1916			<< "layout(vertices = 1) out;\n"
1917			<< "\n"
1918			<< "layout(location = 0) in highp float in_tc_attr[];\n"
1919			<< "\n"
1920			<< "void main (void)\n"
1921			<< "{\n"
1922			<< "    gl_TessLevelInner[0] = in_tc_attr[0];\n"
1923			<< "    gl_TessLevelInner[1] = in_tc_attr[1];\n"
1924			<< "\n"
1925			<< "    gl_TessLevelOuter[0] = in_tc_attr[2];\n"
1926			<< "    gl_TessLevelOuter[1] = in_tc_attr[3];\n"
1927			<< "    gl_TessLevelOuter[2] = in_tc_attr[4];\n"
1928			<< "    gl_TessLevelOuter[3] = in_tc_attr[5];\n"
1929			<< "}\n";
1930
1931		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
1932	}
1933
1934	// Tessellation evaluation shader
1935	{
1936		std::ostringstream tessCoordSrc;
1937
1938		if (caseDef.caseType == CASETYPE_TESS_COORD_RANGE)
1939			tessCoordSrc << "    sb_out.tessCoord[index] = gl_TessCoord;\n";
1940		else if (caseDef.caseType == CASETYPE_ONE_MINUS_TESS_COORD)
1941		{
1942			const char* components[]  = { "x" , "y", "z" };
1943			const int   numComponents = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2);
1944
1945			for (int i = 0; i < numComponents; ++i)
1946				tessCoordSrc << "    {\n"
1947							 << "        float oneMinusComp        = 1.0 - gl_TessCoord." << components[i] << ";\n"
1948							 << "        sb_out.tessCoord[index]." << components[i] << " = gl_TessCoord." << components[i] << " + oneMinusComp;\n"
1949							 << "    }\n";
1950		}
1951		else
1952		{
1953			DE_ASSERT(false);
1954			return;
1955		}
1956
1957		std::ostringstream src;
1958		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
1959			<< "#extension GL_EXT_tessellation_shader : require\n"
1960			<< "\n"
1961			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
1962						 << getSpacingModeShaderName(caseDef.spacingMode) << ", "
1963						 << getWindingShaderName(caseDef.winding)
1964						 << (caseDef.usePointMode ? ", point_mode" : "") << ") in;\n"
1965			<< "\n"
1966			<< "layout(set = 0, binding = 0, std430) coherent restrict buffer Output {\n"
1967			<< "    int  numInvocations;\n"
1968			<< "    vec3 tessCoord[];\n"
1969			<< "} sb_out;\n"
1970			<< "\n"
1971			<< "void main (void)\n"
1972			<< "{\n"
1973			<< "    int index = atomicAdd(sb_out.numInvocations, 1);\n"
1974			<< tessCoordSrc.str()
1975			<< "}\n";
1976
1977		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
1978	}
1979}
1980
1981tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
1982{
1983	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
1984
1985	const DeviceInterface&	vk					= context.getDeviceInterface();
1986	const VkDevice			device				= context.getDevice();
1987	const VkQueue			queue				= context.getUniversalQueue();
1988	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
1989	Allocator&				allocator			= context.getDefaultAllocator();
1990
1991	const int						numTessLevelCases	= 32;
1992	const std::vector<TessLevels>	tessLevelCases		= genTessLevelCases(numTessLevelCases);
1993
1994	int maxNumVerticesInDrawCall = 0;
1995	for (int i = 0; i < numTessLevelCases; ++i)
1996		maxNumVerticesInDrawCall = de::max(maxNumVerticesInDrawCall, referenceVertexCount(caseDef.primitiveType, caseDef.spacingMode, caseDef.usePointMode,
1997										   &tessLevelCases[i].inner[0], &tessLevelCases[i].outer[0]));
1998
1999	// We may get more invocations than expected, so add some more space (arbitrary number).
2000	maxNumVerticesInDrawCall += 4;
2001
2002	// Vertex input attributes buffer: to pass tessellation levels
2003
2004	const VkFormat		vertexFormat        = VK_FORMAT_R32_SFLOAT;
2005	const deUint32		vertexStride        = tcu::getPixelSize(mapVkFormat(vertexFormat));
2006	const VkDeviceSize	vertexDataSizeBytes = NUM_TESS_LEVELS * vertexStride;
2007	const Buffer		vertexBuffer        (vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
2008
2009	DE_ASSERT(vertexDataSizeBytes == sizeof(TessLevels));
2010
2011	// Output buffer: number of invocations and array of tess coords
2012
2013	const int		   resultBufferTessCoordsOffset = (int)sizeof(deInt32) * 4;
2014	const VkDeviceSize resultBufferSizeBytes        = resultBufferTessCoordsOffset + maxNumVerticesInDrawCall * sizeof(tcu::Vec4);
2015	const Buffer       resultBuffer                 (vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
2016
2017	// Descriptors
2018
2019	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
2020		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
2021		.build(vk, device));
2022
2023	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
2024		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
2025		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
2026
2027	const Unique<VkDescriptorSet> descriptorSet    (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
2028	const VkDescriptorBufferInfo  resultBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
2029
2030	DescriptorSetUpdateBuilder()
2031		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
2032		.update(vk, device);
2033
2034	const Unique<VkRenderPass>     renderPass    (makeRenderPassWithoutAttachments (vk, device));
2035	const Unique<VkFramebuffer>    framebuffer   (makeFramebufferWithoutAttachments(vk, device, *renderPass));
2036	const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout               (vk, device, *descriptorSetLayout));
2037	const Unique<VkCommandPool>    cmdPool       (makeCommandPool                  (vk, device, queueFamilyIndex));
2038	const Unique<VkCommandBuffer>  cmdBuffer     (makeCommandBuffer                (vk, device, *cmdPool));
2039
2040	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
2041		.setPatchControlPoints        (NUM_TESS_LEVELS)
2042		.setVertexInputSingleAttribute(vertexFormat, vertexStride)
2043		.setShader                    (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					context.getBinaryCollection().get("vert"), DE_NULL)
2044		.setShader                    (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	context.getBinaryCollection().get("tesc"), DE_NULL)
2045		.setShader                    (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
2046		.build                        (vk, device, *pipelineLayout, *renderPass));
2047
2048	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < numTessLevelCases; ++tessLevelCaseNdx)
2049	{
2050		context.getTestContext().getLog()
2051			<< tcu::TestLog::Message
2052			<< "Testing with tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
2053			<< tcu::TestLog::EndMessage;
2054
2055		{
2056			const Allocation& alloc = vertexBuffer.getAllocation();
2057			deMemcpy(alloc.getHostPtr(), &tessLevelCases[tessLevelCaseNdx], sizeof(TessLevels));
2058			flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
2059		}
2060		{
2061			const Allocation& alloc = resultBuffer.getAllocation();
2062			deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(resultBufferSizeBytes));
2063			flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), resultBufferSizeBytes);
2064		}
2065
2066		beginCommandBuffer(vk, *cmdBuffer);
2067		beginRenderPassWithRasterizationDisabled(vk, *cmdBuffer, *renderPass, *framebuffer);
2068
2069		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2070		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
2071		{
2072			const VkDeviceSize vertexBufferOffset = 0ull;
2073			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
2074		}
2075
2076		vk.cmdDraw(*cmdBuffer, NUM_TESS_LEVELS, 1u, 0u, 0u);
2077		endRenderPass(vk, *cmdBuffer);
2078
2079		{
2080			const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
2081				VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes);
2082
2083			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
2084				0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
2085		}
2086
2087		endCommandBuffer(vk, *cmdBuffer);
2088		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2089
2090		// Verify case result
2091		{
2092			const Allocation& resultAlloc = resultBuffer.getAllocation();
2093			invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSizeBytes);
2094
2095			const deInt32				 numVertices = *static_cast<deInt32*>(resultAlloc.getHostPtr());
2096			const std::vector<tcu::Vec3> vertices    = readInterleavedData<tcu::Vec3>(numVertices, resultAlloc.getHostPtr(), resultBufferTessCoordsOffset, sizeof(tcu::Vec4));
2097
2098			// If this fails then we didn't read all vertices from shader and test must be changed to allow more.
2099			DE_ASSERT(numVertices <= maxNumVerticesInDrawCall);
2100
2101			tcu::TestLog& log           = context.getTestContext().getLog();
2102			const int     numComponents = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2);
2103
2104			CompareFunc compare = (caseDef.caseType == CASETYPE_TESS_COORD_RANGE     ? compareTessCoordRange :
2105								   caseDef.caseType == CASETYPE_ONE_MINUS_TESS_COORD ? compareOneMinusTessCoord : DE_NULL);
2106
2107			DE_ASSERT(compare != DE_NULL);
2108
2109			for (std::vector<tcu::Vec3>::const_iterator vertexIter = vertices.begin(); vertexIter != vertices.end(); ++vertexIter)
2110			for (int i = 0; i < numComponents; ++i)
2111				if (!compare(log, (*vertexIter)[i]))
2112				{
2113						log << tcu::TestLog::Message << "Note: got a wrong tessellation coordinate "
2114							<< (numComponents == 3 ? de::toString(*vertexIter) : de::toString(vertexIter->swizzle(0,1))) << tcu::TestLog::EndMessage;
2115
2116						tcu::TestStatus::fail("Invalid tessellation coordinate component");
2117				}
2118		}
2119	}
2120	return tcu::TestStatus::pass("OK");
2121}
2122
2123tcu::TestCase* makeTessCoordRangeTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const Winding winding, const bool usePointMode)
2124{
2125	const CaseDefinition caseDef = { CASETYPE_TESS_COORD_RANGE, primitiveType, spacingMode, winding, usePointMode };
2126	return createFunctionCaseWithPrograms(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, description, initPrograms, test, caseDef);
2127}
2128
2129tcu::TestCase* makeOneMinusTessCoordTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const Winding winding, const bool usePointMode)
2130{
2131	const CaseDefinition caseDef = { CASETYPE_ONE_MINUS_TESS_COORD, primitiveType, spacingMode, winding, usePointMode };
2132	return createFunctionCaseWithPrograms(testCtx, tcu::NODETYPE_SELF_VALIDATE, name, description, initPrograms, test, caseDef);
2133}
2134
2135} // TessCoordComponent ns
2136
2137} // anonymous
2138
2139//! These tests correspond to dEQP-GLES31.functional.tessellation.invariance.*
2140//! Original OpenGL ES tests used transform feedback to get vertices in primitive order. To emulate this behavior we have to use geometry shader,
2141//! which allows us to intercept verticess of final output primitives. This can't be done with tessellation shaders alone as number and order of
2142//! invocation is undefined.
2143tcu::TestCaseGroup* createInvarianceTests (tcu::TestContext& testCtx)
2144{
2145	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "invariance", "Test tessellation invariance rules"));
2146
2147	de::MovePtr<tcu::TestCaseGroup> invariantPrimitiveSetGroup              (new tcu::TestCaseGroup(testCtx, "primitive_set",					"Test invariance rule #1"));
2148	de::MovePtr<tcu::TestCaseGroup> invariantOuterEdgeGroup					(new tcu::TestCaseGroup(testCtx, "outer_edge_division",				"Test invariance rule #2"));
2149	de::MovePtr<tcu::TestCaseGroup> symmetricOuterEdgeGroup					(new tcu::TestCaseGroup(testCtx, "outer_edge_symmetry",				"Test invariance rule #3"));
2150	de::MovePtr<tcu::TestCaseGroup> outerEdgeVertexSetIndexIndependenceGroup(new tcu::TestCaseGroup(testCtx, "outer_edge_index_independence",	"Test invariance rule #4"));
2151	de::MovePtr<tcu::TestCaseGroup> invariantTriangleSetGroup				(new tcu::TestCaseGroup(testCtx, "triangle_set",					"Test invariance rule #5"));
2152	de::MovePtr<tcu::TestCaseGroup> invariantInnerTriangleSetGroup			(new tcu::TestCaseGroup(testCtx, "inner_triangle_set",				"Test invariance rule #6"));
2153	de::MovePtr<tcu::TestCaseGroup> invariantOuterTriangleSetGroup			(new tcu::TestCaseGroup(testCtx, "outer_triangle_set",				"Test invariance rule #7"));
2154	de::MovePtr<tcu::TestCaseGroup> tessCoordComponentRangeGroup			(new tcu::TestCaseGroup(testCtx, "tess_coord_component_range",		"Test invariance rule #8, first part"));
2155	de::MovePtr<tcu::TestCaseGroup> oneMinusTessCoordComponentGroup			(new tcu::TestCaseGroup(testCtx, "one_minus_tess_coord_component",	"Test invariance rule #8, second part"));
2156
2157	for (int primitiveTypeNdx = 0; primitiveTypeNdx < TESSPRIMITIVETYPE_LAST; ++primitiveTypeNdx)
2158	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
2159	{
2160		const TessPrimitiveType primitiveType = static_cast<TessPrimitiveType>(primitiveTypeNdx);
2161		const SpacingMode       spacingMode   = static_cast<SpacingMode>(spacingModeNdx);
2162		const bool              triOrQuad     = primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS;
2163		const std::string       primName      = getTessPrimitiveTypeShaderName(primitiveType);
2164		const std::string       primSpacName  = primName + "_" + getSpacingModeShaderName(spacingMode);
2165
2166		if (triOrQuad)
2167		{
2168			invariantOuterEdgeGroup->addChild       (    InvariantOuterEdge::makeOuterEdgeDivisionTest        (testCtx, primSpacName, "", primitiveType, spacingMode));
2169			invariantTriangleSetGroup->addChild     (PrimitiveSetInvariance::makeInvariantTriangleSetTest     (testCtx, primSpacName, "", primitiveType, spacingMode));
2170			invariantInnerTriangleSetGroup->addChild(PrimitiveSetInvariance::makeInvariantInnerTriangleSetTest(testCtx, primSpacName, "", primitiveType, spacingMode));
2171			invariantOuterTriangleSetGroup->addChild(PrimitiveSetInvariance::makeInvariantOuterTriangleSetTest(testCtx, primSpacName, "", primitiveType, spacingMode));
2172		}
2173
2174		for (int windingNdx = 0; windingNdx < WINDING_LAST; ++windingNdx)
2175		for (int usePointModeNdx = 0; usePointModeNdx <= 1; ++usePointModeNdx)
2176		{
2177			const Winding     winding               = static_cast<Winding>(windingNdx);
2178			const bool        usePointMode          = (usePointModeNdx != 0);
2179			const std::string primSpacWindPointName = primSpacName + "_" + getWindingShaderName(winding) + (usePointMode ? "_point_mode" : "");
2180
2181			invariantPrimitiveSetGroup->addChild     (PrimitiveSetInvariance::makeInvariantPrimitiveSetTest(testCtx, primSpacWindPointName, "", primitiveType, spacingMode, winding, usePointMode));
2182			tessCoordComponentRangeGroup->addChild   (    TessCoordComponent::makeTessCoordRangeTest       (testCtx, primSpacWindPointName, "", primitiveType, spacingMode, winding, usePointMode));
2183			oneMinusTessCoordComponentGroup->addChild(    TessCoordComponent::makeOneMinusTessCoordTest    (testCtx, primSpacWindPointName, "", primitiveType, spacingMode, winding, usePointMode));
2184			symmetricOuterEdgeGroup->addChild        (    InvariantOuterEdge::makeSymmetricOuterEdgeTest   (testCtx, primSpacWindPointName, "", primitiveType, spacingMode, winding, usePointMode));
2185
2186			if (triOrQuad)
2187				outerEdgeVertexSetIndexIndependenceGroup->addChild(InvariantOuterEdge::makeOuterEdgeIndexIndependenceTest(testCtx, primSpacWindPointName, "", primitiveType, spacingMode, winding, usePointMode));
2188		}
2189	}
2190
2191	group->addChild(invariantPrimitiveSetGroup.release());
2192	group->addChild(invariantOuterEdgeGroup.release());
2193	group->addChild(symmetricOuterEdgeGroup.release());
2194	group->addChild(outerEdgeVertexSetIndexIndependenceGroup.release());
2195	group->addChild(invariantTriangleSetGroup.release());
2196	group->addChild(invariantInnerTriangleSetGroup.release());
2197	group->addChild(invariantOuterTriangleSetGroup.release());
2198	group->addChild(tessCoordComponentRangeGroup.release());
2199	group->addChild(oneMinusTessCoordComponentGroup.release());
2200
2201	return group.release();
2202}
2203
2204} // tessellation
2205} // vkt
2206