From 033ba16affcdbabaeba690f8a2c448d3ca87960e Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Sat, 21 Feb 2026 19:50:26 +0800 Subject: [PATCH] [Refactor] (MG_Backend/DirectVulkan): Decouple default render pass management from VulkanRenderer. --- CMakeLists.txt | 1 + .../Renderer/VkRenderPassManager.cpp | 99 +++++++++++++++++++ .../Renderer/VkRenderPassManager.h | 38 +++++++ .../DirectVulkan/Renderer/VulkanRenderer.cpp | 78 ++++----------- .../DirectVulkan/Renderer/VulkanRenderer.h | 7 +- 5 files changed, 162 insertions(+), 61 deletions(-) create mode 100644 MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp create mode 100644 MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c2a7e078..e74e5311 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,6 +223,7 @@ set(SOURCE_FILES MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkFramebufferManager.cpp + MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureSamplerManager.cpp MobileGL/MG_State/GLState/Core.cpp diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp new file mode 100644 index 00000000..de29fdb9 --- /dev/null +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -0,0 +1,99 @@ +// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +#include "VkRenderPassManager.h" + +namespace MobileGL::MG_Backend::DirectVulkan { + Bool VkRenderPassManager::Initialize(const InitInfo& initInfo) { + Shutdown(); + + if (initInfo.device == VK_NULL_HANDLE || initInfo.colorFormat == VK_FORMAT_UNDEFINED || + initInfo.depthStencilFormat == VK_FORMAT_UNDEFINED) { + return false; + } + + m_device = initInfo.device; + m_colorFormat = initInfo.colorFormat; + m_depthStencilFormat = initInfo.depthStencilFormat; + m_renderPassLoad = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_LOAD); + m_renderPassClear = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_CLEAR); + MGLOG_D("VkRenderPassManager: RenderPasses created (LOAD/CLEAR)."); + return m_renderPassLoad != VK_NULL_HANDLE && m_renderPassClear != VK_NULL_HANDLE; + } + + void VkRenderPassManager::Shutdown() { + if (m_device != VK_NULL_HANDLE) { + if (m_renderPassClear != VK_NULL_HANDLE) { + vkDestroyRenderPass(m_device, m_renderPassClear, nullptr); + } + if (m_renderPassLoad != VK_NULL_HANDLE) { + vkDestroyRenderPass(m_device, m_renderPassLoad, nullptr); + } + } + + m_renderPassClear = VK_NULL_HANDLE; + m_renderPassLoad = VK_NULL_HANDLE; + m_colorFormat = VK_FORMAT_UNDEFINED; + m_depthStencilFormat = VK_FORMAT_UNDEFINED; + m_device = VK_NULL_HANDLE; + } + + VkRenderPass VkRenderPassManager::GetLoadRenderPass() const { + return m_renderPassLoad; + } + + VkRenderPass VkRenderPassManager::GetClearRenderPass() const { + return m_renderPassClear; + } + + VkRenderPass VkRenderPassManager::CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const { + MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "VkRenderPassManager: device is null"); + 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"); + + VkAttachmentDescription color{}; + color.format = m_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; + + 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; + + VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkSubpassDescription subpass{}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorRef; + subpass.pDepthStencilAttachment = &depthStencilRef; + + VkAttachmentDescription attachments[2] = {color, depthStencil}; + + VkRenderPassCreateInfo createInfo{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; + createInfo.attachmentCount = 2; + createInfo.pAttachments = attachments; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpass; + + VkRenderPass renderPass = VK_NULL_HANDLE; + VK_VERIFY(vkCreateRenderPass(m_device, &createInfo, nullptr, &renderPass), "vkCreateRenderPass(default)"); + return renderPass; + } +} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h new file mode 100644 index 00000000..a20a5e71 --- /dev/null +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -0,0 +1,38 @@ +// MobileGL - MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +#pragma once + +#include "../VkIncludes.h" +#include + +namespace MobileGL::MG_Backend::DirectVulkan { + class VkRenderPassManager { + public: + struct InitInfo { + VkDevice device = VK_NULL_HANDLE; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + }; + + Bool Initialize(const InitInfo& initInfo); + void Shutdown(); + + VkRenderPass GetLoadRenderPass() const; + VkRenderPass GetClearRenderPass() const; + + private: + VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp colorLoadOp) const; + + 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; + }; +} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 628db786..417120e0 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -144,7 +144,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { payload.programHash = programHash; payload.vertexInputHash = vertexInputHash; payload.pipelineLayout = pipelineLayout; - payload.renderPass = (m_activeRenderPass != VK_NULL_HANDLE) ? m_activeRenderPass : m_renderPassLoad; + payload.renderPass = (m_activeRenderPass != VK_NULL_HANDLE) ? m_activeRenderPass : GetDefaultLoadRenderPass(); payload.subpass = 0; payload.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; if (MG_State::pGLContext != nullptr) { @@ -202,6 +202,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { CreateAllocator(); CreateCommandPool(); + m_renderPassManager = MakeUnique(); RecreateSwapchain(); @@ -281,6 +282,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } ShutdownSwapchain(); + m_renderPassManager.reset(); if (m_commandPool != VK_NULL_HANDLE) { vkDestroyCommandPool(m_device, m_commandPool, nullptr); @@ -603,7 +605,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = m_renderPassLoad; + renderPassInfo.renderPass = GetDefaultLoadRenderPass(); renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired]; renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent(); @@ -1304,7 +1306,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = m_renderPassLoad; + renderPassInfo.renderPass = GetDefaultLoadRenderPass(); renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired]; renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent(); @@ -1883,7 +1885,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = m_renderPassLoad; + renderPassInfo.renderPass = GetDefaultLoadRenderPass(); renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired]; renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.extent = m_swapchainObject.GetExtent(); @@ -2531,52 +2533,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { MGLOG_I("Command pool created"); } - VkRenderPass VulkanRenderer::CreateDefaultRenderPass(VkAttachmentLoadOp loadOp) { - VkAttachmentDescription color{}; - color.format = m_swapchainObject.GetSurfaceFormat().format; - color.samples = VK_SAMPLE_COUNT_1_BIT; - color.loadOp = loadOp; - color.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - color.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - 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; - - VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference depthStencilRef{1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - VkSubpassDescription sub{}; - sub.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - sub.colorAttachmentCount = 1; - sub.pColorAttachments = &colorRef; - sub.pDepthStencilAttachment = &depthStencilRef; - - VkAttachmentDescription attachments[] = {color, depthStencil}; - - VkRenderPassCreateInfo rpci{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO}; - rpci.attachmentCount = static_cast(std::size(attachments)); - rpci.pAttachments = attachments; - rpci.subpassCount = 1; - rpci.pSubpasses = ⊂ - - VkRenderPass renderPass = VK_NULL_HANDLE; - VK_VERIFY(vkCreateRenderPass(m_device, &rpci, nullptr, &renderPass), "vkCreateRenderPass"); + VkRenderPass VulkanRenderer::GetDefaultLoadRenderPass() const { + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "GetDefaultLoadRenderPass: render pass manager is null"); + const VkRenderPass renderPass = m_renderPassManager->GetLoadRenderPass(); + MOBILEGL_ASSERT(renderPass != VK_NULL_HANDLE, + "GetDefaultLoadRenderPass: default load render pass is unavailable"); return renderPass; } - void VulkanRenderer::CreateDefaultRenderPass() { - m_renderPassLoad = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_LOAD); - m_renderPassClear = CreateDefaultRenderPass(VK_ATTACHMENT_LOAD_OP_CLEAR); - MGLOG_D("RenderPasses created (LOAD/CLEAR)."); - } - void VulkanRenderer::CreateDefaultFramebuffers() { // Create framebuffers now (use swapchain imageviews) const auto& imageViews = m_swapchainObject.GetImageViews(); @@ -2586,7 +2550,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { 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 = m_renderPassLoad; + fbci.renderPass = GetDefaultLoadRenderPass(); fbci.attachmentCount = static_cast(std::size(attachments)); fbci.pAttachments = attachments; fbci.width = swapchainExtent.width; @@ -2750,14 +2714,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { DestroyDepthStencilResources(); - if (m_renderPassClear != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device, m_renderPassClear, nullptr); - m_renderPassClear = VK_NULL_HANDLE; - } - - if (m_renderPassLoad != VK_NULL_HANDLE) { - vkDestroyRenderPass(m_device, m_renderPassLoad, nullptr); - m_renderPassLoad = VK_NULL_HANDLE; + if (m_renderPassManager) { + m_renderPassManager->Shutdown(); } m_swapchainObject.Shutdown(m_device); @@ -2781,7 +2739,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { static_cast(m_swapchainObject.GetImageCount())), "RecreateSwapchain, InitializeSwapchainSemaphores"); CreateDepthStencilResources(); - CreateDefaultRenderPass(); + MOBILEGL_ASSERT(m_renderPassManager != nullptr, "RecreateSwapchain: render pass manager is null"); + VkRenderPassManager::InitInfo renderPassInitInfo{}; + renderPassInitInfo.device = m_device; + renderPassInitInfo.colorFormat = m_swapchainObject.GetSurfaceFormat().format; + renderPassInitInfo.depthStencilFormat = m_depthStencilFormat; + MOBILEGL_ASSERT(m_renderPassManager->Initialize(renderPassInitInfo), + "RecreateSwapchain: render pass manager initialization failed"); CreateDefaultFramebuffers(); 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 d31a00ca..f9b90fb8 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -16,6 +16,7 @@ #include "VertexInputStateFactory.h" #include "VkBufferObject.h" #include "VkFramebufferManager.h" +#include "VkRenderPassManager.h" #include "VkTextureSamplerManager.h" #include "MG_Util/Math/VectorTypes.h" #include @@ -124,8 +125,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkCommandPool m_commandPool = VK_NULL_HANDLE; - VkRenderPass m_renderPassLoad = VK_NULL_HANDLE; - VkRenderPass m_renderPassClear = VK_NULL_HANDLE; Vector m_framebuffers; VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED; Vector m_depthStencilImages; @@ -155,6 +154,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { UniquePtr m_uniformDescriptorBinder; UniquePtr m_vertexInputStateFactory; UniquePtr m_framebufferManager; + UniquePtr m_renderPassManager; UniquePtr m_textureSamplerManager; void CreateInstance(); @@ -171,8 +171,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void CreateFrameContexts(); void CreateDepthStencilResources(); void DestroyDepthStencilResources(); - void CreateDefaultRenderPass(); - VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp loadOp); + VkRenderPass GetDefaultLoadRenderPass() const; void CreateDefaultFramebuffers(); void PrepareDemoPipeline(); VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, VkPipelineLayout pipelineLayout,