1 #ifndef _VKTTESSELLATIONUTIL_HPP
2 #define _VKTTESSELLATIONUTIL_HPP
3 /*------------------------------------------------------------------------
4 * Vulkan Conformance Tests
5 * ------------------------
7 * Copyright (c) 2014 The Android Open Source Project
8 * Copyright (c) 2016 The Khronos Group Inc.
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
24 * \brief Tessellation Utilities
25 *//*--------------------------------------------------------------------*/
28 #include "vkMemUtil.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vktTestCase.hpp"
36 #include "tcuVector.hpp"
37 #include "tcuMaybe.hpp"
39 #include "deStringUtil.hpp"
41 #include <algorithm> // sort
42 #include <iterator> // distance
46 namespace tessellation
49 class GraphicsPipelineBuilder
52 GraphicsPipelineBuilder (void) : m_renderSize (0, 0)
53 , m_shaderStageFlags (0u)
54 , m_cullModeFlags (vk::VK_CULL_MODE_NONE)
55 , m_frontFace (vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
56 , m_patchControlPoints (1u)
57 , m_blendEnable (false)
58 , m_primitiveTopology (vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
59 , m_tessellationDomainOrigin (tcu::Nothing) {}
61 GraphicsPipelineBuilder& setRenderSize (const tcu::IVec2& size) { m_renderSize = size; return *this; }
62 GraphicsPipelineBuilder& setShader (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkShaderStageFlagBits stage, const vk::ProgramBinary& binary, const vk::VkSpecializationInfo* specInfo);
63 GraphicsPipelineBuilder& setPatchControlPoints (const deUint32 controlPoints) { m_patchControlPoints = controlPoints; return *this; }
64 GraphicsPipelineBuilder& setCullModeFlags (const vk::VkCullModeFlags cullModeFlags) { m_cullModeFlags = cullModeFlags; return *this; }
65 GraphicsPipelineBuilder& setFrontFace (const vk::VkFrontFace frontFace) { m_frontFace = frontFace; return *this; }
66 GraphicsPipelineBuilder& setBlend (const bool enable) { m_blendEnable = enable; return *this; }
68 //! Applies only to pipelines without tessellation shaders.
69 GraphicsPipelineBuilder& setPrimitiveTopology (const vk::VkPrimitiveTopology topology) { m_primitiveTopology = topology; return *this; }
71 GraphicsPipelineBuilder& addVertexBinding (const vk::VkVertexInputBindingDescription vertexBinding) { m_vertexInputBindings.push_back(vertexBinding); return *this; }
72 GraphicsPipelineBuilder& addVertexAttribute (const vk::VkVertexInputAttributeDescription vertexAttribute) { m_vertexInputAttributes.push_back(vertexAttribute); return *this; }
74 //! Basic vertex input configuration (uses biding 0, location 0, etc.)
75 GraphicsPipelineBuilder& setVertexInputSingleAttribute (const vk::VkFormat vertexFormat, const deUint32 stride);
77 //! If tessellation domain origin is set, pipeline requires VK__maintenance2
78 GraphicsPipelineBuilder& setTessellationDomainOrigin (const vk::VkTessellationDomainOrigin domainOrigin) { return setTessellationDomainOrigin(tcu::just(domainOrigin)); }
79 GraphicsPipelineBuilder& setTessellationDomainOrigin (const tcu::Maybe<vk::VkTessellationDomainOrigin>& domainOrigin) { m_tessellationDomainOrigin = domainOrigin; return *this; }
81 vk::Move<vk::VkPipeline> build (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkRenderPass renderPass);
84 tcu::IVec2 m_renderSize;
85 vk::Move<vk::VkShaderModule> m_vertexShaderModule;
86 vk::Move<vk::VkShaderModule> m_fragmentShaderModule;
87 vk::Move<vk::VkShaderModule> m_geometryShaderModule;
88 vk::Move<vk::VkShaderModule> m_tessControlShaderModule;
89 vk::Move<vk::VkShaderModule> m_tessEvaluationShaderModule;
90 std::vector<vk::VkPipelineShaderStageCreateInfo> m_shaderStages;
91 std::vector<vk::VkVertexInputBindingDescription> m_vertexInputBindings;
92 std::vector<vk::VkVertexInputAttributeDescription> m_vertexInputAttributes;
93 vk::VkShaderStageFlags m_shaderStageFlags;
94 vk::VkCullModeFlags m_cullModeFlags;
95 vk::VkFrontFace m_frontFace;
96 deUint32 m_patchControlPoints;
98 vk::VkPrimitiveTopology m_primitiveTopology;
99 tcu::Maybe<vk::VkTessellationDomainOrigin> m_tessellationDomainOrigin;
101 GraphicsPipelineBuilder (const GraphicsPipelineBuilder&); // "deleted"
102 GraphicsPipelineBuilder& operator= (const GraphicsPipelineBuilder&);
111 enum TessPrimitiveType
113 TESSPRIMITIVETYPE_TRIANGLES = 0,
114 TESSPRIMITIVETYPE_QUADS,
115 TESSPRIMITIVETYPE_ISOLINES,
117 TESSPRIMITIVETYPE_LAST,
122 SPACINGMODE_EQUAL = 0,
123 SPACINGMODE_FRACTIONAL_ODD,
124 SPACINGMODE_FRACTIONAL_EVEN,
139 SHADER_LANGUAGE_GLSL = 0,
140 SHADER_LANGUAGE_HLSL = 1,
142 SHADER_LANGUAGE_LAST,
147 FEATURE_TESSELLATION_SHADER = 1u << 0,
148 FEATURE_GEOMETRY_SHADER = 1u << 1,
149 FEATURE_SHADER_FLOAT_64 = 1u << 2,
150 FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS = 1u << 3,
151 FEATURE_FRAGMENT_STORES_AND_ATOMICS = 1u << 4,
152 FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE = 1u << 5,
154 typedef deUint32 FeatureFlags;
156 vk::VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const vk::VkFormat format, const vk::VkImageUsageFlags usage, const deUint32 numArrayLayers);
157 vk::Move<vk::VkRenderPass> makeRenderPassWithoutAttachments (const vk::DeviceInterface& vk, const vk::VkDevice device);
158 vk::VkBufferImageCopy makeBufferImageCopy (const vk::VkExtent3D extent, const vk::VkImageSubresourceLayers subresourceLayers);
159 void beginRenderPassWithRasterizationDisabled (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer);
160 void requireFeatures (const vk::InstanceInterface& vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags);
161 float getClampedTessLevel (const SpacingMode mode, const float tessLevel);
162 int getRoundedTessLevel (const SpacingMode mode, const float clampedTessLevel);
163 int getClampedRoundedTessLevel (const SpacingMode mode, const float tessLevel);
164 void getClampedRoundedTriangleTessLevels (const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
165 void getClampedRoundedQuadTessLevels (const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
166 void getClampedRoundedIsolineTessLevels (const SpacingMode mode, const float* outerSrc, int* outerDst);
167 int numOuterTessellationLevels (const TessPrimitiveType primitiveType);
168 std::string getTessellationLevelsString (const TessLevels& tessLevels, const TessPrimitiveType primitiveType);
169 std::string getTessellationLevelsString (const float* inner, const float* outer);
170 bool isPatchDiscarded (const TessPrimitiveType primitiveType, const float* outerLevels);
171 std::vector<tcu::Vec3> generateReferenceTriangleTessCoords (const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2);
172 std::vector<tcu::Vec3> generateReferenceQuadTessCoords (const SpacingMode spacingMode, const int inner0, const int inner1, const int outer0, const int outer1, const int outer2, const int outer3);
173 std::vector<tcu::Vec3> generateReferenceIsolineTessCoords (const int outer0, const int outer1);
174 int referenceVertexCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
175 int referencePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
176 int numVerticesPerPrimitive (const TessPrimitiveType primitiveType, const bool usePointMode);
178 static inline const char* getTessPrimitiveTypeShaderName (const TessPrimitiveType type, bool forSpirv = false)
180 static std::string primitiveName[][2] =
182 // glsl name spirv name
183 { "triangles", "Triangles"},
184 { "quads" , "Quads" },
185 { "isolines" , "Isolines" }
188 if (type >= TESSPRIMITIVETYPE_LAST)
190 DE_FATAL("Unexpected primitive type.");
194 return primitiveName[type][forSpirv].c_str();
197 static inline const char* getDomainName (const TessPrimitiveType type)
201 case TESSPRIMITIVETYPE_TRIANGLES: return "tri";
202 case TESSPRIMITIVETYPE_QUADS: return "quad";
203 case TESSPRIMITIVETYPE_ISOLINES: return "isoline";
205 DE_FATAL("Unexpected primitive type.");
210 static inline const char* getOutputTopologyName (const TessPrimitiveType type, const Winding winding, const bool usePointMode)
214 else if (type == TESSPRIMITIVETYPE_TRIANGLES || type == TESSPRIMITIVETYPE_QUADS)
215 return (winding == WINDING_CCW ? "triangle_ccw" : "triangle_cw");
216 else if (type == TESSPRIMITIVETYPE_ISOLINES)
219 DE_FATAL("Unexpected primitive type.");
223 static inline const char* getSpacingModeShaderName (SpacingMode mode, bool forSpirv = false)
225 static std::string spacingName[][2] =
227 // glsl name spirv name
228 { "equal_spacing", "SpacingEqual"},
229 { "fractional_odd_spacing", "SpacingFractionalOdd" },
230 { "fractional_even_spacing", "SpacingFractionalEven" }
233 if (mode >= SPACINGMODE_LAST)
235 DE_FATAL("Unexpected spacing type.");
239 return spacingName[mode][forSpirv].c_str();
242 static inline const char* getPartitioningShaderName (SpacingMode mode)
246 case SPACINGMODE_EQUAL: return "integer";
247 case SPACINGMODE_FRACTIONAL_ODD: return "fractional_odd";
248 case SPACINGMODE_FRACTIONAL_EVEN: return "fractional_even";
250 DE_FATAL("Unexpected spacing mode.");
255 static inline const char* getWindingShaderName (const Winding winding)
259 case WINDING_CCW: return "ccw";
260 case WINDING_CW: return "cw";
262 DE_FATAL("Unexpected winding type.");
267 static inline const char* getShaderLanguageName (const ShaderLanguage language)
271 case SHADER_LANGUAGE_GLSL: return "glsl";
272 case SHADER_LANGUAGE_HLSL: return "hlsl";
274 DE_FATAL("Unexpected shader language.");
279 static inline const char* getGeometryShaderInputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
286 case TESSPRIMITIVETYPE_TRIANGLES:
287 case TESSPRIMITIVETYPE_QUADS:
290 case TESSPRIMITIVETYPE_ISOLINES:
294 DE_FATAL("Unexpected primitive type.");
299 static inline const char* getGeometryShaderOutputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
306 case TESSPRIMITIVETYPE_TRIANGLES:
307 case TESSPRIMITIVETYPE_QUADS:
308 return "triangle_strip";
310 case TESSPRIMITIVETYPE_ISOLINES:
314 DE_FATAL("Unexpected primitive type.");
319 #ifndef CTS_USES_VULKANSC
321 static inline const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* getPortability (const Context& context)
323 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
324 return &context.getPortabilitySubsetFeatures();
328 static inline void checkIsolines (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features)
330 if (!features.tessellationIsolines)
331 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Tessellation iso lines are not supported by this implementation");
334 static inline void checkPrimitive (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features, const TessPrimitiveType primitive)
336 if (primitive == TESSPRIMITIVETYPE_ISOLINES)
337 checkIsolines(features);
340 static inline void checkSupportPrimitive (Context& context, const TessPrimitiveType primitive)
342 if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* const features = getPortability(context))
343 checkPrimitive(*features, primitive);
346 static inline void checkPointMode (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features)
348 if (!features.tessellationPointMode)
349 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Tessellation point mode is not supported by this implementation");
352 #endif // CTS_USES_VULKANSC
355 inline std::size_t sizeInBytes (const std::vector<T>& vec)
357 return vec.size() * sizeof(vec[0]);
360 template <typename T>
361 static std::vector<T> sorted (const std::vector<T>& unsorted)
363 std::vector<T> result = unsorted;
364 std::sort(result.begin(), result.end());
368 template <typename T, typename P>
369 static std::vector<T> sorted (const std::vector<T>& unsorted, P pred)
371 std::vector<T> result = unsorted;
372 std::sort(result.begin(), result.end(), pred);
376 template <typename IterT>
377 std::string elemsStr (const IterT& begin, const IterT& end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
379 const int bigInt = ~0u/2;
380 const std::string baseIndentation = std::string(numIndentationSpaces, ' ');
381 const std::string deepIndentation = baseIndentation + std::string(4, ' ');
382 const int wrapLength = wrapLengthParam > 0 ? wrapLengthParam : bigInt;
383 const int length = static_cast<int>(std::distance(begin, end));
386 if (length > wrapLength)
387 result += "(amount: " + de::toString(length) + ") ";
388 result += std::string() + "{" + (length > wrapLength ? "\n"+deepIndentation : " ");
392 for (IterT it = begin; it != end; ++it)
395 result += std::string() + ", " + (index % wrapLength == 0 ? "\n"+deepIndentation : "");
396 result += de::toString(*it);
400 result += length > wrapLength ? "\n"+baseIndentation : " ";
407 template <typename ContainerT>
408 std::string containerStr (const ContainerT& c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
410 return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
413 //! Copy 'count' objects of type T from 'memory' into a vector.
414 //! 'offset' is the offset of first object in memory, and 'stride' is the distance between consecutive objects.
416 std::vector<T> readInterleavedData (const int count, const void* memory, const int offset, const int stride)
418 std::vector<T> results(count);
419 const deUint8* pData = static_cast<const deUint8*>(memory) + offset;
421 for (int i = 0; i < count; ++i)
423 deMemcpy(&results[i], pData, sizeof(T));
430 template <typename CaseDef, typename = bool>
433 #ifndef CTS_USES_VULKANSC
434 static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR&, const CaseDef)
437 #endif // CTS_USES_VULKANSC
440 template <typename CaseDef>
441 struct PointMode<CaseDef, decltype(CaseDef().usePointMode)>
443 #ifndef CTS_USES_VULKANSC
444 static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features, const CaseDef caseDef)
446 if (caseDef.usePointMode)
447 checkPointMode(features);
449 #endif // CTS_USES_VULKANSC
452 template <typename CaseDef>
453 void checkSupportCase (Context& context, const CaseDef caseDef)
455 #ifndef CTS_USES_VULKANSC
456 if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* const features = getPortability(context))
458 PointMode<CaseDef>::check(*features, caseDef);
459 checkPrimitive(*features, caseDef.primitiveType);
464 #endif // CTS_USES_VULKANSC
470 #endif // _VKTTESSELLATIONUTIL_HPP