.. _program_listing_file_Source_Azura_RenderSystem_Src_Vulkan_VkScopedRenderPass.cpp: Program Listing for File VkScopedRenderPass.cpp =============================================== |exhale_lsh| :ref:`Return to documentation for file ` (``Source\Azura\RenderSystem\Src\Vulkan\VkScopedRenderPass.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include #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& pipelineBuffers, const Vector& pipelineBufferImages, const Vector& 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 colorReferences{U32(createInfo.m_outputTargets.size()), allocatorTemporary}; VkAttachmentReference depthReference; Vector attachments{U32(createInfo.m_outputTargets.size()), allocatorTemporary}; Vector 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 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& 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 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 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 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& 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& VkScopedRenderPass::GetShaderStageInfo() const { return m_shaderPipelineInfos; } const Containers::Vector& 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 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