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> 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 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 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 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 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 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 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 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 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 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> 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> 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> 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> 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> 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> 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