vulkan_builders.h (17883B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "gpu_device.h" 7 #include "vulkan_loader.h" 8 9 #include "common/small_string.h" 10 #include "common/string_util.h" 11 12 #include <array> 13 #include <string_view> 14 15 class Error; 16 17 #if defined(_DEBUG) && !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_X86) 18 #define ENABLE_VULKAN_DEBUG_OBJECTS 1 19 #endif 20 21 #define LOG_VULKAN_ERROR(res, msg) ::Vulkan::LogVulkanResult(__func__, res, msg) 22 23 namespace Vulkan { 24 // Adds a structure to a chain. 25 void AddPointerToChain(void* head, const void* ptr); 26 27 const char* VkResultToString(VkResult res); 28 void LogVulkanResult(const char* func_name, VkResult res, std::string_view msg); 29 void SetErrorObject(Error* errptr, std::string_view prefix, VkResult res); 30 31 class DescriptorSetLayoutBuilder 32 { 33 public: 34 enum : u32 35 { 36 MAX_BINDINGS = 16, 37 }; 38 39 DescriptorSetLayoutBuilder(); 40 41 void Clear(); 42 void SetPushFlag(); 43 44 VkDescriptorSetLayout Create(VkDevice device); 45 46 void AddBinding(u32 binding, VkDescriptorType dtype, u32 dcount, VkShaderStageFlags stages); 47 48 private: 49 VkDescriptorSetLayoutCreateInfo m_ci{}; 50 std::array<VkDescriptorSetLayoutBinding, MAX_BINDINGS> m_bindings{}; 51 }; 52 53 class PipelineLayoutBuilder 54 { 55 public: 56 enum : u32 57 { 58 MAX_SETS = 8, 59 MAX_PUSH_CONSTANTS = 1 60 }; 61 62 PipelineLayoutBuilder(); 63 64 void Clear(); 65 66 VkPipelineLayout Create(VkDevice device); 67 68 void AddDescriptorSet(VkDescriptorSetLayout layout); 69 70 void AddPushConstants(VkShaderStageFlags stages, u32 offset, u32 size); 71 72 private: 73 VkPipelineLayoutCreateInfo m_ci{}; 74 std::array<VkDescriptorSetLayout, MAX_SETS> m_sets{}; 75 std::array<VkPushConstantRange, MAX_PUSH_CONSTANTS> m_push_constants{}; 76 }; 77 78 class GraphicsPipelineBuilder 79 { 80 public: 81 enum : u32 82 { 83 MAX_SHADER_STAGES = 3, 84 MAX_VERTEX_ATTRIBUTES = 16, 85 MAX_VERTEX_BUFFERS = 8, 86 MAX_ATTACHMENTS = GPUDevice::MAX_RENDER_TARGETS + 1, 87 MAX_INPUT_ATTACHMENTS = 1, 88 MAX_DYNAMIC_STATE = 8 89 }; 90 91 GraphicsPipelineBuilder(); 92 93 void Clear(); 94 95 VkPipeline Create(VkDevice device, VkPipelineCache pipeline_cache, bool clear, Error* error); 96 97 void SetShaderStage(VkShaderStageFlagBits stage, VkShaderModule module, const char* entry_point); 98 void SetVertexShader(VkShaderModule module) { SetShaderStage(VK_SHADER_STAGE_VERTEX_BIT, module, "main"); } 99 void SetGeometryShader(VkShaderModule module) { SetShaderStage(VK_SHADER_STAGE_GEOMETRY_BIT, module, "main"); } 100 void SetFragmentShader(VkShaderModule module) { SetShaderStage(VK_SHADER_STAGE_FRAGMENT_BIT, module, "main"); } 101 102 void AddVertexBuffer(u32 binding, u32 stride, VkVertexInputRate input_rate = VK_VERTEX_INPUT_RATE_VERTEX); 103 void AddVertexAttribute(u32 location, u32 binding, VkFormat format, u32 offset); 104 105 void SetPrimitiveTopology(VkPrimitiveTopology topology, bool enable_primitive_restart = false); 106 107 void SetRasterizationState(VkPolygonMode polygon_mode, VkCullModeFlags cull_mode, VkFrontFace front_face); 108 void SetLineWidth(float width); 109 void SetLineRasterizationMode(VkLineRasterizationModeEXT mode); 110 void SetMultisamples(VkSampleCountFlagBits samples); 111 void SetMultisamples(u32 multisamples, bool per_sample_shading); 112 void SetNoCullRasterizationState(); 113 114 void SetDepthState(bool depth_test, bool depth_write, VkCompareOp compare_op); 115 void SetStencilState(bool stencil_test, const VkStencilOpState& front, const VkStencilOpState& back); 116 void SetNoDepthTestState(); 117 void SetNoStencilState(); 118 119 void AddBlendAttachment(bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor, VkBlendOp op, 120 VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, VkBlendOp alpha_op, 121 VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | 122 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); 123 void SetBlendAttachment(u32 attachment, bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor, 124 VkBlendOp op, VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, 125 VkBlendOp alpha_op, 126 VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | 127 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); 128 void SetColorWriteMask(u32 attachment, 129 VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | 130 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); 131 void AddBlendFlags(u32 flags); 132 void ClearBlendAttachments(); 133 134 void SetBlendConstants(float r, float g, float b, float a); 135 void SetNoBlendingState(); 136 137 void AddDynamicState(VkDynamicState state); 138 139 void SetDynamicViewportAndScissorState(); 140 void SetViewport(float x, float y, float width, float height, float min_depth, float max_depth); 141 void SetScissorRect(s32 x, s32 y, u32 width, u32 height); 142 143 void SetPipelineLayout(VkPipelineLayout layout); 144 void SetRenderPass(VkRenderPass render_pass, u32 subpass); 145 146 void SetProvokingVertex(VkProvokingVertexModeEXT mode); 147 148 void SetDynamicRendering(); 149 void AddDynamicRenderingColorAttachment(VkFormat format); 150 void SetDynamicRenderingDepthAttachment(VkFormat depth_format, VkFormat stencil_format); 151 void AddDynamicRenderingInputAttachment(u32 color_attachment_index); 152 153 private: 154 VkGraphicsPipelineCreateInfo m_ci; 155 std::array<VkPipelineShaderStageCreateInfo, MAX_SHADER_STAGES> m_shader_stages; 156 157 VkPipelineVertexInputStateCreateInfo m_vertex_input_state; 158 std::array<VkVertexInputBindingDescription, MAX_VERTEX_BUFFERS> m_vertex_buffers; 159 std::array<VkVertexInputAttributeDescription, MAX_VERTEX_ATTRIBUTES> m_vertex_attributes; 160 161 VkPipelineInputAssemblyStateCreateInfo m_input_assembly; 162 163 VkPipelineRasterizationStateCreateInfo m_rasterization_state; 164 VkPipelineDepthStencilStateCreateInfo m_depth_state; 165 166 VkPipelineColorBlendStateCreateInfo m_blend_state; 167 std::array<VkPipelineColorBlendAttachmentState, MAX_ATTACHMENTS> m_blend_attachments; 168 169 VkPipelineViewportStateCreateInfo m_viewport_state; 170 VkViewport m_viewport; 171 VkRect2D m_scissor; 172 173 VkPipelineDynamicStateCreateInfo m_dynamic_state; 174 std::array<VkDynamicState, MAX_DYNAMIC_STATE> m_dynamic_state_values; 175 176 VkPipelineMultisampleStateCreateInfo m_multisample_state; 177 178 VkPipelineRasterizationProvokingVertexStateCreateInfoEXT m_provoking_vertex; 179 VkPipelineRasterizationLineStateCreateInfoEXT m_line_rasterization_state; 180 181 VkPipelineRenderingCreateInfoKHR m_rendering; 182 VkRenderingAttachmentLocationInfoKHR m_rendering_input_attachment_locations; 183 std::array<VkFormat, MAX_ATTACHMENTS> m_rendering_color_formats; 184 std::array<u32, MAX_INPUT_ATTACHMENTS> m_rendering_input_attachment_indices; 185 }; 186 187 class ComputePipelineBuilder 188 { 189 public: 190 enum : u32 191 { 192 SPECIALIZATION_CONSTANT_SIZE = 4, 193 MAX_SPECIALIZATION_CONSTANTS = 4, 194 }; 195 196 ComputePipelineBuilder(); 197 198 void Clear(); 199 200 VkPipeline Create(VkDevice device, VkPipelineCache pipeline_cache = VK_NULL_HANDLE, bool clear = true); 201 202 void SetShader(VkShaderModule module, const char* entry_point); 203 204 void SetPipelineLayout(VkPipelineLayout layout); 205 206 void SetSpecializationBool(u32 index, bool value); 207 208 private: 209 void SetSpecializationValue(u32 index, u32 value); 210 211 VkComputePipelineCreateInfo m_ci; 212 213 VkSpecializationInfo m_si; 214 std::array<VkSpecializationMapEntry, MAX_SPECIALIZATION_CONSTANTS> m_smap_entries; 215 std::array<u8, SPECIALIZATION_CONSTANT_SIZE * MAX_SPECIALIZATION_CONSTANTS> m_smap_constants; 216 }; 217 218 class SamplerBuilder 219 { 220 public: 221 SamplerBuilder(); 222 223 void Clear(); 224 225 VkSampler Create(VkDevice device, bool clear = true); 226 227 void SetFilter(VkFilter mag_filter, VkFilter min_filter, VkSamplerMipmapMode mip_filter); 228 void SetAddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w); 229 230 void SetPointSampler(VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); 231 void SetLinearSampler(bool mipmaps, VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); 232 233 private: 234 VkSamplerCreateInfo m_ci; 235 }; 236 237 class DescriptorSetUpdateBuilder 238 { 239 enum : u32 240 { 241 MAX_WRITES = 16, 242 MAX_IMAGE_INFOS = 8, 243 MAX_BUFFER_INFOS = 4, 244 MAX_VIEWS = 4, 245 }; 246 247 public: 248 DescriptorSetUpdateBuilder(); 249 250 void Clear(); 251 252 void Update(VkDevice device, bool clear = true); 253 void PushUpdate(VkCommandBuffer cmdbuf, VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 set, 254 bool clear = true); 255 256 void AddImageDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view, 257 VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 258 void AddSamplerDescriptorWrite(VkDescriptorSet set, u32 binding, VkSampler sampler); 259 void AddSamplerDescriptorWrites(VkDescriptorSet set, u32 binding, const VkSampler* samplers, u32 num_samplers); 260 void AddCombinedImageSamplerDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view, VkSampler sampler, 261 VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 262 void AddCombinedImageSamplerDescriptorWrites(VkDescriptorSet set, u32 binding, const VkImageView* views, 263 const VkSampler* samplers, u32 num_views, 264 VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 265 void AddBufferDescriptorWrite(VkDescriptorSet set, u32 binding, VkDescriptorType dtype, VkBuffer buffer, u32 offset, 266 u32 size); 267 void AddBufferViewDescriptorWrite(VkDescriptorSet set, u32 binding, VkDescriptorType dtype, VkBufferView view); 268 void AddInputAttachmentDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view, 269 VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL); 270 void AddStorageImageDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view, 271 VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL); 272 273 private: 274 std::array<VkWriteDescriptorSet, MAX_WRITES> m_writes; 275 u32 m_num_writes = 0; 276 277 std::array<VkDescriptorBufferInfo, MAX_BUFFER_INFOS> m_buffer_infos; 278 std::array<VkDescriptorImageInfo, MAX_IMAGE_INFOS> m_image_infos; 279 std::array<VkBufferView, MAX_VIEWS> m_views; 280 u32 m_num_buffer_infos = 0; 281 u32 m_num_image_infos = 0; 282 u32 m_num_views = 0; 283 }; 284 285 class FramebufferBuilder 286 { 287 enum : u32 288 { 289 MAX_ATTACHMENTS = GPUDevice::MAX_RENDER_TARGETS + 1, 290 }; 291 292 public: 293 FramebufferBuilder(); 294 295 void Clear(); 296 297 VkFramebuffer Create(VkDevice device, bool clear = true); 298 299 void AddAttachment(VkImageView image); 300 301 void SetSize(u32 width, u32 height, u32 layers); 302 303 void SetRenderPass(VkRenderPass render_pass); 304 305 private: 306 VkFramebufferCreateInfo m_ci; 307 std::array<VkImageView, MAX_ATTACHMENTS> m_images; 308 }; 309 310 class RenderPassBuilder 311 { 312 enum : u32 313 { 314 MAX_ATTACHMENTS = 2, 315 MAX_ATTACHMENT_REFERENCES = 2, 316 MAX_SUBPASSES = 1, 317 }; 318 319 public: 320 RenderPassBuilder(); 321 322 void Clear(); 323 324 VkRenderPass Create(VkDevice device, bool clear = true); 325 326 u32 AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load_op, 327 VkAttachmentStoreOp store_op, VkImageLayout initial_layout, VkImageLayout final_layout); 328 329 u32 AddSubpass(); 330 void AddSubpassColorAttachment(u32 subpass, u32 attachment, VkImageLayout layout); 331 void AddSubpassDepthAttachment(u32 subpass, u32 attachment, VkImageLayout layout); 332 333 private: 334 VkRenderPassCreateInfo m_ci; 335 std::array<VkAttachmentDescription, MAX_ATTACHMENTS> m_attachments; 336 std::array<VkAttachmentReference, MAX_ATTACHMENT_REFERENCES> m_attachment_references; 337 u32 m_num_attachment_references = 0; 338 std::array<VkSubpassDescription, MAX_SUBPASSES> m_subpasses; 339 }; 340 341 class BufferViewBuilder 342 { 343 public: 344 BufferViewBuilder(); 345 346 void Clear(); 347 348 VkBufferView Create(VkDevice device, bool clear = true); 349 350 void Set(VkBuffer buffer, VkFormat format, u32 offset, u32 size); 351 352 private: 353 VkBufferViewCreateInfo m_ci; 354 }; 355 356 #ifdef ENABLE_VULKAN_DEBUG_OBJECTS 357 358 // Provides a compile-time mapping between a Vulkan-type into its matching VkObjectType 359 template<typename T> 360 struct VkObjectTypeMap; 361 362 // clang-format off 363 template<> struct VkObjectTypeMap<VkInstance > { using type = VkInstance; static constexpr VkObjectType value = VK_OBJECT_TYPE_INSTANCE; }; 364 template<> struct VkObjectTypeMap<VkPhysicalDevice > { using type = VkPhysicalDevice; static constexpr VkObjectType value = VK_OBJECT_TYPE_PHYSICAL_DEVICE; }; 365 template<> struct VkObjectTypeMap<VkDevice > { using type = VkDevice; static constexpr VkObjectType value = VK_OBJECT_TYPE_DEVICE; }; 366 template<> struct VkObjectTypeMap<VkQueue > { using type = VkQueue; static constexpr VkObjectType value = VK_OBJECT_TYPE_QUEUE; }; 367 template<> struct VkObjectTypeMap<VkSemaphore > { using type = VkSemaphore; static constexpr VkObjectType value = VK_OBJECT_TYPE_SEMAPHORE; }; 368 template<> struct VkObjectTypeMap<VkCommandBuffer > { using type = VkCommandBuffer; static constexpr VkObjectType value = VK_OBJECT_TYPE_COMMAND_BUFFER; }; 369 template<> struct VkObjectTypeMap<VkFence > { using type = VkFence; static constexpr VkObjectType value = VK_OBJECT_TYPE_FENCE; }; 370 template<> struct VkObjectTypeMap<VkDeviceMemory > { using type = VkDeviceMemory; static constexpr VkObjectType value = VK_OBJECT_TYPE_DEVICE_MEMORY; }; 371 template<> struct VkObjectTypeMap<VkBuffer > { using type = VkBuffer; static constexpr VkObjectType value = VK_OBJECT_TYPE_BUFFER; }; 372 template<> struct VkObjectTypeMap<VkImage > { using type = VkImage; static constexpr VkObjectType value = VK_OBJECT_TYPE_IMAGE; }; 373 template<> struct VkObjectTypeMap<VkEvent > { using type = VkEvent; static constexpr VkObjectType value = VK_OBJECT_TYPE_EVENT; }; 374 template<> struct VkObjectTypeMap<VkQueryPool > { using type = VkQueryPool; static constexpr VkObjectType value = VK_OBJECT_TYPE_QUERY_POOL; }; 375 template<> struct VkObjectTypeMap<VkBufferView > { using type = VkBufferView; static constexpr VkObjectType value = VK_OBJECT_TYPE_BUFFER_VIEW; }; 376 template<> struct VkObjectTypeMap<VkImageView > { using type = VkImageView; static constexpr VkObjectType value = VK_OBJECT_TYPE_IMAGE_VIEW; }; 377 template<> struct VkObjectTypeMap<VkShaderModule > { using type = VkShaderModule; static constexpr VkObjectType value = VK_OBJECT_TYPE_SHADER_MODULE; }; 378 template<> struct VkObjectTypeMap<VkPipelineCache > { using type = VkPipelineCache; static constexpr VkObjectType value = VK_OBJECT_TYPE_PIPELINE_CACHE; }; 379 template<> struct VkObjectTypeMap<VkPipelineLayout > { using type = VkPipelineLayout; static constexpr VkObjectType value = VK_OBJECT_TYPE_PIPELINE_LAYOUT; }; 380 template<> struct VkObjectTypeMap<VkRenderPass > { using type = VkRenderPass; static constexpr VkObjectType value = VK_OBJECT_TYPE_RENDER_PASS; }; 381 template<> struct VkObjectTypeMap<VkPipeline > { using type = VkPipeline; static constexpr VkObjectType value = VK_OBJECT_TYPE_PIPELINE; }; 382 template<> struct VkObjectTypeMap<VkDescriptorSetLayout > { using type = VkDescriptorSetLayout; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT; }; 383 template<> struct VkObjectTypeMap<VkSampler > { using type = VkSampler; static constexpr VkObjectType value = VK_OBJECT_TYPE_SAMPLER; }; 384 template<> struct VkObjectTypeMap<VkDescriptorPool > { using type = VkDescriptorPool; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_POOL; }; 385 template<> struct VkObjectTypeMap<VkDescriptorSet > { using type = VkDescriptorSet; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_SET; }; 386 template<> struct VkObjectTypeMap<VkFramebuffer > { using type = VkFramebuffer; static constexpr VkObjectType value = VK_OBJECT_TYPE_FRAMEBUFFER; }; 387 template<> struct VkObjectTypeMap<VkCommandPool > { using type = VkCommandPool; static constexpr VkObjectType value = VK_OBJECT_TYPE_COMMAND_POOL; }; 388 template<> struct VkObjectTypeMap<VkDescriptorUpdateTemplate> { using type = VkDescriptorUpdateTemplate; static constexpr VkObjectType value = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE; }; 389 template<> struct VkObjectTypeMap<VkSurfaceKHR > { using type = VkSurfaceKHR; static constexpr VkObjectType value = VK_OBJECT_TYPE_SURFACE_KHR; }; 390 template<> struct VkObjectTypeMap<VkSwapchainKHR > { using type = VkSwapchainKHR; static constexpr VkObjectType value = VK_OBJECT_TYPE_SWAPCHAIN_KHR; }; 391 template<> struct VkObjectTypeMap<VkDebugUtilsMessengerEXT > { using type = VkDebugUtilsMessengerEXT; static constexpr VkObjectType value = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT; }; 392 // clang-format on 393 394 #endif 395 396 template<typename T> 397 static inline void SetObjectName(VkDevice device, T object_handle, const std::string_view name) 398 { 399 #ifdef ENABLE_VULKAN_DEBUG_OBJECTS 400 if (!vkSetDebugUtilsObjectNameEXT) 401 return; 402 403 const SmallString terminated_name(name); 404 const VkDebugUtilsObjectNameInfoEXT name_info{ 405 VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, nullptr, VkObjectTypeMap<T>::value, 406 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(static_cast<typename VkObjectTypeMap<T>::type>(object_handle))), 407 terminated_name.c_str()}; 408 vkSetDebugUtilsObjectNameEXT(device, &name_info); 409 #endif 410 } 411 } // namespace Vulkan