• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _VKTTESSELLATIONUTIL_HPP
2 #define _VKTTESSELLATIONUTIL_HPP
3 /*------------------------------------------------------------------------
4  * Vulkan Conformance Tests
5  * ------------------------
6  *
7  * Copyright (c) 2014 The Android Open Source Project
8  * Copyright (c) 2016 The Khronos Group Inc.
9  *
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
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
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.
21  *
22  *//*!
23  * \file
24  * \brief Tessellation Utilities
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vkDefs.hpp"
28 #include "vkMemUtil.hpp"
29 #include "vkRef.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vktTestCase.hpp"
35 
36 #include "tcuVector.hpp"
37 #include "tcuMaybe.hpp"
38 
39 #include "deStringUtil.hpp"
40 
41 #include <algorithm> // sort
42 #include <iterator>  // distance
43 
44 namespace vkt
45 {
46 namespace tessellation
47 {
48 
49 class GraphicsPipelineBuilder
50 {
51 public:
GraphicsPipelineBuilder(void)52     GraphicsPipelineBuilder(void)
53         : m_renderSize(0, 0)
54         , m_shaderStageFlags(0u)
55         , m_cullModeFlags(vk::VK_CULL_MODE_NONE)
56         , m_frontFace(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
57         , m_patchControlPoints(1u)
58         , m_blendEnable(false)
59         , m_primitiveTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
60         , m_tessellationDomainOrigin(tcu::Nothing)
61     {
62     }
63 
setRenderSize(const tcu::IVec2 & size)64     GraphicsPipelineBuilder &setRenderSize(const tcu::IVec2 &size)
65     {
66         m_renderSize = size;
67         return *this;
68     }
69     GraphicsPipelineBuilder &setShader(const vk::DeviceInterface &vk, const vk::VkDevice device,
70                                        const vk::VkShaderStageFlagBits stage, const vk::ProgramBinary &binary,
71                                        const vk::VkSpecializationInfo *specInfo);
setPatchControlPoints(const uint32_t controlPoints)72     GraphicsPipelineBuilder &setPatchControlPoints(const uint32_t controlPoints)
73     {
74         m_patchControlPoints = controlPoints;
75         return *this;
76     }
setCullModeFlags(const vk::VkCullModeFlags cullModeFlags)77     GraphicsPipelineBuilder &setCullModeFlags(const vk::VkCullModeFlags cullModeFlags)
78     {
79         m_cullModeFlags = cullModeFlags;
80         return *this;
81     }
setFrontFace(const vk::VkFrontFace frontFace)82     GraphicsPipelineBuilder &setFrontFace(const vk::VkFrontFace frontFace)
83     {
84         m_frontFace = frontFace;
85         return *this;
86     }
setBlend(const bool enable)87     GraphicsPipelineBuilder &setBlend(const bool enable)
88     {
89         m_blendEnable = enable;
90         return *this;
91     }
92 
93     //! Applies only to pipelines without tessellation shaders.
setPrimitiveTopology(const vk::VkPrimitiveTopology topology)94     GraphicsPipelineBuilder &setPrimitiveTopology(const vk::VkPrimitiveTopology topology)
95     {
96         m_primitiveTopology = topology;
97         return *this;
98     }
99 
addVertexBinding(const vk::VkVertexInputBindingDescription vertexBinding)100     GraphicsPipelineBuilder &addVertexBinding(const vk::VkVertexInputBindingDescription vertexBinding)
101     {
102         m_vertexInputBindings.push_back(vertexBinding);
103         return *this;
104     }
addVertexAttribute(const vk::VkVertexInputAttributeDescription vertexAttribute)105     GraphicsPipelineBuilder &addVertexAttribute(const vk::VkVertexInputAttributeDescription vertexAttribute)
106     {
107         m_vertexInputAttributes.push_back(vertexAttribute);
108         return *this;
109     }
110 
111     //! Basic vertex input configuration (uses biding 0, location 0, etc.)
112     GraphicsPipelineBuilder &setVertexInputSingleAttribute(const vk::VkFormat vertexFormat, const uint32_t stride);
113 
114     //! If tessellation domain origin is set, pipeline requires VK__maintenance2
setTessellationDomainOrigin(const vk::VkTessellationDomainOrigin domainOrigin)115     GraphicsPipelineBuilder &setTessellationDomainOrigin(const vk::VkTessellationDomainOrigin domainOrigin)
116     {
117         return setTessellationDomainOrigin(tcu::just(domainOrigin));
118     }
setTessellationDomainOrigin(const tcu::Maybe<vk::VkTessellationDomainOrigin> & domainOrigin)119     GraphicsPipelineBuilder &setTessellationDomainOrigin(const tcu::Maybe<vk::VkTessellationDomainOrigin> &domainOrigin)
120     {
121         m_tessellationDomainOrigin = domainOrigin;
122         return *this;
123     }
124 
125     vk::Move<vk::VkPipeline> build(const vk::DeviceInterface &vk, const vk::VkDevice device,
126                                    const vk::VkPipelineLayout pipelineLayout, const vk::VkRenderPass renderPass);
127 
128 private:
129     tcu::IVec2 m_renderSize;
130     vk::Move<vk::VkShaderModule> m_vertexShaderModule;
131     vk::Move<vk::VkShaderModule> m_fragmentShaderModule;
132     vk::Move<vk::VkShaderModule> m_geometryShaderModule;
133     vk::Move<vk::VkShaderModule> m_tessControlShaderModule;
134     vk::Move<vk::VkShaderModule> m_tessEvaluationShaderModule;
135     std::vector<vk::VkPipelineShaderStageCreateInfo> m_shaderStages;
136     std::vector<vk::VkVertexInputBindingDescription> m_vertexInputBindings;
137     std::vector<vk::VkVertexInputAttributeDescription> m_vertexInputAttributes;
138     vk::VkShaderStageFlags m_shaderStageFlags;
139     vk::VkCullModeFlags m_cullModeFlags;
140     vk::VkFrontFace m_frontFace;
141     uint32_t m_patchControlPoints;
142     bool m_blendEnable;
143     vk::VkPrimitiveTopology m_primitiveTopology;
144     tcu::Maybe<vk::VkTessellationDomainOrigin> m_tessellationDomainOrigin;
145 
146     GraphicsPipelineBuilder(const GraphicsPipelineBuilder &); // "deleted"
147     GraphicsPipelineBuilder &operator=(const GraphicsPipelineBuilder &);
148 };
149 
150 struct TessLevels
151 {
152     float inner[2];
153     float outer[4];
154 };
155 
156 enum TessPrimitiveType
157 {
158     TESSPRIMITIVETYPE_TRIANGLES = 0,
159     TESSPRIMITIVETYPE_QUADS,
160     TESSPRIMITIVETYPE_ISOLINES,
161 
162     TESSPRIMITIVETYPE_LAST,
163 };
164 
165 enum DrawType
166 {
167     DRAWTYPE_DRAW = 0,
168     DRAWTYPE_DRAW_INDIRECT,
169 
170     DRAWTYPE_LAST,
171 };
172 
173 enum SpacingMode
174 {
175     SPACINGMODE_EQUAL = 0,
176     SPACINGMODE_FRACTIONAL_ODD,
177     SPACINGMODE_FRACTIONAL_EVEN,
178 
179     SPACINGMODE_LAST,
180 };
181 
182 enum Winding
183 {
184     WINDING_CCW = 0,
185     WINDING_CW,
186 
187     WINDING_LAST,
188 };
189 
190 enum ShaderLanguage
191 {
192     SHADER_LANGUAGE_GLSL = 0,
193     SHADER_LANGUAGE_HLSL = 1,
194 
195     SHADER_LANGUAGE_LAST,
196 };
197 
198 enum FeatureFlagBits
199 {
200     FEATURE_TESSELLATION_SHADER                         = 1u << 0,
201     FEATURE_GEOMETRY_SHADER                             = 1u << 1,
202     FEATURE_SHADER_FLOAT_64                             = 1u << 2,
203     FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS          = 1u << 3,
204     FEATURE_FRAGMENT_STORES_AND_ATOMICS                 = 1u << 4,
205     FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE = 1u << 5,
206 };
207 typedef uint32_t FeatureFlags;
208 
209 vk::VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const vk::VkFormat format,
210                                           const vk::VkImageUsageFlags usage, const uint32_t numArrayLayers);
211 vk::Move<vk::VkRenderPass> makeRenderPassWithoutAttachments(const vk::DeviceInterface &vk, const vk::VkDevice device);
212 vk::VkBufferImageCopy makeBufferImageCopy(const vk::VkExtent3D extent,
213                                           const vk::VkImageSubresourceLayers subresourceLayers);
214 void requireFeatures(const vk::InstanceInterface &vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags);
215 float getClampedTessLevel(const SpacingMode mode, const float tessLevel);
216 int getRoundedTessLevel(const SpacingMode mode, const float clampedTessLevel);
217 int getClampedRoundedTessLevel(const SpacingMode mode, const float tessLevel);
218 void getClampedRoundedTriangleTessLevels(const SpacingMode mode, const float *innerSrc, const float *outerSrc,
219                                          int *innerDst, int *outerDst);
220 void getClampedRoundedQuadTessLevels(const SpacingMode mode, const float *innerSrc, const float *outerSrc,
221                                      int *innerDst, int *outerDst);
222 void getClampedRoundedIsolineTessLevels(const SpacingMode mode, const float *outerSrc, int *outerDst);
223 int numOuterTessellationLevels(const TessPrimitiveType primitiveType);
224 std::string getTessellationLevelsString(const TessLevels &tessLevels, const TessPrimitiveType primitiveType);
225 std::string getTessellationLevelsString(const float *inner, const float *outer);
226 bool isPatchDiscarded(const TessPrimitiveType primitiveType, const float *outerLevels);
227 std::vector<tcu::Vec3> generateReferenceTriangleTessCoords(const SpacingMode spacingMode, const int inner,
228                                                            const int outer0, const int outer1, const int outer2);
229 std::vector<tcu::Vec3> generateReferenceQuadTessCoords(const SpacingMode spacingMode, const int inner0,
230                                                        const int inner1, const int outer0, const int outer1,
231                                                        const int outer2, const int outer3);
232 std::vector<tcu::Vec3> generateReferenceIsolineTessCoords(const int outer0, const int outer1);
233 int referenceVertexCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode,
234                          const float *innerLevels, const float *outerLevels);
235 int referencePrimitiveCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode,
236                             const bool usePointMode, const float *innerLevels, const float *outerLevels);
237 int numVerticesPerPrimitive(const TessPrimitiveType primitiveType, const bool usePointMode);
238 
getTessPrimitiveTypeShaderName(const TessPrimitiveType type,bool forSpirv=false)239 static inline const char *getTessPrimitiveTypeShaderName(const TessPrimitiveType type, bool forSpirv = false)
240 {
241     static std::string primitiveName[][2] = {// glsl name    spirv name
242                                              {"triangles", "Triangles"},
243                                              {"quads", "Quads"},
244                                              {"isolines", "Isolines"}};
245 
246     if (type >= TESSPRIMITIVETYPE_LAST)
247     {
248         DE_FATAL("Unexpected primitive type.");
249         return nullptr;
250     }
251 
252     return primitiveName[type][forSpirv].c_str();
253 }
254 
getDomainName(const TessPrimitiveType type)255 static inline const char *getDomainName(const TessPrimitiveType type)
256 {
257     switch (type)
258     {
259     case TESSPRIMITIVETYPE_TRIANGLES:
260         return "tri";
261     case TESSPRIMITIVETYPE_QUADS:
262         return "quad";
263     case TESSPRIMITIVETYPE_ISOLINES:
264         return "isoline";
265     default:
266         DE_FATAL("Unexpected primitive type.");
267         return nullptr;
268     }
269 }
270 
getDrawName(const DrawType type)271 static inline const char *getDrawName(const DrawType type)
272 {
273     switch (type)
274     {
275     case DRAWTYPE_DRAW:
276         return "draw";
277     case DRAWTYPE_DRAW_INDIRECT:
278         return "draw_indirect";
279     default:
280         DE_FATAL("Unexpected draw type.");
281         return nullptr;
282     }
283 }
284 
getOutputTopologyName(const TessPrimitiveType type,const Winding winding,const bool usePointMode)285 static inline const char *getOutputTopologyName(const TessPrimitiveType type, const Winding winding,
286                                                 const bool usePointMode)
287 {
288     if (usePointMode)
289         return "point";
290     else if (type == TESSPRIMITIVETYPE_TRIANGLES || type == TESSPRIMITIVETYPE_QUADS)
291         return (winding == WINDING_CCW ? "triangle_ccw" : "triangle_cw");
292     else if (type == TESSPRIMITIVETYPE_ISOLINES)
293         return "line";
294 
295     DE_FATAL("Unexpected primitive type.");
296     return nullptr;
297 }
298 
getSpacingModeShaderName(SpacingMode mode,bool forSpirv=false)299 static inline const char *getSpacingModeShaderName(SpacingMode mode, bool forSpirv = false)
300 {
301     static std::string spacingName[][2] = {// glsl name                    spirv name
302                                            {"equal_spacing", "SpacingEqual"},
303                                            {"fractional_odd_spacing", "SpacingFractionalOdd"},
304                                            {"fractional_even_spacing", "SpacingFractionalEven"}};
305 
306     if (mode >= SPACINGMODE_LAST)
307     {
308         DE_FATAL("Unexpected spacing type.");
309         return nullptr;
310     }
311 
312     return spacingName[mode][forSpirv].c_str();
313 }
314 
getPartitioningShaderName(SpacingMode mode)315 static inline const char *getPartitioningShaderName(SpacingMode mode)
316 {
317     switch (mode)
318     {
319     case SPACINGMODE_EQUAL:
320         return "integer";
321     case SPACINGMODE_FRACTIONAL_ODD:
322         return "fractional_odd";
323     case SPACINGMODE_FRACTIONAL_EVEN:
324         return "fractional_even";
325     default:
326         DE_FATAL("Unexpected spacing mode.");
327         return nullptr;
328     }
329 }
330 
getWindingShaderName(const Winding winding)331 static inline const char *getWindingShaderName(const Winding winding)
332 {
333     switch (winding)
334     {
335     case WINDING_CCW:
336         return "ccw";
337     case WINDING_CW:
338         return "cw";
339     default:
340         DE_FATAL("Unexpected winding type.");
341         return nullptr;
342     }
343 }
344 
getShaderLanguageName(const ShaderLanguage language)345 static inline const char *getShaderLanguageName(const ShaderLanguage language)
346 {
347     switch (language)
348     {
349     case SHADER_LANGUAGE_GLSL:
350         return "glsl";
351     case SHADER_LANGUAGE_HLSL:
352         return "hlsl";
353     default:
354         DE_FATAL("Unexpected shader language.");
355         return nullptr;
356     }
357 }
358 
getGeometryShaderInputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)359 static inline const char *getGeometryShaderInputPrimitiveTypeShaderName(const TessPrimitiveType type,
360                                                                         const bool usePointMode)
361 {
362     if (usePointMode)
363         return "points";
364 
365     switch (type)
366     {
367     case TESSPRIMITIVETYPE_TRIANGLES:
368     case TESSPRIMITIVETYPE_QUADS:
369         return "triangles";
370 
371     case TESSPRIMITIVETYPE_ISOLINES:
372         return "lines";
373 
374     default:
375         DE_FATAL("Unexpected primitive type.");
376         return nullptr;
377     }
378 }
379 
getGeometryShaderOutputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)380 static inline const char *getGeometryShaderOutputPrimitiveTypeShaderName(const TessPrimitiveType type,
381                                                                          const bool usePointMode)
382 {
383     if (usePointMode)
384         return "points";
385 
386     switch (type)
387     {
388     case TESSPRIMITIVETYPE_TRIANGLES:
389     case TESSPRIMITIVETYPE_QUADS:
390         return "triangle_strip";
391 
392     case TESSPRIMITIVETYPE_ISOLINES:
393         return "line_strip";
394 
395     default:
396         DE_FATAL("Unexpected primitive type.");
397         return nullptr;
398     }
399 }
400 
401 #ifndef CTS_USES_VULKANSC
402 
getPortability(const Context & context)403 static inline const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR *getPortability(const Context &context)
404 {
405     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
406         return &context.getPortabilitySubsetFeatures();
407     return nullptr;
408 }
409 
checkIsolines(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features)410 static inline void checkIsolines(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features)
411 {
412     if (!features.tessellationIsolines)
413         TCU_THROW(NotSupportedError,
414                   "VK_KHR_portability_subset: Tessellation iso lines are not supported by this implementation");
415 }
416 
checkPrimitive(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features,const TessPrimitiveType primitive)417 static inline void checkPrimitive(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features,
418                                   const TessPrimitiveType primitive)
419 {
420     if (primitive == TESSPRIMITIVETYPE_ISOLINES)
421         checkIsolines(features);
422 }
423 
checkSupportPrimitive(Context & context,const TessPrimitiveType primitive)424 static inline void checkSupportPrimitive(Context &context, const TessPrimitiveType primitive)
425 {
426     if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR *const features = getPortability(context))
427         checkPrimitive(*features, primitive);
428 }
429 
checkPointMode(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features)430 static inline void checkPointMode(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features)
431 {
432     if (!features.tessellationPointMode)
433         TCU_THROW(NotSupportedError,
434                   "VK_KHR_portability_subset: Tessellation point mode is not supported by this implementation");
435 }
436 
437 #endif // CTS_USES_VULKANSC
438 
439 template <typename T>
sizeInBytes(const std::vector<T> & vec)440 inline std::size_t sizeInBytes(const std::vector<T> &vec)
441 {
442     return vec.size() * sizeof(vec[0]);
443 }
444 
445 template <typename T>
sorted(const std::vector<T> & unsorted)446 static std::vector<T> sorted(const std::vector<T> &unsorted)
447 {
448     std::vector<T> result = unsorted;
449     std::sort(result.begin(), result.end());
450     return result;
451 }
452 
453 template <typename T, typename P>
sorted(const std::vector<T> & unsorted,P pred)454 static std::vector<T> sorted(const std::vector<T> &unsorted, P pred)
455 {
456     std::vector<T> result = unsorted;
457     std::sort(result.begin(), result.end(), pred);
458     return result;
459 }
460 
461 template <typename IterT>
elemsStr(const IterT & begin,const IterT & end,int wrapLengthParam=0,int numIndentationSpaces=0)462 std::string elemsStr(const IterT &begin, const IterT &end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
463 {
464     const int bigInt                  = ~0u / 2;
465     const std::string baseIndentation = std::string(numIndentationSpaces, ' ');
466     const std::string deepIndentation = baseIndentation + std::string(4, ' ');
467     const int wrapLength              = wrapLengthParam > 0 ? wrapLengthParam : bigInt;
468     const int length                  = static_cast<int>(std::distance(begin, end));
469     std::string result;
470 
471     if (length > wrapLength)
472         result += "(amount: " + de::toString(length) + ") ";
473     result += std::string() + "{" + (length > wrapLength ? "\n" + deepIndentation : " ");
474 
475     {
476         int index = 0;
477         for (IterT it = begin; it != end; ++it)
478         {
479             if (it != begin)
480                 result += std::string() + ", " + (index % wrapLength == 0 ? "\n" + deepIndentation : "");
481             result += de::toString(*it);
482             index++;
483         }
484 
485         result += length > wrapLength ? "\n" + baseIndentation : " ";
486     }
487 
488     result += "}";
489     return result;
490 }
491 
492 template <typename ContainerT>
containerStr(const ContainerT & c,int wrapLengthParam=0,int numIndentationSpaces=0)493 std::string containerStr(const ContainerT &c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
494 {
495     return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
496 }
497 
498 //! Copy 'count' objects of type T from 'memory' into a vector.
499 //! 'offset' is the offset of first object in memory, and 'stride' is the distance between consecutive objects.
500 template <typename T>
readInterleavedData(const int count,const void * memory,const int offset,const int stride)501 std::vector<T> readInterleavedData(const int count, const void *memory, const int offset, const int stride)
502 {
503     std::vector<T> results(count);
504     const uint8_t *pData = static_cast<const uint8_t *>(memory) + offset;
505 
506     for (int i = 0; i < count; ++i)
507     {
508         deMemcpy(&results[i], pData, sizeof(T));
509         pData += stride;
510     }
511 
512     return results;
513 }
514 
515 template <typename CaseDef, typename = bool>
516 struct PointMode
517 {
518 #ifndef CTS_USES_VULKANSC
checkvkt::tessellation::PointMode519     static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &, const CaseDef)
520     {
521     }
522 #endif // CTS_USES_VULKANSC
523 };
524 
525 template <typename CaseDef>
526 struct PointMode<CaseDef, decltype(CaseDef().usePointMode)>
527 {
528 #ifndef CTS_USES_VULKANSC
checkvkt::tessellation::PointMode529     static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features, const CaseDef caseDef)
530     {
531         if (caseDef.usePointMode)
532             checkPointMode(features);
533     }
534 #endif // CTS_USES_VULKANSC
535 };
536 
537 template <typename CaseDef>
checkSupportCase(Context & context,const CaseDef caseDef)538 void checkSupportCase(Context &context, const CaseDef caseDef)
539 {
540 #ifndef CTS_USES_VULKANSC
541     if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR *const features = getPortability(context))
542     {
543         PointMode<CaseDef>::check(*features, caseDef);
544         checkPrimitive(*features, caseDef.primitiveType);
545     }
546 #else
547     DE_UNREF(context);
548     DE_UNREF(caseDef);
549 #endif // CTS_USES_VULKANSC
550 }
551 
552 } // namespace tessellation
553 } // namespace vkt
554 
555 #endif // _VKTTESSELLATIONUTIL_HPP
556