xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/tessellation/vktTessellationUtil.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 SpacingMode
166 {
167     SPACINGMODE_EQUAL = 0,
168     SPACINGMODE_FRACTIONAL_ODD,
169     SPACINGMODE_FRACTIONAL_EVEN,
170 
171     SPACINGMODE_LAST,
172 };
173 
174 enum Winding
175 {
176     WINDING_CCW = 0,
177     WINDING_CW,
178 
179     WINDING_LAST,
180 };
181 
182 enum ShaderLanguage
183 {
184     SHADER_LANGUAGE_GLSL = 0,
185     SHADER_LANGUAGE_HLSL = 1,
186 
187     SHADER_LANGUAGE_LAST,
188 };
189 
190 enum FeatureFlagBits
191 {
192     FEATURE_TESSELLATION_SHADER                         = 1u << 0,
193     FEATURE_GEOMETRY_SHADER                             = 1u << 1,
194     FEATURE_SHADER_FLOAT_64                             = 1u << 2,
195     FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS          = 1u << 3,
196     FEATURE_FRAGMENT_STORES_AND_ATOMICS                 = 1u << 4,
197     FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE = 1u << 5,
198 };
199 typedef uint32_t FeatureFlags;
200 
201 vk::VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const vk::VkFormat format,
202                                           const vk::VkImageUsageFlags usage, const uint32_t numArrayLayers);
203 vk::Move<vk::VkRenderPass> makeRenderPassWithoutAttachments(const vk::DeviceInterface &vk, const vk::VkDevice device);
204 vk::VkBufferImageCopy makeBufferImageCopy(const vk::VkExtent3D extent,
205                                           const vk::VkImageSubresourceLayers subresourceLayers);
206 void requireFeatures(const vk::InstanceInterface &vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags);
207 float getClampedTessLevel(const SpacingMode mode, const float tessLevel);
208 int getRoundedTessLevel(const SpacingMode mode, const float clampedTessLevel);
209 int getClampedRoundedTessLevel(const SpacingMode mode, const float tessLevel);
210 void getClampedRoundedTriangleTessLevels(const SpacingMode mode, const float *innerSrc, const float *outerSrc,
211                                          int *innerDst, int *outerDst);
212 void getClampedRoundedQuadTessLevels(const SpacingMode mode, const float *innerSrc, const float *outerSrc,
213                                      int *innerDst, int *outerDst);
214 void getClampedRoundedIsolineTessLevels(const SpacingMode mode, const float *outerSrc, int *outerDst);
215 int numOuterTessellationLevels(const TessPrimitiveType primitiveType);
216 std::string getTessellationLevelsString(const TessLevels &tessLevels, const TessPrimitiveType primitiveType);
217 std::string getTessellationLevelsString(const float *inner, const float *outer);
218 bool isPatchDiscarded(const TessPrimitiveType primitiveType, const float *outerLevels);
219 std::vector<tcu::Vec3> generateReferenceTriangleTessCoords(const SpacingMode spacingMode, const int inner,
220                                                            const int outer0, const int outer1, const int outer2);
221 std::vector<tcu::Vec3> generateReferenceQuadTessCoords(const SpacingMode spacingMode, const int inner0,
222                                                        const int inner1, const int outer0, const int outer1,
223                                                        const int outer2, const int outer3);
224 std::vector<tcu::Vec3> generateReferenceIsolineTessCoords(const int outer0, const int outer1);
225 int referenceVertexCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode,
226                          const float *innerLevels, const float *outerLevels);
227 int referencePrimitiveCount(const TessPrimitiveType primitiveType, const SpacingMode spacingMode,
228                             const bool usePointMode, const float *innerLevels, const float *outerLevels);
229 int numVerticesPerPrimitive(const TessPrimitiveType primitiveType, const bool usePointMode);
230 
getTessPrimitiveTypeShaderName(const TessPrimitiveType type,bool forSpirv=false)231 static inline const char *getTessPrimitiveTypeShaderName(const TessPrimitiveType type, bool forSpirv = false)
232 {
233     static std::string primitiveName[][2] = {// glsl name    spirv name
234                                              {"triangles", "Triangles"},
235                                              {"quads", "Quads"},
236                                              {"isolines", "Isolines"}};
237 
238     if (type >= TESSPRIMITIVETYPE_LAST)
239     {
240         DE_FATAL("Unexpected primitive type.");
241         return DE_NULL;
242     }
243 
244     return primitiveName[type][forSpirv].c_str();
245 }
246 
getDomainName(const TessPrimitiveType type)247 static inline const char *getDomainName(const TessPrimitiveType type)
248 {
249     switch (type)
250     {
251     case TESSPRIMITIVETYPE_TRIANGLES:
252         return "tri";
253     case TESSPRIMITIVETYPE_QUADS:
254         return "quad";
255     case TESSPRIMITIVETYPE_ISOLINES:
256         return "isoline";
257     default:
258         DE_FATAL("Unexpected primitive type.");
259         return DE_NULL;
260     }
261 }
262 
getOutputTopologyName(const TessPrimitiveType type,const Winding winding,const bool usePointMode)263 static inline const char *getOutputTopologyName(const TessPrimitiveType type, const Winding winding,
264                                                 const bool usePointMode)
265 {
266     if (usePointMode)
267         return "point";
268     else if (type == TESSPRIMITIVETYPE_TRIANGLES || type == TESSPRIMITIVETYPE_QUADS)
269         return (winding == WINDING_CCW ? "triangle_ccw" : "triangle_cw");
270     else if (type == TESSPRIMITIVETYPE_ISOLINES)
271         return "line";
272 
273     DE_FATAL("Unexpected primitive type.");
274     return DE_NULL;
275 }
276 
getSpacingModeShaderName(SpacingMode mode,bool forSpirv=false)277 static inline const char *getSpacingModeShaderName(SpacingMode mode, bool forSpirv = false)
278 {
279     static std::string spacingName[][2] = {// glsl name                    spirv name
280                                            {"equal_spacing", "SpacingEqual"},
281                                            {"fractional_odd_spacing", "SpacingFractionalOdd"},
282                                            {"fractional_even_spacing", "SpacingFractionalEven"}};
283 
284     if (mode >= SPACINGMODE_LAST)
285     {
286         DE_FATAL("Unexpected spacing type.");
287         return DE_NULL;
288     }
289 
290     return spacingName[mode][forSpirv].c_str();
291 }
292 
getPartitioningShaderName(SpacingMode mode)293 static inline const char *getPartitioningShaderName(SpacingMode mode)
294 {
295     switch (mode)
296     {
297     case SPACINGMODE_EQUAL:
298         return "integer";
299     case SPACINGMODE_FRACTIONAL_ODD:
300         return "fractional_odd";
301     case SPACINGMODE_FRACTIONAL_EVEN:
302         return "fractional_even";
303     default:
304         DE_FATAL("Unexpected spacing mode.");
305         return DE_NULL;
306     }
307 }
308 
getWindingShaderName(const Winding winding)309 static inline const char *getWindingShaderName(const Winding winding)
310 {
311     switch (winding)
312     {
313     case WINDING_CCW:
314         return "ccw";
315     case WINDING_CW:
316         return "cw";
317     default:
318         DE_FATAL("Unexpected winding type.");
319         return DE_NULL;
320     }
321 }
322 
getShaderLanguageName(const ShaderLanguage language)323 static inline const char *getShaderLanguageName(const ShaderLanguage language)
324 {
325     switch (language)
326     {
327     case SHADER_LANGUAGE_GLSL:
328         return "glsl";
329     case SHADER_LANGUAGE_HLSL:
330         return "hlsl";
331     default:
332         DE_FATAL("Unexpected shader language.");
333         return DE_NULL;
334     }
335 }
336 
getGeometryShaderInputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)337 static inline const char *getGeometryShaderInputPrimitiveTypeShaderName(const TessPrimitiveType type,
338                                                                         const bool usePointMode)
339 {
340     if (usePointMode)
341         return "points";
342 
343     switch (type)
344     {
345     case TESSPRIMITIVETYPE_TRIANGLES:
346     case TESSPRIMITIVETYPE_QUADS:
347         return "triangles";
348 
349     case TESSPRIMITIVETYPE_ISOLINES:
350         return "lines";
351 
352     default:
353         DE_FATAL("Unexpected primitive type.");
354         return DE_NULL;
355     }
356 }
357 
getGeometryShaderOutputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)358 static inline const char *getGeometryShaderOutputPrimitiveTypeShaderName(const TessPrimitiveType type,
359                                                                          const bool usePointMode)
360 {
361     if (usePointMode)
362         return "points";
363 
364     switch (type)
365     {
366     case TESSPRIMITIVETYPE_TRIANGLES:
367     case TESSPRIMITIVETYPE_QUADS:
368         return "triangle_strip";
369 
370     case TESSPRIMITIVETYPE_ISOLINES:
371         return "line_strip";
372 
373     default:
374         DE_FATAL("Unexpected primitive type.");
375         return DE_NULL;
376     }
377 }
378 
379 #ifndef CTS_USES_VULKANSC
380 
getPortability(const Context & context)381 static inline const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR *getPortability(const Context &context)
382 {
383     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
384         return &context.getPortabilitySubsetFeatures();
385     return DE_NULL;
386 }
387 
checkIsolines(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features)388 static inline void checkIsolines(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features)
389 {
390     if (!features.tessellationIsolines)
391         TCU_THROW(NotSupportedError,
392                   "VK_KHR_portability_subset: Tessellation iso lines are not supported by this implementation");
393 }
394 
checkPrimitive(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features,const TessPrimitiveType primitive)395 static inline void checkPrimitive(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features,
396                                   const TessPrimitiveType primitive)
397 {
398     if (primitive == TESSPRIMITIVETYPE_ISOLINES)
399         checkIsolines(features);
400 }
401 
checkSupportPrimitive(Context & context,const TessPrimitiveType primitive)402 static inline void checkSupportPrimitive(Context &context, const TessPrimitiveType primitive)
403 {
404     if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR *const features = getPortability(context))
405         checkPrimitive(*features, primitive);
406 }
407 
checkPointMode(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features)408 static inline void checkPointMode(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features)
409 {
410     if (!features.tessellationPointMode)
411         TCU_THROW(NotSupportedError,
412                   "VK_KHR_portability_subset: Tessellation point mode is not supported by this implementation");
413 }
414 
415 #endif // CTS_USES_VULKANSC
416 
417 template <typename T>
sizeInBytes(const std::vector<T> & vec)418 inline std::size_t sizeInBytes(const std::vector<T> &vec)
419 {
420     return vec.size() * sizeof(vec[0]);
421 }
422 
423 template <typename T>
sorted(const std::vector<T> & unsorted)424 static std::vector<T> sorted(const std::vector<T> &unsorted)
425 {
426     std::vector<T> result = unsorted;
427     std::sort(result.begin(), result.end());
428     return result;
429 }
430 
431 template <typename T, typename P>
sorted(const std::vector<T> & unsorted,P pred)432 static std::vector<T> sorted(const std::vector<T> &unsorted, P pred)
433 {
434     std::vector<T> result = unsorted;
435     std::sort(result.begin(), result.end(), pred);
436     return result;
437 }
438 
439 template <typename IterT>
elemsStr(const IterT & begin,const IterT & end,int wrapLengthParam=0,int numIndentationSpaces=0)440 std::string elemsStr(const IterT &begin, const IterT &end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
441 {
442     const int bigInt                  = ~0u / 2;
443     const std::string baseIndentation = std::string(numIndentationSpaces, ' ');
444     const std::string deepIndentation = baseIndentation + std::string(4, ' ');
445     const int wrapLength              = wrapLengthParam > 0 ? wrapLengthParam : bigInt;
446     const int length                  = static_cast<int>(std::distance(begin, end));
447     std::string result;
448 
449     if (length > wrapLength)
450         result += "(amount: " + de::toString(length) + ") ";
451     result += std::string() + "{" + (length > wrapLength ? "\n" + deepIndentation : " ");
452 
453     {
454         int index = 0;
455         for (IterT it = begin; it != end; ++it)
456         {
457             if (it != begin)
458                 result += std::string() + ", " + (index % wrapLength == 0 ? "\n" + deepIndentation : "");
459             result += de::toString(*it);
460             index++;
461         }
462 
463         result += length > wrapLength ? "\n" + baseIndentation : " ";
464     }
465 
466     result += "}";
467     return result;
468 }
469 
470 template <typename ContainerT>
containerStr(const ContainerT & c,int wrapLengthParam=0,int numIndentationSpaces=0)471 std::string containerStr(const ContainerT &c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
472 {
473     return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
474 }
475 
476 //! Copy 'count' objects of type T from 'memory' into a vector.
477 //! 'offset' is the offset of first object in memory, and 'stride' is the distance between consecutive objects.
478 template <typename T>
readInterleavedData(const int count,const void * memory,const int offset,const int stride)479 std::vector<T> readInterleavedData(const int count, const void *memory, const int offset, const int stride)
480 {
481     std::vector<T> results(count);
482     const uint8_t *pData = static_cast<const uint8_t *>(memory) + offset;
483 
484     for (int i = 0; i < count; ++i)
485     {
486         deMemcpy(&results[i], pData, sizeof(T));
487         pData += stride;
488     }
489 
490     return results;
491 }
492 
493 template <typename CaseDef, typename = bool>
494 struct PointMode
495 {
496 #ifndef CTS_USES_VULKANSC
checkvkt::tessellation::PointMode497     static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &, const CaseDef)
498     {
499     }
500 #endif // CTS_USES_VULKANSC
501 };
502 
503 template <typename CaseDef>
504 struct PointMode<CaseDef, decltype(CaseDef().usePointMode)>
505 {
506 #ifndef CTS_USES_VULKANSC
checkvkt::tessellation::PointMode507     static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR &features, const CaseDef caseDef)
508     {
509         if (caseDef.usePointMode)
510             checkPointMode(features);
511     }
512 #endif // CTS_USES_VULKANSC
513 };
514 
515 template <typename CaseDef>
checkSupportCase(Context & context,const CaseDef caseDef)516 void checkSupportCase(Context &context, const CaseDef caseDef)
517 {
518 #ifndef CTS_USES_VULKANSC
519     if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR *const features = getPortability(context))
520     {
521         PointMode<CaseDef>::check(*features, caseDef);
522         checkPrimitive(*features, caseDef.primitiveType);
523     }
524 #else
525     DE_UNREF(context);
526     DE_UNREF(caseDef);
527 #endif // CTS_USES_VULKANSC
528 }
529 
530 } // namespace tessellation
531 } // namespace vkt
532 
533 #endif // _VKTTESSELLATIONUTIL_HPP
534