mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Fix] (MG_Backend/DirectVulkan): use hash to save active render pass
This commit is contained in:
@@ -99,7 +99,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
auto* activeRenderPass = GetActiveRenderPass();
|
||||
auto compatibilityHash = ComputeHash(fbo, swapchainImageIndex, false);
|
||||
if (activeRenderPass != nullptr && activeRenderPass->CompatibleWith(compatibilityHash)) {
|
||||
return *activeRenderPass;
|
||||
auto activeIt = m_renderPasses.find(activeRenderPass->hash);
|
||||
MOBILEGL_ASSERT(activeIt != m_renderPasses.end(),
|
||||
"GetOrCreateRenderPass: active render pass hash=0x%llx is missing from cache",
|
||||
static_cast<unsigned long long>(activeRenderPass->hash));
|
||||
return activeIt->second;
|
||||
}
|
||||
auto hash = ComputeHash(fbo, swapchainImageIndex, true);
|
||||
auto it = m_renderPasses.find(hash);
|
||||
@@ -157,9 +161,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
desc.initialLayout = hasClear ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
desc.finalLayout = isDefaultFbo ?
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
@@ -178,6 +179,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const auto& swapchainViews = m_swapchainObject.GetImageViews();
|
||||
MOBILEGL_ASSERT(swapchainImageIndex < swapchainViews.size(),
|
||||
"GetOrCreateRenderPass: swapchain image index out of range");
|
||||
desc.initialLayout = hasClear ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachmentViews[i] = swapchainViews[swapchainImageIndex];
|
||||
} else {
|
||||
textureResources[i] = m_textureManager.SyncTextureAndGetDescriptor(*texture);
|
||||
@@ -186,6 +190,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MOBILEGL_ASSERT(hasClear || textureResources[i]->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
"GetOrCreateRenderPass: color attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD (attachment=%d)",
|
||||
texture->GetExternalIndex(), i);
|
||||
desc.initialLayout = hasClear ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
textureResources[i]->layout;
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.texture = texture,
|
||||
.finalLayout = desc.finalLayout,
|
||||
@@ -219,6 +226,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload);
|
||||
Bool clearDepth = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Depth;
|
||||
Bool clearStencil = hasClear && clearPayload.attachmentType == FramebufferAttachmentType::Stencil;
|
||||
VkImageLayout trackedDepthLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
if (!isDefaultFbo) {
|
||||
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
|
||||
MOBILEGL_ASSERT(depthTextureResource,
|
||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
|
||||
trackedDepthLayout = depthTextureResource->layout;
|
||||
}
|
||||
depthAttachmentDescription.flags = 0;
|
||||
depthAttachmentDescription.format =
|
||||
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
|
||||
@@ -231,15 +245,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VK_ATTACHMENT_LOAD_OP_CLEAR :
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
depthAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
// UNDEFINED is only valid when both depth and stencil are discarded/cleared.
|
||||
depthAttachmentDescription.initialLayout = (clearDepth && clearStencil) ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
depthAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
MOBILEGL_ASSERT(!(depthAttachmentDescription.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
|
||||
depthAttachmentDescription.initialLayout == VK_IMAGE_LAYOUT_UNDEFINED),
|
||||
"GetOrCreateRenderPass: invalid depth-stencil state (stencil LOAD + initialLayout UNDEFINED), textureId=%d",
|
||||
texture.GetExternalIndex());
|
||||
if (!isDefaultFbo && trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
if (!clearDepth) {
|
||||
depthAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
if (!clearStencil) {
|
||||
depthAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
}
|
||||
depthAttachmentDescription.initialLayout =
|
||||
(clearDepth && clearStencil) || (!isDefaultFbo && trackedDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED) ?
|
||||
VK_IMAGE_LAYOUT_UNDEFINED :
|
||||
trackedDepthLayout;
|
||||
if (hasClear) {
|
||||
pendingClearAttachments.emplace_back(PendingClearAttachmentInfo {
|
||||
.attachmentIndex = depthAttachmentIndex,
|
||||
@@ -249,9 +267,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (isDefaultFbo) {
|
||||
attachmentViews.emplace_back(m_swapchainObject.GetDepthStencilImageView(swapchainImageIndex));
|
||||
} else {
|
||||
depthTextureResource = m_textureManager.SyncTextureAndGetDescriptor(texture);
|
||||
MOBILEGL_ASSERT(depthTextureResource,
|
||||
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at depth attachment");
|
||||
MOBILEGL_ASSERT(clearDepth || clearStencil || depthTextureResource->layout != VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
"GetOrCreateRenderPass: depth attachment textureId=%d has undefined tracked layout with LOAD_OP_LOAD",
|
||||
texture.GetExternalIndex());
|
||||
@@ -314,6 +329,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VK_VERIFY(vkCreateFramebuffer(m_device, &framebufferCreateInfo, nullptr, &framebuffer));
|
||||
IntVec2 extent = {width, height};
|
||||
RenderPassEntry renderPassEntry {
|
||||
hash,
|
||||
renderPass,
|
||||
framebuffer,
|
||||
compatibilityHash,
|
||||
@@ -372,13 +388,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
for (const auto& pending: renderPassEntry.pendingClearAttachments) {
|
||||
s_clearManager->PopPendingClear(pending.texture);
|
||||
}
|
||||
s_activeRenderPass = &renderPassEntry;
|
||||
s_activeRenderPass.hash = renderPassEntry.hash;
|
||||
s_activeRenderPass.compatibilityHash = renderPassEntry.compatibilityHash;
|
||||
s_activeRenderPass.trackedAttachmentLayouts = renderPassEntry.trackedAttachmentLayouts;
|
||||
s_activeRenderPass.extent = renderPassEntry.extent;
|
||||
s_hasActiveRenderPass = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) {
|
||||
auto* activeRenderPass = s_activeRenderPass;
|
||||
auto* activeRenderPass = GetActiveRenderPass();
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
if (activeRenderPass != nullptr && !activeRenderPass->trackedAttachmentLayouts.empty()) {
|
||||
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
||||
@@ -386,11 +406,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
|
||||
}
|
||||
}
|
||||
s_activeRenderPass = nullptr;
|
||||
s_activeRenderPass = {};
|
||||
s_hasActiveRenderPass = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderPassEntry* VkRenderPassManager::GetActiveRenderPass() {
|
||||
return s_activeRenderPass;
|
||||
ActiveRenderPassInfo* VkRenderPassManager::GetActiveRenderPass() {
|
||||
return s_hasActiveRenderPass ? &s_activeRenderPass : nullptr;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct RenderPassEntry {
|
||||
static inline VkDevice s_device;
|
||||
static inline Vector<VkTextureManager::TextureResource*> s_textureResourcesScratch;
|
||||
Uint64 hash = 0;
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
Uint64 compatibilityHash = 0;
|
||||
@@ -44,6 +45,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
RenderPassEntry() = default;
|
||||
RenderPassEntry(const RenderPassEntry&) = delete;
|
||||
RenderPassEntry(RenderPassEntry&& that) noexcept {
|
||||
std::swap(hash, that.hash);
|
||||
std::swap(renderPass, that.renderPass);
|
||||
std::swap(framebuffer, that.framebuffer);
|
||||
std::swap(compatibilityHash, that.compatibilityHash);
|
||||
@@ -54,6 +56,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
std::swap(subpass, that.subpass);
|
||||
}
|
||||
RenderPassEntry(
|
||||
Uint64 hash,
|
||||
VkRenderPass renderpass,
|
||||
VkFramebuffer framebuffer,
|
||||
Uint64 compatibilityHash,
|
||||
@@ -61,6 +64,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const Vector<TrackedAttachmentLayoutInfo>& trackedAttachmentLayouts,
|
||||
Uint32 attachmentCount,
|
||||
IntVec2 extent, int subpass):
|
||||
hash(hash),
|
||||
renderPass(renderpass),
|
||||
framebuffer(framebuffer),
|
||||
compatibilityHash(compatibilityHash),
|
||||
@@ -89,6 +93,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
};
|
||||
|
||||
struct ActiveRenderPassInfo {
|
||||
Uint64 hash = 0;
|
||||
Uint64 compatibilityHash = 0;
|
||||
Vector<TrackedAttachmentLayoutInfo> trackedAttachmentLayouts;
|
||||
IntVec2 extent = {0, 0};
|
||||
|
||||
Bool CompatibleWith(const RenderPassEntry& that) const {
|
||||
return compatibilityHash == that.compatibilityHash;
|
||||
}
|
||||
|
||||
Bool CompatibleWith(Uint64 thatCompatibilityHash) const {
|
||||
return compatibilityHash == thatCompatibilityHash;
|
||||
}
|
||||
};
|
||||
|
||||
class VkRenderPassManager {
|
||||
public:
|
||||
using HashType = Uint64;
|
||||
@@ -107,7 +126,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
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();
|
||||
static ActiveRenderPassInfo* GetActiveRenderPass();
|
||||
private:
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
const VulkanRendererConfig& m_config;
|
||||
@@ -116,7 +135,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const SwapchainObject& m_swapchainObject;
|
||||
UnorderedMap<Uint64, RenderPassEntry> m_renderPasses;
|
||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||
static inline RenderPassEntry* s_activeRenderPass = nullptr;
|
||||
static inline ActiveRenderPassInfo s_activeRenderPass{};
|
||||
static inline Bool s_hasActiveRenderPass = false;
|
||||
static inline VkClearManager* s_clearManager = nullptr;
|
||||
static inline VkTextureManager* s_textureManager = nullptr;
|
||||
};
|
||||
|
||||
@@ -242,7 +242,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
resource.~TextureResource();
|
||||
resource.Reset();
|
||||
|
||||
auto aspect = GetAspectMaskForFormat(format);
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
// Begin render pass, and handle clear
|
||||
|
||||
if (activeRenderPass && (activeRenderPass == &renderPassEntry || activeRenderPass->CompatibleWith(renderPassEntry))) {
|
||||
if (activeRenderPass && activeRenderPass->CompatibleWith(renderPassEntry)) {
|
||||
ClearAttachmentsOnActiveRenderPass(frame.commandBuffer, renderPassEntry);
|
||||
} else {
|
||||
// No active render pass or active one not compatible.
|
||||
|
||||
Reference in New Issue
Block a user