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
34 #include "tcuVector.hpp"
35 #include "tcuMaybe.hpp"
36
37 #include "deStringUtil.hpp"
38
39 #include <algorithm> // sort
40 #include <iterator> // distance
41
42 namespace vkt
43 {
44 namespace tessellation
45 {
46
47 class Buffer
48 {
49 public:
Buffer(const vk::DeviceInterface & vk,const vk::VkDevice device,vk::Allocator & allocator,const vk::VkBufferCreateInfo & bufferCreateInfo,const vk::MemoryRequirement memoryRequirement)50 Buffer (const vk::DeviceInterface& vk,
51 const vk::VkDevice device,
52 vk::Allocator& allocator,
53 const vk::VkBufferCreateInfo& bufferCreateInfo,
54 const vk::MemoryRequirement memoryRequirement)
55
56 : m_buffer (createBuffer(vk, device, &bufferCreateInfo))
57 , m_allocation (allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), memoryRequirement))
58 {
59 VK_CHECK(vk.bindBufferMemory(device, *m_buffer, m_allocation->getMemory(), m_allocation->getOffset()));
60 }
61
get(void) const62 const vk::VkBuffer& get (void) const { return *m_buffer; }
operator *(void) const63 const vk::VkBuffer& operator* (void) const { return get(); }
getAllocation(void) const64 vk::Allocation& getAllocation (void) const { return *m_allocation; }
65
66 private:
67 const vk::Unique<vk::VkBuffer> m_buffer;
68 const de::UniquePtr<vk::Allocation> m_allocation;
69
70 // "deleted"
71 Buffer (const Buffer&);
72 Buffer& operator= (const Buffer&);
73 };
74
75 class Image
76 {
77 public:
Image(const vk::DeviceInterface & vk,const vk::VkDevice device,vk::Allocator & allocator,const vk::VkImageCreateInfo & imageCreateInfo,const vk::MemoryRequirement memoryRequirement)78 Image (const vk::DeviceInterface& vk,
79 const vk::VkDevice device,
80 vk::Allocator& allocator,
81 const vk::VkImageCreateInfo& imageCreateInfo,
82 const vk::MemoryRequirement memoryRequirement)
83
84 : m_image (createImage(vk, device, &imageCreateInfo))
85 , m_allocation (allocator.allocate(getImageMemoryRequirements(vk, device, *m_image), memoryRequirement))
86 {
87 VK_CHECK(vk.bindImageMemory(device, *m_image, m_allocation->getMemory(), m_allocation->getOffset()));
88 }
89
get(void) const90 const vk::VkImage& get (void) const { return *m_image; }
operator *(void) const91 const vk::VkImage& operator* (void) const { return get(); }
getAllocation(void) const92 vk::Allocation& getAllocation (void) const { return *m_allocation; }
93
94 private:
95 const vk::Unique<vk::VkImage> m_image;
96 const de::UniquePtr<vk::Allocation> m_allocation;
97
98 // "deleted"
99 Image (const Image&);
100 Image& operator= (const Image&);
101 };
102
103 class GraphicsPipelineBuilder
104 {
105 public:
GraphicsPipelineBuilder(void)106 GraphicsPipelineBuilder (void) : m_renderSize (0, 0)
107 , m_shaderStageFlags (0u)
108 , m_cullModeFlags (vk::VK_CULL_MODE_NONE)
109 , m_frontFace (vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
110 , m_patchControlPoints (1u)
111 , m_blendEnable (false)
112 , m_primitiveTopology (vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
113 , m_tessellationDomainOrigin (tcu::nothing<vk::VkTessellationDomainOrigin>()) {}
114
setRenderSize(const tcu::IVec2 & size)115 GraphicsPipelineBuilder& setRenderSize (const tcu::IVec2& size) { m_renderSize = size; return *this; }
116 GraphicsPipelineBuilder& setShader (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkShaderStageFlagBits stage, const vk::ProgramBinary& binary, const vk::VkSpecializationInfo* specInfo);
setPatchControlPoints(const deUint32 controlPoints)117 GraphicsPipelineBuilder& setPatchControlPoints (const deUint32 controlPoints) { m_patchControlPoints = controlPoints; return *this; }
setCullModeFlags(const vk::VkCullModeFlags cullModeFlags)118 GraphicsPipelineBuilder& setCullModeFlags (const vk::VkCullModeFlags cullModeFlags) { m_cullModeFlags = cullModeFlags; return *this; }
setFrontFace(const vk::VkFrontFace frontFace)119 GraphicsPipelineBuilder& setFrontFace (const vk::VkFrontFace frontFace) { m_frontFace = frontFace; return *this; }
setBlend(const bool enable)120 GraphicsPipelineBuilder& setBlend (const bool enable) { m_blendEnable = enable; return *this; }
121
122 //! Applies only to pipelines without tessellation shaders.
setPrimitiveTopology(const vk::VkPrimitiveTopology topology)123 GraphicsPipelineBuilder& setPrimitiveTopology (const vk::VkPrimitiveTopology topology) { m_primitiveTopology = topology; return *this; }
124
addVertexBinding(const vk::VkVertexInputBindingDescription vertexBinding)125 GraphicsPipelineBuilder& addVertexBinding (const vk::VkVertexInputBindingDescription vertexBinding) { m_vertexInputBindings.push_back(vertexBinding); return *this; }
addVertexAttribute(const vk::VkVertexInputAttributeDescription vertexAttribute)126 GraphicsPipelineBuilder& addVertexAttribute (const vk::VkVertexInputAttributeDescription vertexAttribute) { m_vertexInputAttributes.push_back(vertexAttribute); return *this; }
127
128 //! Basic vertex input configuration (uses biding 0, location 0, etc.)
129 GraphicsPipelineBuilder& setVertexInputSingleAttribute (const vk::VkFormat vertexFormat, const deUint32 stride);
130
131 //! If tessellation domain origin is set, pipeline requires VK__maintenance2
setTessellationDomainOrigin(const vk::VkTessellationDomainOrigin domainOrigin)132 GraphicsPipelineBuilder& setTessellationDomainOrigin (const vk::VkTessellationDomainOrigin domainOrigin) { return setTessellationDomainOrigin(tcu::just(domainOrigin)); }
setTessellationDomainOrigin(const tcu::Maybe<vk::VkTessellationDomainOrigin> & domainOrigin)133 GraphicsPipelineBuilder& setTessellationDomainOrigin (const tcu::Maybe<vk::VkTessellationDomainOrigin>& domainOrigin) { m_tessellationDomainOrigin = domainOrigin; return *this; }
134
135 vk::Move<vk::VkPipeline> build (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkRenderPass renderPass);
136
137 private:
138 tcu::IVec2 m_renderSize;
139 vk::Move<vk::VkShaderModule> m_vertexShaderModule;
140 vk::Move<vk::VkShaderModule> m_fragmentShaderModule;
141 vk::Move<vk::VkShaderModule> m_geometryShaderModule;
142 vk::Move<vk::VkShaderModule> m_tessControlShaderModule;
143 vk::Move<vk::VkShaderModule> m_tessEvaluationShaderModule;
144 std::vector<vk::VkPipelineShaderStageCreateInfo> m_shaderStages;
145 std::vector<vk::VkVertexInputBindingDescription> m_vertexInputBindings;
146 std::vector<vk::VkVertexInputAttributeDescription> m_vertexInputAttributes;
147 vk::VkShaderStageFlags m_shaderStageFlags;
148 vk::VkCullModeFlags m_cullModeFlags;
149 vk::VkFrontFace m_frontFace;
150 deUint32 m_patchControlPoints;
151 bool m_blendEnable;
152 vk::VkPrimitiveTopology m_primitiveTopology;
153 tcu::Maybe<vk::VkTessellationDomainOrigin> m_tessellationDomainOrigin;
154
155 GraphicsPipelineBuilder (const GraphicsPipelineBuilder&); // "deleted"
156 GraphicsPipelineBuilder& operator= (const GraphicsPipelineBuilder&);
157 };
158
159 struct TessLevels
160 {
161 float inner[2];
162 float outer[4];
163 };
164
165 enum TessPrimitiveType
166 {
167 TESSPRIMITIVETYPE_TRIANGLES = 0,
168 TESSPRIMITIVETYPE_QUADS,
169 TESSPRIMITIVETYPE_ISOLINES,
170
171 TESSPRIMITIVETYPE_LAST,
172 };
173
174 enum SpacingMode
175 {
176 SPACINGMODE_EQUAL = 0,
177 SPACINGMODE_FRACTIONAL_ODD,
178 SPACINGMODE_FRACTIONAL_EVEN,
179
180 SPACINGMODE_LAST,
181 };
182
183 enum Winding
184 {
185 WINDING_CCW = 0,
186 WINDING_CW,
187
188 WINDING_LAST,
189 };
190
191 enum ShaderLanguage
192 {
193 SHADER_LANGUAGE_GLSL = 0,
194 SHADER_LANGUAGE_HLSL = 1,
195
196 SHADER_LANGUAGE_LAST,
197 };
198
199 enum FeatureFlagBits
200 {
201 FEATURE_TESSELLATION_SHADER = 1u << 0,
202 FEATURE_GEOMETRY_SHADER = 1u << 1,
203 FEATURE_SHADER_FLOAT_64 = 1u << 2,
204 FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS = 1u << 3,
205 FEATURE_FRAGMENT_STORES_AND_ATOMICS = 1u << 4,
206 FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE = 1u << 5,
207 };
208 typedef deUint32 FeatureFlags;
209
210 vk::VkBufferCreateInfo makeBufferCreateInfo (const vk::VkDeviceSize bufferSize, const vk::VkBufferUsageFlags usage);
211 vk::VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const vk::VkFormat format, const vk::VkImageUsageFlags usage, const deUint32 numArrayLayers);
212 vk::Move<vk::VkCommandPool> makeCommandPool (const vk::DeviceInterface& vk, const vk::VkDevice device, const deUint32 queueFamilyIndex);
213 vk::Move<vk::VkDescriptorSet> makeDescriptorSet (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkDescriptorPool descriptorPool, const vk::VkDescriptorSetLayout setLayout);
214 vk::Move<vk::VkPipelineLayout> makePipelineLayout (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkDescriptorSetLayout descriptorSetLayout);
215 vk::Move<vk::VkPipelineLayout> makePipelineLayoutWithoutDescriptors (const vk::DeviceInterface& vk, const vk::VkDevice device);
216 vk::Move<vk::VkPipeline> makeComputePipeline (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkShaderModule shaderModule, const vk::VkSpecializationInfo* specInfo);
217 vk::Move<vk::VkRenderPass> makeRenderPassWithoutAttachments (const vk::DeviceInterface& vk, const vk::VkDevice device);
218 vk::Move<vk::VkFramebuffer> makeFramebuffer (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkRenderPass renderPass, const vk::VkImageView colorAttachment, const deUint32 width, const deUint32 height, const deUint32 layers);
219 vk::Move<vk::VkFramebuffer> makeFramebufferWithoutAttachments (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkRenderPass renderPass);
220 vk::Move<vk::VkImageView> makeImageView (const vk::DeviceInterface& vk, const vk::VkDevice vkDevice, const vk::VkImage image, const vk::VkImageViewType viewType, const vk::VkFormat format, const vk::VkImageSubresourceRange subresourceRange);
221 vk::VkBufferImageCopy makeBufferImageCopy (const vk::VkExtent3D extent, const vk::VkImageSubresourceLayers subresourceLayers);
222 void beginRenderPassWithRasterizationDisabled (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer);
223 void requireFeatures (const vk::InstanceInterface& vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags);
224 float getClampedTessLevel (const SpacingMode mode, const float tessLevel);
225 int getRoundedTessLevel (const SpacingMode mode, const float clampedTessLevel);
226 int getClampedRoundedTessLevel (const SpacingMode mode, const float tessLevel);
227 void getClampedRoundedTriangleTessLevels (const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
228 void getClampedRoundedQuadTessLevels (const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
229 void getClampedRoundedIsolineTessLevels (const SpacingMode mode, const float* outerSrc, int* outerDst);
230 int numOuterTessellationLevels (const TessPrimitiveType primitiveType);
231 std::string getTessellationLevelsString (const TessLevels& tessLevels, const TessPrimitiveType primitiveType);
232 std::string getTessellationLevelsString (const float* inner, const float* outer);
233 bool isPatchDiscarded (const TessPrimitiveType primitiveType, const float* outerLevels);
234 std::vector<tcu::Vec3> generateReferenceTriangleTessCoords (const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2);
235 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);
236 std::vector<tcu::Vec3> generateReferenceIsolineTessCoords (const int outer0, const int outer1);
237 int referenceVertexCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
238 int referencePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
239 int numVerticesPerPrimitive (const TessPrimitiveType primitiveType, const bool usePointMode);
240
getTessPrimitiveTypeShaderName(const TessPrimitiveType type)241 static inline const char* getTessPrimitiveTypeShaderName (const TessPrimitiveType type)
242 {
243 switch (type)
244 {
245 case TESSPRIMITIVETYPE_TRIANGLES: return "triangles";
246 case TESSPRIMITIVETYPE_QUADS: return "quads";
247 case TESSPRIMITIVETYPE_ISOLINES: return "isolines";
248 default:
249 DE_FATAL("Unexpected primitive type.");
250 return DE_NULL;
251 }
252 }
253
getDomainName(const TessPrimitiveType type)254 static inline const char* getDomainName (const TessPrimitiveType type)
255 {
256 switch (type)
257 {
258 case TESSPRIMITIVETYPE_TRIANGLES: return "tri";
259 case TESSPRIMITIVETYPE_QUADS: return "quad";
260 case TESSPRIMITIVETYPE_ISOLINES: return "isoline";
261 default:
262 DE_FATAL("Unexpected primitive type.");
263 return DE_NULL;
264 }
265 }
266
getOutputTopologyName(const TessPrimitiveType type,const Winding winding,const bool usePointMode)267 static inline const char* getOutputTopologyName (const TessPrimitiveType type, const Winding winding, const bool usePointMode)
268 {
269 if (usePointMode)
270 return "point";
271 else if (type == TESSPRIMITIVETYPE_TRIANGLES || type == TESSPRIMITIVETYPE_QUADS)
272 return (winding == WINDING_CCW ? "triangle_ccw" : "triangle_cw");
273 else if (type == TESSPRIMITIVETYPE_ISOLINES)
274 return "line";
275
276 DE_FATAL("Unexpected primitive type.");
277 return DE_NULL;
278 }
279
getSpacingModeShaderName(SpacingMode mode)280 static inline const char* getSpacingModeShaderName (SpacingMode mode)
281 {
282 switch (mode)
283 {
284 case SPACINGMODE_EQUAL: return "equal_spacing";
285 case SPACINGMODE_FRACTIONAL_ODD: return "fractional_odd_spacing";
286 case SPACINGMODE_FRACTIONAL_EVEN: return "fractional_even_spacing";
287 default:
288 DE_FATAL("Unexpected spacing mode.");
289 return DE_NULL;
290 }
291 }
292
getPartitioningShaderName(SpacingMode mode)293 static inline const char* getPartitioningShaderName (SpacingMode mode)
294 {
295 switch (mode)
296 {
297 case SPACINGMODE_EQUAL: return "integer";
298 case SPACINGMODE_FRACTIONAL_ODD: return "fractional_odd";
299 case SPACINGMODE_FRACTIONAL_EVEN: return "fractional_even";
300 default:
301 DE_FATAL("Unexpected spacing mode.");
302 return DE_NULL;
303 }
304 }
305
getWindingShaderName(const Winding winding)306 static inline const char* getWindingShaderName (const Winding winding)
307 {
308 switch (winding)
309 {
310 case WINDING_CCW: return "ccw";
311 case WINDING_CW: return "cw";
312 default:
313 DE_FATAL("Unexpected winding type.");
314 return DE_NULL;
315 }
316 }
317
getShaderLanguageName(const ShaderLanguage language)318 static inline const char* getShaderLanguageName (const ShaderLanguage language)
319 {
320 switch (language)
321 {
322 case SHADER_LANGUAGE_GLSL: return "glsl";
323 case SHADER_LANGUAGE_HLSL: return "hlsl";
324 default:
325 DE_FATAL("Unexpected shader language.");
326 return DE_NULL;
327 }
328 }
329
getGeometryShaderInputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)330 static inline const char* getGeometryShaderInputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
331 {
332 if (usePointMode)
333 return "points";
334
335 switch (type)
336 {
337 case TESSPRIMITIVETYPE_TRIANGLES:
338 case TESSPRIMITIVETYPE_QUADS:
339 return "triangles";
340
341 case TESSPRIMITIVETYPE_ISOLINES:
342 return "lines";
343
344 default:
345 DE_FATAL("Unexpected primitive type.");
346 return DE_NULL;
347 }
348 }
349
getGeometryShaderOutputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)350 static inline const char* getGeometryShaderOutputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
351 {
352 if (usePointMode)
353 return "points";
354
355 switch (type)
356 {
357 case TESSPRIMITIVETYPE_TRIANGLES:
358 case TESSPRIMITIVETYPE_QUADS:
359 return "triangle_strip";
360
361 case TESSPRIMITIVETYPE_ISOLINES:
362 return "line_strip";
363
364 default:
365 DE_FATAL("Unexpected primitive type.");
366 return DE_NULL;
367 }
368 }
369
370 template<typename T>
sizeInBytes(const std::vector<T> & vec)371 inline std::size_t sizeInBytes (const std::vector<T>& vec)
372 {
373 return vec.size() * sizeof(vec[0]);
374 }
375
376 template <typename T>
sorted(const std::vector<T> & unsorted)377 static std::vector<T> sorted (const std::vector<T>& unsorted)
378 {
379 std::vector<T> result = unsorted;
380 std::sort(result.begin(), result.end());
381 return result;
382 }
383
384 template <typename T, typename P>
sorted(const std::vector<T> & unsorted,P pred)385 static std::vector<T> sorted (const std::vector<T>& unsorted, P pred)
386 {
387 std::vector<T> result = unsorted;
388 std::sort(result.begin(), result.end(), pred);
389 return result;
390 }
391
392 template <typename IterT>
elemsStr(const IterT & begin,const IterT & end,int wrapLengthParam=0,int numIndentationSpaces=0)393 std::string elemsStr (const IterT& begin, const IterT& end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
394 {
395 const int bigInt = ~0u/2;
396 const std::string baseIndentation = std::string(numIndentationSpaces, ' ');
397 const std::string deepIndentation = baseIndentation + std::string(4, ' ');
398 const int wrapLength = wrapLengthParam > 0 ? wrapLengthParam : bigInt;
399 const int length = static_cast<int>(std::distance(begin, end));
400 std::string result;
401
402 if (length > wrapLength)
403 result += "(amount: " + de::toString(length) + ") ";
404 result += std::string() + "{" + (length > wrapLength ? "\n"+deepIndentation : " ");
405
406 {
407 int index = 0;
408 for (IterT it = begin; it != end; ++it)
409 {
410 if (it != begin)
411 result += std::string() + ", " + (index % wrapLength == 0 ? "\n"+deepIndentation : "");
412 result += de::toString(*it);
413 index++;
414 }
415
416 result += length > wrapLength ? "\n"+baseIndentation : " ";
417 }
418
419 result += "}";
420 return result;
421 }
422
423 template <typename ContainerT>
containerStr(const ContainerT & c,int wrapLengthParam=0,int numIndentationSpaces=0)424 std::string containerStr (const ContainerT& c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
425 {
426 return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
427 }
428
429 //! Copy 'count' objects of type T from 'memory' into a vector.
430 //! 'offset' is the offset of first object in memory, and 'stride' is the distance between consecutive objects.
431 template<typename T>
readInterleavedData(const int count,const void * memory,const int offset,const int stride)432 std::vector<T> readInterleavedData (const int count, const void* memory, const int offset, const int stride)
433 {
434 std::vector<T> results(count);
435 const deUint8* pData = static_cast<const deUint8*>(memory) + offset;
436
437 for (int i = 0; i < count; ++i)
438 {
439 deMemcpy(&results[i], pData, sizeof(T));
440 pData += stride;
441 }
442
443 return results;
444 }
445
446 } // tessellation
447 } // vkt
448
449 #endif // _VKTTESSELLATIONUTIL_HPP
450