Program Listing for File VkScopedRenderPass.cpp

Return to documentation for file (Source\Azura\RenderSystem\Src\Vulkan\VkScopedRenderPass.cpp)

#include <utility>
#include "Vulkan/VkScopedRenderPass.h"
#include "Vulkan/VkTypeMapping.h"
#include "Vulkan/VkCore.h"
#include "Memory/MemoryFactory.h"
#include "Vulkan/VkMacros.h"
#include "Vulkan/VkScopedSwapChain.h"

namespace Azura {
namespace Vulkan {

using namespace Containers; // NOLINT

VkScopedRenderPass::VkScopedRenderPass(U32 idx, Memory::Allocator& mainAllocator, Log logger)
  : log_VulkanRenderSystem(std::move(logger)),
    m_id(idx),
    m_descriptorSetLayout(VK_NULL_HANDLE),
    m_frameBuffers(mainAllocator),
    m_commandBuffers(mainAllocator),
    m_inputAttachments(mainAllocator),
    m_colorBlendAttachments(mainAllocator),
    m_clearValues(mainAllocator),
    m_shaderPipelineInfos(mainAllocator) {
}

void VkScopedRenderPass::Create(VkDevice device,
                                VkCommandPool commandPool,
                                const PipelinePassCreateInfo& createInfo,
                                const Vector<RenderTargetCreateInfo>& pipelineBuffers,
                                const Vector<VkScopedImage>& pipelineBufferImages,
                                const Vector<VkShader>& allShaders,
                                const VkScopedSwapChain& swapChain) {
  STACK_ALLOCATOR(Temporary, Memory::MonotonicAllocator, 2048);

  m_commandBuffers.Reserve(1);
  m_frameBuffers.Resize(1);

  LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Creating Render Pass: ID %d", m_id);

  CreateDescriptorSetLayout(device, createInfo);

  m_shaderPipelineInfos.Reserve(U32(createInfo.m_shaders.size()));

  for (const auto& vkShaderId : createInfo.m_shaders) {
    const auto& vkShader = allShaders[vkShaderId];
    m_shaderPipelineInfos.PushBack(vkShader.GetShaderStageInfo());
  }

  Vector<VkAttachmentReference> colorReferences{U32(createInfo.m_outputTargets.size()), allocatorTemporary};
  VkAttachmentReference depthReference;
  Vector<VkAttachmentDescription> attachments{U32(createInfo.m_outputTargets.size()), allocatorTemporary};
  Vector<VkImageView> attachmentViews{U32(createInfo.m_outputTargets.size()), allocatorTemporary};
  m_colorBlendAttachments.Reserve(U32(createInfo.m_outputTargets.size()));
  m_clearValues.Reserve(U32(createInfo.m_outputTargets.size()));

  U32 refCount  = 0;
  bool hasDepth = false;

  for (const auto& output : createInfo.m_outputTargets) {
    const auto& selected = pipelineBuffers[output];

    VkClearValue clearValue = {};

    // Push View to Vector as we process output
    attachmentViews.PushBack(pipelineBufferImages[output].View());

    const auto vkFormat = VkCore::GetVkFormat(selected.m_format, log_VulkanRenderSystem);

    VkAttachmentDescription attachmentDescription = {};
    attachmentDescription.format                  = vkFormat;
    attachmentDescription.samples                 = VK_SAMPLE_COUNT_1_BIT;
    attachmentDescription.loadOp                  = VK_ATTACHMENT_LOAD_OP_CLEAR;
    attachmentDescription.storeOp                 = VK_ATTACHMENT_STORE_OP_STORE;

    // Not using Stencil buffer
    attachmentDescription.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    attachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;

    if (HasDepthComponent(selected.m_format) || HasStencilComponent(selected.m_format)) {
      // Record Depth Reference
      depthReference = VkAttachmentReference{refCount, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};

      hasDepth = true;

      // Shader Read for Color
      attachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
      attachmentDescription.finalLayout   = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

      clearValue.depthStencil = { createInfo.m_clearData.m_depth, createInfo.m_clearData.m_stencil };
      m_clearValues.PushBack(clearValue);

    } else {
      // Record Color Reference
      colorReferences.PushBack({refCount, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});

      // Shader Read for Color
      attachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
      attachmentDescription.finalLayout   = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;

      VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
      colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
      colorBlendAttachment.blendEnable = VkBool32(createInfo.m_blendState.m_enable);

      if (createInfo.m_blendState.m_enable) {
        LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Enabling Blend State For Render Pass");

        const auto colorSrcFactor = ToVkBlendFactor(createInfo.m_blendState.m_color.m_srcFactor);
        VERIFY_OPT(log_VulkanRenderSystem, colorSrcFactor, "Invalid colorSrcFactor converted for Blend State");

        const auto colorDstFactor = ToVkBlendFactor(createInfo.m_blendState.m_color.m_dstFactor);
        VERIFY_OPT(log_VulkanRenderSystem, colorDstFactor, "Invalid colorDstFactor converted for Blend State");

        const auto colorOp = ToVkBlendOp(createInfo.m_blendState.m_color.m_op);
        VERIFY_OPT(log_VulkanRenderSystem, colorOp, "Invalid colorOp converted for Blend State");

        const auto alphaSrcFactor = ToVkBlendFactor(createInfo.m_blendState.m_alpha.m_srcFactor);
        VERIFY_OPT(log_VulkanRenderSystem, alphaSrcFactor, "Invalid alphaSrcFactor converted for Blend State");

        const auto alphaDstFactor = ToVkBlendFactor(createInfo.m_blendState.m_alpha.m_dstFactor);
        VERIFY_OPT(log_VulkanRenderSystem, alphaDstFactor, "Invalid alphaDstFactor converted for Blend State");

        const auto alphaOp = ToVkBlendOp(createInfo.m_blendState.m_alpha.m_op);
        VERIFY_OPT(log_VulkanRenderSystem, alphaOp, "Invalid alphaOp converted for Blend State");

        colorBlendAttachment.srcColorBlendFactor = colorSrcFactor.value();
        colorBlendAttachment.dstColorBlendFactor = colorDstFactor.value();
        colorBlendAttachment.colorBlendOp = colorOp.value();

        colorBlendAttachment.srcAlphaBlendFactor = alphaSrcFactor.value();
        colorBlendAttachment.dstAlphaBlendFactor = alphaDstFactor.value();
        colorBlendAttachment.alphaBlendOp = alphaOp.value();
      }

      m_colorBlendAttachments.PushBack(colorBlendAttachment);

      clearValue.color = { createInfo.m_clearData.m_color[0], createInfo.m_clearData.m_color[1], createInfo.m_clearData.m_color[2], createInfo.m_clearData.m_color[3] };
      m_clearValues.PushBack(clearValue);
    }

    attachments.PushBack(attachmentDescription);

    ++refCount;
  }

  VkSubpassDescription subpass    = {};
  subpass.pipelineBindPoint       = VK_PIPELINE_BIND_POINT_GRAPHICS;
  subpass.colorAttachmentCount    = colorReferences.GetSize();
  subpass.pColorAttachments       = colorReferences.Data();
  subpass.pDepthStencilAttachment = hasDepth ? &depthReference : nullptr;

  VkRenderPassCreateInfo renderPassInfo = {};
  renderPassInfo.sType                  = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
  renderPassInfo.attachmentCount        = attachments.GetSize();
  renderPassInfo.pAttachments           = attachments.Data();
  renderPassInfo.subpassCount           = 1;
  renderPassInfo.pSubpasses             = &subpass;

  // Tell special subpass to wait for Image acquisition from semaphore
  std::array<VkSubpassDependency, 2> dependencies = {};

  dependencies[0].srcSubpass    = VK_SUBPASS_EXTERNAL;
  dependencies[0].dstSubpass    = 0;
  dependencies[0].srcStageMask  = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[0].srcAccessMask = 0;
  dependencies[0].dstStageMask  = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

  dependencies[1].srcSubpass      = 0;
  dependencies[1].dstSubpass      = VK_SUBPASS_EXTERNAL;
  dependencies[1].srcStageMask    = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[1].dstStageMask    = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
  dependencies[1].srcAccessMask   = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  dependencies[1].dstAccessMask   = VK_ACCESS_MEMORY_READ_BIT;
  dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

  renderPassInfo.dependencyCount = U32(dependencies.size());
  renderPassInfo.pDependencies   = dependencies.data();

  VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateRenderPass(device, &renderPassInfo, nullptr, &m_renderPass),
    "Failed to create render pass");

