diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h index e8d67575..736a1605 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h @@ -127,6 +127,9 @@ protected: void initMTLCommandQueue(); void initGPUCaptureScopes(); void destroyExecQueue(); + void unlockQueue(); + MVKSemaphoreImpl* addNewEvent(uint32_t submitCount); + void removeEvent(MVKSemaphoreImpl* event); VkResult submit(MVKQueueSubmission* qSubmit); MVKQueueFamily* _queueFamily; @@ -139,7 +142,9 @@ protected: MVKMTLCommandBufferID _nextMTLCmdBuffID; MVKGPUCaptureScope* _submissionCaptureScope; MVKGPUCaptureScope* _presentationCaptureScope; - MVKSemaphoreImpl _queueIdleEvent; + std::mutex _activeCountLock; + std::atomic _activeCount; + std::unordered_set _pendingSubmitDoneEvents; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index 83065fe7..26aae59a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -86,7 +86,8 @@ VkResult MVKQueue::submit(MVKQueueSubmission* qSubmit) { VkResult MVKQueue::submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence, MVKCommandUse cmdBuffUse) { - VkResult rslt = VK_SUCCESS; + VkResult rslt = VK_SUCCESS; + MVKSemaphoreImpl* submitDoneEvent = addNewEvent(submitCount); for (uint32_t sIdx = 0; sIdx < submitCount; sIdx++) { VkResult subRslt = submit(new MVKQueueCommandBufferSubmission(_device, this, &pSubmits[sIdx], cmdBuffUse)); if (rslt == VK_SUCCESS) { rslt = subRslt; } @@ -94,8 +95,10 @@ VkResult MVKQueue::submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, if (rslt == VK_SUCCESS && fence) { // Fence must wait for all completion blocks to finish. dispatch_async(_execQueue ? _execQueue : _fenceQueue, ^{ - _queueIdleEvent.wait(); + submitDoneEvent->wait(); ((MVKFence*)fence)->signal(); + this->removeEvent(submitDoneEvent); + delete submitDoneEvent; }); } return rslt; @@ -105,6 +108,34 @@ VkResult MVKQueue::submit(const VkPresentInfoKHR* pPresentInfo) { return submit(new MVKQueuePresentSurfaceSubmission(_device, this, pPresentInfo)); } +// Decrements the queue activation count and all known events. +void MVKQueue::unlockQueue() { + lock_guard lock(_activeCountLock); + for (auto iter = _pendingSubmitDoneEvents.begin(), end = _pendingSubmitDoneEvents.end(); iter != end; ) { + if ((*iter)->release()) { + iter = _pendingSubmitDoneEvents.erase(iter); + } else { + ++iter; + } + } + --_activeCount; +} + +// Adds a new event with the current active count plus any additional submissions. +MVKSemaphoreImpl* MVKQueue::addNewEvent(uint32_t submitCount) { + lock_guard lock(_activeCountLock); + _activeCount += submitCount; + auto* submitDoneEvent = new MVKSemaphoreImpl(true, _activeCount); + _pendingSubmitDoneEvents.insert(submitDoneEvent); + return submitDoneEvent; +} + +// Removes an event from the set of pending submission completion events. +void MVKQueue::removeEvent(MVKSemaphoreImpl* event) { + lock_guard lock(_activeCountLock); + _pendingSubmitDoneEvents.erase(event); +} + // Create an empty submit struct and fence, submit to queue and wait on fence. VkResult MVKQueue::waitIdle(MVKCommandUse cmdBuffUse) { @@ -121,9 +152,6 @@ VkResult MVKQueue::waitIdle(MVKCommandUse cmdBuffUse) { if (rslt != VK_SUCCESS) return rslt; - // Wait for all completion routines across all submissions to execute. - _queueIdleEvent.wait(); - return VK_SUCCESS; } @@ -133,7 +161,7 @@ VkResult MVKQueue::waitIdle(MVKCommandUse cmdBuffUse) { #define MVK_DISPATCH_QUEUE_QOS_CLASS QOS_CLASS_USER_INITIATED MVKQueue::MVKQueue(MVKDevice* device, MVKQueueFamily* queueFamily, uint32_t index, float priority) - : MVKDispatchableDeviceObject(device) { + : MVKDispatchableDeviceObject(device), _activeCount(0) { _queueFamily = queueFamily; _index = index; @@ -328,8 +356,6 @@ MVKQueueCommandBufferSubmission::MVKQueueCommandBufferSubmission(MVKDevice* devi (pSubmit ? pSubmit->waitSemaphoreCount : 0), (pSubmit ? pSubmit->pWaitSemaphores : nullptr)) { - _queue->_queueIdleEvent.reserve(); - // pSubmit can be null if just tracking the fence alone if (pSubmit) { uint32_t cbCnt = pSubmit->commandBufferCount; @@ -355,7 +381,7 @@ MVKQueueCommandBufferSubmission::MVKQueueCommandBufferSubmission(MVKDevice* devi } MVKQueueCommandBufferSubmission::~MVKQueueCommandBufferSubmission() { - _queue->_queueIdleEvent.release(); + _queue->unlockQueue(); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h index aa325b59..be0cd1e4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h @@ -53,8 +53,9 @@ public: /** * Depending on configuration, releases one or all reservations. When all reservations * have been released, unblocks all waiting threads to continue processing. + * Returns true if the last reservation was released. */ - void release(); + bool release(); /** * Blocks processing on the current thread until any or all (depending on configuration) outstanding @@ -84,6 +85,9 @@ public: MVKSemaphoreImpl(bool waitAll = true, uint32_t reservationCount = 0) : _shouldWaitAll(waitAll), _reservationCount(reservationCount) {} + /** Destructor. */ + ~MVKSemaphoreImpl(); + private: bool operator()(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index 1d198036..d8873663 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -25,9 +25,9 @@ using namespace std; #pragma mark - #pragma mark MVKSemaphoreImpl -void MVKSemaphoreImpl::release() { +bool MVKSemaphoreImpl::release() { lock_guard lock(_lock); - if (isClear()) { return; } + if (isClear()) { return true; } // Either decrement the reservation counter, or clear it altogether if (_shouldWaitAll) { @@ -37,6 +37,7 @@ void MVKSemaphoreImpl::release() { } // If all reservations have been released, unblock all waiting threads if ( isClear() ) { _blocker.notify_all(); } + return isClear(); } void MVKSemaphoreImpl::reserve() { @@ -64,6 +65,11 @@ bool MVKSemaphoreImpl::wait(uint64_t timeout, bool reserveAgain) { return isDone; } +MVKSemaphoreImpl::~MVKSemaphoreImpl() { + // Acquire the lock to ensure proper ordering. + lock_guard lock(_lock); +} + #pragma mark - #pragma mark MVKSemaphore