diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp index e6953340..7dc9ec17 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp @@ -240,16 +240,16 @@ namespace MobileGL::MG_Backend::DirectVulkan { return false; } - Bool VkFramebufferManager::GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass, - VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, - VkFormat& outDepthStencilFormat) const { + Bool VkFramebufferManager::GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, + VkFormat& outColorFormat, VkImageView& outDepthStencilView, + VkFormat& outDepthStencilFormat, VkExtent2D& outExtent) const { auto it = m_offscreenColorTargets.find(glFboExternalIndex); - if (it == m_offscreenColorTargets.end() || it->second.framebuffer == VK_NULL_HANDLE || - it->second.renderPassLoad == VK_NULL_HANDLE) { + if (it == m_offscreenColorTargets.end() || it->second.imageView == VK_NULL_HANDLE) { return false; } - outRenderPass = it->second.renderPassLoad; - outFramebuffer = it->second.framebuffer; + outColorView = it->second.imageView; + outColorFormat = it->second.format; + outDepthStencilView = it->second.depthStencilImageView; outExtent = it->second.extent; outDepthStencilFormat = it->second.depthStencilFormat; return true; @@ -378,76 +378,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { "vkCreateImageView(offscreen depth/stencil)"); } - VkAttachmentDescription colorAttachmentDesc{}; - colorAttachmentDesc.format = format; - colorAttachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT; - colorAttachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - colorAttachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colorAttachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorAttachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorAttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorAttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentReference colorAttachmentRef{}; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass{}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - - VkAttachmentDescription depthAttachmentDesc{}; - VkAttachmentReference depthAttachmentRef{}; - Array attachments{}; - attachments[0] = colorAttachmentDesc; - Uint32 attachmentCount = 1; - if (hasDepthStencil) { - depthAttachmentDesc.format = depthStencilFormat; - depthAttachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT; - depthAttachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - depthAttachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - depthAttachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - depthAttachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - depthAttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depthAttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - depthAttachmentRef.attachment = 1; - depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - subpass.pDepthStencilAttachment = &depthAttachmentRef; - - attachments[1] = depthAttachmentDesc; - attachmentCount = 2; - } - - VkRenderPassCreateInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = attachmentCount; - renderPassInfo.pAttachments = attachments.data(); - renderPassInfo.subpassCount = 1; - renderPassInfo.pSubpasses = &subpass; - VK_VERIFY(vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &target.renderPassLoad), - "vkCreateRenderPass(offscreen)"); - - Array framebufferAttachments{}; - framebufferAttachments[0] = target.imageView; - Uint32 framebufferAttachmentCount = 1; - if (hasDepthStencil) { - framebufferAttachments[1] = target.depthStencilImageView; - framebufferAttachmentCount = 2; - } - - VkFramebufferCreateInfo framebufferInfo{}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = target.renderPassLoad; - framebufferInfo.attachmentCount = framebufferAttachmentCount; - framebufferInfo.pAttachments = framebufferAttachments.data(); - framebufferInfo.width = static_cast(size.x()); - framebufferInfo.height = static_cast(size.y()); - framebufferInfo.layers = 1; - VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer), - "vkCreateFramebuffer(offscreen)"); - target.layout = VK_IMAGE_LAYOUT_UNDEFINED; target.extent = {static_cast(size.x()), static_cast(size.y())}; target.format = format; @@ -461,14 +391,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { } void VkFramebufferManager::DestroyOffscreenColorTarget(OffscreenColorTarget& target) { - if (target.framebuffer != VK_NULL_HANDLE) { - vkDestroyFramebuffer(m_device, target.framebuffer, nullptr); - target.framebuffer = VK_NULL_HANDLE; - } - if (target.renderPassLoad != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr); - target.renderPassLoad = VK_NULL_HANDLE; - } if (target.imageView != VK_NULL_HANDLE) { vkDestroyImageView(m_device, target.imageView, nullptr); target.imageView = VK_NULL_HANDLE; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h index e1dd1391..35206246 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.h @@ -39,9 +39,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool GetOffscreenDepthStencilImage(Uint glFboExternalIndex, VkImage& outImage, VkExtent2D& outExtent, VkFormat& outFormat) const; Bool GetOffscreenColorViewByTexture(Uint textureExternalIndex, VkImageView& outImageView) const; - Bool GetOffscreenRenderTarget(Uint glFboExternalIndex, VkRenderPass& outRenderPass, - VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, - VkFormat& outDepthStencilFormat) const; + Bool GetOffscreenRenderSurface(Uint glFboExternalIndex, VkImageView& outColorView, VkFormat& outColorFormat, + VkImageView& outDepthStencilView, VkFormat& outDepthStencilFormat, + VkExtent2D& outExtent) const; private: struct OffscreenColorTarget { @@ -56,8 +56,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkImageView depthStencilImageView = VK_NULL_HANDLE; VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; - VkRenderPass renderPassLoad = VK_NULL_HANDLE; - VkFramebuffer framebuffer = VK_NULL_HANDLE; Uint16 glObjectVersion = 0; Uint colorTextureExternalIndex = 0; }; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index de29fdb9..cde021ba 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -27,6 +27,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { } void VkRenderPassManager::Shutdown() { + DestroyDefaultFramebuffers(); + for (auto& [_, target] : m_offscreenRenderTargets) { + DestroyOffscreenRenderTarget(target); + } + m_offscreenRenderTargets.clear(); + if (m_device != VK_NULL_HANDLE) { if (m_renderPassClear != VK_NULL_HANDLE) { vkDestroyRenderPass(m_device, m_renderPassClear, nullptr); @@ -40,9 +46,202 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_renderPassLoad = VK_NULL_HANDLE; m_colorFormat = VK_FORMAT_UNDEFINED; m_depthStencilFormat = VK_FORMAT_UNDEFINED; + m_defaultExtent = {0, 0}; m_device = VK_NULL_HANDLE; } + Bool VkRenderPassManager::RecreateDefaultFramebuffers(const Vector& colorViews, + const Vector& depthStencilViews, + VkExtent2D extent) { + DestroyDefaultFramebuffers(); + + if (m_device == VK_NULL_HANDLE || m_renderPassLoad == VK_NULL_HANDLE || extent.width == 0 || + extent.height == 0 || colorViews.empty() || colorViews.size() != depthStencilViews.size()) { + return false; + } + + m_defaultFramebuffers.reserve(colorViews.size()); + for (SizeT i = 0; i < colorViews.size(); ++i) { + if (colorViews[i] == VK_NULL_HANDLE || depthStencilViews[i] == VK_NULL_HANDLE) { + DestroyDefaultFramebuffers(); + return false; + } + VkImageView attachments[] = {colorViews[i], depthStencilViews[i]}; + VkFramebufferCreateInfo createInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + createInfo.renderPass = m_renderPassLoad; + createInfo.attachmentCount = static_cast(std::size(attachments)); + createInfo.pAttachments = attachments; + createInfo.width = extent.width; + createInfo.height = extent.height; + createInfo.layers = 1; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + if (vkCreateFramebuffer(m_device, &createInfo, nullptr, &framebuffer) != VK_SUCCESS) { + DestroyDefaultFramebuffers(); + return false; + } + m_defaultFramebuffers.push_back(framebuffer); + } + m_defaultExtent = extent; + return true; + } + + Bool VkRenderPassManager::GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, + VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, + VkFormat& outDepthStencilFormat) const { + if (imageIndex >= m_defaultFramebuffers.size() || m_renderPassLoad == VK_NULL_HANDLE) { + return false; + } + outRenderPass = m_renderPassLoad; + outFramebuffer = m_defaultFramebuffers[imageIndex]; + outExtent = m_defaultExtent; + outDepthStencilFormat = m_depthStencilFormat; + return outFramebuffer != VK_NULL_HANDLE; + } + + Bool VkRenderPassManager::EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo) { + if (m_device == VK_NULL_HANDLE || targetInfo.colorView == VK_NULL_HANDLE || + targetInfo.colorFormat == VK_FORMAT_UNDEFINED || targetInfo.extent.width == 0 || + targetInfo.extent.height == 0) { + return false; + } + + const Bool hasDepthStencil = + targetInfo.depthStencilView != VK_NULL_HANDLE && targetInfo.depthStencilFormat != VK_FORMAT_UNDEFINED; + + auto& target = m_offscreenRenderTargets[targetInfo.targetExternalIndex]; + if (target.framebuffer != VK_NULL_HANDLE && target.renderPassLoad != VK_NULL_HANDLE && + target.targetVersion == targetInfo.targetVersion && target.colorView == targetInfo.colorView && + target.colorFormat == targetInfo.colorFormat && target.depthStencilView == targetInfo.depthStencilView && + target.depthStencilFormat == targetInfo.depthStencilFormat && + target.extent.width == targetInfo.extent.width && target.extent.height == targetInfo.extent.height) { + return true; + } + + DestroyOffscreenRenderTarget(target); + + const VkFormat depthStencilFormat = hasDepthStencil ? targetInfo.depthStencilFormat : VK_FORMAT_UNDEFINED; + target.renderPassLoad = CreateRenderPass(targetInfo.colorFormat, depthStencilFormat, VK_ATTACHMENT_LOAD_OP_LOAD, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + if (target.renderPassLoad == VK_NULL_HANDLE) { + return false; + } + + Array attachments{}; + attachments[0] = targetInfo.colorView; + Uint32 attachmentCount = 1; + if (hasDepthStencil) { + attachments[1] = targetInfo.depthStencilView; + attachmentCount = 2; + } + + VkFramebufferCreateInfo framebufferInfo{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + framebufferInfo.renderPass = target.renderPassLoad; + framebufferInfo.attachmentCount = attachmentCount; + framebufferInfo.pAttachments = attachments.data(); + framebufferInfo.width = targetInfo.extent.width; + framebufferInfo.height = targetInfo.extent.height; + framebufferInfo.layers = 1; + VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &target.framebuffer), + "vkCreateFramebuffer(offscreen)"); + + target.targetVersion = targetInfo.targetVersion; + target.colorView = targetInfo.colorView; + target.colorFormat = targetInfo.colorFormat; + target.depthStencilView = targetInfo.depthStencilView; + target.depthStencilFormat = targetInfo.depthStencilFormat; + target.extent = targetInfo.extent; + return true; + } + + Bool VkRenderPassManager::GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass, + VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, + VkFormat& outDepthStencilFormat) const { + auto it = m_offscreenRenderTargets.find(targetExternalIndex); + if (it == m_offscreenRenderTargets.end() || it->second.renderPassLoad == VK_NULL_HANDLE || + it->second.framebuffer == VK_NULL_HANDLE) { + return false; + } + + outRenderPass = it->second.renderPassLoad; + outFramebuffer = it->second.framebuffer; + outExtent = it->second.extent; + outDepthStencilFormat = it->second.depthStencilFormat; + return true; + } + + void VkRenderPassManager::RemoveOffscreenRenderTarget(Uint targetExternalIndex) { + auto it = m_offscreenRenderTargets.find(targetExternalIndex); + if (it == m_offscreenRenderTargets.end()) { + return; + } + DestroyOffscreenRenderTarget(it->second); + m_offscreenRenderTargets.erase(it); + } + + void VkRenderPassManager::BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, + VkFramebuffer framebuffer, VkExtent2D extent) const { + VkRenderPassBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + beginInfo.renderPass = renderPass; + beginInfo.framebuffer = framebuffer; + beginInfo.renderArea.offset = {0, 0}; + beginInfo.renderArea.extent = extent; + beginInfo.clearValueCount = 0; + beginInfo.pClearValues = nullptr; + vkCmdBeginRenderPass(commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE); + } + + void VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) const { + vkCmdEndRenderPass(commandBuffer); + } + + void VkRenderPassManager::RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent, + const VkClearColorValue& clearColor) const { + VkClearAttachment clearAttachment{}; + clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clearAttachment.colorAttachment = 0; + clearAttachment.clearValue.color = clearColor; + + VkClearRect clearRect{}; + clearRect.rect.offset = {0, 0}; + clearRect.rect.extent = extent; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = 1; + + vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect); + } + + void VkRenderPassManager::RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, + Float depth, Uint32 stencil, VkFormat depthStencilFormat) const { + if (depthStencilFormat == VK_FORMAT_UNDEFINED) { + return; + } + + VkImageAspectFlags aspectMask = 0; + if ((mask & GL_DEPTH_BUFFER_BIT) != 0) { + aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(depthStencilFormat)) { + aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + if (aspectMask == 0) { + return; + } + + VkClearAttachment clearAttachment{}; + clearAttachment.aspectMask = aspectMask; + clearAttachment.clearValue.depthStencil.depth = depth; + clearAttachment.clearValue.depthStencil.stencil = stencil; + + VkClearRect clearRect{}; + clearRect.rect.offset = {0, 0}; + clearRect.rect.extent = extent; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = 1; + + vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect); + } + VkRenderPass VkRenderPassManager::GetLoadRenderPass() const { return m_renderPassLoad; } @@ -56,24 +255,34 @@ namespace MobileGL::MG_Backend::DirectVulkan { MOBILEGL_ASSERT(m_colorFormat != VK_FORMAT_UNDEFINED, "VkRenderPassManager: color format is undefined"); MOBILEGL_ASSERT(m_depthStencilFormat != VK_FORMAT_UNDEFINED, "VkRenderPassManager: depth/stencil format is undefined"); + return CreateRenderPass(m_colorFormat, m_depthStencilFormat, colorLoadOp, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + } + VkRenderPass VkRenderPassManager::CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, + VkAttachmentLoadOp colorLoadOp, + VkImageLayout colorFinalLayout) const { VkAttachmentDescription color{}; - color.format = m_colorFormat; + color.format = colorFormat; color.samples = VK_SAMPLE_COUNT_1_BIT; color.loadOp = colorLoadOp; color.storeOp = VK_ATTACHMENT_STORE_OP_STORE; color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - color.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + color.finalLayout = colorFinalLayout; + color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + const Bool hasDepthStencil = depthStencilFormat != VK_FORMAT_UNDEFINED; VkAttachmentDescription depthStencil{}; - depthStencil.format = m_depthStencilFormat; - depthStencil.samples = VK_SAMPLE_COUNT_1_BIT; - depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (hasDepthStencil) { + depthStencil.format = depthStencilFormat; + depthStencil.samples = VK_SAMPLE_COUNT_1_BIT; + depthStencil.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + depthStencil.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthStencil.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + depthStencil.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthStencil.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depthStencil.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + } VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; @@ -82,18 +291,57 @@ namespace MobileGL::MG_Backend::DirectVulkan { subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorRef; - subpass.pDepthStencilAttachment = &depthStencilRef; + if (hasDepthStencil) { + subpass.pDepthStencilAttachment = &depthStencilRef; + } - VkAttachmentDescription attachments[2] = {color, depthStencil}; + Array attachments{}; + attachments[0] = color; + Uint32 attachmentCount = 1; + if (hasDepthStencil) { + attachments[1] = depthStencil; + attachmentCount = 2; + } VkRenderPassCreateInfo createInfo{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; - createInfo.attachmentCount = 2; - createInfo.pAttachments = attachments; + createInfo.attachmentCount = attachmentCount; + createInfo.pAttachments = attachments.data(); createInfo.subpassCount = 1; createInfo.pSubpasses = &subpass; VkRenderPass renderPass = VK_NULL_HANDLE; - VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass(default)"); + VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass"); return renderPass; } + + void VkRenderPassManager::DestroyDefaultFramebuffers() { + for (auto framebuffer : m_defaultFramebuffers) { + if (framebuffer != VK_NULL_HANDLE) { + vkDestroyFramebuffer(m_device, framebuffer, nullptr); + } + } + m_defaultFramebuffers.clear(); + m_defaultExtent = {0, 0}; + } + + void VkRenderPassManager::DestroyOffscreenRenderTarget(OffscreenRenderTarget& target) { + if (target.framebuffer != VK_NULL_HANDLE) { + vkDestroyFramebuffer(m_device, target.framebuffer, nullptr); + target.framebuffer = VK_NULL_HANDLE; + } + if (target.renderPassLoad != VK_NULL_HANDLE) { + vkDestroyRenderPass(m_device, target.renderPassLoad, nullptr); + target.renderPassLoad = VK_NULL_HANDLE; + } + target.targetVersion = 0; + target.colorView = VK_NULL_HANDLE; + target.colorFormat = VK_FORMAT_UNDEFINED; + target.depthStencilView = VK_NULL_HANDLE; + target.depthStencilFormat = VK_FORMAT_UNDEFINED; + target.extent = {0, 0}; + } + + Bool VkRenderPassManager::HasStencilComponent(VkFormat format) { + return format == VK_FORMAT_D24_UNORM_S8_UINT || format == VK_FORMAT_D32_SFLOAT_S8_UINT; + } } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h index a20a5e71..fa01bffb 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -20,19 +20,67 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; }; + struct OffscreenRenderTargetInfo { + Uint targetExternalIndex = 0; + Uint16 targetVersion = 0; + VkImageView colorView = VK_NULL_HANDLE; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; + VkImageView depthStencilView = VK_NULL_HANDLE; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + VkExtent2D extent = {0, 0}; + }; + Bool Initialize(const InitInfo& initInfo); void Shutdown(); + Bool RecreateDefaultFramebuffers(const Vector& colorViews, + const Vector& depthStencilViews, VkExtent2D extent); + Bool GetDefaultRenderTarget(Uint32 imageIndex, VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, + VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const; + + Bool EnsureOffscreenRenderTarget(const OffscreenRenderTargetInfo& targetInfo); + Bool GetOffscreenRenderTarget(Uint targetExternalIndex, VkRenderPass& outRenderPass, + VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, + VkFormat& outDepthStencilFormat) const; + void RemoveOffscreenRenderTarget(Uint targetExternalIndex); + + void BeginRenderPass(VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer, + VkExtent2D extent) const; + void EndRenderPass(VkCommandBuffer commandBuffer) const; + void RecordColorClear(VkCommandBuffer commandBuffer, VkExtent2D extent, + const VkClearColorValue& clearColor) const; + void RecordDepthStencilClear(VkCommandBuffer commandBuffer, VkExtent2D extent, GLbitfield mask, Float depth, + Uint32 stencil, VkFormat depthStencilFormat) const; + VkRenderPass GetLoadRenderPass() const; VkRenderPass GetClearRenderPass() const; private: + struct OffscreenRenderTarget { + Uint16 targetVersion = 0; + VkImageView colorView = VK_NULL_HANDLE; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; + VkImageView depthStencilView = VK_NULL_HANDLE; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + VkExtent2D extent = {0, 0}; + VkRenderPass renderPassLoad = VK_NULL_HANDLE; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + }; + VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const; + VkRenderPass CreateRenderPass(VkFormat colorFormat, VkFormat depthStencilFormat, VkAttachmentLoadOp colorLoadOp, + VkImageLayout colorFinalLayout) const; + void DestroyDefaultFramebuffers(); + void DestroyOffscreenRenderTarget(OffscreenRenderTarget& target); + static Bool HasStencilComponent(VkFormat format); VkDevice m_device = VK_NULL_HANDLE; VkFormat m_colorFormat = VK_FORMAT_UNDEFINED; VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED; VkRenderPass m_renderPassLoad = VK_NULL_HANDLE; VkRenderPass m_renderPassClear = VK_NULL_HANDLE; + Vector m_defaultFramebuffers; + VkExtent2D m_defaultExtent = {0, 0}; + UnorderedMap m_offscreenRenderTargets; }; } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 417120e0..0ea372ba 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -254,10 +254,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_textureSamplerManager.reset(); } m_vertexInputStateFactory.reset(); - if (m_framebufferManager) { - m_framebufferManager->Shutdown(); - m_framebufferManager.reset(); - } for (auto& buffer : m_frameVertexUploadBuffers) { buffer.Destroy(); } @@ -283,6 +279,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { ShutdownSwapchain(); m_renderPassManager.reset(); + if (m_framebufferManager) { + m_framebufferManager->Shutdown(); + m_framebufferManager.reset(); + } if (m_commandPool != VK_NULL_HANDLE) { vkDestroyCommandPool(m_device, m_commandPool, nullptr); @@ -383,52 +383,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_swapchainObject.SetImageLayout(imageIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } - void VulkanRenderer::RecordColorClear(VkCommandBuffer commandBuffer, const VkClearColorValue& clearColor) { - VkClearAttachment clearAttachment{}; - clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - clearAttachment.colorAttachment = 0; - clearAttachment.clearValue.color = clearColor; - - VkClearRect clearRect{}; - clearRect.rect.offset = {0, 0}; - clearRect.rect.extent = m_activeRenderExtent; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = 1; - - vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect); - } - - void VulkanRenderer::RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth, - Uint32 stencil) { - if (m_activeDepthStencilFormat == VK_FORMAT_UNDEFINED) { - return; - } - - VkImageAspectFlags aspectMask = 0; - if ((mask & GL_DEPTH_BUFFER_BIT) != 0) { - aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - } - if ((mask & GL_STENCIL_BUFFER_BIT) != 0 && HasStencilComponent(m_activeDepthStencilFormat)) { - aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - if (aspectMask == 0) { - return; - } - - VkClearAttachment clearAttachment{}; - clearAttachment.aspectMask = aspectMask; - clearAttachment.clearValue.depthStencil.depth = depth; - clearAttachment.clearValue.depthStencil.stencil = stencil; - - VkClearRect clearRect{}; - clearRect.rect.offset = {0, 0}; - clearRect.rect.extent = m_activeRenderExtent; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = 1; - - vkCmdClearAttachments(commandBuffer, 1, &clearAttachment, 1, &clearRect); - } - void VulkanRenderer::TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex) { if (m_depthStencilImageLayouts.empty()) { return; @@ -487,7 +441,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { (drawTargetsDefault != m_activeRenderTargetIsDefault) || (!drawTargetsDefault && m_activeDrawFboExternalIndex != drawFboExternalIndex); if (activeTargetMismatch) { - vkCmdEndRenderPass(frame.commandBuffer); + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null"); + m_renderPassManager->EndRenderPass(frame.commandBuffer); if (m_activeRenderTargetIsDefault) { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } @@ -514,15 +469,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkCommandBuffer& commandBuffer = *commandBufferPtr; if (!drawTargetsDefault) { - if (!m_framebufferManager || !drawFbo) { + if (!m_framebufferManager || !m_renderPassManager || !drawFbo) { MGLOG_D("EnsureFrameRecordingStarted skipped: offscreen draw target is unavailable"); return; } - if (!m_framebufferManager->EnsureOffscreenColorTarget(drawFboExternalIndex, *drawFbo)) { - MGLOG_D("EnsureFrameRecordingStarted skipped: failed to materialize offscreen target for FBO %u", - drawFboExternalIndex); - return; - } // This frame touched only offscreen resources. Present still requires // the acquired swapchain image to be in PRESENT layout. @@ -549,33 +499,24 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } - if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, drawFboExternalIndex)) { - MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen FBO %u for attachment", - drawFboExternalIndex); - return; - } - VkRenderPass offscreenRenderPass = VK_NULL_HANDLE; VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE; VkExtent2D offscreenExtent{}; VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED; - if (!m_framebufferManager->GetOffscreenRenderTarget(drawFboExternalIndex, offscreenRenderPass, - offscreenFramebuffer, offscreenExtent, - offscreenDepthStencilFormat)) { + if (!EnsureOffscreenRenderTarget(drawFboExternalIndex, *drawFbo, offscreenRenderPass, offscreenFramebuffer, + offscreenExtent, offscreenDepthStencilFormat)) { MGLOG_D("EnsureFrameRecordingStarted skipped: offscreen render target for FBO %u is unavailable", drawFboExternalIndex); return; } - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = offscreenRenderPass; - renderPassInfo.framebuffer = offscreenFramebuffer; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = offscreenExtent; - renderPassInfo.clearValueCount = 0; - renderPassInfo.pClearValues = nullptr; - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, drawFboExternalIndex)) { + MGLOG_D("EnsureFrameRecordingStarted skipped: failed to transition offscreen FBO %u for attachment", + drawFboExternalIndex); + return; + } + m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer, + offscreenExtent); m_isMainRenderPassActive = true; m_activeRenderPass = offscreenRenderPass; m_activeRenderExtent = offscreenExtent; @@ -585,12 +526,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { auto pendingIt = m_pendingClears.find(drawTargetKey); if (pendingIt != m_pendingClears.end()) { if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) { - RecordColorClear(commandBuffer, pendingIt->second.color); + m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color); pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT; } if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - RecordDepthStencilClear(commandBuffer, pendingIt->second.mask, pendingIt->second.depth, - pendingIt->second.stencil); + m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, + pendingIt->second.mask, pendingIt->second.depth, + pendingIt->second.stencil, m_activeDepthStencilFormat); pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } if (pendingIt->second.mask == 0) { @@ -603,30 +545,33 @@ namespace MobileGL::MG_Backend::DirectVulkan { TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired); TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired); - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = GetDefaultLoadRenderPass(); - renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired]; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent(); - renderPassInfo.clearValueCount = 0; - renderPassInfo.pClearValues = nullptr; - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + VkRenderPass defaultRenderPass = VK_NULL_HANDLE; + VkFramebuffer defaultFramebuffer = VK_NULL_HANDLE; + VkExtent2D defaultExtent{}; + VkFormat defaultDepthStencilFormat = VK_FORMAT_UNDEFINED; + if (!GetDefaultRenderTargetForCurrentImage(defaultRenderPass, defaultFramebuffer, defaultExtent, + defaultDepthStencilFormat)) { + MGLOG_D("EnsureFrameRecordingStarted skipped: default render target unavailable"); + return; + } + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureFrameRecordingStarted: manager is null"); + m_renderPassManager->BeginRenderPass(commandBuffer, defaultRenderPass, defaultFramebuffer, defaultExtent); m_isMainRenderPassActive = true; - m_activeRenderPass = renderPassInfo.renderPass; - m_activeRenderExtent = renderPassInfo.renderArea.extent; - m_activeDepthStencilFormat = m_depthStencilFormat; + m_activeRenderPass = defaultRenderPass; + m_activeRenderExtent = defaultExtent; + m_activeDepthStencilFormat = defaultDepthStencilFormat; m_activeRenderTargetIsDefault = true; m_activeDrawFboExternalIndex = drawFboExternalIndex; auto pendingIt = m_pendingClears.find(drawTargetKey); if (pendingIt != m_pendingClears.end()) { if ((pendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) { - RecordColorClear(commandBuffer, pendingIt->second.color); + m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pendingIt->second.color); pendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT; } if ((pendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - RecordDepthStencilClear(commandBuffer, pendingIt->second.mask, pendingIt->second.depth, - pendingIt->second.stencil); + m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, + pendingIt->second.mask, pendingIt->second.depth, + pendingIt->second.stencil, m_activeDepthStencilFormat); pendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } if (pendingIt->second.mask == 0) { @@ -642,7 +587,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { } if (m_isMainRenderPassActive) { - vkCmdEndRenderPass(frame.commandBuffer); + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EndFrameRecordingIfNeeded: manager is null"); + m_renderPassManager->EndRenderPass(frame.commandBuffer); if (m_activeRenderTargetIsDefault) { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } @@ -1270,7 +1216,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkCommandBuffer commandBuffer = frame.commandBuffer; if (m_isMainRenderPassActive) { - vkCmdEndRenderPass(commandBuffer); + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "BlitFramebuffer: render pass manager is null"); + m_renderPassManager->EndRenderPass(commandBuffer); if (m_activeRenderTargetIsDefault) { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } @@ -1286,6 +1233,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { MGLOG_W("BlitFramebuffer skipped: offscreen framebuffer manager not available"); return false; } + if (!m_renderPassManager) { + MGLOG_W("BlitFramebuffer skipped: render pass manager not available"); + return false; + } auto consumePendingClearForTarget = [&](Bool targetIsDefault, Uint targetFboExternalIndex) { const Uint64 pendingKey = BuildPendingClearKey(targetFboExternalIndex, targetIsDefault); @@ -1304,60 +1255,55 @@ namespace MobileGL::MG_Backend::DirectVulkan { TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired); TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired); - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = GetDefaultLoadRenderPass(); - renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired]; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent(); - renderPassInfo.clearValueCount = 0; - renderPassInfo.pClearValues = nullptr; - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + VkRenderPass renderPass = VK_NULL_HANDLE; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VkExtent2D extent{}; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + if (!GetDefaultRenderTargetForCurrentImage(renderPass, framebuffer, extent, depthStencilFormat)) { + return; + } + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "BlitFramebuffer: manager is null"); + m_renderPassManager->BeginRenderPass(commandBuffer, renderPass, framebuffer, extent); - m_activeRenderExtent = renderPassInfo.renderArea.extent; - m_activeDepthStencilFormat = m_depthStencilFormat; + m_activeRenderExtent = extent; + m_activeDepthStencilFormat = depthStencilFormat; if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) { - RecordColorClear(commandBuffer, pending.color); + m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pending.color); } if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - RecordDepthStencilClear(commandBuffer, pending.mask, pending.depth, pending.stencil); + m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, pending.mask, + pending.depth, pending.stencil, + m_activeDepthStencilFormat); } - vkCmdEndRenderPass(commandBuffer); + m_renderPassManager->EndRenderPass(commandBuffer); } else if (m_framebufferManager && MG_State::pGLContext) { const auto targetFbo = MG_State::pGLContext->GetFramebufferObject(targetFboExternalIndex); - if (targetFbo && m_framebufferManager->EnsureOffscreenColorTarget(targetFboExternalIndex, *targetFbo) && + VkRenderPass offscreenRenderPass = VK_NULL_HANDLE; + VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE; + VkExtent2D offscreenExtent{}; + VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED; + if (targetFbo && + EnsureOffscreenRenderTarget(targetFboExternalIndex, *targetFbo, offscreenRenderPass, + offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat) && m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, targetFboExternalIndex)) { - VkRenderPass offscreenRenderPass = VK_NULL_HANDLE; - VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE; - VkExtent2D offscreenExtent{}; - VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED; - if (m_framebufferManager->GetOffscreenRenderTarget(targetFboExternalIndex, offscreenRenderPass, - offscreenFramebuffer, offscreenExtent, - offscreenDepthStencilFormat)) { - VkRenderPassBeginInfo offscreenPassInfo{}; - offscreenPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - offscreenPassInfo.renderPass = offscreenRenderPass; - offscreenPassInfo.framebuffer = offscreenFramebuffer; - offscreenPassInfo.renderArea.offset = {0, 0}; - offscreenPassInfo.renderArea.extent = offscreenExtent; - offscreenPassInfo.clearValueCount = 0; - offscreenPassInfo.pClearValues = nullptr; - vkCmdBeginRenderPass(commandBuffer, &offscreenPassInfo, VK_SUBPASS_CONTENTS_INLINE); + m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer, + offscreenExtent); - m_activeRenderExtent = offscreenPassInfo.renderArea.extent; - m_activeDepthStencilFormat = offscreenDepthStencilFormat; + m_activeRenderExtent = offscreenExtent; + m_activeDepthStencilFormat = offscreenDepthStencilFormat; - if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) { - RecordColorClear(commandBuffer, pending.color); - } - if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - RecordDepthStencilClear(commandBuffer, pending.mask, pending.depth, pending.stencil); - } - - vkCmdEndRenderPass(commandBuffer); + if ((pending.mask & GL_COLOR_BUFFER_BIT) != 0) { + m_renderPassManager->RecordColorClear(commandBuffer, m_activeRenderExtent, pending.color); } + if ((pending.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { + m_renderPassManager->RecordDepthStencilClear(commandBuffer, m_activeRenderExtent, pending.mask, + pending.depth, pending.stencil, + m_activeDepthStencilFormat); + } + + m_renderPassManager->EndRenderPass(commandBuffer); } } @@ -1858,6 +1804,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (frame.hasCommandBufferRecorded) { return false; } + if (!m_renderPassManager) { + return false; + } if (!frame.isCommandRecording) { m_frameContext.BeginCommandRecording(); if (m_uniformDescriptorBinder) { @@ -1867,7 +1816,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkCommandBuffer commandBuffer = frame.commandBuffer; if (m_isMainRenderPassActive) { - vkCmdEndRenderPass(commandBuffer); + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "Present: render pass manager is null"); + m_renderPassManager->EndRenderPass(commandBuffer); if (m_activeRenderTargetIsDefault) { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } @@ -1883,19 +1833,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { TransitionSwapchainImageToColorAttachment(commandBuffer, m_imageIndexAcquired); TransitionDepthStencilImageToAttachment(commandBuffer, m_imageIndexAcquired); - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = GetDefaultLoadRenderPass(); - renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired]; - renderPassInfo.renderArea.offset = {0, 0}; - renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent(); - renderPassInfo.clearValueCount = 0; - renderPassInfo.pClearValues = nullptr; - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + VkRenderPass renderPass = VK_NULL_HANDLE; + VkFramebuffer framebuffer = VK_NULL_HANDLE; + VkExtent2D extent{}; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + if (!GetDefaultRenderTargetForCurrentImage(renderPass, framebuffer, extent, depthStencilFormat)) { + return false; + } + m_renderPassManager->BeginRenderPass(commandBuffer, renderPass, framebuffer, extent); m_isMainRenderPassActive = true; - m_activeRenderPass = renderPassInfo.renderPass; - m_activeRenderExtent = renderPassInfo.renderArea.extent; - m_activeDepthStencilFormat = m_depthStencilFormat; + m_activeRenderPass = renderPass; + m_activeRenderExtent = extent; + m_activeDepthStencilFormat = depthStencilFormat; m_activeRenderTargetIsDefault = true; m_activeDrawFboExternalIndex = 0; return true; @@ -1908,21 +1857,16 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (!pendingFbo) { return false; } - if (!m_framebufferManager->EnsureOffscreenColorTarget(targetFboExternalIndex, *pendingFbo)) { - return false; - } - if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, - targetFboExternalIndex)) { - return false; - } - VkRenderPass offscreenRenderPass = VK_NULL_HANDLE; VkFramebuffer offscreenFramebuffer = VK_NULL_HANDLE; VkExtent2D offscreenExtent{}; VkFormat offscreenDepthStencilFormat = VK_FORMAT_UNDEFINED; - if (!m_framebufferManager->GetOffscreenRenderTarget(targetFboExternalIndex, offscreenRenderPass, - offscreenFramebuffer, offscreenExtent, - offscreenDepthStencilFormat)) { + if (!EnsureOffscreenRenderTarget(targetFboExternalIndex, *pendingFbo, offscreenRenderPass, + offscreenFramebuffer, offscreenExtent, offscreenDepthStencilFormat)) { + return false; + } + if (!m_framebufferManager->TransitionOffscreenColorToAttachment(commandBuffer, + targetFboExternalIndex)) { return false; } @@ -1949,15 +1893,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } - VkRenderPassBeginInfo offscreenPassInfo{}; - offscreenPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - offscreenPassInfo.renderPass = offscreenRenderPass; - offscreenPassInfo.framebuffer = offscreenFramebuffer; - offscreenPassInfo.renderArea.offset = {0, 0}; - offscreenPassInfo.renderArea.extent = offscreenExtent; - offscreenPassInfo.clearValueCount = 0; - offscreenPassInfo.pClearValues = nullptr; - vkCmdBeginRenderPass(commandBuffer, &offscreenPassInfo, VK_SUBPASS_CONTENTS_INLINE); + m_renderPassManager->BeginRenderPass(commandBuffer, offscreenRenderPass, offscreenFramebuffer, + offscreenExtent); m_isMainRenderPassActive = true; m_activeRenderPass = offscreenRenderPass; m_activeRenderExtent = offscreenExtent; @@ -1994,12 +1931,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { } if ((activePendingIt->second.mask & GL_COLOR_BUFFER_BIT) != 0) { - RecordColorClear(frame.commandBuffer, activePendingIt->second.color); + m_renderPassManager->RecordColorClear(frame.commandBuffer, m_activeRenderExtent, + activePendingIt->second.color); activePendingIt->second.mask &= ~GL_COLOR_BUFFER_BIT; } if ((activePendingIt->second.mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0) { - RecordDepthStencilClear(frame.commandBuffer, activePendingIt->second.mask, - activePendingIt->second.depth, activePendingIt->second.stencil); + m_renderPassManager->RecordDepthStencilClear( + frame.commandBuffer, m_activeRenderExtent, activePendingIt->second.mask, + activePendingIt->second.depth, activePendingIt->second.stencil, m_activeDepthStencilFormat); activePendingIt->second.mask &= ~(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } if (activePendingIt->second.mask == 0) { @@ -2541,26 +2480,49 @@ namespace MobileGL::MG_Backend::DirectVulkan { return renderPass; } - void VulkanRenderer::CreateDefaultFramebuffers() { - // Create framebuffers now (use swapchain imageviews) - const auto& imageViews = m_swapchainObject.GetImageViews(); - const auto swapchainExtent = m_swapchainObject.GetExtent(); - Vector& fbs = m_framebuffers; - fbs.reserve(imageViews.size()); - for (SizeT i = 0; i < imageViews.size(); ++i) { - VkImageView attachments[] = {imageViews[i], m_depthStencilImageViews[i]}; - VkFramebufferCreateInfo fbci{VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; - fbci.renderPass = GetDefaultLoadRenderPass(); - fbci.attachmentCount = static_cast(std::size(attachments)); - fbci.pAttachments = attachments; - fbci.width = swapchainExtent.width; - fbci.height = swapchainExtent.height; - fbci.layers = 1; - VkFramebuffer fb; - VK_VERIFY(vkCreateFramebuffer(m_device, &fbci, nullptr, &fb), "vkCreateFramebuffer"); - fbs.push_back(fb); + Bool VulkanRenderer::GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, + VkFramebuffer& outFramebuffer, VkExtent2D& outExtent, + VkFormat& outDepthStencilFormat) const { + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "GetDefaultRenderTargetForCurrentImage: manager is null"); + return m_renderPassManager->GetDefaultRenderTarget(m_imageIndexAcquired, outRenderPass, outFramebuffer, + outExtent, outDepthStencilFormat); + } + + Bool VulkanRenderer::EnsureOffscreenRenderTarget(Uint glFboExternalIndex, + const MG_State::GLState::FramebufferObject& glFbo, + VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, + VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) { + MOBILEGL_ASSERT(m_framebufferManager != nullptr, "EnsureOffscreenRenderTarget: framebuffer manager is null"); + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "EnsureOffscreenRenderTarget: render pass manager is null"); + + if (!m_framebufferManager->EnsureOffscreenColorTarget(glFboExternalIndex, glFbo)) { + return false; } - MGLOG_D("Default framebuffer created."); + + VkImageView colorView = VK_NULL_HANDLE; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; + VkImageView depthStencilView = VK_NULL_HANDLE; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + VkExtent2D extent{}; + if (!m_framebufferManager->GetOffscreenRenderSurface(glFboExternalIndex, colorView, colorFormat, + depthStencilView, depthStencilFormat, extent)) { + return false; + } + + VkRenderPassManager::OffscreenRenderTargetInfo targetInfo{}; + targetInfo.targetExternalIndex = glFboExternalIndex; + targetInfo.targetVersion = glFbo.GetObjectVersion(); + targetInfo.colorView = colorView; + targetInfo.colorFormat = colorFormat; + targetInfo.depthStencilView = depthStencilView; + targetInfo.depthStencilFormat = depthStencilFormat; + targetInfo.extent = extent; + if (!m_renderPassManager->EnsureOffscreenRenderTarget(targetInfo)) { + return false; + } + + return m_renderPassManager->GetOffscreenRenderTarget(glFboExternalIndex, outRenderPass, outFramebuffer, + outExtent, outDepthStencilFormat); } void VulkanRenderer::CreateSurface() { @@ -2707,11 +2669,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { } void VulkanRenderer::ShutdownSwapchain() { - for (auto fb : m_framebuffers) { - vkDestroyFramebuffer(m_device, fb, nullptr); - } - m_framebuffers.clear(); - DestroyDepthStencilResources(); if (m_renderPassManager) { @@ -2746,7 +2703,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { renderPassInitInfo.depthStencilFormat = m_depthStencilFormat; MOBILEGL_ASSERT(m_renderPassManager->Initialize(renderPassInitInfo), "RecreateSwapchain: render pass manager initialization failed"); - CreateDefaultFramebuffers(); + MOBILEGL_ASSERT(m_renderPassManager->RecreateDefaultFramebuffers( + m_swapchainObject.GetImageViews(), m_depthStencilImageViews, m_swapchainObject.GetExtent()), + "RecreateSwapchain: default framebuffers initialization failed"); if (m_pipelineFactory) { m_pipelineFactory->DestroyAll(); } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index f9b90fb8..ace154b1 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -25,6 +25,7 @@ #include "../VkIncludes.h" namespace MobileGL::MG_State::GLState { + class FramebufferObject; class ProgramObject; class VertexArrayObject; } // namespace MobileGL::MG_State::GLState @@ -125,7 +126,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkCommandPool m_commandPool = VK_NULL_HANDLE; - Vector m_framebuffers; VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED; Vector m_depthStencilImages; Vector m_depthStencilImageMemories; @@ -172,15 +172,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { void CreateDepthStencilResources(); void DestroyDepthStencilResources(); VkRenderPass GetDefaultLoadRenderPass() const; - void CreateDefaultFramebuffers(); + Bool GetDefaultRenderTargetForCurrentImage(VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, + VkExtent2D& outExtent, VkFormat& outDepthStencilFormat) const; + Bool EnsureOffscreenRenderTarget(Uint glFboExternalIndex, const MG_State::GLState::FramebufferObject& glFbo, + VkRenderPass& outRenderPass, VkFramebuffer& outFramebuffer, + VkExtent2D& outExtent, VkFormat& outDepthStencilFormat); void PrepareDemoPipeline(); VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout, Uint64 vertexInputHash, const VkPipelineVertexInputStateCreateInfo& vertexInputState); void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex); void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex); - void RecordColorClear(VkCommandBuffer commandBuffer, const VkClearColorValue& clearColor); - void RecordDepthStencilClear(VkCommandBuffer commandBuffer, GLbitfield mask, Float depth, Uint32 stencil); void EndFrameRecordingIfNeeded(); void DeferDestroyBuffer(VkBufferObject& buffer); void CollectDeferredBufferReleases(Uint32 frameIndex);