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.cpp (34595B)


      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 #include "vulkan_builders.h"
      5 
      6 #include "common/assert.h"
      7 #include "common/error.h"
      8 #include "common/log.h"
      9 
     10 #include <limits>
     11 
     12 void Vulkan::AddPointerToChain(void* head, const void* ptr)
     13 {
     14   VkBaseInStructure* last_st = static_cast<VkBaseInStructure*>(head);
     15   while (last_st->pNext)
     16   {
     17     if (last_st->pNext == ptr)
     18       return;
     19 
     20     last_st = const_cast<VkBaseInStructure*>(last_st->pNext);
     21   }
     22 
     23   last_st->pNext = static_cast<const VkBaseInStructure*>(ptr);
     24 }
     25 
     26 const char* Vulkan::VkResultToString(VkResult res)
     27 {
     28   switch (res)
     29   {
     30     case VK_SUCCESS:
     31       return "VK_SUCCESS";
     32 
     33     case VK_NOT_READY:
     34       return "VK_NOT_READY";
     35 
     36     case VK_TIMEOUT:
     37       return "VK_TIMEOUT";
     38 
     39     case VK_EVENT_SET:
     40       return "VK_EVENT_SET";
     41 
     42     case VK_EVENT_RESET:
     43       return "VK_EVENT_RESET";
     44 
     45     case VK_INCOMPLETE:
     46       return "VK_INCOMPLETE";
     47 
     48     case VK_ERROR_OUT_OF_HOST_MEMORY:
     49       return "VK_ERROR_OUT_OF_HOST_MEMORY";
     50 
     51     case VK_ERROR_OUT_OF_DEVICE_MEMORY:
     52       return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
     53 
     54     case VK_ERROR_INITIALIZATION_FAILED:
     55       return "VK_ERROR_INITIALIZATION_FAILED";
     56 
     57     case VK_ERROR_DEVICE_LOST:
     58       return "VK_ERROR_DEVICE_LOST";
     59 
     60     case VK_ERROR_MEMORY_MAP_FAILED:
     61       return "VK_ERROR_MEMORY_MAP_FAILED";
     62 
     63     case VK_ERROR_LAYER_NOT_PRESENT:
     64       return "VK_ERROR_LAYER_NOT_PRESENT";
     65 
     66     case VK_ERROR_EXTENSION_NOT_PRESENT:
     67       return "VK_ERROR_EXTENSION_NOT_PRESENT";
     68 
     69     case VK_ERROR_FEATURE_NOT_PRESENT:
     70       return "VK_ERROR_FEATURE_NOT_PRESENT";
     71 
     72     case VK_ERROR_INCOMPATIBLE_DRIVER:
     73       return "VK_ERROR_INCOMPATIBLE_DRIVER";
     74 
     75     case VK_ERROR_TOO_MANY_OBJECTS:
     76       return "VK_ERROR_TOO_MANY_OBJECTS";
     77 
     78     case VK_ERROR_FORMAT_NOT_SUPPORTED:
     79       return "VK_ERROR_FORMAT_NOT_SUPPORTED";
     80 
     81     case VK_ERROR_SURFACE_LOST_KHR:
     82       return "VK_ERROR_SURFACE_LOST_KHR";
     83 
     84     case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
     85       return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
     86 
     87     case VK_SUBOPTIMAL_KHR:
     88       return "VK_SUBOPTIMAL_KHR";
     89 
     90     case VK_ERROR_OUT_OF_DATE_KHR:
     91       return "VK_ERROR_OUT_OF_DATE_KHR";
     92 
     93     case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
     94       return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
     95 
     96     case VK_ERROR_VALIDATION_FAILED_EXT:
     97       return "VK_ERROR_VALIDATION_FAILED_EXT";
     98 
     99     case VK_ERROR_INVALID_SHADER_NV:
    100       return "VK_ERROR_INVALID_SHADER_NV";
    101 
    102     default:
    103       return "UNKNOWN_VK_RESULT";
    104   }
    105 }
    106 
    107 void Vulkan::LogVulkanResult(const char* func_name, VkResult res, std::string_view msg)
    108 {
    109   Log::FastWrite("VulkanDevice", func_name, LOGLEVEL_ERROR, "{} (0x{:08X}: {})", msg, static_cast<unsigned>(res),
    110                  VkResultToString(res));
    111 }
    112 
    113 void Vulkan::SetErrorObject(Error* errptr, std::string_view prefix, VkResult res)
    114 {
    115   Error::SetStringFmt(errptr, "{} (0x{:08X}: {})", prefix, static_cast<unsigned>(res), VkResultToString(res));
    116 }
    117 
    118 Vulkan::DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder()
    119 {
    120   Clear();
    121 }
    122 
    123 void Vulkan::DescriptorSetLayoutBuilder::Clear()
    124 {
    125   m_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
    126   m_ci.pNext = nullptr;
    127   m_ci.flags = 0;
    128   m_ci.pBindings = nullptr;
    129   m_ci.bindingCount = 0;
    130 }
    131 
    132 void Vulkan::DescriptorSetLayoutBuilder::SetPushFlag()
    133 {
    134   m_ci.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
    135 }
    136 
    137 VkDescriptorSetLayout Vulkan::DescriptorSetLayoutBuilder::Create(VkDevice device)
    138 {
    139   VkDescriptorSetLayout layout;
    140   VkResult res = vkCreateDescriptorSetLayout(device, &m_ci, nullptr, &layout);
    141   if (res != VK_SUCCESS)
    142   {
    143     LOG_VULKAN_ERROR(res, "vkCreateDescriptorSetLayout() failed: ");
    144     return VK_NULL_HANDLE;
    145   }
    146 
    147   Clear();
    148   return layout;
    149 }
    150 
    151 void Vulkan::DescriptorSetLayoutBuilder::AddBinding(u32 binding, VkDescriptorType dtype, u32 dcount,
    152                                                     VkShaderStageFlags stages)
    153 {
    154   DebugAssert(m_ci.bindingCount < MAX_BINDINGS);
    155 
    156   VkDescriptorSetLayoutBinding& b = m_bindings[m_ci.bindingCount];
    157   b.binding = binding;
    158   b.descriptorType = dtype;
    159   b.descriptorCount = dcount;
    160   b.stageFlags = stages;
    161   b.pImmutableSamplers = nullptr;
    162 
    163   m_ci.pBindings = m_bindings.data();
    164   m_ci.bindingCount++;
    165 }
    166 
    167 Vulkan::PipelineLayoutBuilder::PipelineLayoutBuilder()
    168 {
    169   Clear();
    170 }
    171 
    172 void Vulkan::PipelineLayoutBuilder::Clear()
    173 {
    174   m_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
    175   m_ci.pNext = nullptr;
    176   m_ci.flags = 0;
    177   m_ci.pSetLayouts = nullptr;
    178   m_ci.setLayoutCount = 0;
    179   m_ci.pPushConstantRanges = nullptr;
    180   m_ci.pushConstantRangeCount = 0;
    181 }
    182 
    183 VkPipelineLayout Vulkan::PipelineLayoutBuilder::Create(VkDevice device)
    184 {
    185   VkPipelineLayout layout;
    186   VkResult res = vkCreatePipelineLayout(device, &m_ci, nullptr, &layout);
    187   if (res != VK_SUCCESS)
    188   {
    189     LOG_VULKAN_ERROR(res, "vkCreatePipelineLayout() failed: ");
    190     return VK_NULL_HANDLE;
    191   }
    192 
    193   Clear();
    194   return layout;
    195 }
    196 
    197 void Vulkan::PipelineLayoutBuilder::AddDescriptorSet(VkDescriptorSetLayout layout)
    198 {
    199   DebugAssert(m_ci.setLayoutCount < MAX_SETS);
    200 
    201   m_sets[m_ci.setLayoutCount] = layout;
    202 
    203   m_ci.setLayoutCount++;
    204   m_ci.pSetLayouts = m_sets.data();
    205 }
    206 
    207 void Vulkan::PipelineLayoutBuilder::AddPushConstants(VkShaderStageFlags stages, u32 offset, u32 size)
    208 {
    209   DebugAssert(m_ci.pushConstantRangeCount < MAX_PUSH_CONSTANTS);
    210 
    211   VkPushConstantRange& r = m_push_constants[m_ci.pushConstantRangeCount];
    212   r.stageFlags = stages;
    213   r.offset = offset;
    214   r.size = size;
    215 
    216   m_ci.pushConstantRangeCount++;
    217   m_ci.pPushConstantRanges = m_push_constants.data();
    218 }
    219 
    220 Vulkan::GraphicsPipelineBuilder::GraphicsPipelineBuilder()
    221 {
    222   Clear();
    223 }
    224 
    225 void Vulkan::GraphicsPipelineBuilder::Clear()
    226 {
    227   m_ci = {};
    228   m_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    229 
    230   m_shader_stages = {};
    231 
    232   m_vertex_input_state = {};
    233   m_vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    234   m_ci.pVertexInputState = &m_vertex_input_state;
    235   m_vertex_attributes = {};
    236   m_vertex_buffers = {};
    237 
    238   m_input_assembly = {};
    239   m_input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
    240 
    241   m_rasterization_state = {};
    242   m_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
    243   m_rasterization_state.lineWidth = 1.0f;
    244   m_depth_state = {};
    245   m_depth_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
    246   m_blend_state = {};
    247   m_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    248   m_blend_attachments = {};
    249 
    250   m_viewport_state = {};
    251   m_viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
    252   m_viewport = {};
    253   m_scissor = {};
    254 
    255   m_dynamic_state = {};
    256   m_dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
    257   m_dynamic_state_values = {};
    258 
    259   m_multisample_state = {};
    260   m_multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
    261 
    262   m_provoking_vertex = {};
    263   m_provoking_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
    264 
    265   m_line_rasterization_state = {};
    266   m_line_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
    267 
    268   m_rendering = {};
    269   m_rendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
    270 
    271   m_rendering_input_attachment_locations = {};
    272   m_rendering_input_attachment_locations.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR;
    273 
    274   // set defaults
    275   SetNoCullRasterizationState();
    276   SetNoDepthTestState();
    277   SetNoBlendingState();
    278   SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
    279 
    280   // have to be specified even if dynamic
    281   SetViewport(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f);
    282   SetScissorRect(0, 0, 1, 1);
    283   SetMultisamples(VK_SAMPLE_COUNT_1_BIT);
    284 }
    285 
    286 VkPipeline Vulkan::GraphicsPipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache, bool clear,
    287                                                    Error* error)
    288 {
    289   VkPipeline pipeline;
    290   VkResult res = vkCreateGraphicsPipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
    291   if (res != VK_SUCCESS)
    292   {
    293     LOG_VULKAN_ERROR(res, "vkCreateGraphicsPipelines() failed: ");
    294     SetErrorObject(error, "vkCreateGraphicsPipelines() failed: ", res);
    295     return VK_NULL_HANDLE;
    296   }
    297 
    298   if (clear)
    299     Clear();
    300 
    301   return pipeline;
    302 }
    303 
    304 void Vulkan::GraphicsPipelineBuilder::SetShaderStage(VkShaderStageFlagBits stage, VkShaderModule module,
    305                                                      const char* entry_point)
    306 {
    307   DebugAssert(m_ci.stageCount < MAX_SHADER_STAGES);
    308 
    309   u32 index = 0;
    310   for (; index < m_ci.stageCount; index++)
    311   {
    312     if (m_shader_stages[index].stage == stage)
    313       break;
    314   }
    315   if (index == m_ci.stageCount)
    316   {
    317     m_ci.stageCount++;
    318     m_ci.pStages = m_shader_stages.data();
    319   }
    320 
    321   VkPipelineShaderStageCreateInfo& s = m_shader_stages[index];
    322   s.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    323   s.stage = stage;
    324   s.module = module;
    325   s.pName = entry_point;
    326 }
    327 
    328 void Vulkan::GraphicsPipelineBuilder::AddVertexBuffer(u32 binding, u32 stride,
    329                                                       VkVertexInputRate input_rate /*= VK_VERTEX_INPUT_RATE_VERTEX*/)
    330 {
    331   DebugAssert(m_vertex_input_state.vertexAttributeDescriptionCount < MAX_VERTEX_BUFFERS);
    332 
    333   VkVertexInputBindingDescription& b = m_vertex_buffers[m_vertex_input_state.vertexBindingDescriptionCount];
    334   b.binding = binding;
    335   b.stride = stride;
    336   b.inputRate = input_rate;
    337 
    338   m_vertex_input_state.vertexBindingDescriptionCount++;
    339   m_vertex_input_state.pVertexBindingDescriptions = m_vertex_buffers.data();
    340   m_ci.pVertexInputState = &m_vertex_input_state;
    341 }
    342 
    343 void Vulkan::GraphicsPipelineBuilder::AddVertexAttribute(u32 location, u32 binding, VkFormat format, u32 offset)
    344 {
    345   DebugAssert(m_vertex_input_state.vertexAttributeDescriptionCount < MAX_VERTEX_BUFFERS);
    346 
    347   VkVertexInputAttributeDescription& a = m_vertex_attributes[m_vertex_input_state.vertexAttributeDescriptionCount];
    348   a.location = location;
    349   a.binding = binding;
    350   a.format = format;
    351   a.offset = offset;
    352 
    353   m_vertex_input_state.vertexAttributeDescriptionCount++;
    354   m_vertex_input_state.pVertexAttributeDescriptions = m_vertex_attributes.data();
    355   m_ci.pVertexInputState = &m_vertex_input_state;
    356 }
    357 
    358 void Vulkan::GraphicsPipelineBuilder::SetPrimitiveTopology(VkPrimitiveTopology topology,
    359                                                            bool enable_primitive_restart /*= false*/)
    360 {
    361   m_input_assembly.topology = topology;
    362   m_input_assembly.primitiveRestartEnable = enable_primitive_restart;
    363 
    364   m_ci.pInputAssemblyState = &m_input_assembly;
    365 }
    366 
    367 void Vulkan::GraphicsPipelineBuilder::SetRasterizationState(VkPolygonMode polygon_mode, VkCullModeFlags cull_mode,
    368                                                             VkFrontFace front_face)
    369 {
    370   m_rasterization_state.polygonMode = polygon_mode;
    371   m_rasterization_state.cullMode = cull_mode;
    372   m_rasterization_state.frontFace = front_face;
    373 
    374   m_ci.pRasterizationState = &m_rasterization_state;
    375 }
    376 
    377 void Vulkan::GraphicsPipelineBuilder::SetLineWidth(float width)
    378 {
    379   m_rasterization_state.lineWidth = width;
    380 }
    381 
    382 void Vulkan::GraphicsPipelineBuilder::SetLineRasterizationMode(VkLineRasterizationModeEXT mode)
    383 {
    384   AddPointerToChain(&m_rasterization_state, &m_line_rasterization_state);
    385 
    386   m_line_rasterization_state.lineRasterizationMode = mode;
    387 }
    388 
    389 void Vulkan::GraphicsPipelineBuilder::SetMultisamples(u32 multisamples, bool per_sample_shading)
    390 {
    391   m_multisample_state.rasterizationSamples = static_cast<VkSampleCountFlagBits>(multisamples);
    392   m_multisample_state.sampleShadingEnable = per_sample_shading;
    393   m_multisample_state.minSampleShading = (multisamples > 1) ? 1.0f : 0.0f;
    394   m_ci.pMultisampleState = &m_multisample_state;
    395 }
    396 
    397 void Vulkan::GraphicsPipelineBuilder::SetMultisamples(VkSampleCountFlagBits samples)
    398 {
    399   m_multisample_state.rasterizationSamples = samples;
    400   m_ci.pMultisampleState = &m_multisample_state;
    401 }
    402 
    403 void Vulkan::GraphicsPipelineBuilder::SetNoCullRasterizationState()
    404 {
    405   SetRasterizationState(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
    406 }
    407 
    408 void Vulkan::GraphicsPipelineBuilder::SetDepthState(bool depth_test, bool depth_write, VkCompareOp compare_op)
    409 {
    410   m_depth_state.depthTestEnable = depth_test;
    411   m_depth_state.depthWriteEnable = depth_write;
    412   m_depth_state.depthCompareOp = compare_op;
    413 
    414   m_ci.pDepthStencilState = &m_depth_state;
    415 }
    416 
    417 void Vulkan::GraphicsPipelineBuilder::SetStencilState(bool stencil_test, const VkStencilOpState& front,
    418                                                       const VkStencilOpState& back)
    419 {
    420   m_depth_state.stencilTestEnable = stencil_test;
    421   m_depth_state.front = front;
    422   m_depth_state.back = back;
    423 }
    424 
    425 void Vulkan::GraphicsPipelineBuilder::SetNoStencilState()
    426 {
    427   m_depth_state.stencilTestEnable = VK_FALSE;
    428   m_depth_state.front = {};
    429   m_depth_state.back = {};
    430 }
    431 
    432 void Vulkan::GraphicsPipelineBuilder::SetNoDepthTestState()
    433 {
    434   SetDepthState(false, false, VK_COMPARE_OP_ALWAYS);
    435 }
    436 
    437 void Vulkan::GraphicsPipelineBuilder::SetBlendConstants(float r, float g, float b, float a)
    438 {
    439   m_blend_state.blendConstants[0] = r;
    440   m_blend_state.blendConstants[1] = g;
    441   m_blend_state.blendConstants[2] = b;
    442   m_blend_state.blendConstants[3] = a;
    443   m_ci.pColorBlendState = &m_blend_state;
    444 }
    445 
    446 void Vulkan::GraphicsPipelineBuilder::AddBlendAttachment(
    447   bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor, VkBlendOp op,
    448   VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, VkBlendOp alpha_op, VkColorComponentFlags write_mask /* = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT */)
    449 {
    450   DebugAssert(m_blend_state.attachmentCount < MAX_ATTACHMENTS);
    451 
    452   VkPipelineColorBlendAttachmentState& bs = m_blend_attachments[m_blend_state.attachmentCount];
    453   bs.blendEnable = blend_enable;
    454   bs.srcColorBlendFactor = src_factor;
    455   bs.dstColorBlendFactor = dst_factor;
    456   bs.colorBlendOp = op;
    457   bs.srcAlphaBlendFactor = alpha_src_factor;
    458   bs.dstAlphaBlendFactor = alpha_dst_factor;
    459   bs.alphaBlendOp = alpha_op;
    460   bs.colorWriteMask = write_mask;
    461 
    462   m_blend_state.attachmentCount++;
    463   m_blend_state.pAttachments = m_blend_attachments.data();
    464   m_ci.pColorBlendState = &m_blend_state;
    465 }
    466 
    467 void Vulkan::GraphicsPipelineBuilder::SetBlendAttachment(
    468   u32 attachment, bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor, VkBlendOp op,
    469   VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, VkBlendOp alpha_op, VkColorComponentFlags write_mask /*= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT*/)
    470 {
    471   DebugAssert(attachment < MAX_ATTACHMENTS);
    472 
    473   VkPipelineColorBlendAttachmentState& bs = m_blend_attachments[attachment];
    474   bs.blendEnable = blend_enable;
    475   bs.srcColorBlendFactor = src_factor;
    476   bs.dstColorBlendFactor = dst_factor;
    477   bs.colorBlendOp = op;
    478   bs.srcAlphaBlendFactor = alpha_src_factor;
    479   bs.dstAlphaBlendFactor = alpha_dst_factor;
    480   bs.alphaBlendOp = alpha_op;
    481   bs.colorWriteMask = write_mask;
    482 
    483   if (attachment >= m_blend_state.attachmentCount)
    484   {
    485     m_blend_state.attachmentCount = attachment + 1u;
    486     m_blend_state.pAttachments = m_blend_attachments.data();
    487     m_ci.pColorBlendState = &m_blend_state;
    488   }
    489 }
    490 
    491 void Vulkan::GraphicsPipelineBuilder::SetColorWriteMask(u32 attachment, VkColorComponentFlags write_mask)
    492 {
    493   DebugAssert(attachment < MAX_ATTACHMENTS);
    494 
    495   VkPipelineColorBlendAttachmentState& bs = m_blend_attachments[attachment];
    496   bs.colorWriteMask = write_mask;
    497 }
    498 
    499 void Vulkan::GraphicsPipelineBuilder::AddBlendFlags(u32 flags)
    500 {
    501   m_blend_state.flags |= flags;
    502 }
    503 
    504 void Vulkan::GraphicsPipelineBuilder::ClearBlendAttachments()
    505 {
    506   m_blend_attachments = {};
    507   m_blend_state.attachmentCount = 0;
    508 }
    509 
    510 void Vulkan::GraphicsPipelineBuilder::SetNoBlendingState()
    511 {
    512   ClearBlendAttachments();
    513   SetBlendAttachment(0, false, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE,
    514                      VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD,
    515                      VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
    516                        VK_COLOR_COMPONENT_A_BIT);
    517 }
    518 
    519 void Vulkan::GraphicsPipelineBuilder::AddDynamicState(VkDynamicState state)
    520 {
    521   DebugAssert(m_dynamic_state.dynamicStateCount < MAX_DYNAMIC_STATE);
    522 
    523   m_dynamic_state_values[m_dynamic_state.dynamicStateCount] = state;
    524   m_dynamic_state.dynamicStateCount++;
    525   m_dynamic_state.pDynamicStates = m_dynamic_state_values.data();
    526   m_ci.pDynamicState = &m_dynamic_state;
    527 }
    528 
    529 void Vulkan::GraphicsPipelineBuilder::SetDynamicViewportAndScissorState()
    530 {
    531   AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
    532   AddDynamicState(VK_DYNAMIC_STATE_SCISSOR);
    533 }
    534 
    535 void Vulkan::GraphicsPipelineBuilder::SetViewport(float x, float y, float width, float height, float min_depth,
    536                                                   float max_depth)
    537 {
    538   m_viewport.x = x;
    539   m_viewport.y = y;
    540   m_viewport.width = width;
    541   m_viewport.height = height;
    542   m_viewport.minDepth = min_depth;
    543   m_viewport.maxDepth = max_depth;
    544 
    545   m_viewport_state.pViewports = &m_viewport;
    546   m_viewport_state.viewportCount = 1u;
    547   m_ci.pViewportState = &m_viewport_state;
    548 }
    549 
    550 void Vulkan::GraphicsPipelineBuilder::SetScissorRect(s32 x, s32 y, u32 width, u32 height)
    551 {
    552   m_scissor.offset.x = x;
    553   m_scissor.offset.y = y;
    554   m_scissor.extent.width = width;
    555   m_scissor.extent.height = height;
    556 
    557   m_viewport_state.pScissors = &m_scissor;
    558   m_viewport_state.scissorCount = 1u;
    559   m_ci.pViewportState = &m_viewport_state;
    560 }
    561 
    562 void Vulkan::GraphicsPipelineBuilder::SetPipelineLayout(VkPipelineLayout layout)
    563 {
    564   m_ci.layout = layout;
    565 }
    566 
    567 void Vulkan::GraphicsPipelineBuilder::SetRenderPass(VkRenderPass render_pass, u32 subpass)
    568 {
    569   m_ci.renderPass = render_pass;
    570   m_ci.subpass = subpass;
    571 }
    572 
    573 void Vulkan::GraphicsPipelineBuilder::SetProvokingVertex(VkProvokingVertexModeEXT mode)
    574 {
    575   AddPointerToChain(&m_rasterization_state, &m_provoking_vertex);
    576 
    577   m_provoking_vertex.provokingVertexMode = mode;
    578 }
    579 
    580 void Vulkan::GraphicsPipelineBuilder::SetDynamicRendering()
    581 {
    582   AddPointerToChain(&m_ci, &m_rendering);
    583 }
    584 
    585 void Vulkan::GraphicsPipelineBuilder::AddDynamicRenderingColorAttachment(VkFormat format)
    586 {
    587   SetDynamicRendering();
    588 
    589   DebugAssert(m_rendering.colorAttachmentCount < MAX_ATTACHMENTS);
    590   m_rendering_color_formats[m_rendering.colorAttachmentCount++] = format;
    591 
    592   m_rendering.pColorAttachmentFormats = m_rendering_color_formats.data();
    593 }
    594 
    595 void Vulkan::GraphicsPipelineBuilder::SetDynamicRenderingDepthAttachment(VkFormat depth_format, VkFormat stencil_format)
    596 {
    597   SetDynamicRendering();
    598 
    599   m_rendering.depthAttachmentFormat = depth_format;
    600   m_rendering.stencilAttachmentFormat = stencil_format;
    601 }
    602 
    603 void Vulkan::GraphicsPipelineBuilder::AddDynamicRenderingInputAttachment(u32 color_attachment_index)
    604 {
    605   AddPointerToChain(&m_ci, &m_rendering_input_attachment_locations);
    606 
    607   DebugAssert(color_attachment_index < m_rendering.colorAttachmentCount);
    608   DebugAssert(m_rendering_input_attachment_locations.colorAttachmentCount < MAX_INPUT_ATTACHMENTS);
    609 
    610   m_rendering_input_attachment_locations.pColorAttachmentLocations = m_rendering_input_attachment_indices.data();
    611   m_rendering_input_attachment_indices[m_rendering_input_attachment_locations.colorAttachmentCount] =
    612     color_attachment_index;
    613   m_rendering_input_attachment_locations.colorAttachmentCount++;
    614 }
    615 
    616 Vulkan::ComputePipelineBuilder::ComputePipelineBuilder()
    617 {
    618   Clear();
    619 }
    620 
    621 void Vulkan::ComputePipelineBuilder::Clear()
    622 {
    623   m_ci = {};
    624   m_ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
    625   m_si = {};
    626   m_smap_entries = {};
    627   m_smap_constants = {};
    628 }
    629 
    630 VkPipeline Vulkan::ComputePipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache /*= VK_NULL_HANDLE*/,
    631                                                   bool clear /*= true*/)
    632 {
    633   VkPipeline pipeline;
    634   VkResult res = vkCreateComputePipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
    635   if (res != VK_SUCCESS)
    636   {
    637     LOG_VULKAN_ERROR(res, "vkCreateComputePipelines() failed: ");
    638     return VK_NULL_HANDLE;
    639   }
    640 
    641   if (clear)
    642     Clear();
    643 
    644   return pipeline;
    645 }
    646 
    647 void Vulkan::ComputePipelineBuilder::SetShader(VkShaderModule module, const char* entry_point)
    648 {
    649   m_ci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    650   m_ci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
    651   m_ci.stage.module = module;
    652   m_ci.stage.pName = entry_point;
    653 }
    654 
    655 void Vulkan::ComputePipelineBuilder::SetPipelineLayout(VkPipelineLayout layout)
    656 {
    657   m_ci.layout = layout;
    658 }
    659 
    660 void Vulkan::ComputePipelineBuilder::SetSpecializationBool(u32 index, bool value)
    661 {
    662   const u32 u32_value = static_cast<u32>(value);
    663   SetSpecializationValue(index, u32_value);
    664 }
    665 
    666 void Vulkan::ComputePipelineBuilder::SetSpecializationValue(u32 index, u32 value)
    667 {
    668   if (m_si.mapEntryCount == 0)
    669   {
    670     m_si.pMapEntries = m_smap_entries.data();
    671     m_si.pData = m_smap_constants.data();
    672     m_ci.stage.pSpecializationInfo = &m_si;
    673   }
    674 
    675   m_smap_entries[m_si.mapEntryCount++] = {index, index * SPECIALIZATION_CONSTANT_SIZE, SPECIALIZATION_CONSTANT_SIZE};
    676   m_si.dataSize += SPECIALIZATION_CONSTANT_SIZE;
    677 }
    678 
    679 Vulkan::SamplerBuilder::SamplerBuilder()
    680 {
    681   Clear();
    682 }
    683 
    684 void Vulkan::SamplerBuilder::Clear()
    685 {
    686   m_ci = {};
    687   m_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
    688 }
    689 
    690 VkSampler Vulkan::SamplerBuilder::Create(VkDevice device, bool clear /* = true */)
    691 {
    692   VkSampler sampler;
    693   VkResult res = vkCreateSampler(device, &m_ci, nullptr, &sampler);
    694   if (res != VK_SUCCESS)
    695   {
    696     LOG_VULKAN_ERROR(res, "vkCreateSampler() failed: ");
    697     return VK_NULL_HANDLE;
    698   }
    699 
    700   return sampler;
    701 }
    702 
    703 void Vulkan::SamplerBuilder::SetFilter(VkFilter mag_filter, VkFilter min_filter, VkSamplerMipmapMode mip_filter)
    704 {
    705   m_ci.magFilter = mag_filter;
    706   m_ci.minFilter = min_filter;
    707   m_ci.mipmapMode = mip_filter;
    708 }
    709 
    710 void Vulkan::SamplerBuilder::SetAddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w)
    711 {
    712   m_ci.addressModeU = u;
    713   m_ci.addressModeV = v;
    714   m_ci.addressModeW = w;
    715 }
    716 
    717 void Vulkan::SamplerBuilder::SetPointSampler(
    718   VkSamplerAddressMode address_mode /* = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER */)
    719 {
    720   Clear();
    721   SetFilter(VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST);
    722   SetAddressMode(address_mode, address_mode, address_mode);
    723 }
    724 
    725 void Vulkan::SamplerBuilder::SetLinearSampler(
    726   bool mipmaps, VkSamplerAddressMode address_mode /* = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER */)
    727 {
    728   Clear();
    729   SetFilter(VK_FILTER_LINEAR, VK_FILTER_LINEAR,
    730             mipmaps ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST);
    731   SetAddressMode(address_mode, address_mode, address_mode);
    732 
    733   if (mipmaps)
    734   {
    735     m_ci.minLod = std::numeric_limits<float>::min();
    736     m_ci.maxLod = std::numeric_limits<float>::max();
    737   }
    738 }
    739 
    740 Vulkan::DescriptorSetUpdateBuilder::DescriptorSetUpdateBuilder()
    741 {
    742   Clear();
    743 }
    744 
    745 void Vulkan::DescriptorSetUpdateBuilder::Clear()
    746 {
    747   m_writes = {};
    748   m_num_writes = 0;
    749 }
    750 
    751 void Vulkan::DescriptorSetUpdateBuilder::Update(VkDevice device, bool clear /*= true*/)
    752 {
    753   DebugAssert(m_num_writes > 0);
    754 
    755   vkUpdateDescriptorSets(device, m_num_writes, (m_num_writes > 0) ? m_writes.data() : nullptr, 0, nullptr);
    756 
    757   if (clear)
    758     Clear();
    759 }
    760 
    761 void Vulkan::DescriptorSetUpdateBuilder::PushUpdate(VkCommandBuffer cmdbuf, VkPipelineBindPoint bind_point,
    762                                                     VkPipelineLayout layout, u32 set, bool clear /*= true*/)
    763 {
    764   DebugAssert(m_num_writes > 0);
    765 
    766   vkCmdPushDescriptorSetKHR(cmdbuf, bind_point, layout, set, m_num_writes, m_writes.data());
    767 
    768   if (clear)
    769     Clear();
    770 }
    771 
    772 void Vulkan::DescriptorSetUpdateBuilder::AddImageDescriptorWrite(
    773   VkDescriptorSet set, u32 binding, VkImageView view,
    774   VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/)
    775 {
    776   DebugAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
    777 
    778   VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
    779   ii.imageView = view;
    780   ii.imageLayout = layout;
    781   ii.sampler = VK_NULL_HANDLE;
    782 
    783   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    784   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    785   dw.dstSet = set;
    786   dw.dstBinding = binding;
    787   dw.descriptorCount = 1;
    788   dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
    789   dw.pImageInfo = &ii;
    790 }
    791 
    792 void Vulkan::DescriptorSetUpdateBuilder::AddSamplerDescriptorWrite(VkDescriptorSet set, u32 binding, VkSampler sampler)
    793 {
    794   DebugAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
    795 
    796   VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
    797   ii.imageView = VK_NULL_HANDLE;
    798   ii.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    799   ii.sampler = sampler;
    800 
    801   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    802   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    803   dw.dstSet = set;
    804   dw.dstBinding = binding;
    805   dw.descriptorCount = 1;
    806   dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
    807   dw.pImageInfo = &ii;
    808 }
    809 
    810 void Vulkan::DescriptorSetUpdateBuilder::AddSamplerDescriptorWrites(VkDescriptorSet set, u32 binding,
    811                                                                     const VkSampler* samplers, u32 num_samplers)
    812 {
    813   DebugAssert(m_num_writes < MAX_WRITES && (m_num_image_infos + num_samplers) < MAX_IMAGE_INFOS);
    814 
    815   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    816   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    817   dw.dstSet = set;
    818   dw.dstBinding = binding;
    819   dw.descriptorCount = num_samplers;
    820   dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
    821   dw.pImageInfo = &m_image_infos[m_num_image_infos];
    822 
    823   for (u32 i = 0; i < num_samplers; i++)
    824   {
    825     VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
    826     ii.imageView = VK_NULL_HANDLE;
    827     ii.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
    828     ii.sampler = samplers[i];
    829   }
    830 }
    831 
    832 void Vulkan::DescriptorSetUpdateBuilder::AddCombinedImageSamplerDescriptorWrite(
    833   VkDescriptorSet set, u32 binding, VkImageView view, VkSampler sampler,
    834   VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/)
    835 {
    836   DebugAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
    837 
    838   VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
    839   ii.imageView = view;
    840   ii.imageLayout = layout;
    841   ii.sampler = sampler;
    842 
    843   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    844   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    845   dw.dstSet = set;
    846   dw.dstBinding = binding;
    847   dw.descriptorCount = 1;
    848   dw.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
    849   dw.pImageInfo = &ii;
    850 }
    851 
    852 void Vulkan::DescriptorSetUpdateBuilder::AddCombinedImageSamplerDescriptorWrites(
    853   VkDescriptorSet set, u32 binding, const VkImageView* views, const VkSampler* samplers, u32 num_views,
    854   VkImageLayout layout /* = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL */)
    855 {
    856   DebugAssert(m_num_writes < MAX_WRITES && (m_num_image_infos + num_views) < MAX_IMAGE_INFOS);
    857 
    858   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    859   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    860   dw.dstSet = set;
    861   dw.dstBinding = binding;
    862   dw.descriptorCount = num_views;
    863   dw.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
    864   dw.pImageInfo = &m_image_infos[m_num_image_infos];
    865 
    866   for (u32 i = 0; i < num_views; i++)
    867   {
    868     VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
    869     ii.imageView = views[i];
    870     ii.sampler = samplers[i];
    871     ii.imageLayout = layout;
    872   }
    873 }
    874 
    875 void Vulkan::DescriptorSetUpdateBuilder::AddBufferDescriptorWrite(VkDescriptorSet set, u32 binding,
    876                                                                   VkDescriptorType dtype, VkBuffer buffer, u32 offset,
    877                                                                   u32 size)
    878 {
    879   DebugAssert(m_num_writes < MAX_WRITES && m_num_buffer_infos < MAX_BUFFER_INFOS);
    880 
    881   VkDescriptorBufferInfo& bi = m_buffer_infos[m_num_buffer_infos++];
    882   bi.buffer = buffer;
    883   bi.offset = offset;
    884   bi.range = size;
    885 
    886   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    887   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    888   dw.dstSet = set;
    889   dw.dstBinding = binding;
    890   dw.descriptorCount = 1;
    891   dw.descriptorType = dtype;
    892   dw.pBufferInfo = &bi;
    893 }
    894 
    895 void Vulkan::DescriptorSetUpdateBuilder::AddBufferViewDescriptorWrite(VkDescriptorSet set, u32 binding,
    896                                                                       VkDescriptorType dtype, VkBufferView view)
    897 {
    898   DebugAssert(m_num_writes < MAX_WRITES && m_num_views < MAX_VIEWS);
    899 
    900   VkBufferView& bi = m_views[m_num_views++];
    901   bi = view;
    902 
    903   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    904   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    905   dw.dstSet = set;
    906   dw.dstBinding = binding;
    907   dw.descriptorCount = 1;
    908   dw.descriptorType = dtype;
    909   dw.pTexelBufferView = &bi;
    910 }
    911 
    912 void Vulkan::DescriptorSetUpdateBuilder::AddInputAttachmentDescriptorWrite(
    913   VkDescriptorSet set, u32 binding, VkImageView view, VkImageLayout layout /*= VK_IMAGE_LAYOUT_GENERAL*/)
    914 {
    915   DebugAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
    916 
    917   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    918   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    919   dw.dstSet = set;
    920   dw.dstBinding = binding;
    921   dw.descriptorCount = 1;
    922   dw.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
    923   dw.pImageInfo = &m_image_infos[m_num_image_infos];
    924 
    925   VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
    926   ii.imageView = view;
    927   ii.imageLayout = layout;
    928   ii.sampler = VK_NULL_HANDLE;
    929 }
    930 
    931 void Vulkan::DescriptorSetUpdateBuilder::AddStorageImageDescriptorWrite(
    932   VkDescriptorSet set, u32 binding, VkImageView view, VkImageLayout layout /*= VK_IMAGE_LAYOUT_GENERAL*/)
    933 {
    934   DebugAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
    935 
    936   VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
    937   dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    938   dw.dstSet = set;
    939   dw.dstBinding = binding;
    940   dw.descriptorCount = 1;
    941   dw.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
    942   dw.pImageInfo = &m_image_infos[m_num_image_infos];
    943 
    944   VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
    945   ii.imageView = view;
    946   ii.imageLayout = layout;
    947   ii.sampler = VK_NULL_HANDLE;
    948 }
    949 
    950 Vulkan::FramebufferBuilder::FramebufferBuilder()
    951 {
    952   Clear();
    953 }
    954 
    955 void Vulkan::FramebufferBuilder::Clear()
    956 {
    957   m_ci = {};
    958   m_ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
    959   m_images = {};
    960 }
    961 
    962 VkFramebuffer Vulkan::FramebufferBuilder::Create(VkDevice device, bool clear /*= true*/)
    963 {
    964   VkFramebuffer fb;
    965   VkResult res = vkCreateFramebuffer(device, &m_ci, nullptr, &fb);
    966   if (res != VK_SUCCESS)
    967   {
    968     LOG_VULKAN_ERROR(res, "vkCreateFramebuffer() failed: ");
    969     return VK_NULL_HANDLE;
    970   }
    971 
    972   if (clear)
    973     Clear();
    974 
    975   return fb;
    976 }
    977 
    978 void Vulkan::FramebufferBuilder::AddAttachment(VkImageView image)
    979 {
    980   DebugAssert(m_ci.attachmentCount < MAX_ATTACHMENTS);
    981 
    982   m_images[m_ci.attachmentCount] = image;
    983 
    984   m_ci.attachmentCount++;
    985   m_ci.pAttachments = m_images.data();
    986 }
    987 
    988 void Vulkan::FramebufferBuilder::SetSize(u32 width, u32 height, u32 layers)
    989 {
    990   m_ci.width = width;
    991   m_ci.height = height;
    992   m_ci.layers = layers;
    993 }
    994 
    995 void Vulkan::FramebufferBuilder::SetRenderPass(VkRenderPass render_pass)
    996 {
    997   m_ci.renderPass = render_pass;
    998 }
    999 
   1000 Vulkan::RenderPassBuilder::RenderPassBuilder()
   1001 {
   1002   Clear();
   1003 }
   1004 
   1005 void Vulkan::RenderPassBuilder::Clear()
   1006 {
   1007   m_ci = {};
   1008   m_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
   1009   m_attachments = {};
   1010   m_attachment_references = {};
   1011   m_num_attachment_references = 0;
   1012   m_subpasses = {};
   1013 }
   1014 
   1015 VkRenderPass Vulkan::RenderPassBuilder::Create(VkDevice device, bool clear /*= true*/)
   1016 {
   1017   VkRenderPass rp;
   1018   VkResult res = vkCreateRenderPass(device, &m_ci, nullptr, &rp);
   1019   if (res != VK_SUCCESS)
   1020   {
   1021     LOG_VULKAN_ERROR(res, "vkCreateRenderPass() failed: ");
   1022     return VK_NULL_HANDLE;
   1023   }
   1024 
   1025   return rp;
   1026 }
   1027 
   1028 u32 Vulkan::RenderPassBuilder::AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load_op,
   1029                                              VkAttachmentStoreOp store_op, VkImageLayout initial_layout,
   1030                                              VkImageLayout final_layout)
   1031 {
   1032   DebugAssert(m_ci.attachmentCount < MAX_ATTACHMENTS);
   1033 
   1034   const u32 index = m_ci.attachmentCount;
   1035   VkAttachmentDescription& ad = m_attachments[index];
   1036   ad.format = format;
   1037   ad.samples = samples;
   1038   ad.loadOp = load_op;
   1039   ad.storeOp = store_op;
   1040   ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
   1041   ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
   1042   ad.initialLayout = initial_layout;
   1043   ad.finalLayout = final_layout;
   1044 
   1045   m_ci.attachmentCount++;
   1046   m_ci.pAttachments = m_attachments.data();
   1047 
   1048   return index;
   1049 }
   1050 
   1051 u32 Vulkan::RenderPassBuilder::AddSubpass()
   1052 {
   1053   DebugAssert(m_ci.subpassCount < MAX_SUBPASSES);
   1054 
   1055   const u32 index = m_ci.subpassCount;
   1056   VkSubpassDescription& sp = m_subpasses[index];
   1057   sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
   1058 
   1059   m_ci.subpassCount++;
   1060   m_ci.pSubpasses = m_subpasses.data();
   1061 
   1062   return index;
   1063 }
   1064 
   1065 void Vulkan::RenderPassBuilder::AddSubpassColorAttachment(u32 subpass, u32 attachment, VkImageLayout layout)
   1066 {
   1067   DebugAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES);
   1068 
   1069   VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++];
   1070   ar.attachment = attachment;
   1071   ar.layout = layout;
   1072 
   1073   VkSubpassDescription& sp = m_subpasses[subpass];
   1074   if (sp.colorAttachmentCount == 0)
   1075     sp.pColorAttachments = &ar;
   1076   sp.colorAttachmentCount++;
   1077 }
   1078 
   1079 void Vulkan::RenderPassBuilder::AddSubpassDepthAttachment(u32 subpass, u32 attachment, VkImageLayout layout)
   1080 {
   1081   DebugAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES);
   1082 
   1083   VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++];
   1084   ar.attachment = attachment;
   1085   ar.layout = layout;
   1086 
   1087   VkSubpassDescription& sp = m_subpasses[subpass];
   1088   sp.pDepthStencilAttachment = &ar;
   1089 }
   1090 
   1091 Vulkan::BufferViewBuilder::BufferViewBuilder()
   1092 {
   1093   Clear();
   1094 }
   1095 
   1096 void Vulkan::BufferViewBuilder::Clear()
   1097 {
   1098   m_ci = {};
   1099   m_ci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
   1100 }
   1101 
   1102 VkBufferView Vulkan::BufferViewBuilder::Create(VkDevice device, bool clear /*= true*/)
   1103 {
   1104   VkBufferView bv;
   1105   VkResult res = vkCreateBufferView(device, &m_ci, nullptr, &bv);
   1106   if (res != VK_SUCCESS)
   1107   {
   1108     LOG_VULKAN_ERROR(res, "vkCreateBufferView() failed: ");
   1109     return VK_NULL_HANDLE;
   1110   }
   1111 
   1112   return bv;
   1113 }
   1114 
   1115 void Vulkan::BufferViewBuilder::Set(VkBuffer buffer, VkFormat format, u32 offset, u32 size)
   1116 {
   1117   m_ci.buffer = buffer;
   1118   m_ci.format = format;
   1119   m_ci.offset = offset;
   1120   m_ci.range = size;
   1121 }