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: 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 62 const vk::VkBuffer& get (void) const { return *m_buffer; } 63 const vk::VkBuffer& operator* (void) const { return get(); } 64 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: 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 90 const vk::VkImage& get (void) const { return *m_image; } 91 const vk::VkImage& operator* (void) const { return get(); } 92 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: 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 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); 117 GraphicsPipelineBuilder& setPatchControlPoints (const deUint32 controlPoints) { m_patchControlPoints = controlPoints; return *this; } 118 GraphicsPipelineBuilder& setCullModeFlags (const vk::VkCullModeFlags cullModeFlags) { m_cullModeFlags = cullModeFlags; return *this; } 119 GraphicsPipelineBuilder& setFrontFace (const vk::VkFrontFace frontFace) { m_frontFace = frontFace; return *this; } 120 GraphicsPipelineBuilder& setBlend (const bool enable) { m_blendEnable = enable; return *this; } 121 122 //! Applies only to pipelines without tessellation shaders. 123 GraphicsPipelineBuilder& setPrimitiveTopology (const vk::VkPrimitiveTopology topology) { m_primitiveTopology = topology; return *this; } 124 125 GraphicsPipelineBuilder& addVertexBinding (const vk::VkVertexInputBindingDescription vertexBinding) { m_vertexInputBindings.push_back(vertexBinding); return *this; } 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 132 GraphicsPipelineBuilder& setTessellationDomainOrigin (const vk::VkTessellationDomainOrigin domainOrigin) { return setTessellationDomainOrigin(tcu::just(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> makeRenderPass (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkFormat colorFormat); 218 vk::Move<vk::VkRenderPass> makeRenderPassWithoutAttachments (const vk::DeviceInterface& vk, const vk::VkDevice device); 219 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); 220 vk::Move<vk::VkFramebuffer> makeFramebufferWithoutAttachments (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkRenderPass renderPass); 221 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); 222 vk::VkBufferImageCopy makeBufferImageCopy (const vk::VkExtent3D extent, const vk::VkImageSubresourceLayers subresourceLayers); 223 vk::VkBufferMemoryBarrier makeBufferMemoryBarrier (const vk::VkAccessFlags srcAccessMask, const vk::VkAccessFlags dstAccessMask, const vk::VkBuffer buffer, const vk::VkDeviceSize offset, const vk::VkDeviceSize bufferSizeBytes); 224 vk::VkImageMemoryBarrier makeImageMemoryBarrier (const vk::VkAccessFlags srcAccessMask, const vk::VkAccessFlags dstAccessMask, const vk::VkImageLayout oldLayout, const vk::VkImageLayout newLayout, const vk::VkImage image, const vk::VkImageSubresourceRange subresourceRange); 225 226 void beginCommandBuffer (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer); 227 void endCommandBuffer (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer); 228 void submitCommandsAndWait (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkQueue queue, const vk::VkCommandBuffer commandBuffer); 229 void beginRenderPass (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer, const vk::VkRect2D& renderArea, const tcu::Vec4& clearColor); 230 void beginRenderPassWithRasterizationDisabled (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer); 231 void endRenderPass (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer); 232 void requireFeatures (const vk::InstanceInterface& vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags); 233 234 float getClampedTessLevel (const SpacingMode mode, const float tessLevel); 235 int getRoundedTessLevel (const SpacingMode mode, const float clampedTessLevel); 236 int getClampedRoundedTessLevel (const SpacingMode mode, const float tessLevel); 237 void getClampedRoundedTriangleTessLevels (const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst); 238 void getClampedRoundedQuadTessLevels (const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst); 239 void getClampedRoundedIsolineTessLevels (const SpacingMode mode, const float* outerSrc, int* outerDst); 240 int numOuterTessellationLevels (const TessPrimitiveType primitiveType); 241 std::string getTessellationLevelsString (const TessLevels& tessLevels, const TessPrimitiveType primitiveType); 242 std::string getTessellationLevelsString (const float* inner, const float* outer); 243 bool isPatchDiscarded (const TessPrimitiveType primitiveType, const float* outerLevels); 244 std::vector<tcu::Vec3> generateReferenceTriangleTessCoords (const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2); 245 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); 246 std::vector<tcu::Vec3> generateReferenceIsolineTessCoords (const int outer0, const int outer1); 247 int referenceVertexCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels); 248 int referencePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels); 249 int numVerticesPerPrimitive (const TessPrimitiveType primitiveType, const bool usePointMode); 250 251 static inline const char* getTessPrimitiveTypeShaderName (const TessPrimitiveType type) 252 { 253 switch (type) 254 { 255 case TESSPRIMITIVETYPE_TRIANGLES: return "triangles"; 256 case TESSPRIMITIVETYPE_QUADS: return "quads"; 257 case TESSPRIMITIVETYPE_ISOLINES: return "isolines"; 258 default: 259 DE_FATAL("Unexpected primitive type."); 260 return DE_NULL; 261 } 262 } 263 264 static inline const char* getDomainName (const TessPrimitiveType type) 265 { 266 switch (type) 267 { 268 case TESSPRIMITIVETYPE_TRIANGLES: return "tri"; 269 case TESSPRIMITIVETYPE_QUADS: return "quad"; 270 case TESSPRIMITIVETYPE_ISOLINES: return "isoline"; 271 default: 272 DE_FATAL("Unexpected primitive type."); 273 return DE_NULL; 274 } 275 } 276 277 static inline const char* getOutputTopologyName (const TessPrimitiveType type, const Winding winding, const bool usePointMode) 278 { 279 if (usePointMode) 280 return "point"; 281 else if (type == TESSPRIMITIVETYPE_TRIANGLES || type == TESSPRIMITIVETYPE_QUADS) 282 return (winding == WINDING_CCW ? "triangle_ccw" : "triangle_cw"); 283 else if (type == TESSPRIMITIVETYPE_ISOLINES) 284 return "line"; 285 286 DE_FATAL("Unexpected primitive type."); 287 return DE_NULL; 288 } 289 290 static inline const char* getSpacingModeShaderName (SpacingMode mode) 291 { 292 switch (mode) 293 { 294 case SPACINGMODE_EQUAL: return "equal_spacing"; 295 case SPACINGMODE_FRACTIONAL_ODD: return "fractional_odd_spacing"; 296 case SPACINGMODE_FRACTIONAL_EVEN: return "fractional_even_spacing"; 297 default: 298 DE_FATAL("Unexpected spacing mode."); 299 return DE_NULL; 300 } 301 } 302 303 static inline const char* getPartitioningShaderName (SpacingMode mode) 304 { 305 switch (mode) 306 { 307 case SPACINGMODE_EQUAL: return "integer"; 308 case SPACINGMODE_FRACTIONAL_ODD: return "fractional_odd"; 309 case SPACINGMODE_FRACTIONAL_EVEN: return "fractional_even"; 310 default: 311 DE_FATAL("Unexpected spacing mode."); 312 return DE_NULL; 313 } 314 } 315 316 static inline const char* getWindingShaderName (const Winding winding) 317 { 318 switch (winding) 319 { 320 case WINDING_CCW: return "ccw"; 321 case WINDING_CW: return "cw"; 322 default: 323 DE_FATAL("Unexpected winding type."); 324 return DE_NULL; 325 } 326 } 327 328 static inline const char* getShaderLanguageName (const ShaderLanguage language) 329 { 330 switch (language) 331 { 332 case SHADER_LANGUAGE_GLSL: return "glsl"; 333 case SHADER_LANGUAGE_HLSL: return "hlsl"; 334 default: 335 DE_FATAL("Unexpected shader language."); 336 return DE_NULL; 337 } 338 } 339 340 static inline const char* getGeometryShaderInputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode) 341 { 342 if (usePointMode) 343 return "points"; 344 345 switch (type) 346 { 347 case TESSPRIMITIVETYPE_TRIANGLES: 348 case TESSPRIMITIVETYPE_QUADS: 349 return "triangles"; 350 351 case TESSPRIMITIVETYPE_ISOLINES: 352 return "lines"; 353 354 default: 355 DE_FATAL("Unexpected primitive type."); 356 return DE_NULL; 357 } 358 } 359 360 static inline const char* getGeometryShaderOutputPrimitiveTypeShaderName (const TessPrimitiveType type, 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 "triangle_strip"; 370 371 case TESSPRIMITIVETYPE_ISOLINES: 372 return "line_strip"; 373 374 default: 375 DE_FATAL("Unexpected primitive type."); 376 return DE_NULL; 377 } 378 } 379 380 template<typename T> 381 inline std::size_t sizeInBytes (const std::vector<T>& vec) 382 { 383 return vec.size() * sizeof(vec[0]); 384 } 385 386 template <typename T> 387 static std::vector<T> sorted (const std::vector<T>& unsorted) 388 { 389 std::vector<T> result = unsorted; 390 std::sort(result.begin(), result.end()); 391 return result; 392 } 393 394 template <typename T, typename P> 395 static std::vector<T> sorted (const std::vector<T>& unsorted, P pred) 396 { 397 std::vector<T> result = unsorted; 398 std::sort(result.begin(), result.end(), pred); 399 return result; 400 } 401 402 template <typename IterT> 403 std::string elemsStr (const IterT& begin, const IterT& end, int wrapLengthParam = 0, int numIndentationSpaces = 0) 404 { 405 const int bigInt = ~0u/2; 406 const std::string baseIndentation = std::string(numIndentationSpaces, ' '); 407 const std::string deepIndentation = baseIndentation + std::string(4, ' '); 408 const int wrapLength = wrapLengthParam > 0 ? wrapLengthParam : bigInt; 409 const int length = static_cast<int>(std::distance(begin, end)); 410 std::string result; 411 412 if (length > wrapLength) 413 result += "(amount: " + de::toString(length) + ") "; 414 result += std::string() + "{" + (length > wrapLength ? "\n"+deepIndentation : " "); 415 416 { 417 int index = 0; 418 for (IterT it = begin; it != end; ++it) 419 { 420 if (it != begin) 421 result += std::string() + ", " + (index % wrapLength == 0 ? "\n"+deepIndentation : ""); 422 result += de::toString(*it); 423 index++; 424 } 425 426 result += length > wrapLength ? "\n"+baseIndentation : " "; 427 } 428 429 result += "}"; 430 return result; 431 } 432 433 template <typename ContainerT> 434 std::string containerStr (const ContainerT& c, int wrapLengthParam = 0, int numIndentationSpaces = 0) 435 { 436 return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces); 437 } 438 439 //! Copy 'count' objects of type T from 'memory' into a vector. 440 //! 'offset' is the offset of first object in memory, and 'stride' is the distance between consecutive objects. 441 template<typename T> 442 std::vector<T> readInterleavedData (const int count, const void* memory, const int offset, const int stride) 443 { 444 std::vector<T> results(count); 445 const deUint8* pData = static_cast<const deUint8*>(memory) + offset; 446 447 for (int i = 0; i < count; ++i) 448 { 449 deMemcpy(&results[i], pData, sizeof(T)); 450 pData += stride; 451 } 452 453 return results; 454 } 455 456 } // tessellation 457 } // vkt 458 459 #endif // _VKTTESSELLATIONUTIL_HPP 460