diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index e4d43bff..93e38e88 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -20,6 +20,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_swapchainObject(swapchainObject) { RenderPassEntry::s_device = m_device; s_clearManager = &m_clearManager; + s_textureManager = &m_textureManager; } VkRenderPassManager::~VkRenderPassManager() {} @@ -120,6 +121,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Vector attachmentDescriptions(validDrawBufCount); Vector colorAttachmentRefs(validDrawBufCount); Vector pendingClearAttachments; + Vector trackedAttachmentLayouts; auto& textureResources = RenderPassEntry::s_textureResourcesScratch; textureResources.clear(); textureResources.resize(validDrawBufCount, nullptr); @@ -184,6 +186,10 @@ 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); + trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo { + .texture = texture, + .finalLayout = desc.finalLayout, + }); attachmentViews[i] = textureResources[i]->view; } @@ -249,6 +255,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { 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()); + trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo { + .texture = &texture, + .finalLayout = depthAttachmentDescription.finalLayout, + }); textureResources.emplace_back(depthTextureResource); attachmentViews.emplace_back(depthTextureResource->view); if (width == 0 || height == 0) { @@ -308,6 +318,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { framebuffer, compatibilityHash, Move(pendingClearAttachments), + Move(trackedAttachmentLayouts), static_cast(attachmentViews.size()), extent, 1 }; @@ -367,7 +378,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { } Bool VkRenderPassManager::EndRenderPass(VkCommandBuffer commandBuffer) { + auto* activeRenderPass = s_activeRenderPass; vkCmdEndRenderPass(commandBuffer); + if (activeRenderPass != nullptr && !activeRenderPass->trackedAttachmentLayouts.empty()) { + MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null"); + for (const auto& trackedAttachment : activeRenderPass->trackedAttachmentLayouts) { + s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout); + } + } s_activeRenderPass = nullptr; return true; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h index 1685e74f..cd308f94 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.h @@ -18,11 +18,17 @@ #include namespace MobileGL::MG_Backend::DirectVulkan { + struct PendingClearAttachmentInfo { Uint32 attachmentIndex = 0; MG_State::GLState::ITextureObject* texture = nullptr; }; + struct TrackedAttachmentLayoutInfo { + MG_State::GLState::ITextureObject* texture = nullptr; + VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; + }; + struct RenderPassEntry { static inline VkDevice s_device; static inline Vector s_textureResourcesScratch; @@ -30,6 +36,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkFramebuffer framebuffer = VK_NULL_HANDLE; Uint64 compatibilityHash = 0; Vector pendingClearAttachments; + Vector trackedAttachmentLayouts; Uint32 attachmentCount = 0; IntVec2 extent = {0, 0}; Uint32 subpass = 0; @@ -41,6 +48,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { std::swap(framebuffer, that.framebuffer); std::swap(compatibilityHash, that.compatibilityHash); std::swap(pendingClearAttachments, that.pendingClearAttachments); + std::swap(trackedAttachmentLayouts, that.trackedAttachmentLayouts); std::swap(attachmentCount, that.attachmentCount); std::swap(extent, that.extent); std::swap(subpass, that.subpass); @@ -50,12 +58,14 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkFramebuffer framebuffer, Uint64 compatibilityHash, const Vector& pendingClearAttachments, + const Vector& trackedAttachmentLayouts, Uint32 attachmentCount, IntVec2 extent, int subpass): renderPass(renderpass), framebuffer(framebuffer), compatibilityHash(compatibilityHash), pendingClearAttachments(Move(pendingClearAttachments)), + trackedAttachmentLayouts(Move(trackedAttachmentLayouts)), attachmentCount(attachmentCount), extent(extent), subpass(subpass) @@ -70,9 +80,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { } } - Bool CompatibleWith(const RenderPassEntry& that) { + Bool CompatibleWith(const RenderPassEntry& that) const { return this->compatibilityHash == that.compatibilityHash; } + + Bool CompatibleWith(Uint64 compatibilityHash) const { + return this->compatibilityHash == compatibilityHash; + } }; class VkRenderPassManager { @@ -104,5 +118,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { static inline XXH64_state_t* m_hashState = XXH64_createState(); static inline RenderPassEntry* s_activeRenderPass = nullptr; static inline VkClearManager* s_clearManager = nullptr; + static inline VkTextureManager* s_textureManager = nullptr; }; } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index d5d4c2f2..43afa601 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -58,6 +58,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { return &(it->second); } + + void VkTextureManager::UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout) { + MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayout: texture is null"); + auto it = m_textureResources.find(texture); + MOBILEGL_ASSERT(it != m_textureResources.end(), + "UpdateTrackedImageLayout: textureId=%d has no tracked resource", texture->GetExternalIndex()); + MOBILEGL_ASSERT(it->second.image != VK_NULL_HANDLE, + "UpdateTrackedImageLayout: textureId=%d has null image", texture->GetExternalIndex()); + it->second.layout = newLayout; + } + Bool VkTextureManager::TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, VkImageLayout newLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h index 89280d63..58b4b299 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h @@ -75,6 +75,7 @@ public: TextureResource* SyncTextureAndGetDescriptor( MG_State::GLState::ITextureObject& texture); + void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout); static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,