From 34b06da83b559b5f5141f05045999161a46e456a Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 2 Mar 2026 09:49:32 +0800 Subject: [PATCH] [Fix] (MG_Backend/DirectVulkan): get ImageView from swapchain when creating render pass for default FBO --- .../Renderer/VkRenderPassManager.cpp | 56 ++++++++++++------- .../Renderer/VkRenderPassManager.h | 13 ++++- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 10 ++-- 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index a8865f60..91755136 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -14,8 +14,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPassManager::VkRenderPassManager(VkDevice device, - const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager): - m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager) { + const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager, + const SwapchainObject& swapchainObject): + m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager), + m_swapchainObject(swapchainObject) { RenderPassEntry::s_device = m_device; } @@ -29,8 +31,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { } VkRenderPassManager::HashType VkRenderPassManager::ComputeHash( - const MG_State::GLState::FramebufferObject& fbo) const { + const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex) const { XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion)); + const Bool isDefaultFbo = (&fbo == MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo->defaultFBO.get()); + if (isDefaultFbo) { + XXHASH_VERIFY(XXH64_update(m_hashState, &swapchainImageIndex, sizeof(swapchainImageIndex))); + } auto& drawBuffers = fbo.GetDrawBuffers(); XXHASH_VERIFY(XXH64_update(m_hashState, drawBuffers.data(), drawBuffers.size() * sizeof(drawBuffers[0]))); auto readBuffer = fbo.GetReadBuffer(); @@ -75,9 +81,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { return XXH64_digest(m_hashState); } - RenderPassEntry& VkRenderPassManager::GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo) { + RenderPassEntry& VkRenderPassManager::GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, + Uint32 swapchainImageIndex) { // retrieve from cache first - auto hash = ComputeHash(fbo); + auto hash = ComputeHash(fbo, swapchainImageIndex); auto it = m_renderPasses.find(hash); if (it != m_renderPasses.end()) return it->second; @@ -97,6 +104,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Vector attachmentDescriptions(validDrawBufCount); Vector colorAttachmentRefs(validDrawBufCount); Vector textureResources(validDrawBufCount, nullptr); + Vector attachmentViews(validDrawBufCount, VK_NULL_HANDLE); // This should automatically work on default & offscreen FBO // assuming default FBO has the right param for (Int i = 0; i < validDrawBufCount; ++i) { @@ -136,8 +144,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (height == 0) height = texture2d->GetBaseSize().y(); - textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture); - MOBILEGL_ASSERT(textureResources[i], "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i); + if (isDefaultFbo) { + const auto& swapchainViews = m_swapchainObject.GetImageViews(); + MOBILEGL_ASSERT(swapchainImageIndex < swapchainViews.size(), + "GetOrCreateRenderPass: swapchain image index out of range"); + attachmentViews[i] = swapchainViews[swapchainImageIndex]; + } else { + textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture); + MOBILEGL_ASSERT(textureResources[i], + "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i); + attachmentViews[i] = textureResources[i]->view; + } break; } @@ -166,13 +183,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; depthAttachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depthAttachmentDescription.finalLayout = isDefaultFbo ? - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture); - MOBILEGL_ASSERT(depthTextureResource, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment"); + depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + if (isDefaultFbo) { + attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex)); + } else { + depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture); + MOBILEGL_ASSERT(depthTextureResource, + "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment"); + textureResources.emplace_back(depthTextureResource); + attachmentViews.emplace_back(depthTextureResource->view); + } attachmentDescriptions.emplace_back(depthAttachmentDescription); - textureResources.emplace_back(depthTextureResource); } // Depth attachment ref @@ -208,11 +229,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPass renderPass = VK_NULL_HANDLE; VK_VERIFY(vkCreateRenderPass(m_device, &renderPassCreateInfo, nullptr, &renderPass)); - Vector attachmentViews(textureResources.size(), VK_NULL_HANDLE); - for (Int i = 0; i < textureResources.size(); i++) { - attachmentViews[i] = textureResources[i]->view; - } - // Framebuffer VkFramebufferCreateInfo framebufferCreateInfo; framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -228,7 +244,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer)); IntVec2 extent = {width, height}; RenderPassEntry renderPassEntry { - renderPass, framebuffer, Move(textureResources), extent, 1 }; + renderPass, framebuffer, Move(textureResources), static_cast(attachmentViews.size()), extent, 1 }; auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry)); return insertedIt->second; } @@ -248,7 +264,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkClearValue defaultClearValue; defaultClearValue.color = { 0.0f, 0.0f, 0.0f, 1.0f }; defaultClearValue.depthStencil = { 1.0f, 0 }; - Vector clearValue(renderPassEntry.textureResources.size(), defaultClearValue); + Vector clearValue(renderPassEntry.attachmentCount, defaultClearValue); renderPassBeginInfo.clearValueCount = clearValue.size(); renderPassBeginInfo.pClearValues = clearValue.data(); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h index 0850da3c..435f1060 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -8,6 +8,7 @@ #pragma once +#include "SwapchainObject.h" #include "VkClearManager.h" #include "VkTextureManager.h" #include "../VkIncludes.h" @@ -23,6 +24,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkFramebuffer framebuffer = VK_NULL_HANDLE; // Should we hold pointer-to-resource here? Vector textureResources; + Uint32 attachmentCount = 0; IntVec2 extent = {0, 0}; Uint32 subpass = 0; @@ -32,6 +34,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { std::swap(renderPass, that.renderPass); std::swap(framebuffer, that.framebuffer); std::swap(textureResources, that.textureResources); + std::swap(attachmentCount, that.attachmentCount); std::swap(extent, that.extent); std::swap(subpass, that.subpass); } @@ -39,10 +42,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPass renderpass, VkFramebuffer framebuffer, const std::vector& textureResources, + Uint32 attachmentCount, IntVec2 extent, int subpass): renderPass(renderpass), framebuffer(framebuffer), textureResources(Move(textureResources)), + attachmentCount(attachmentCount), extent(extent), subpass(subpass) {} @@ -61,14 +66,15 @@ namespace MobileGL::MG_Backend::DirectVulkan { public: using HashType = Uint64; VkRenderPassManager(VkDevice device, - const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager); + const VulkanRendererConfig& config, VkClearManager& clearManager, VkTextureManager& textureManager, + const SwapchainObject& swapchainObject); ~VkRenderPassManager(); Bool Initialize(); void Shutdown(); - HashType ComputeHash(const MG_State::GLState::FramebufferObject& fbo) const; - RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo); + HashType ComputeHash(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex) const; + RenderPassEntry& GetOrCreateRenderPass(const MG_State::GLState::FramebufferObject& fbo, Uint32 swapchainImageIndex); static Bool BeginRenderPass(VkCommandBuffer commandBuffer, RenderPassEntry& renderPassEntry); static Bool EndRenderPass(VkCommandBuffer commandBuffer); static RenderPassEntry* GetActiveRenderPass(); @@ -77,6 +83,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { const VulkanRendererConfig& m_config; VkClearManager& m_clearManager; VkTextureManager& m_textureManager; + const SwapchainObject& m_swapchainObject; UnorderedMap m_renderPasses; static inline XXH64_state_t* m_hashState = XXH64_createState(); static inline RenderPassEntry* s_activeRenderPass = nullptr; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index afb68f40..9d365fea 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -112,7 +112,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { MOBILEGL_ASSERT(m_clearManager != nullptr, "VkClearManager creation failed."); succeeded = m_clearManager->Initialize(); MOBILEGL_ASSERT(succeeded, "VkClearManager initialization failed."); - m_renderPassManager = MakeUnique(m_device, m_config, *m_clearManager, *m_textureManager); + m_renderPassManager = + MakeUnique(m_device, m_config, *m_clearManager, *m_textureManager, m_swapchainObject); MOBILEGL_ASSERT(m_renderPassManager != nullptr, "VkRenderPassManager creation failed."); succeeded = m_renderPassManager->Initialize(); MOBILEGL_ASSERT(succeeded, "VkRenderPassManager initialization failed."); @@ -463,7 +464,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { auto vertexInputHash = m_vertexInputStateFactory->ComputeHash(vao); auto& vis = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao); auto pipelineLayout = m_uniformDescriptorBinder->GetOrCreatePipelineLayout(program); - auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(drawFbo); + auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(drawFbo, m_imageIndexAcquired); auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest); BlendFactor srcRGB = BlendFactor::One; BlendFactor dstRGB = BlendFactor::Zero; @@ -505,11 +506,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_uniformDescriptorBinder->BeginFrame(m_frameContext.GetCurrentFrameIndex()); } - const auto& drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); + const auto& drawFbo = + MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); // Begin render pass // TODO: properly deal with clear - auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*drawFbo); + auto& renderPassEntry = m_renderPassManager->GetOrCreateRenderPass(*drawFbo, m_imageIndexAcquired); auto* activeRenderPass = VkRenderPassManager::GetActiveRenderPass(); if (activeRenderPass != &renderPassEntry) { if (activeRenderPass) {