From 65ce335d67c43a008ab1ccbd77ccf8db66fa56e3 Mon Sep 17 00:00:00 2001 From: Michael Lentine Date: Thu, 17 Mar 2016 16:34:32 -0500 Subject: [PATCH] layers: Track lifetime when using cross-queue semaphores. --- layers/core_validation.cpp | 79 ++++++++++++++++++++++++++++++++++++---------- layers/core_validation.h | 7 ++-- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp index eda9770..dba3927 100644 --- a/layers/core_validation.cpp +++ b/layers/core_validation.cpp @@ -5049,9 +5049,7 @@ void decrementResources(layer_data *my_data, uint32_t fenceCount, const VkFence return; fence_data->second.needsSignaled = false; fence_data->second.in_use.fetch_sub(1); - if (fence_data->second.priorFence != VK_NULL_HANDLE) { - decrementResources(my_data, 1, &fence_data->second.priorFence); - } + decrementResources(my_data, fence_data->second.priorFences.size(), &fence_data->second.priorFences[0]); for (auto cmdBuffer : fence_data->second.cmdBuffers) { decrementResources(my_data, cmdBuffer); } @@ -5065,28 +5063,58 @@ void decrementResources(layer_data *my_data, VkQueue queue) { decrementResources(my_data, cmdBuffer); } queue_data->second.untrackedCmdBuffers.clear(); - decrementResources(my_data, 1, &queue_data->second.priorFence); + decrementResources(my_data, queue_data->second.lastFences.size(), &queue_data->second.lastFences[0]); + } +} + +void updateTrackedCommandBuffers(layer_data *dev_data, VkQueue queue, VkQueue other_queue, VkFence fence) { + if (queue == other_queue) { + return; + } + auto queue_data = dev_data->queueMap.find(queue); + auto other_queue_data = dev_data->queueMap.find(other_queue); + if (queue_data == dev_data->queueMap.end() || other_queue_data == dev_data->queueMap.end()) { + return; + } + for (auto fence : other_queue_data->second.lastFences) { + queue_data->second.lastFences.push_back(fence); + } + if (fence != VK_NULL_HANDLE) { + auto fence_data = dev_data->fenceMap.find(fence); + if (fence_data == dev_data->fenceMap.end()) { + return; + } + for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) { + fence_data->second.cmdBuffers.push_back(cmdbuffer); + } + other_queue_data->second.untrackedCmdBuffers.clear(); + } else { + for (auto cmdbuffer : other_queue_data->second.untrackedCmdBuffers) { + queue_data->second.untrackedCmdBuffers.push_back(cmdbuffer); + } + other_queue_data->second.untrackedCmdBuffers.clear(); } } void trackCommandBuffers(layer_data *my_data, VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) { auto queue_data = my_data->queueMap.find(queue); if (fence != VK_NULL_HANDLE) { - VkFence priorFence = VK_NULL_HANDLE; + vector prior_fences; auto fence_data = my_data->fenceMap.find(fence); if (fence_data == my_data->fenceMap.end()) { return; } if (queue_data != my_data->queueMap.end()) { - priorFence = queue_data->second.priorFence; - queue_data->second.priorFence = fence; - for (auto cmdBuffer : queue_data->second.untrackedCmdBuffers) { - fence_data->second.cmdBuffers.push_back(cmdBuffer); + prior_fences = queue_data->second.lastFences; + queue_data->second.lastFences.clear(); + queue_data->second.lastFences.push_back(fence); + for (auto cmdbuffer : queue_data->second.untrackedCmdBuffers) { + fence_data->second.cmdBuffers.push_back(cmdbuffer); } queue_data->second.untrackedCmdBuffers.clear(); } fence_data->second.cmdBuffers.clear(); - fence_data->second.priorFence = priorFence; + fence_data->second.priorFences = prior_fences; fence_data->second.needsSignaled = true; fence_data->second.queue = queue; fence_data->second.in_use.fetch_add(1); @@ -5310,23 +5338,41 @@ vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, "Fence %#" PRIx64 " is already in use by another submission.", (uint64_t)(fence)); } // Now verify each individual submit + std::unordered_set processed_other_queues; for (uint32_t submit_idx = 0; submit_idx < submitCount; submit_idx++) { const VkSubmitInfo *submit = &pSubmits[submit_idx]; vector semaphoreList; for (uint32_t i = 0; i < submit->waitSemaphoreCount; ++i) { - semaphoreList.push_back(submit->pWaitSemaphores[i]); - if (dev_data->semaphoreMap[submit->pWaitSemaphores[i]].signaled) { - dev_data->semaphoreMap[submit->pWaitSemaphores[i]].signaled = 0; + const VkSemaphore &semaphore = submit->pWaitSemaphores[i]; + semaphoreList.push_back(semaphore); + if (dev_data->semaphoreMap[semaphore].signaled) { + dev_data->semaphoreMap[semaphore].signaled = 0; } else { skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, "DS", "Queue %#" PRIx64 " is waiting on semaphore %#" PRIx64 " that has no way to be signaled.", - (uint64_t)(queue), (uint64_t)(submit->pWaitSemaphores[i])); + reinterpret_cast(queue), reinterpret_cast(semaphore)); + } + const VkQueue &other_queue = dev_data->semaphoreMap[semaphore].queue; + if (other_queue != VK_NULL_HANDLE && !processed_other_queues.count(other_queue)) { + updateTrackedCommandBuffers(dev_data, queue, other_queue, fence); + processed_other_queues.insert(other_queue); } } for (uint32_t i = 0; i < submit->signalSemaphoreCount; ++i) { - semaphoreList.push_back(submit->pSignalSemaphores[i]); - dev_data->semaphoreMap[submit->pSignalSemaphores[i]].signaled = 1; + const VkSemaphore &semaphore = submit->pSignalSemaphores[i]; + semaphoreList.push_back(semaphore); + if (dev_data->semaphoreMap[semaphore].signaled) { + skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, + VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, 0, __LINE__, DRAWSTATE_QUEUE_FORWARD_PROGRESS, + "DS", "Queue %#" PRIx64 " is signaling semaphore %#" PRIx64 + " that has already been signaled but not waited on by queue %#" PRIx64 ".", + reinterpret_cast(queue), reinterpret_cast(semaphore), + reinterpret_cast(dev_data->semaphoreMap[semaphore].queue)); + } else { + dev_data->semaphoreMap[semaphore].signaled = 1; + dev_data->semaphoreMap[semaphore].queue = queue; + } } for (uint32_t i = 0; i < submit->commandBufferCount; i++) { skipCall |= ValidateCmdBufImageLayouts(submit->pCommandBuffers[i]); @@ -10407,6 +10453,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaph loader_platform_thread_lock_mutex(&globalLock); SEMAPHORE_NODE* sNode = &dev_data->semaphoreMap[*pSemaphore]; sNode->signaled = 0; + sNode->queue = VK_NULL_HANDLE; sNode->in_use.store(0); sNode->state = MEMTRACK_SEMAPHORE_STATE_UNSET; loader_platform_thread_unlock_mutex(&globalLock); diff --git a/layers/core_validation.h b/layers/core_validation.h index 8fe9ba2..3d3f980 100644 --- a/layers/core_validation.h +++ b/layers/core_validation.h @@ -561,10 +561,10 @@ class FENCE_NODE : public BASE_NODE { VkQueue queue; vector cmdBuffers; bool needsSignaled; - VkFence priorFence; + vector priorFences; // Default constructor - FENCE_NODE() : queue(NULL), needsSignaled(VK_FALSE), priorFence(static_cast(NULL)){}; + FENCE_NODE() : queue(NULL), needsSignaled(VK_FALSE){}; }; class SEMAPHORE_NODE : public BASE_NODE { @@ -572,6 +572,7 @@ class SEMAPHORE_NODE : public BASE_NODE { using BASE_NODE::in_use; uint32_t signaled; SemaphoreState state; + VkQueue queue; }; class EVENT_NODE : public BASE_NODE { @@ -584,7 +585,7 @@ class EVENT_NODE : public BASE_NODE { class QUEUE_NODE { public: VkDevice device; - VkFence priorFence; + vector lastFences; #if MTMERGE uint64_t lastRetiredId; uint64_t lastSubmittedId; -- 2.7.4