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