  VkFramebufferCreateInfo framebufferInfo = {};
  framebufferInfo.sType                   = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
  framebufferInfo.renderPass              = m_renderPass;
  framebufferInfo.attachmentCount         = U32(attachmentViews.GetSize());
  framebufferInfo.pAttachments            = attachmentViews.Data();
  framebufferInfo.width                   = swapChain.GetExtent().width;
  framebufferInfo.height                  = swapChain.GetExtent().height;
  framebufferInfo.layers                  = 1;

  m_numAttachments = attachmentViews.GetSize();

  VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateFramebuffer(device, &framebufferInfo, nullptr, m_frameBuffers.Data()),
    "Failed to create single framebuffer");

  m_commandBuffers.PushBack(VkCore::CreateCommandBuffer(device, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
                                                        log_VulkanRenderSystem));

  m_beginRenderSemaphore = VkCore::CreateSemaphore(device, log_VulkanRenderSystem);
}

void VkScopedRenderPass::CreateForSwapChain(VkDevice device,
                                            VkCommandPool commandPool,
                                            const PipelinePassCreateInfo& createInfo,
                                            const Vector<VkShader>& allShaders,
                                            const VkScopedSwapChain& swapChain) {
  STACK_ALLOCATOR(Temporary, Memory::MonotonicAllocator, 2048);

  CreateDescriptorSetLayout(device, createInfo);

  LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Creating Render Pass (Swap Chain): ID %d", m_id);

  m_shaderPipelineInfos.Reserve(U32(createInfo.m_shaders.size()));
  m_clearValues.Reserve(2);

  VkClearValue clearValue;

  for (const auto& vkShaderId : createInfo.m_shaders) {
    const auto& vkShader = allShaders[vkShaderId];
    m_shaderPipelineInfos.PushBack(vkShader.GetShaderStageInfo());
  }

  VkAttachmentDescription colorAttachment = {};
  colorAttachment.format                  = swapChain.GetSurfaceFormat();
  colorAttachment.samples                 = VK_SAMPLE_COUNT_1_BIT;
  colorAttachment.loadOp                  = VK_ATTACHMENT_LOAD_OP_CLEAR;
  colorAttachment.storeOp                 = VK_ATTACHMENT_STORE_OP_STORE;

  // Not using Stencil buffer
  colorAttachment.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;

  colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  colorAttachment.finalLayout   = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

  m_colorBlendAttachments.Reserve(1);

  VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
  colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
  colorBlendAttachment.blendEnable = VkBool32(createInfo.m_blendState.m_enable);

  if (createInfo.m_blendState.m_enable) {
    LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Enabling Blend State For Render Pass");

    const auto colorSrcFactor = ToVkBlendFactor(createInfo.m_blendState.m_color.m_srcFactor);
    VERIFY_OPT(log_VulkanRenderSystem, colorSrcFactor, "Invalid colorSrcFactor converted for Blend State");

    const auto colorDstFactor = ToVkBlendFactor(createInfo.m_blendState.m_color.m_dstFactor);
    VERIFY_OPT(log_VulkanRenderSystem, colorDstFactor, "Invalid colorDstFactor converted for Blend State");

    const auto colorOp = ToVkBlendOp(createInfo.m_blendState.m_color.m_op);
    VERIFY_OPT(log_VulkanRenderSystem, colorOp, "Invalid colorOp converted for Blend State");

    const auto alphaSrcFactor = ToVkBlendFactor(createInfo.m_blendState.m_alpha.m_srcFactor);
    VERIFY_OPT(log_VulkanRenderSystem, alphaSrcFactor, "Invalid alphaSrcFactor converted for Blend State");

    const auto alphaDstFactor = ToVkBlendFactor(createInfo.m_blendState.m_alpha.m_dstFactor);
    VERIFY_OPT(log_VulkanRenderSystem, alphaDstFactor, "Invalid alphaDstFactor converted for Blend State");

    const auto alphaOp = ToVkBlendOp(createInfo.m_blendState.m_alpha.m_op);
    VERIFY_OPT(log_VulkanRenderSystem, alphaOp, "Invalid alphaOp converted for Blend State");

    colorBlendAttachment.srcColorBlendFactor = colorSrcFactor.value();
    colorBlendAttachment.dstColorBlendFactor = colorDstFactor.value();
    colorBlendAttachment.colorBlendOp = colorOp.value();

    colorBlendAttachment.srcAlphaBlendFactor = alphaSrcFactor.value();
    colorBlendAttachment.dstAlphaBlendFactor = alphaDstFactor.value();
    colorBlendAttachment.alphaBlendOp = alphaOp.value();
  }

  m_colorBlendAttachments.PushBack(colorBlendAttachment);

  VkAttachmentDescription depthAttachment = {};
  depthAttachment.format                  = swapChain.GetDepthFormat();
  depthAttachment.samples                 = VK_SAMPLE_COUNT_1_BIT;
  depthAttachment.loadOp                  = VK_ATTACHMENT_LOAD_OP_CLEAR;
  depthAttachment.storeOp                 = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  depthAttachment.stencilLoadOp           = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  depthAttachment.stencilStoreOp          = VK_ATTACHMENT_STORE_OP_DONT_CARE;
  depthAttachment.initialLayout           = VK_IMAGE_LAYOUT_UNDEFINED;
  depthAttachment.finalLayout             = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

  VkAttachmentReference colorAttachmentRef = {};
  colorAttachmentRef.attachment            = 0;
  colorAttachmentRef.layout                = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

  VkAttachmentReference depthAttachmentRef = {};
  depthAttachmentRef.attachment            = 1;
  depthAttachmentRef.layout                = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;

  VkSubpassDescription subpass    = {};
  subpass.pipelineBindPoint       = VK_PIPELINE_BIND_POINT_GRAPHICS;
  subpass.colorAttachmentCount    = 1;
  subpass.pColorAttachments       = &colorAttachmentRef;
  subpass.pDepthStencilAttachment = swapChain.HasDepthSupport() ? &depthAttachmentRef : nullptr;

  Vector<VkAttachmentDescription> attachments{ 2, allocatorTemporary };
  attachments.PushBack(colorAttachment);

  clearValue.color = { createInfo.m_clearData.m_color[0], createInfo.m_clearData.m_color[1], createInfo.m_clearData.m_color[2], createInfo.m_clearData.m_color[3] };
  m_clearValues.PushBack(clearValue);

  if (swapChain.HasDepthSupport())
  {
    attachments.PushBack(depthAttachment);

    clearValue.depthStencil = { createInfo.m_clearData.m_depth, createInfo.m_clearData.m_stencil };
    m_clearValues.PushBack(clearValue);
  }

  VkRenderPassCreateInfo renderPassInfo = {};
  renderPassInfo.sType                  = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
  renderPassInfo.attachmentCount        = attachments.GetSize();
  renderPassInfo.pAttachments           = attachments.Data();
  renderPassInfo.subpassCount           = 1;
  renderPassInfo.pSubpasses             = &subpass;

  m_numAttachments = attachments.GetSize();

  // Tell special subpass to wait for Image acquisition from semaphore
  std::array<VkSubpassDependency, 1> dependencies = {};

  dependencies[0].srcSubpass    = VK_SUBPASS_EXTERNAL;
  dependencies[0].dstSubpass    = 0;
  dependencies[0].srcStageMask  = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[0].srcAccessMask = 0;
  dependencies[0].dstStageMask  = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

  renderPassInfo.dependencyCount = U32(dependencies.size());
  renderPassInfo.pDependencies   = dependencies.data();

  VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateRenderPass(device, &renderPassInfo, nullptr, &m_renderPass),
    "Failed to create render pass");

  const auto& allImages      = swapChain.GetAllImages();
  const auto swapChainExtent = swapChain.GetExtent();

  m_frameBuffers.Resize(allImages.GetSize());

  const VkImageView depthImageView = swapChain.GetDepthImage().View();

  for (U32 idx = 0; idx < allImages.GetSize(); ++idx) {
    Vector<VkImageView> swapAttachments{ 2, allocatorTemporary };
    swapAttachments.PushBack(allImages[idx].View());

    if (swapChain.HasDepthSupport())
    {
      swapAttachments.PushBack(depthImageView);
    }

    VkFramebufferCreateInfo framebufferInfo = {};
    framebufferInfo.sType                   = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
    framebufferInfo.renderPass              = m_renderPass;
    framebufferInfo.attachmentCount         = swapAttachments.GetSize();
    framebufferInfo.pAttachments            = swapAttachments.Data();
    framebufferInfo.width                   = swapChainExtent.width;
    framebufferInfo.height                  = swapChainExtent.height;
    framebufferInfo.layers                  = 1;

    VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateFramebuffer(device, &framebufferInfo, nullptr, &m_frameBuffers[idx]),
      "Failed to create framebuffer");
  }

  m_commandBuffers.Resize(m_frameBuffers.GetSize());
  VkCore::CreateCommandBuffers(device, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
                               m_commandBuffers, log_VulkanRenderSystem);

  m_beginRenderSemaphore = VkCore::CreateSemaphore(device, log_VulkanRenderSystem);
}

