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