diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.cpp index 681724fc..e0522e38 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.cpp @@ -96,7 +96,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { return true; } - GpuProgressMarkers::Bracket GpuProgressMarkers::Acquire() { + GpuProgressMarkers::Bracket GpuProgressMarkers::Acquire(Uint64 completedSubmitIndex) { Bracket bracket; if (m_device == VK_NULL_HANDLE) return bracket; const std::lock_guard lock(m_mutex); @@ -106,7 +106,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (slot.Claimed) continue; // Retire what finished since the watch last looked: frames come faster than its polls. if (slot.InFlight && vkGetEventStatus(m_device, slot.Finished) == VK_EVENT_SET) slot.InFlight = false; - if (!slot.InFlight && free == nullptr) free = &slot; + // Free once its submission is complete by fence, not by the event read (see the header). + if (!slot.InFlight && slot.SubmitIndex <= completedSubmitIndex && free == nullptr) free = &slot; } if (free == nullptr) { if (!AddSlot()) return bracket; @@ -125,7 +126,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { return bracket; } - void GpuProgressMarkers::Submitted(const Bracket& bracket) { + void GpuProgressMarkers::Submitted(const Bracket& bracket, Uint64 submitIndex) { if (!bracket.Valid()) return; const std::lock_guard lock(m_mutex); if (bracket.Slot >= m_slots.size()) return; @@ -133,6 +134,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { slot.Claimed = false; slot.InFlight = true; slot.Dirty = true; + slot.SubmitIndex = submitIndex; slot.Id = m_nextId++; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.h index 2dcbf268..f1649939 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/GpuProgressMarkers.h @@ -50,9 +50,18 @@ namespace MobileGL::MG_Backend::DirectVulkan { // The two buffers to put first and last in one submission (an invalid bracket when off or // when every slot is in flight: the submission then goes unwatched). - Bracket Acquire(); - // The submission carrying `bracket` was accepted by vkQueueSubmit / was not submitted. - void Submitted(const Bracket& bracket); + // + // A slot is reused only once the submission it last bracketed is COMPLETE by its fence + // (`completedSubmitIndex`, the renderer's contiguous completed-submit floor), not merely once + // the host has read its `finished` event as set. A host read of an event gives no device-side + // ordering: nothing orders the bracket's `started` set (TOP_OF_PIPE, first buffer) against + // its `finished` set, so a host vkResetEvent plus a re-set in a later submission could + // overlap a set the earlier submission has not executed yet. The synchronization validator + // reports that as SYNC-vkCmdSetEvent-missingbarrier-set. Event reads still drive the watch. + Bracket Acquire(Uint64 completedSubmitIndex); + // The submission carrying `bracket` (renderer submit index `submitIndex`) was accepted by + // vkQueueSubmit / was not submitted. + void Submitted(const Bracket& bracket, Uint64 submitIndex); void Abandon(const Bracket& bracket); // The watch named one of this device's submissions as hanging the GPU. @@ -74,6 +83,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { Bool InFlight = false; // submitted and not yet seen finished Bool Claimed = false; // handed out by Acquire, not yet submitted or abandoned Bool Dirty = false; // its events were set by a past submission: reset before reuse + Uint64 SubmitIndex = 0; // the renderer submit index of the submission it last bracketed }; static constexpr Uint32 kMaxSlots = 16; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index de9e7b8b..650f68c4 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -6117,9 +6117,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (LatchIfGpuHung("flush-submit")) return false; SharedImageSubmitSync sharedImageSync; AttachSharedImageSync(submitInfo, sharedImageSync); - const GpuProgressMarkers::Bracket bracket = m_progressMarkers.Acquire(); + const GpuProgressMarkers::Bracket bracket = m_progressMarkers.Acquire(m_completedSubmitCounter); const VkResult result = GpuProgressMarkers::SubmitBracketed(m_graphicsQueue, submitInfo, fence, bracket); - if (result == VK_SUCCESS) m_progressMarkers.Submitted(bracket); + if (result == VK_SUCCESS) m_progressMarkers.Submitted(bracket, m_submitCounter + 1); // RegisterSubmit below else m_progressMarkers.Abandon(bracket); #else const VkResult result = vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, fence); @@ -6586,10 +6586,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (LatchIfGpuHung("present-submit")) return; SharedImageSubmitSync sharedImageSync; AttachSharedImageSync(submitPacket.submitInfo, sharedImageSync); - const GpuProgressMarkers::Bracket bracket = m_progressMarkers.Acquire(); + const GpuProgressMarkers::Bracket bracket = m_progressMarkers.Acquire(m_completedSubmitCounter); const VkResult presentSubmit = GpuProgressMarkers::SubmitBracketed(m_graphicsQueue, submitPacket.submitInfo, frame.imageInFlightFence, bracket); - if (presentSubmit == VK_SUCCESS) m_progressMarkers.Submitted(bracket); + if (presentSubmit == VK_SUCCESS) m_progressMarkers.Submitted(bracket, m_submitCounter + 1); // RegisterSubmit below else m_progressMarkers.Abandon(bracket); #else const VkResult presentSubmit = vkQueueSubmit(m_graphicsQueue, 1, &submitPacket.submitInfo, frame.imageInFlightFence);