VkRenderPass VkScopedRenderPass::GetRenderPass() const {
  return m_renderPass;
}

VkFramebuffer VkScopedRenderPass::GetFrameBuffer(U32 idx) const {
  return m_frameBuffers[idx];
}

VkCommandBuffer VkScopedRenderPass::GetCommandBuffer(U32 idx) const {
  return m_commandBuffers[idx];
}

const Containers::Vector<PipelinePassInput>& VkScopedRenderPass::GetPassInputs() const {
  return m_inputAttachments;
}

U32 VkScopedRenderPass::GetFrameBufferCount() const {
  return m_frameBuffers.GetSize();
}

VkSemaphore VkScopedRenderPass::GetRenderSemaphore() const {
  return m_beginRenderSemaphore;
}

VkDescriptorSetLayout VkScopedRenderPass::GetDescriptorSetLayout() const {
  return m_descriptorSetLayout;
}

U32 VkScopedRenderPass::GetId() const {
  return m_id;
}

U32 VkScopedRenderPass::GetDescriptorSetId() const {
  return m_descriptorSet;
}

void VkScopedRenderPass::SetDescriptorSetId(U32 id) {
  m_descriptorSet = id;
}

void VkScopedRenderPass::Begin(const VkScopedSwapChain& swapChain) const {
  for (U32 idx = 0; idx < m_frameBuffers.GetSize(); ++idx) {
    VkCore::BeginCommandBuffer(m_commandBuffers[idx], VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
                               log_VulkanRenderSystem);

    VkRenderPassBeginInfo renderPassInfo = {};
    renderPassInfo.sType                 = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    renderPassInfo.renderPass            = m_renderPass;
    renderPassInfo.framebuffer           = m_frameBuffers[idx];
    renderPassInfo.renderArea.offset     = {0, 0};
    renderPassInfo.renderArea.extent     = swapChain.GetExtent();
    renderPassInfo.clearValueCount       = m_clearValues.GetSize();
    renderPassInfo.pClearValues          = m_clearValues.Data();

    vkCmdBeginRenderPass(m_commandBuffers[idx], &renderPassInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
  }
}

void VkScopedRenderPass::End() const {
  for (U32 idx = 0; idx < m_commandBuffers.GetSize(); ++idx) {
    vkCmdEndRenderPass(m_commandBuffers[idx]);
    VkCore::EndCommandBuffer(m_commandBuffers[idx], log_VulkanRenderSystem);
  }
}

const Vector<VkPipelineShaderStageCreateInfo>& VkScopedRenderPass::GetShaderStageInfo() const {
  return m_shaderPipelineInfos;
}

const Containers::Vector<VkPipelineColorBlendAttachmentState>& VkScopedRenderPass::GetColorBlendAttachments() const {
  return m_colorBlendAttachments;
}

void VkScopedRenderPass::CleanUp(VkDevice device, VkCommandPool commandPool) const {
  vkDestroyRenderPass(device, m_renderPass, nullptr);

  for (const auto& frameBuffer : m_frameBuffers) {
    vkDestroyFramebuffer(device, frameBuffer, nullptr);
  }

  vkDestroySemaphore(device, m_beginRenderSemaphore, nullptr);

  vkFreeCommandBuffers(device, commandPool, m_commandBuffers.GetSize(), m_commandBuffers.Data());
}

void VkScopedRenderPass::CreateDescriptorSetLayout(VkDevice device, const PipelinePassCreateInfo& createInfo) {
  if (createInfo.m_inputTargets.empty()) {
    return;
  }

  STACK_ALLOCATOR(Temporary, Memory::MonotonicAllocator, 1024);

  U32 bindingId = 0;

  m_inputAttachments.Reserve(U32(createInfo.m_inputTargets.size()));

  Vector<VkDescriptorSetLayoutBinding> currentBindings(U32(createInfo.m_inputTargets.size()), allocatorTemporary);
  for (const auto& input : createInfo.m_inputTargets) {
    m_inputAttachments.PushBack(input);

    const auto combinedShaderFlagBits = GetCombinedShaderStageFlag(input.m_stages);
    VkCore::CreateSampledImageBinding(currentBindings, bindingId, 1, combinedShaderFlagBits);

    ++bindingId;
  }

  m_descriptorSetLayout = VkCore::CreateDescriptorSetLayout(device, currentBindings, log_VulkanRenderSystem);
}
} // namespace Vulkan
} // namespace Azura