[Refactor] (MG_Backend/DirectVulkan): Decouple default render pass management from VulkanRenderer.

This commit is contained in:
BZLZHH
2026-02-21 19:50:26 +08:00
parent d84b4da766
commit 033ba16aff
5 changed files with 162 additions and 61 deletions
+1
View File
@@ -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
@@ -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
@@ -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 <Includes.h>
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
@@ -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<VkRenderPassManager>();
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<Uint32>(std::size(attachments));
rpci.pAttachments = attachments;
rpci.subpassCount = 1;
rpci.pSubpasses = &sub;
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<Uint32>(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<Uint32>(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();
@@ -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 <Includes.h>
@@ -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<VkFramebuffer> m_framebuffers;
VkFormat m_depthStencilFormat = VK_FORMAT_UNDEFINED;
Vector<VkImage> m_depthStencilImages;
@@ -155,6 +154,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
UniquePtr<UniformDescriptorBinder> m_uniformDescriptorBinder;
UniquePtr<VertexInputStateFactory> m_vertexInputStateFactory;
UniquePtr<VkFramebufferManager> m_framebufferManager;
UniquePtr<VkRenderPassManager> m_renderPassManager;
UniquePtr<VkTextureSamplerManager> 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,