duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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