1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2014 The Android Open Source Project
6 * Copyright (c) 2016 The Khronos Group Inc.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Tessellation Invariance Tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktTessellationInvarianceTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuVectorUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkTypeUtil.hpp"
38 #include "deUniquePtr.hpp"
39 #include "deStringUtil.hpp"
40 #include "deRandom.hpp"
48 namespace tessellation
58 NUM_TESS_LEVELS = 6, // two inner and four outer levels
63 WINDING_USAGE_CCW = 0,
70 inline WindingUsage getWindingUsage (const Winding winding)
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);
78 std::vector<Winding> getWindingCases (const WindingUsage windingUsage)
80 std::vector<Winding> cases;
83 case WINDING_USAGE_CCW:
84 cases.push_back(WINDING_CCW);
86 case WINDING_USAGE_CW:
87 cases.push_back(WINDING_CW);
89 case WINDING_USAGE_VARY:
90 cases.push_back(WINDING_CCW);
91 cases.push_back(WINDING_CW);
102 POINT_MODE_USAGE_DONT_USE = 0,
103 POINT_MODE_USAGE_USE,
104 POINT_MODE_USAGE_VARY,
106 POINT_MODE_USAGE_LAST,
109 inline PointModeUsage getPointModeUsage (const bool usePointMode)
111 return usePointMode ? POINT_MODE_USAGE_USE : POINT_MODE_USAGE_DONT_USE;
114 std::vector<bool> getUsePointModeCases (const PointModeUsage pointModeUsage)
116 std::vector<bool> cases;
117 switch (pointModeUsage)
119 case POINT_MODE_USAGE_DONT_USE:
120 cases.push_back(false);
122 case POINT_MODE_USAGE_USE:
123 cases.push_back(true);
125 case POINT_MODE_USAGE_VARY:
126 cases.push_back(false);
127 cases.push_back(true);
136 //! Data captured in the shader per output primitive (in geometry stage).
139 deInt32 patchPrimitiveID; //!< gl_PrimitiveID in tessellation evaluation shader
140 deInt32 primitiveID; //!< ID of an output primitive in geometry shader (user-defined)
142 deInt32 unused_padding[2];
144 tcu::Vec4 tessCoord[3]; //!< 3 coords for triangles/quads, 2 for isolines, 1 for point mode. Vec4 due to alignment.
147 typedef std::vector<PerPrimitive> PerPrimitiveVec;
149 inline bool byPatchPrimitiveID (const PerPrimitive& a, const PerPrimitive& b)
151 return a.patchPrimitiveID < b.patchPrimitiveID;
154 inline std::string getProgramName (const std::string& baseName, const Winding winding, const bool usePointMode)
156 std::ostringstream str;
157 str << baseName << "_" << getWindingShaderName(winding) << (usePointMode ? "_point_mode" : "");
161 inline std::string getProgramName (const std::string& baseName, const bool usePointMode)
163 std::ostringstream str;
164 str << baseName << (usePointMode ? "_point_mode" : "");
168 inline std::string getProgramDescription (const Winding winding, const bool usePointMode)
170 std::ostringstream str;
171 str << "winding mode " << getWindingShaderName(winding) << ", " << (usePointMode ? "" : "don't ") << "use point mode";
175 template <typename T, int N>
176 std::vector<T> arrayToVector (const T (&arr)[N])
178 return std::vector<T>(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
181 template <typename T, int N>
182 T arrayMax (const T (&arr)[N])
184 return *std::max_element(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
188 inline tcu::Vector<bool, Size> singleTrueMask (int index)
190 DE_ASSERT(de::inBounds(index, 0, Size));
191 tcu::Vector<bool, Size> result;
192 result[index] = true;
196 template <typename ContainerT, typename T>
197 inline bool contains (const ContainerT& c, const T& key)
199 return c.find(key) != c.end();
202 template <typename SeqT, int Size, typename Pred>
206 LexCompare (void) : m_pred(Pred()) {}
208 bool operator() (const SeqT& a, const SeqT& b) const
210 for (int i = 0; i < Size; ++i)
212 if (m_pred(a[i], b[i]))
214 if (m_pred(b[i], a[i]))
225 class VecLexLessThan : public LexCompare<tcu::Vector<float, Size>, Size, std::less<float> >
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)
242 std::ostringstream src;
243 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
245 << "layout(location = 0) in highp float in_v_attr;\n"
246 << "layout(location = 0) out highp float in_tc_attr;\n"
248 << "void main (void)\n"
250 << " in_tc_attr = in_v_attr;\n"
253 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
256 // Tessellation control shader
258 std::ostringstream src;
259 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
260 << "#extension GL_EXT_tessellation_shader : require\n"
262 << "layout(vertices = 1) out;\n"
264 << "layout(location = 0) in highp float in_tc_attr[];\n"
266 << "void main (void)\n"
268 << " gl_TessLevelInner[0] = in_tc_attr[0];\n"
269 << " gl_TessLevelInner[1] = in_tc_attr[1];\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"
277 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
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
286 // Alternative tess coordinates handling code
287 std::ostringstream tessEvalCoordSrc;
289 switch (primitiveType)
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"
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";
302 case TESSPRIMITIVETYPE_QUADS:
303 tessEvalCoordSrc << " float x = gl_TessCoord.x;\n"
304 << " float y = gl_TessCoord.y;\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";
311 case TESSPRIMITIVETYPE_ISOLINES:
312 tessEvalCoordSrc << " float x = gl_TessCoord.x;\n"
313 << " float y = gl_TessCoord.y;\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";
324 tessEvalCoordSrc << " ib_out.in_gs_tessCoord = vec4(gl_TessCoord, 0.0);\n";
326 const std::vector<Winding> windingCases = getWindingCases(windingUsage);
327 const std::vector<bool> usePointModeCases = getUsePointModeCases(pointModeUsage);
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)
332 // Tessellation evaluation shader
334 std::ostringstream src;
335 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
336 << "#extension GL_EXT_tessellation_shader : require\n"
338 << "layout(" << getTessPrimitiveTypeShaderName(primitiveType) << ", "
339 << getSpacingModeShaderName(spacingMode) << ", "
340 << getWindingShaderName(*windingIter)
341 << (*usePointModeIter ? ", point_mode" : "") << ") in;\n"
343 << "layout(location = 0) out " << perVertexInterfaceBlock << " ib_out;\n"
345 << "void main (void)\n"
347 << tessEvalCoordSrc.str()
348 << " ib_out.in_gs_primitiveID = gl_PrimitiveID;\n"
351 programCollection.glslSources.add(getProgramName("tese", *windingIter, *usePointModeIter)) << glu::TessellationEvaluationSource(src.str());
353 } // for windingNdx, usePointModeNdx
355 // Geometry shader: data is captured here.
357 for (std::vector<bool>::const_iterator usePointModeIter = usePointModeCases.begin(); usePointModeIter != usePointModeCases.end(); ++usePointModeIter)
359 const int numVertices = numVerticesPerPrimitive(primitiveType, *usePointModeIter); // Primitives that the tessellated patch comprises of.
361 std::ostringstream src;
362 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
363 << "#extension GL_EXT_geometry_shader : require\n"
365 << "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(primitiveType, *usePointModeIter) << ") in;\n"
366 << "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(primitiveType, *usePointModeIter) << ", max_vertices = " << numVertices << ") out;\n"
368 << "layout(location = 0) in " << perVertexInterfaceBlock << " ib_in[];\n"
370 << "struct PerPrimitive {\n"
371 << " int patchPrimitiveID;\n"
372 << " int primitiveID;\n"
373 << " vec4 tessCoord[3];\n"
376 << "layout(set = 0, binding = 0, std430) coherent restrict buffer Output {\n"
377 << " int numPrimitives;\n"
378 << " PerPrimitive primitive[];\n"
381 << "void main (void)\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)
390 << " gl_Position = vec4(0.0);\n"
391 << " EmitVertex();\n";
394 programCollection.glslSources.add(getProgramName("geom", *usePointModeIter)) << glu::GeometrySource(src.str());
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
404 int constantCoordinateIndex;
405 float constantCoordinateValueChoices[2];
406 int numConstantCoordinateValueChoices;
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; }
411 std::string description (void) const
413 static const char* const coordinateNames[] = { "u", "v", "w" };
415 for (int i = 0; i < numConstantCoordinateValueChoices; ++i)
416 result += std::string() + (i > 0 ? " or " : "") + coordinateNames[constantCoordinateIndex] + "=" + de::toString(constantCoordinateValueChoices[i]);
420 bool contains (const tcu::Vec3& v) const
422 for (int i = 0; i < numConstantCoordinateValueChoices; ++i)
423 if (v[constantCoordinateIndex] == constantCoordinateValueChoices[i])
429 std::vector<OuterEdgeDescription> outerEdgeDescriptions (const TessPrimitiveType primType)
431 static const OuterEdgeDescription triangleOuterEdgeDescriptions[3] =
433 OuterEdgeDescription(0, 0.0f),
434 OuterEdgeDescription(1, 0.0f),
435 OuterEdgeDescription(2, 0.0f)
438 static const OuterEdgeDescription quadOuterEdgeDescriptions[4] =
440 OuterEdgeDescription(0, 0.0f),
441 OuterEdgeDescription(1, 0.0f),
442 OuterEdgeDescription(0, 1.0f),
443 OuterEdgeDescription(1, 1.0f)
446 static const OuterEdgeDescription isolinesOuterEdgeDescriptions[1] =
448 OuterEdgeDescription(0, 0.0f, 1.0f),
453 case TESSPRIMITIVETYPE_TRIANGLES: return arrayToVector(triangleOuterEdgeDescriptions);
454 case TESSPRIMITIVETYPE_QUADS: return arrayToVector(quadOuterEdgeDescriptions);
455 case TESSPRIMITIVETYPE_ISOLINES: return arrayToVector(isolinesOuterEdgeDescriptions);
459 return std::vector<OuterEdgeDescription>();
463 namespace InvariantOuterEdge
466 struct CaseDefinition
468 TessPrimitiveType primitiveType;
469 SpacingMode spacingMode;
474 typedef std::set<tcu::Vec3, VecLexLessThan<3> > Vec3Set;
476 std::vector<float> generateRandomPatchTessLevels (const int numPatches, const int constantOuterLevelIndex, const float constantOuterLevel, de::Random& rnd)
478 std::vector<float> tessLevels(numPatches*NUM_TESS_LEVELS);
480 for (int patchNdx = 0; patchNdx < numPatches; ++patchNdx)
482 float* const inner = &tessLevels[patchNdx*NUM_TESS_LEVELS + 0];
483 float* const outer = &tessLevels[patchNdx*NUM_TESS_LEVELS + 2];
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);
494 std::vector<float> generatePatchTessLevels (const int numPatches, const int constantOuterLevelIndex, const float constantOuterLevel)
497 return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
500 int multiplePatchReferencePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* levels, int numPatches)
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]);
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])
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);
516 void logOuterTessellationLevel (tcu::TestLog& log, const float tessLevel, const OuterEdgeDescription& edgeDesc)
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;
523 void logPrimitiveCountError (tcu::TestLog& log, const int numPatchesToDraw, int numPrimitives, const int refNumPrimitives, const std::vector<float>& patchTessLevels)
525 log << tcu::TestLog::Message
526 << "Failure: the number of generated primitives is " << numPrimitives << ", expected at least " << refNumPrimitives
527 << tcu::TestLog::EndMessage;
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;
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;
542 class BaseTestInstance : public TestInstance
548 int refNumPrimitives;
549 int numPrimitiveVertices;
550 deInt32 numPrimitives;
551 PerPrimitiveVec primitives;
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);
559 static const float m_singleOuterEdgeLevels[];
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;
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 };
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))
612 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(),
613 FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
615 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(m_resultBuffer.get(), 0ull, m_resultBufferSizeBytes);
617 DescriptorSetUpdateBuilder()
618 .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
619 .update(m_context.getDeviceInterface(), m_context.getDevice());
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)
625 const DeviceInterface& vk = m_context.getDeviceInterface();
626 const VkDevice device = m_context.getDevice();
627 const VkQueue queue = m_context.getUniversalQueue();
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));
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);
644 beginCommandBuffer(vk, *m_cmdBuffer);
645 beginRenderPassWithRasterizationDisabled(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer);
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);
650 const VkDeviceSize vertexBufferOffset = 0ull;
651 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
654 vk.cmdDraw(*m_cmdBuffer, vertexCount, 1u, 0u, 0u);
655 endRenderPass(vk, *m_cmdBuffer);
658 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
659 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *m_resultBuffer, 0ull, m_resultBufferSizeBytes);
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);
665 endCommandBuffer(vk, *m_cmdBuffer);
666 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
668 // Read back and check results
670 const Allocation& resultAlloc = m_resultBuffer.getAllocation();
671 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_resultBufferSizeBytes);
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)),
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);
684 tcu::TestLog& log = m_context.getTestContext().getLog();
685 if (result.numPrimitives != result.refNumPrimitives)
687 logPrimitiveCountError(log, m_numPatchesToDraw, result.numPrimitives, result.refNumPrimitives, patchTessLevels);
688 result.success = false;
693 void BaseTestInstance::uploadVertexAttributes (const std::vector<float>& vertexData)
695 const DeviceInterface& vk = m_context.getDeviceInterface();
696 const VkDevice device = m_context.getDevice();
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));
703 /*--------------------------------------------------------------------*//*!
704 * \brief Test invariance rule #2
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.
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
719 OuterEdgeDivisionTestInstance (Context& context, const CaseDefinition caseDef) : BaseTestInstance (context, caseDef, 10) {}
720 tcu::TestStatus iterate (void);
723 tcu::TestStatus OuterEdgeDivisionTestInstance::iterate (void)
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)
728 const OuterEdgeDescription& edgeDesc = m_edgeDescriptions[outerEdgeIndex];
729 const std::vector<float> patchTessLevels = generatePatchTessLevels(m_numPatchesToDraw, outerEdgeIndex, m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
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.
733 uploadVertexAttributes(patchTessLevels);
734 logOuterTessellationLevel(m_context.getTestContext().getLog(), m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx], edgeDesc);
736 for (int windingNdx = 0; windingNdx < WINDING_LAST; ++windingNdx)
737 for (int usePointModeNdx = 0; usePointModeNdx <= 1; ++usePointModeNdx)
739 const Winding winding = static_cast<Winding>(windingNdx);
740 const bool usePointMode = (usePointModeNdx != 0);
741 const bool isFirstProgram = (windingNdx == 0 && usePointModeNdx == 0);
743 const DrawResult result = draw(static_cast<deUint32>(patchTessLevels.size()), patchTessLevels, winding, usePointMode);
746 return tcu::TestStatus::fail("Invalid set of vertices");
748 // Check the vertices of each patch.
750 int primitiveNdx = 0;
751 for (int patchNdx = 0; patchNdx < m_numPatchesToDraw; ++patchNdx)
753 DE_ASSERT(primitiveNdx < result.numPrimitives);
755 const float* const innerLevels = &patchTessLevels[NUM_TESS_LEVELS*patchNdx + 0];
756 const float* const outerLevels = &patchTessLevels[NUM_TESS_LEVELS*patchNdx + 2];
758 Vec3Set outerEdgeVertices;
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)
764 const tcu::Vec3& coord = result.primitives[primitiveNdx].tessCoord[i].swizzle(0, 1, 2);
765 if (edgeDesc.contains(coord))
766 outerEdgeVertices.insert(coord);
769 // Compare the vertices to those of the first patch (unless this is the first patch).
771 if (isFirstProgram && patchNdx == 0)
772 firstOuterEdgeVertices = outerEdgeVertices;
773 else if (firstOuterEdgeVertices != outerEdgeVertices)
775 tcu::TestLog& log = m_context.getTestContext().getLog();
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;
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;
791 return tcu::TestStatus::fail("Invalid set of vertices");
794 DE_ASSERT(primitiveNdx == result.numPrimitives);
795 } // for windingNdx, usePointModeNdx
796 } // for outerEdgeIndex, outerEdgeLevelCaseNdx
798 return tcu::TestStatus::pass("OK");
801 /*--------------------------------------------------------------------*//*!
802 * \brief Test invariance rule #4
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
810 OuterEdgeIndexIndependenceTestInstance (Context& context, const CaseDefinition caseDef) : BaseTestInstance (context, caseDef, 1) {}
811 tcu::TestStatus iterate (void);
814 tcu::TestStatus OuterEdgeIndexIndependenceTestInstance::iterate (void)
816 for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(m_singleOuterEdgeLevels); ++outerEdgeLevelCaseNdx)
818 Vec3Set firstEdgeVertices;
820 for (int outerEdgeIndex = 0; outerEdgeIndex < static_cast<int>(m_edgeDescriptions.size()); ++outerEdgeIndex)
822 const OuterEdgeDescription& edgeDesc = m_edgeDescriptions[outerEdgeIndex];
823 const std::vector<float> patchTessLevels = generatePatchTessLevels(m_numPatchesToDraw, outerEdgeIndex, m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
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);
829 // Verify case result
832 return tcu::TestStatus::fail("Invalid set of vertices");
834 Vec3Set currentEdgeVertices;
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)
840 const tcu::Vec3& coord = result.primitives[primitiveNdx].tessCoord[i].swizzle(0, 1, 2);
841 if (edgeDesc.contains(coord))
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,
859 if (outerEdgeIndex == 0)
860 firstEdgeVertices = currentEdgeVertices;
863 // Compare vertices of this edge to those of the first edge.
864 if (currentEdgeVertices != firstEdgeVertices)
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)
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;
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;
886 return tcu::TestStatus::fail("Invalid set of vertices");
891 return tcu::TestStatus::pass("OK");
894 /*--------------------------------------------------------------------*//*!
895 * \brief Test invariance rule #3
897 * Test that the vertices along an outer edge are placed symmetrically.
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
908 SymmetricOuterEdgeTestInstance (Context& context, const CaseDefinition caseDef) : BaseTestInstance (context, caseDef, 1) {}
909 tcu::TestStatus iterate (void);
912 tcu::TestStatus SymmetricOuterEdgeTestInstance::iterate (void)
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)
917 const OuterEdgeDescription& edgeDesc = m_edgeDescriptions[outerEdgeIndex];
918 const std::vector<float> patchTessLevels = generatePatchTessLevels(m_numPatchesToDraw, outerEdgeIndex, m_singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
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);
924 // Verify case result
927 return tcu::TestStatus::fail("Invalid set of vertices");
929 Vec3Set nonMirroredEdgeVertices;
930 Vec3Set mirroredEdgeVertices;
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)
936 const tcu::Vec3& coord = result.primitives[primitiveNdx].tessCoord[i].swizzle(0, 1, 2);
937 if (edgeDesc.contains(coord))
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)))
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)))
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)))
951 const bool isMirrored = result.primitives[primitiveNdx].tessCoord[i].w() > 0.5f;
953 mirroredEdgeVertices.insert(coord);
955 nonMirroredEdgeVertices.insert(coord);
959 if (m_caseDef.primitiveType != TESSPRIMITIVETYPE_ISOLINES)
961 // Check that both endpoints are present. Note that endpoints aren't mirrored by the shader, since they belong to more than one edge.
966 if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
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));
971 else if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
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));
979 if (!contains(nonMirroredEdgeVertices, endpointA) ||
980 !contains(nonMirroredEdgeVertices, endpointB))
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;
987 return tcu::TestStatus::fail("Invalid set of vertices");
989 nonMirroredEdgeVertices.erase(endpointA);
990 nonMirroredEdgeVertices.erase(endpointB);
993 if (nonMirroredEdgeVertices != mirroredEdgeVertices)
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;
1000 return tcu::TestStatus::fail("Invalid set of vertices");
1003 return tcu::TestStatus::pass("OK");
1006 class OuterEdgeDivisionTest : public TestCase
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)
1015 void initPrograms (vk::SourceCollections& programCollection) const
1017 addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, WINDING_USAGE_VARY, POINT_MODE_USAGE_VARY);
1020 TestInstance* createInstance (Context& context) const
1022 return new OuterEdgeDivisionTestInstance(context, m_caseDef);
1026 const CaseDefinition m_caseDef;
1029 class OuterEdgeIndexIndependenceTest : public TestCase
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)
1036 DE_ASSERT(m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
1039 void initPrograms (vk::SourceCollections& programCollection) const
1041 addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, getWindingUsage(m_caseDef.winding), getPointModeUsage(m_caseDef.usePointMode));
1044 TestInstance* createInstance (Context& context) const
1046 return new OuterEdgeIndexIndependenceTestInstance(context, m_caseDef);
1050 const CaseDefinition m_caseDef;
1053 class SymmetricOuterEdgeTest : public TestCase
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)
1062 void initPrograms (vk::SourceCollections& programCollection) const
1064 const bool mirrorCoords = true;
1065 addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, getWindingUsage(m_caseDef.winding), getPointModeUsage(m_caseDef.usePointMode), mirrorCoords);
1068 TestInstance* createInstance (Context& context) const
1070 return new SymmetricOuterEdgeTestInstance(context, m_caseDef);
1074 const CaseDefinition m_caseDef;
1077 tcu::TestCase* makeOuterEdgeDivisionTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
1079 const CaseDefinition caseDef = { primitiveType, spacingMode, WINDING_LAST, false }; // winding is ignored by this test
1080 return new OuterEdgeDivisionTest(testCtx, name, description, caseDef);
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)
1085 const CaseDefinition caseDef = { primitiveType, spacingMode, winding, usePointMode };
1086 return new OuterEdgeIndexIndependenceTest(testCtx, name, description, caseDef);
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)
1091 const CaseDefinition caseDef = { primitiveType, spacingMode, winding, usePointMode };
1092 return new SymmetricOuterEdgeTest(testCtx, name, description, caseDef);
1095 } // InvariantOuterEdge ns
1097 namespace PrimitiveSetInvariance
1102 CASETYPE_INVARIANT_PRIMITIVE_SET,
1103 CASETYPE_INVARIANT_TRIANGLE_SET,
1104 CASETYPE_INVARIANT_OUTER_TRIANGLE_SET,
1105 CASETYPE_INVARIANT_INNER_TRIANGLE_SET,
1108 struct CaseDefinition
1111 TessPrimitiveType primitiveType;
1112 SpacingMode spacingMode;
1113 WindingUsage windingUsage;
1119 std::vector<TessLevels> levels;
1120 int mem; //!< Subclass-defined arbitrary piece of data, for type of the levelcase, if needed.
1122 LevelCase (const TessLevels& lev) : levels(std::vector<TessLevels>(1, lev)), mem(0) {}
1123 LevelCase (void) : mem(0) {}
1126 typedef tcu::Vector<tcu::Vec3, 3> Triangle;
1128 inline Triangle makeTriangle (const PerPrimitive& primitive)
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));
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,
1140 const IsTriangleRelevantT& isTriangleRelevant,
1141 const char* ignoredTriangleDescription = DE_NULL)
1143 typedef LexCompare<Triangle, 3, VecLexLessThan<3> > TriangleLexLessThan;
1144 typedef std::set<Triangle, TriangleLexLessThan> TriangleSet;
1146 const int numTrianglesA = static_cast<int>(primitivesA.size());
1147 const int numTrianglesB = static_cast<int>(primitivesB.size());
1148 TriangleSet trianglesA;
1149 TriangleSet trianglesB;
1151 for (int aOrB = 0; aOrB < 2; ++aOrB)
1153 const PerPrimitiveVec& primitives = aOrB == 0 ? primitivesA : primitivesB;
1154 const int numTriangles = aOrB == 0 ? numTrianglesA : numTrianglesB;
1155 TriangleSet& triangles = aOrB == 0 ? trianglesA : trianglesB;
1157 for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
1159 Triangle triangle = makeTriangle(primitives[triNdx]);
1161 if (isTriangleRelevant(triangle.getPtr()))
1163 std::sort(triangle.getPtr(), triangle.getPtr()+3, VecLexLessThan<3>());
1164 triangles.insert(triangle);
1169 TriangleSet::const_iterator aIt = trianglesA.begin();
1170 TriangleSet::const_iterator bIt = trianglesB.begin();
1172 while (aIt != trianglesA.end() || bIt != trianglesB.end())
1174 const bool aEnd = aIt == trianglesA.end();
1175 const bool bEnd = bIt == trianglesB.end();
1177 if (aEnd || bEnd || *aIt != *bIt)
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;
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;
1185 log << tcu::TestLog::Message << "Note: e.g. triangle " << *bIt << " exists for second case but not for first" << tcu::TestLog::EndMessage;
1198 template <typename ArgT, bool res>
1199 struct ConstantUnaryPredicate
1201 bool operator() (const ArgT&) const { return res; }
1204 bool compareTriangleSets (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, tcu::TestLog& log)
1206 return compareTriangleSets(primitivesA, primitivesB, log, ConstantUnaryPredicate<const tcu::Vec3*, true>());
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)
1214 for (int ndxA = 0; ndxA < numPrimitivesPerPatch; ++ndxA)
1216 const tcu::Vec4 (&coordsA)[3] = primitivesA[ndxA].tessCoord;
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)
1222 const tcu::Vec4 (&coordsB)[3] = primitivesB[ndxB].tessCoord;
1223 ndxB = (ndxB + 1) % numPrimitivesPerPatch;
1225 if (coordsA[0] == coordsB[0] && coordsA[1] == coordsB[1] && coordsA[2] == coordsB[2])
1238 /*--------------------------------------------------------------------*//*!
1239 * \brief Base class for testing invariance of entire primitive set
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
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
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) {}
1261 virtual ~InvarianceTestCase (void) {}
1263 void initPrograms (SourceCollections& programCollection) const;
1264 TestInstance* createInstance (Context& context) const;
1267 const CaseDefinition m_caseDef;
1270 void InvarianceTestCase::initPrograms (SourceCollections& programCollection) const
1272 addDefaultPrograms(programCollection, m_caseDef.primitiveType, m_caseDef.spacingMode, m_caseDef.windingUsage, getPointModeUsage(m_caseDef.usePointMode));
1275 class InvarianceTestInstance : public TestInstance
1278 InvarianceTestInstance (Context& context, const CaseDefinition& caseDef) : TestInstance(context), m_caseDef(caseDef) {}
1279 virtual ~InvarianceTestInstance (void) {}
1281 tcu::TestStatus iterate (void);
1284 virtual std::vector<LevelCase> genTessLevelCases (void) const;
1285 virtual bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int levelCaseMem) const = 0;
1287 const CaseDefinition m_caseDef;
1290 std::vector<LevelCase> InvarianceTestInstance::genTessLevelCases (void) const
1292 static const TessLevels basicTessLevelCases[] =
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 } }
1305 std::vector<LevelCase> result;
1306 for (int i = 0; i < DE_LENGTH_OF_ARRAY(basicTessLevelCases); ++i)
1307 result.push_back(LevelCase(basicTessLevelCases[i]));
1310 de::Random rnd(123);
1311 for (int i = 0; i < 10; ++i)
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));
1325 tcu::TestStatus InvarianceTestInstance::iterate (void)
1327 requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(),
1328 FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
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();
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;
1341 for (int caseNdx = 0; caseNdx < static_cast<int>(tessLevelCases.size()); ++caseNdx)
1343 primitiveCounts.push_back(std::vector<int>());
1344 for (int levelNdx = 0; levelNdx < static_cast<int>(tessLevelCases[caseNdx].levels.size()); ++levelNdx)
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);
1353 // Vertex input attributes buffer: to pass tessellation levels
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);
1360 // Output buffer: number of primitives and an array of PerPrimitive structures
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);
1369 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
1370 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_GEOMETRY_BIT)
1371 .build(vk, device));
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));
1377 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1378 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
1380 DescriptorSetUpdateBuilder()
1381 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
1382 .update(vk, device);
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));
1390 for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < static_cast<int>(tessLevelCases.size()); ++tessLevelCaseNdx)
1392 const LevelCase& levelCase = tessLevelCases[tessLevelCaseNdx];
1393 PerPrimitiveVec firstPrim;
1396 tcu::TestLog& log = m_context.getTestContext().getLog();
1397 std::ostringstream tessLevelsStr;
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);
1402 log << tcu::TestLog::Message << "Tessellation level sets: " << tessLevelsStr.str() << tcu::TestLog::EndMessage;
1405 for (int subTessLevelCaseNdx = 0; subTessLevelCaseNdx < static_cast<int>(levelCase.levels.size()); ++subTessLevelCaseNdx)
1407 const TessLevels& tessLevels = levelCase.levels[subTessLevelCaseNdx];
1410 data[0] = tessLevels;
1411 data[1] = tessLevels;
1413 const Allocation& alloc = vertexBuffer.getAllocation();
1414 deMemcpy(alloc.getHostPtr(), data, sizeof(data));
1415 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(data));
1419 const std::vector<Winding> windingCases = getWindingCases(m_caseDef.windingUsage);
1420 for (std::vector<Winding>::const_iterator windingIter = windingCases.begin(); windingIter != windingCases.end(); ++windingIter)
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));
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);
1437 beginCommandBuffer(vk, *cmdBuffer);
1438 beginRenderPassWithRasterizationDisabled(vk, *cmdBuffer, *renderPass, *framebuffer);
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);
1443 const VkDeviceSize vertexBufferOffset = 0ull;
1444 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1447 vk.cmdDraw(*cmdBuffer, numPatchesPerDrawCall * NUM_TESS_LEVELS, 1u, 0u, 0u);
1448 endRenderPass(vk, *cmdBuffer);
1451 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
1452 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes);
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);
1458 endCommandBuffer(vk, *cmdBuffer);
1459 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1461 // Verify case result
1463 const Allocation& resultAlloc = resultBuffer.getAllocation();
1464 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSizeBytes);
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);
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);
1476 tcu::TestLog& log = m_context.getTestContext().getLog();
1478 if (numPrimitives != refNumPrimitives)
1480 log << tcu::TestLog::Message << "Failure: got " << numPrimitives << " primitives, but expected " << refNumPrimitives << tcu::TestLog::EndMessage;
1482 return tcu::TestStatus::fail("Invalid set of primitives");
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];
1489 if (!comparePrimitivesExact(&prim0[0], prim1, half))
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;
1494 return tcu::TestStatus::fail("Invalid set of primitives");
1497 if (programNdx == 0 && subTessLevelCaseNdx == 0)
1501 const bool compareOk = compare(firstPrim, prim0, levelCase.mem);
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;
1510 return tcu::TestStatus::fail("Invalid set of primitives");
1518 return tcu::TestStatus::pass("OK");
1521 /*--------------------------------------------------------------------*//*!
1522 * \brief Test invariance rule #1
1524 * Test that the sequence of primitives input to the TES only depends on
1525 * the tessellation levels, tessellation mode, spacing mode, winding, and
1527 *//*--------------------------------------------------------------------*/
1528 class InvariantPrimitiveSetTestInstance : public InvarianceTestInstance
1531 InvariantPrimitiveSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1534 bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int) const
1536 if (!comparePrimitivesExact(&primitivesA[0], &primitivesB[0], static_cast<int>(primitivesA.size())))
1538 m_context.getTestContext().getLog()
1539 << tcu::TestLog::Message << "Failure: tessellation coordinates differ between two programs" << tcu::TestLog::EndMessage;
1547 /*--------------------------------------------------------------------*//*!
1548 * \brief Test invariance rule #5
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
1559 InvariantTriangleSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1562 bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int) const
1564 return compareTriangleSets(primitivesA, primitivesB, m_context.getTestContext().getLog());
1568 /*--------------------------------------------------------------------*//*!
1569 * \brief Test invariance rule #6
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
1577 InvariantInnerTriangleSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1580 std::vector<LevelCase> genTessLevelCases (void) const
1582 const int numSubCases = 4;
1583 const std::vector<LevelCase> baseResults = InvarianceTestInstance::genTessLevelCases();
1584 std::vector<LevelCase> result;
1585 de::Random rnd (123);
1587 // Generate variants with different values for irrelevant levels.
1588 for (int baseNdx = 0; baseNdx < static_cast<int>(baseResults.size()); ++baseNdx)
1590 const TessLevels& base = baseResults[baseNdx].levels[0];
1591 TessLevels levels = base;
1592 LevelCase levelCase;
1594 for (int subNdx = 0; subNdx < numSubCases; ++subNdx)
1596 levelCase.levels.push_back(levels);
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);
1604 result.push_back(levelCase);
1610 struct IsInnerTriangleTriangle
1612 bool operator() (const tcu::Vec3* vertices) const
1614 for (int v = 0; v < 3; ++v)
1615 for (int c = 0; c < 3; ++c)
1616 if (vertices[v][c] == 0.0f)
1622 struct IsInnerQuadTriangle
1624 bool operator() (const tcu::Vec3* vertices) const
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)
1634 bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int) const
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");
1648 /*--------------------------------------------------------------------*//*!
1649 * \brief Test invariance rule #7
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
1655 *//*--------------------------------------------------------------------*/
1656 class InvariantOuterTriangleSetTestInstance : public InvarianceTestInstance
1659 InvariantOuterTriangleSetTestInstance (Context& context, const CaseDefinition& caseDef) : InvarianceTestInstance(context, caseDef) {}
1662 std::vector<LevelCase> genTessLevelCases (void) const
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);
1671 // Generate variants with different values for irrelevant levels.
1672 for (int baseNdx = 0; baseNdx < static_cast<int>(baseResult.size()); ++baseNdx)
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))
1678 for (int edgeNdx = 0; edgeNdx < numEdges; ++edgeNdx)
1680 TessLevels levels = base;
1681 LevelCase levelCase;
1682 levelCase.mem = edgeNdx;
1684 for (int subCaseNdx = 0; subCaseNdx < numSubCasesPerEdge; ++subCaseNdx)
1686 levelCase.levels.push_back(levels);
1688 for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); ++i)
1691 levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
1694 if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1695 levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
1698 result.push_back(levelCase);
1705 class IsTriangleTriangleOnOuterEdge
1708 IsTriangleTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
1709 bool operator() (const tcu::Vec3* vertices) const
1711 bool touchesAppropriateEdge = false;
1712 for (int v = 0; v < 3; ++v)
1713 if (vertices[v][m_edgeNdx] == 0.0f)
1714 touchesAppropriateEdge = true;
1716 if (touchesAppropriateEdge)
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];
1726 const int m_edgeNdx;
1729 class IsQuadTriangleOnOuterEdge
1732 IsQuadTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
1734 bool onEdge (const tcu::Vec3& v) const
1736 return v[m_edgeNdx%2] == (m_edgeNdx <= 1 ? 0.0f : 1.0f);
1739 static inline bool onAnyEdge (const tcu::Vec3& v)
1741 return v[0] == 0.0f || v[0] == 1.0f || v[1] == 0.0f || v[1] == 1.0f;
1744 bool operator() (const tcu::Vec3* vertices) const
1746 for (int v = 0; v < 3; ++v)
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))
1753 if (onEdge(c) && !onAnyEdge(a) && !onAnyEdge(b) && a[m_edgeNdx%2] == b[m_edgeNdx%2])
1761 const int m_edgeNdx;
1764 bool compare (const PerPrimitiveVec& primitivesA, const PerPrimitiveVec& primitivesB, const int outerEdgeNdx) const
1766 if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
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());
1773 else if (m_caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
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());
1787 TestInstance* InvarianceTestCase::createInstance (Context& context) const
1789 switch (m_caseDef.caseType)
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);
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)
1803 const CaseDefinition caseDef = { CASETYPE_INVARIANT_PRIMITIVE_SET, primitiveType, spacingMode, getWindingUsage(winding), usePointMode };
1804 return new InvarianceTestCase(testCtx, name, description, caseDef);
1807 TestCase* makeInvariantTriangleSetTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
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);
1814 TestCase* makeInvariantInnerTriangleSetTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
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);
1821 TestCase* makeInvariantOuterTriangleSetTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
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);
1828 } // PrimitiveSetInvariance ns
1830 namespace TessCoordComponent
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.
1841 struct CaseDefinition
1844 TessPrimitiveType primitiveType;
1845 SpacingMode spacingMode;
1850 std::vector<TessLevels> genTessLevelCases (const int numCases)
1852 de::Random rnd(123);
1853 std::vector<TessLevels> result;
1855 for (int i = 0; i < numCases; ++i)
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);
1870 typedef bool (*CompareFunc)(tcu::TestLog& log, const float value);
1872 bool compareTessCoordRange (tcu::TestLog& log, const float value)
1874 if (!de::inRange(value, 0.0f, 1.0f))
1876 log << tcu::TestLog::Message << "Failure: tess coord component isn't in range [0,1]" << tcu::TestLog::EndMessage;
1882 bool compareOneMinusTessCoord (tcu::TestLog& log, const float value)
1886 log << tcu::TestLog::Message << "Failure: comp + (1.0-comp) doesn't equal 1.0 for some component of tessellation coordinate" << tcu::TestLog::EndMessage;
1892 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
1896 std::ostringstream src;
1897 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
1899 << "layout(location = 0) in highp float in_v_attr;\n"
1900 << "layout(location = 0) out highp float in_tc_attr;\n"
1902 << "void main (void)\n"
1904 << " in_tc_attr = in_v_attr;\n"
1907 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1910 // Tessellation control shader
1912 std::ostringstream src;
1913 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
1914 << "#extension GL_EXT_tessellation_shader : require\n"
1916 << "layout(vertices = 1) out;\n"
1918 << "layout(location = 0) in highp float in_tc_attr[];\n"
1920 << "void main (void)\n"
1922 << " gl_TessLevelInner[0] = in_tc_attr[0];\n"
1923 << " gl_TessLevelInner[1] = in_tc_attr[1];\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"
1931 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
1934 // Tessellation evaluation shader
1936 std::ostringstream tessCoordSrc;
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)
1942 const char* components[] = { "x" , "y", "z" };
1943 const int numComponents = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2);
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"
1957 std::ostringstream src;
1958 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
1959 << "#extension GL_EXT_tessellation_shader : require\n"
1961 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
1962 << getSpacingModeShaderName(caseDef.spacingMode) << ", "
1963 << getWindingShaderName(caseDef.winding)
1964 << (caseDef.usePointMode ? ", point_mode" : "") << ") in;\n"
1966 << "layout(set = 0, binding = 0, std430) coherent restrict buffer Output {\n"
1967 << " int numInvocations;\n"
1968 << " vec3 tessCoord[];\n"
1971 << "void main (void)\n"
1973 << " int index = atomicAdd(sb_out.numInvocations, 1);\n"
1974 << tessCoordSrc.str()
1977 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
1981 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
1983 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
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();
1991 const int numTessLevelCases = 32;
1992 const std::vector<TessLevels> tessLevelCases = genTessLevelCases(numTessLevelCases);
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]));
1999 // We may get more invocations than expected, so add some more space (arbitrary number).
2000 maxNumVerticesInDrawCall += 4;
2002 // Vertex input attributes buffer: to pass tessellation levels
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);
2009 DE_ASSERT(vertexDataSizeBytes == sizeof(TessLevels));
2011 // Output buffer: number of invocations and array of tess coords
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);
2019 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
2020 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
2021 .build(vk, device));
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));
2027 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
2028 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
2030 DescriptorSetUpdateBuilder()
2031 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
2032 .update(vk, device);
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));
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));
2048 for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < numTessLevelCases; ++tessLevelCaseNdx)
2050 context.getTestContext().getLog()
2051 << tcu::TestLog::Message
2052 << "Testing with tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
2053 << tcu::TestLog::EndMessage;
2056 const Allocation& alloc = vertexBuffer.getAllocation();
2057 deMemcpy(alloc.getHostPtr(), &tessLevelCases[tessLevelCaseNdx], sizeof(TessLevels));
2058 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
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);
2066 beginCommandBuffer(vk, *cmdBuffer);
2067 beginRenderPassWithRasterizationDisabled(vk, *cmdBuffer, *renderPass, *framebuffer);
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);
2072 const VkDeviceSize vertexBufferOffset = 0ull;
2073 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
2076 vk.cmdDraw(*cmdBuffer, NUM_TESS_LEVELS, 1u, 0u, 0u);
2077 endRenderPass(vk, *cmdBuffer);
2080 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
2081 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes);
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);
2087 endCommandBuffer(vk, *cmdBuffer);
2088 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2090 // Verify case result
2092 const Allocation& resultAlloc = resultBuffer.getAllocation();
2093 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSizeBytes);
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));
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);
2101 tcu::TestLog& log = context.getTestContext().getLog();
2102 const int numComponents = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2);
2104 CompareFunc compare = (caseDef.caseType == CASETYPE_TESS_COORD_RANGE ? compareTessCoordRange :
2105 caseDef.caseType == CASETYPE_ONE_MINUS_TESS_COORD ? compareOneMinusTessCoord : DE_NULL);
2107 DE_ASSERT(compare != DE_NULL);
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]))
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;
2116 tcu::TestStatus::fail("Invalid tessellation coordinate component");
2120 return tcu::TestStatus::pass("OK");
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)
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);
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)
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);
2135 } // TessCoordComponent ns
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)
2145 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "invariance", "Test tessellation invariance rules"));
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"));
2157 for (int primitiveTypeNdx = 0; primitiveTypeNdx < TESSPRIMITIVETYPE_LAST; ++primitiveTypeNdx)
2158 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
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);
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));
2174 for (int windingNdx = 0; windingNdx < WINDING_LAST; ++windingNdx)
2175 for (int usePointModeNdx = 0; usePointModeNdx <= 1; ++usePointModeNdx)
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" : "");
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));
2187 outerEdgeVertexSetIndexIndependenceGroup->addChild(InvariantOuterEdge::makeOuterEdgeIndexIndependenceTest(testCtx, primSpacWindPointName, "", primitiveType, spacingMode, winding, usePointMode));
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());
2201 return group.release();