[Fix] (MG_Backend/DirectVulkan): query clear color/state inside of RenderPassManager

This commit is contained in:
2026-03-02 10:13:59 +08:00
parent 34b06da83b
commit 282468c9d5
3 changed files with 108 additions and 21 deletions
@@ -47,7 +47,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
QueueClear({ QueueClear({
.stencil = clearPayload.stencil, .stencil = clearPayload.stencil,
.attachmentType = FramebufferAttachmentType::Stencil, .attachmentType = FramebufferAttachmentType::Stencil,
}, drawFbo.GetAttachment(FramebufferAttachmentType::Depth).GetTexture()); }, drawFbo.GetAttachment(FramebufferAttachmentType::Stencil).GetTexture());
} }
} }
@@ -19,6 +19,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager), m_device(device), m_config(config), m_clearManager(clearManager), m_textureManager(textureManager),
m_swapchainObject(swapchainObject) { m_swapchainObject(swapchainObject) {
RenderPassEntry::s_device = m_device; RenderPassEntry::s_device = m_device;
s_clearManager = &m_clearManager;
} }
VkRenderPassManager::~VkRenderPassManager() {} VkRenderPassManager::~VkRenderPassManager() {}
@@ -65,8 +66,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr))); XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr)));
if (att.IsTexture()) { if (att.IsTexture()) {
auto hasClear = m_clearManager.HasPendingClear(att.GetTexture().get()); auto* texture = att.GetTexture().get();
auto hasClear = m_clearManager.HasPendingClear(texture);
XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear))); XXHASH_VERIFY(XXH64_update(m_hashState, &hasClear, sizeof(hasClear)));
if (hasClear) {
ClearAttachmentPayload clearPayload{};
Bool hasPayload = m_clearManager.GetPendingClear(texture, clearPayload);
XXHASH_VERIFY(XXH64_update(m_hashState, &hasPayload, sizeof(hasPayload)));
if (hasPayload) {
XXHASH_VERIFY(XXH64_update(
m_hashState, &clearPayload.attachmentType, sizeof(clearPayload.attachmentType)));
}
}
} }
}; };
@@ -103,6 +114,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Int height = 0; Int height = 0;
Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount); Vector<VkAttachmentDescription> attachmentDescriptions(validDrawBufCount);
Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount); Vector<VkAttachmentReference> colorAttachmentRefs(validDrawBufCount);
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
Vector<VkTextureManager::TextureResource*> textureResources(validDrawBufCount, nullptr); Vector<VkTextureManager::TextureResource*> textureResources(validDrawBufCount, nullptr);
Vector<VkImageView> attachmentViews(validDrawBufCount, VK_NULL_HANDLE); Vector<VkImageView> attachmentViews(validDrawBufCount, VK_NULL_HANDLE);
// This should automatically work on default & offscreen FBO // This should automatically work on default & offscreen FBO
@@ -128,17 +140,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MG_Util::ConvertTextureInternalFormatToVkEnum( MG_Util::ConvertTextureInternalFormatToVkEnum(
texture2d->GetFormat()); texture2d->GetFormat());
desc.samples = VK_SAMPLE_COUNT_1_BIT; desc.samples = VK_SAMPLE_COUNT_1_BIT;
Bool hasClear = m_clearManager.HasPendingClear(texture); ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(texture, clearPayload);
desc.loadOp = hasClear ? desc.loadOp = hasClear ?
VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_CLEAR :
VK_ATTACHMENT_LOAD_OP_LOAD; VK_ATTACHMENT_LOAD_OP_LOAD;
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; desc.initialLayout = hasClear ?
VK_IMAGE_LAYOUT_UNDEFINED :
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
desc.finalLayout = isDefaultFbo ? desc.finalLayout = isDefaultFbo ?
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (hasClear) {
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
.attachmentIndex = static_cast<Uint32>(i),
.texture = texture
});
}
if (width == 0) if (width == 0)
width = texture2d->GetBaseSize().x(); width = texture2d->GetBaseSize().x();
if (height == 0) if (height == 0)
@@ -171,19 +192,39 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// Depth attachment description // Depth attachment description
auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth); auto& depthAtt = fbo.GetAttachment(FramebufferAttachmentType::Depth);
VkAttachmentDescription depthAttachmentDescription; VkAttachmentDescription depthAttachmentDescription;
VkAttachmentReference depthAttachmentRef;
depthAttachmentRef.attachment = VK_ATTACHMENT_UNUSED;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkTextureManager::TextureResource* depthTextureResource = nullptr; VkTextureManager::TextureResource* depthTextureResource = nullptr;
if (depthAtt.IsComplete() && depthAtt.IsTexture()) { if (depthAtt.IsComplete() && depthAtt.IsTexture()) {
auto& texture = *depthAtt.GetTexture(); auto& texture = *depthAtt.GetTexture();
const Uint32 depthAttachmentIndex = static_cast<Uint32>(attachmentDescriptions.size());
ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
depthAttachmentDescription.flags = 0; depthAttachmentDescription.flags = 0;
depthAttachmentDescription.format = depthAttachmentDescription.format =
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat()); MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT; depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; depthAttachmentDescription.loadOp = clearDepth ?
VK_ATTACHMENT_LOAD_OP_CLEAR :
VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; depthAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthAttachmentDescription.stencilLoadOp = clearStencil ?
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; VK_ATTACHMENT_LOAD_OP_CLEAR :
depthAttachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachmentDescription.initialLayout = hasClear ?
VK_IMAGE_LAYOUT_UNDEFINED :
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
if (hasClear) {
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
.attachmentIndex = depthAttachmentIndex,
.texture = &texture
});
}
if (isDefaultFbo) { if (isDefaultFbo) {
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex)); attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
} else { } else {
@@ -192,15 +233,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment"); "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
textureResources.emplace_back(depthTextureResource); textureResources.emplace_back(depthTextureResource);
attachmentViews.emplace_back(depthTextureResource->view); attachmentViews.emplace_back(depthTextureResource->view);
if (width == 0 || height == 0) {
auto texture2d = static_cast<MG_State::GLState::TextureObject2D*>(&texture);
width = texture2d->GetBaseSize().x();
height = texture2d->GetBaseSize().y();
}
} }
attachmentDescriptions.emplace_back(depthAttachmentDescription); attachmentDescriptions.emplace_back(depthAttachmentDescription);
depthAttachmentRef.attachment = depthAttachmentIndex;
} }
// Depth attachment ref
VkAttachmentReference depthAttachmentRef;
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
// Subpass // Subpass
VkSubpassDescription subpassDesc; VkSubpassDescription subpassDesc;
subpassDesc.flags = 0; subpassDesc.flags = 0;
@@ -244,7 +286,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer)); VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
IntVec2 extent = {width, height}; IntVec2 extent = {width, height};
RenderPassEntry renderPassEntry { RenderPassEntry renderPassEntry {
renderPass, framebuffer, Move(textureResources), static_cast<Uint32>(attachmentViews.size()), extent, 1 }; renderPass,
framebuffer,
Move(textureResources),
Move(pendingClearAttachments),
static_cast<Uint32>(attachmentViews.size()),
extent,
1 };
auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry)); auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry));
return insertedIt->second; return insertedIt->second;
} }
@@ -260,16 +308,45 @@ namespace MobileGL::MG_Backend::DirectVulkan {
renderPassBeginInfo.renderArea.extent = { renderPassBeginInfo.renderArea.extent = {
(Uint32)renderPassEntry.extent.x(), (Uint32)renderPassEntry.extent.y() }; (Uint32)renderPassEntry.extent.x(), (Uint32)renderPassEntry.extent.y() };
// TODO: should query proper clear color Vector<VkClearValue> clearValues(renderPassEntry.attachmentCount);
VkClearValue defaultClearValue; for (auto& clearValue: clearValues) {
defaultClearValue.color = { 0.0f, 0.0f, 0.0f, 1.0f }; clearValue.color = {0.0f, 0.0f, 0.0f, 1.0f};
defaultClearValue.depthStencil = { 1.0f, 0 }; clearValue.depthStencil = {1.0f, 0};
Vector<VkClearValue> clearValue(renderPassEntry.attachmentCount, defaultClearValue); }
if (s_clearManager) {
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
if (!pending.texture || pending.attachmentIndex >= clearValues.size()) {
continue;
}
ClearAttachmentPayload clearPayload{};
if (!s_clearManager->GetPendingClear(pending.texture, clearPayload)) {
continue;
}
if (clearPayload.attachmentType >= FramebufferAttachmentType::Color0 &&
clearPayload.attachmentType <= FramebufferAttachmentType::Color31) {
clearValues[pending.attachmentIndex].color = {
clearPayload.color.x(),
clearPayload.color.y(),
clearPayload.color.z(),
clearPayload.color.w()
};
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Depth) {
clearValues[pending.attachmentIndex].depthStencil.depth = clearPayload.depth;
} else if (clearPayload.attachmentType == FramebufferAttachmentType::Stencil) {
clearValues[pending.attachmentIndex].depthStencil.stencil = clearPayload.stencil;
}
}
}
renderPassBeginInfo.clearValueCount = clearValue.size(); renderPassBeginInfo.clearValueCount = static_cast<Uint32>(clearValues.size());
renderPassBeginInfo.pClearValues = clearValue.data(); renderPassBeginInfo.pClearValues = clearValues.data();
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
if (s_clearManager) {
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
s_clearManager->PopPendingClear(pending.texture);
}
}
s_activeRenderPass = &renderPassEntry; s_activeRenderPass = &renderPassEntry;
return true; return true;
@@ -18,12 +18,18 @@
#include <Includes.h> #include <Includes.h>
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
struct PendingClearAttachmentInfo {
Uint32 attachmentIndex = 0;
MG_State::GLState::ITextureObject* texture = nullptr;
};
struct RenderPassEntry { struct RenderPassEntry {
static inline VkDevice s_device; static inline VkDevice s_device;
VkRenderPass renderPass = VK_NULL_HANDLE; VkRenderPass renderPass = VK_NULL_HANDLE;
VkFramebuffer framebuffer = VK_NULL_HANDLE; VkFramebuffer framebuffer = VK_NULL_HANDLE;
// Should we hold pointer-to-resource here? // Should we hold pointer-to-resource here?
Vector<VkTextureManager::TextureResource*> textureResources; Vector<VkTextureManager::TextureResource*> textureResources;
Vector<PendingClearAttachmentInfo> pendingClearAttachments;
Uint32 attachmentCount = 0; Uint32 attachmentCount = 0;
IntVec2 extent = {0, 0}; IntVec2 extent = {0, 0};
Uint32 subpass = 0; Uint32 subpass = 0;
@@ -34,6 +40,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
std::swap(renderPass, that.renderPass); std::swap(renderPass, that.renderPass);
std::swap(framebuffer, that.framebuffer); std::swap(framebuffer, that.framebuffer);
std::swap(textureResources, that.textureResources); std::swap(textureResources, that.textureResources);
std::swap(pendingClearAttachments, that.pendingClearAttachments);
std::swap(attachmentCount, that.attachmentCount); std::swap(attachmentCount, that.attachmentCount);
std::swap(extent, that.extent); std::swap(extent, that.extent);
std::swap(subpass, that.subpass); std::swap(subpass, that.subpass);
@@ -42,11 +49,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkRenderPass renderpass, VkRenderPass renderpass,
VkFramebuffer framebuffer, VkFramebuffer framebuffer,
const std::vector<VkTextureManager::TextureResource*>& textureResources, const std::vector<VkTextureManager::TextureResource*>& textureResources,
const Vector<PendingClearAttachmentInfo>& pendingClearAttachments,
Uint32 attachmentCount, Uint32 attachmentCount,
IntVec2 extent, int subpass): IntVec2 extent, int subpass):
renderPass(renderpass), renderPass(renderpass),
framebuffer(framebuffer), framebuffer(framebuffer),
textureResources(Move(textureResources)), textureResources(Move(textureResources)),
pendingClearAttachments(Move(pendingClearAttachments)),
attachmentCount(attachmentCount), attachmentCount(attachmentCount),
extent(extent), extent(extent),
subpass(subpass) subpass(subpass)
@@ -87,5 +96,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses; UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
static inline XXH64_state_t* m_hashState = XXH64_createState(); static inline XXH64_state_t* m_hashState = XXH64_createState();
static inline RenderPassEntry* s_activeRenderPass = nullptr; static inline RenderPassEntry* s_activeRenderPass = nullptr;
static inline VkClearManager* s_clearManager = nullptr;
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan