From 43f204347879e9d8e911cc726e9c631338183c24 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 1 Mar 2026 21:21:32 +0800 Subject: [PATCH] [Fix] (MG_Backend/DirectVulkan): Vulkan backend default framebuffer initialization --- .../DirectVulkan/Renderer/SwapchainObject.cpp | 32 ++++++++++ .../Renderer/UniformDescriptorBinder.cpp | 9 +-- .../Renderer/VkRenderPassManager.cpp | 14 ++--- .../Renderer/VkRenderPassManager.h | 3 +- .../Renderer/VkTextureManager.cpp | 61 ++++++++++--------- .../DirectVulkan/Renderer/VkTextureManager.h | 44 +++++++++++-- MobileGL/MG_Impl/Init.cpp | 4 +- 7 files changed, 116 insertions(+), 51 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp index 519d5fae..d81a8512 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp @@ -8,6 +8,9 @@ #include "SwapchainObject.h" +#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h" +#include "MG_State/GLState/TextureState/TextureObject2D.h" + #if defined(__has_include) #if __has_include() #include @@ -228,6 +231,35 @@ namespace MobileGL::MG_Backend::DirectVulkan { MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_extent.width, m_extent.height, imageCount); + + // Properly initialize Default FBO here + auto* defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo; + auto* colorTex = static_cast(defaultFBOInfo->colorAttachment.get()); + colorTex->AllocateStorage( + TextureUploadTarget::Texture2D, 0, { + {(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1}, + createInfo.imageExtent.width * (Int)createInfo.imageExtent.height * 4}); // TODO: 4 is format size + TextureInternalFormat depthFormat = TextureInternalFormat::Depth24Stencil8; + switch (m_depthStencilFormat) { + case VK_FORMAT_D24_UNORM_S8_UINT: + depthFormat = TextureInternalFormat::Depth24Stencil8; + break; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + depthFormat = TextureInternalFormat::Depth32FStencil8; + break; + case VK_FORMAT_D32_SFLOAT: + depthFormat = TextureInternalFormat::DepthComponent32F; + break; + default: + depthFormat = TextureInternalFormat::Depth24Stencil8; + break; + } + auto* depthTex = static_cast(defaultFBOInfo->depthAttachment.get()); + depthTex->SetInternalFormat(depthFormat); + depthTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, { + {(Int)createInfo.imageExtent.width, (Int)createInfo.imageExtent.height, 1}, + createInfo.imageExtent.width * createInfo.imageExtent.width * 4}); // TODO: 4 is format size + } void SwapchainObject::CreateDepthStencilResources(VkDevice device, VkPhysicalDevice physicalDevice) { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp index 609c0777..37adefcb 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp @@ -475,14 +475,15 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (!samplerToUse) { return false; } - VkTextureManager::TextureResource resource; - if (!m_textureManager->SyncTextureAndGetDescriptor(*texture, resource)) { + VkTextureManager::TextureResource* resource = + m_textureManager->SyncTextureAndGetDescriptor(*texture); + if (resource == nullptr) { return false; } outImageInfo = { .sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse), - .imageView = resource.view, - .imageLayout = resource.layout, + .imageView = resource->view, + .imageLayout = resource->layout, }; return outImageInfo.sampler != VK_NULL_HANDLE; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index 122d32cf..498fcbb0 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -96,7 +96,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Int height = 0; Vector attachmentDescriptions(validDrawBufCount); Vector colorAttachmentRefs(validDrawBufCount); - Vector textureResources(validDrawBufCount); + Vector textureResources(validDrawBufCount, nullptr); // This should automatically work on default & offscreen FBO // assuming default FBO has the right param for (Int i = 0; i < validDrawBufCount; ++i) { @@ -135,8 +135,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (height == 0) height = texture2d->GetBaseSize().y(); - Bool ok = m_textureManager.SyncTextureAndGetDescriptor(*texture, textureResources[i]); - MOBILEGL_ASSERT(ok, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i); + textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture); + MOBILEGL_ASSERT(textureResources[i], "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i); break; } @@ -153,7 +153,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { // Depth attachment description auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth); VkAttachmentDescription depthAttachmentDescription; - VkTextureManager::TextureResource depthTextureResource; + VkTextureManager::TextureResource* depthTextureResource = nullptr; if (depthAtt.IsComplete() && depthAtt.IsTexture()) { auto& texture = *depthAtt.GetTexture(); depthAttachmentDescription.format = @@ -167,8 +167,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { depthAttachmentDescription.finalLayout = isDefaultFbo ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - Bool ok = m_textureManager.SyncTextureAndGetDescriptor(texture, depthTextureResource); - MOBILEGL_ASSERT(ok, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment"); + depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture); + MOBILEGL_ASSERT(depthTextureResource, "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment"); attachmentDescriptions.emplace_back(depthAttachmentDescription); } @@ -207,7 +207,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Vector attachmentViews(textureResources.size(), VK_NULL_HANDLE); for (Int i = 0; i < textureResources.size(); i++) { - attachmentViews[i] = textureResources[i].view; + attachmentViews[i] = textureResources[i]->view; } // Framebuffer diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h index 2302e524..b7292df5 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -21,7 +21,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { static inline VkDevice s_device; VkRenderPass renderPass = VK_NULL_HANDLE; VkFramebuffer framebuffer = VK_NULL_HANDLE; - Vector textureResources; + // Should we hold pointer-to-resource here? + Vector textureResources; IntVec2 extent = {0, 0}; Uint32 subpass = 0; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index f74147e7..18d15af8 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -24,13 +24,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_commandPool != VK_NULL_HANDLE && m_graphicsQueue != VK_NULL_HANDLE, "VkTextureManager::Initialize failed: invalid initialization info"); + TextureResource::s_device = m_device; + TextureResource::s_allocator = m_allocator; + return true; } void VkTextureManager::Shutdown() { - for (auto& [_, resource] : m_textureResources) { - DestroyTextureResource(resource); - } m_textureResources.clear(); m_device = VK_NULL_HANDLE; @@ -40,25 +40,21 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_graphicsQueue = VK_NULL_HANDLE; } - Bool VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture, - TextureResource& outTextureResource) { + VkTextureManager::TextureResource* VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture) { MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "SyncTextureAndGetDescriptor: m_device == VK_NULL_HANDLE"); - auto it = m_textureResources.find(texture.GetExternalIndex()); + auto it = m_textureResources.find(&texture); if (it == m_textureResources.end()) { TextureResource initial{}; - initial.textureExternalIndex = texture.GetExternalIndex(); - auto [insertIt, _] = m_textureResources.emplace(texture.GetExternalIndex(), initial); + auto [insertIt, _] = m_textureResources.emplace(&texture, Move(initial)); it = insertIt; } if (!SyncTexture(texture, it->second)) { - return false; + return nullptr; } - outTextureResource = it->second; - - return true; + return &(it->second); } Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, VkImageLayout newLayout, @@ -91,6 +87,22 @@ namespace MobileGL::MG_Backend::DirectVulkan { return true; } + SizeT VkTextureManager::CollectGarbage() { + m_gcCounter++; + if (m_gcCounter != 0) { + return 0; + } + SizeT count = 0; + for (const auto& [raw, weak]: m_aliveObjects) { + if (weak.expired()) { + count++; + m_textureResources.erase(raw); + m_aliveObjects.erase(raw); + } + } + return count; + } + Bool VkTextureManager::SyncTexture(MG_State::GLState::ITextureObject &texture, TextureResource &outResource) { TextureUploadTarget uploadTarget = TextureUploadTarget::Unknown; @@ -153,7 +165,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { return true; } - DestroyTextureResource(resource); + resource.~TextureResource(); VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -191,7 +203,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { resource.extent = {static_cast(texelSize.x()), static_cast(texelSize.y())}; resource.mipLevels = mipLevels; resource.format = format; - resource.textureExternalIndex = texture.GetExternalIndex(); return true; } @@ -339,22 +350,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { return true; } - void VkTextureManager::DestroyTextureResource(TextureResource& resource) const { - if (m_device != VK_NULL_HANDLE && resource.view != VK_NULL_HANDLE) { - vkDestroyImageView(m_device, resource.view, nullptr); - } - if (m_allocator != nullptr && resource.image != VK_NULL_HANDLE && resource.allocation != nullptr) { - vmaDestroyImage(m_allocator, resource.image, resource.allocation); - } - resource.view = VK_NULL_HANDLE; - resource.image = VK_NULL_HANDLE; - resource.allocation = nullptr; - resource.layout = VK_IMAGE_LAYOUT_UNDEFINED; - resource.extent = {0, 0}; - resource.mipLevels = 1; - resource.format = VK_FORMAT_UNDEFINED; - } - Bool VkTextureManager::CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture, TextureUploadTarget& outTarget, IntVec3& outTexelSize, @@ -416,6 +411,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { return VK_FORMAT_R8G8B8A8_UNORM; case TextureInternalFormat::SRGB8Alpha8: return VK_FORMAT_R8G8B8A8_SRGB; + case TextureInternalFormat::Depth24Stencil8: + return VK_FORMAT_D24_UNORM_S8_UINT; + case TextureInternalFormat::Depth32FStencil8: + return VK_FORMAT_D32_SFLOAT_S8_UINT; + case TextureInternalFormat::DepthComponent32F: + return VK_FORMAT_D32_SFLOAT; default: return VK_FORMAT_UNDEFINED; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h index 640920b8..219b657e 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h @@ -36,20 +36,51 @@ public: VkExtent2D extent = {0, 0}; Uint32 mipLevels = 1; VkFormat format = VK_FORMAT_UNDEFINED; - Uint textureExternalIndex = 0; + + TextureResource() {} + TextureResource(const TextureResource&) = delete; + TextureResource(TextureResource&& that) noexcept { + std::swap(this->image, that.image); + std::swap(this->allocation, that.allocation); + std::swap(this->view, that.view); + std::swap(this->layout, that.layout); + std::swap(this->extent, that.extent); + std::swap(this->mipLevels, that.mipLevels); + std::swap(this->format, that.format); + } + + ~TextureResource() { + if (view != VK_NULL_HANDLE) { + vkDestroyImageView(s_device, view, nullptr); + } + if (image != VK_NULL_HANDLE && allocation != nullptr) { + vmaDestroyImage(s_allocator, image, allocation); + } + view = VK_NULL_HANDLE; + image = VK_NULL_HANDLE; + allocation = nullptr; + layout = VK_IMAGE_LAYOUT_UNDEFINED; + extent = {0, 0}; + mipLevels = 1; + format = VK_FORMAT_UNDEFINED; + } + + static inline VkDevice s_device = VK_NULL_HANDLE; + static inline VmaAllocator s_allocator = VK_NULL_HANDLE; }; Bool Initialize(const InitInfo& initInfo); void Shutdown(); - Bool SyncTextureAndGetDescriptor( - MG_State::GLState::ITextureObject& texture, TextureResource& outTextureResource); - + TextureResource* SyncTextureAndGetDescriptor( + MG_State::GLState::ITextureObject& texture); static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, VkImageLayout newLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask); + + SizeT CollectGarbage(); private: Bool SyncTexture(MG_State::GLState::ITextureObject &texture, @@ -62,7 +93,6 @@ private: TextureUploadTarget uploadTarget, TextureResource &outResource); Bool ExecuteCmdBufImmediate(const std::function& recorder) const; - void DestroyTextureResource(TextureResource& resource) const; static Bool CheckMipmapCompleteness(const MG_State::GLState::ITextureObject& texture, TextureUploadTarget& outTarget, IntVec3& outTexelSize, @@ -77,6 +107,8 @@ private: VkCommandPool m_commandPool = VK_NULL_HANDLE; VkQueue m_graphicsQueue = VK_NULL_HANDLE; - UnorderedMap m_textureResources; + Uint8 m_gcCounter = 0; + UnorderedMap> m_aliveObjects; + UnorderedMap m_textureResources; }; } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Impl/Init.cpp b/MobileGL/MG_Impl/Init.cpp index c7fbfeb4..52fcd87b 100644 --- a/MobileGL/MG_Impl/Init.cpp +++ b/MobileGL/MG_Impl/Init.cpp @@ -25,15 +25,13 @@ namespace MobileGL::MG_Impl { auto colorTex = MakeShared(0); colorTex->SetInternalFormat(TextureInternalFormat::RGBA8); colorTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0}); - // colorTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); + auto depthTex = MakeShared(0); depthTex->SetInternalFormat(TextureInternalFormat::Depth32FStencil8); depthTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0}); - // depthTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); auto stencilTex = MakeShared(0); stencilTex->SetInternalFormat(TextureInternalFormat::Depth32FStencil8); stencilTex->AllocateStorage(TextureUploadTarget::Texture2D, 0, {{512, 512, 1}, 0}); - // stencilTex->SetMipmapLevel({{512, 512, 1}, 0, false, 0, {nullptr, 0}}); fbo0->AttachTexture(FramebufferAttachmentType::Color0, colorTex); fbo0->AttachTexture(FramebufferAttachmentType::Depth, depthTex); fbo0->AttachTexture(FramebufferAttachmentType::Stencil, stencilTex);