[Fix] (MG_Backend/DirectVulkan): Vulkan backend default framebuffer initialization

This commit is contained in:
2026-03-01 21:21:32 +08:00
parent f61f068e28
commit 43f2043478
7 changed files with 116 additions and 51 deletions
@@ -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(<vulkan/vk_enum_string_helper.h>)
#include <vulkan/vk_enum_string_helper.h>
@@ -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<MG_State::GLState::TextureObject2D*>(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<MG_State::GLState::TextureObject2D*>(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) {
@@ -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;
}
@@ -96,7 +96,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Int height = 0;
Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
Vector<VkTextureManager::TextureResource> textureResources(validDrawBufCount);
Vector<VkTextureManager::TextureResource*> 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<VkImageView> 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
@@ -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<VkTextureManager::TextureResource> textureResources;
// Should we hold pointer-to-resource here?
Vector<VkTextureManager::TextureResource*> textureResources;
IntVec2 extent = {0, 0};
Uint32 subpass = 0;
@@ -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<Uint32>(texelSize.x()), static_cast<Uint32>(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;
}
@@ -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<void(VkCommandBuffer)>& 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<Uint, TextureResource> m_textureResources;
Uint8 m_gcCounter = 0;
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
+1 -3
View File
@@ -25,15 +25,13 @@ namespace MobileGL::MG_Impl {
auto colorTex = MakeShared<MG_State::GLState::TextureObject2D>(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<MG_State::GLState::TextureObject2D>(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<MG_State::GLState::TextureObject2D>(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);