diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index 93e38e88..da609a17 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -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(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 diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h index cd308f94..7311ae65 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -32,6 +32,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { struct RenderPassEntry { static inline VkDevice s_device; static inline Vector 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& 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 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 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; }; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index 538ba3a7..c8d171de 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -242,7 +242,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { return true; } - resource.~TextureResource(); + resource.Reset(); auto aspect = GetAspectMaskForFormat(format); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 7e77759b..b248faaa 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -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.