Merge pull request #124 from billhollings/master
Queue and device wait idle logic and update to latest version of VulkanSamples.
This commit is contained in:
commit
9c8117efe6
@ -42,7 +42,7 @@
|
||||
self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale;
|
||||
|
||||
demo_main(&demo, self.view);
|
||||
demo_update_and_draw(&demo);
|
||||
demo_draw(&demo);
|
||||
|
||||
uint32_t fps = 60;
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(renderLoop)];
|
||||
@ -51,7 +51,7 @@
|
||||
}
|
||||
|
||||
-(void) renderLoop {
|
||||
demo_update_and_draw(&demo);
|
||||
demo_draw(&demo);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -59,7 +59,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink,
|
||||
CVOptionFlags flagsIn,
|
||||
CVOptionFlags* flagsOut,
|
||||
void* target) {
|
||||
demo_update_and_draw((struct demo*)target);
|
||||
demo_draw((struct demo*)target);
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
|
@ -1 +1 @@
|
||||
d435e00dc9f614155621cdadd2f00fbd0585cda6
|
||||
8dc54f70b2f11858b422477e7a9eaa7fb455dee2
|
||||
|
@ -90,10 +90,9 @@ VkResult MVKQueue::submitPresentKHR(const VkPresentInfoKHR* pPresentInfo) {
|
||||
return rslt;
|
||||
}
|
||||
|
||||
// Create an empty submit struct and fence, submit to queue and wait on fence.
|
||||
VkResult MVKQueue::waitIdle(MVKCommandUse cmdBuffUse) {
|
||||
|
||||
// Create submit struct including a temp Vulkan reference to a semaphore
|
||||
VkSemaphore vkSem4;
|
||||
VkSubmitInfo vkSbmtInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.pNext = NULL,
|
||||
@ -101,22 +100,20 @@ VkResult MVKQueue::waitIdle(MVKCommandUse cmdBuffUse) {
|
||||
.pWaitSemaphores = VK_NULL_HANDLE,
|
||||
.commandBufferCount = 0,
|
||||
.pCommandBuffers = VK_NULL_HANDLE,
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = &vkSem4
|
||||
.signalSemaphoreCount = 0,
|
||||
.pSignalSemaphores = VK_NULL_HANDLE
|
||||
};
|
||||
|
||||
VkSemaphoreCreateInfo vkSemInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
};
|
||||
VkFenceCreateInfo vkFenceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
MVKSemaphore mvkSem4(_device, &vkSemInfo); // Construct MVKSemaphore
|
||||
vkSem4 = (VkSemaphore)&mvkSem4; // Set reference to MVKSemaphore in submit struct
|
||||
submit(1, &vkSbmtInfo, VK_NULL_HANDLE, cmdBuffUse); // Submit semaphore queue
|
||||
mvkSem4.wait(); // Wait on the semaphore
|
||||
|
||||
return VK_SUCCESS;
|
||||
MVKFence mvkFence(_device, &vkFenceInfo);
|
||||
VkFence fence = (VkFence)&mvkFence;
|
||||
submit(1, &vkSbmtInfo, fence, cmdBuffUse);
|
||||
return mvkWaitForFences(1, &fence, false);
|
||||
}
|
||||
|
||||
// This function is guarded against conflict with the mtlCommandBufferHasCompleted()
|
||||
|
@ -68,35 +68,17 @@ VkResult MVKSwapchain::acquireNextImageKHR(uint64_t timeout,
|
||||
MVKSwapchainImageAvailability minAvailability = { .acquisitionID = numeric_limits<uint64_t>::max(), .waitCount = numeric_limits<uint32_t>::max(), .isAvailable = false };
|
||||
for (MVKSwapchainImage* mvkSCImg : _surfaceImages) {
|
||||
const MVKSwapchainImageAvailability* currAvailability = mvkSCImg->getAvailability();
|
||||
// MVKLogDebug("Comparing availability (isAvailable: %d waitCount: %d, acquisitionID: %d) to (isAvailable: %d waitCount: %d, acquisitionID: %d)",
|
||||
// currAvailability->isAvailable, currAvailability->waitCount, currAvailability->acquisitionID,
|
||||
// minAvailability.isAvailable, minAvailability.waitCount, minAvailability.acquisitionID);
|
||||
if (*currAvailability < minAvailability) {
|
||||
minAvailability = *currAvailability;
|
||||
minWaitIndex = mvkSCImg->getSwapchainIndex();
|
||||
// MVKLogDebug("Is smaller! Index: %d", minWaitIndex);
|
||||
}
|
||||
}
|
||||
// MVKLogDebug("Selected MVKSwapchainImage %p, index: %d to trigger semaphore %p and fence %p", _surfaceImages[minWaitIndex], minWaitIndex, semaphore, fence);
|
||||
|
||||
*pImageIndex = minWaitIndex; // Return the index of the image with the shortest wait
|
||||
|
||||
if (semaphore || fence) {
|
||||
MVKSemaphore* mvkSem4 = (MVKSemaphore*)semaphore;
|
||||
MVKFence* mvkFence = (MVKFence*)fence;
|
||||
_surfaceImages[minWaitIndex]->signalWhenAvailable(mvkSem4, mvkFence);
|
||||
} else {
|
||||
// Interpret a NULL semaphore to mean that this function itself should block
|
||||
// until the image is available. Create temp semaphore and wait on it here.
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = NULL,
|
||||
};
|
||||
MVKSemaphore mvkSem4(_device, &semaphoreCreateInfo);
|
||||
_surfaceImages[minWaitIndex]->signalWhenAvailable(&mvkSem4, NULL);
|
||||
if ( !mvkSem4.wait(timeout) ) { return VK_TIMEOUT; }
|
||||
}
|
||||
|
||||
_surfaceImages[minWaitIndex]->signalWhenAvailable((MVKSemaphore*)semaphore, (MVKFence*)fence);
|
||||
|
||||
return getHasSurfaceSizeChanged() ? VK_SUBOPTIMAL_KHR : VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -55,24 +55,17 @@ public:
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Indefinitely blocks processing on the current thread until either any or all
|
||||
* (depending on configuration) outstanding reservations have been released.
|
||||
*
|
||||
* If reserveAgain is set to true, a single reservation will be added to this
|
||||
* instance once the wait is finished.
|
||||
*/
|
||||
void wait(bool reserveAgain = false);
|
||||
|
||||
/**
|
||||
* Blocks processing on the current thread until any or all (depending on configuration) outstanding
|
||||
* reservations have been released, or until the specified timeout interval in nanoseconds expires.
|
||||
*
|
||||
* If timeout is the special value UINT64_MAX the timeout is treated as infinite.
|
||||
*
|
||||
* If reserveAgain is set to true, a single reservation will be added once this wait is finished.
|
||||
*
|
||||
* Returns true if all reservations were cleared, or false if the timeout interval expired.
|
||||
*/
|
||||
bool wait(uint64_t timeout, bool reserveAgain = false);
|
||||
bool wait(uint64_t timeout = UINT64_MAX, bool reserveAgain = false);
|
||||
|
||||
|
||||
#pragma mark Construction
|
||||
@ -111,16 +104,15 @@ class MVKSemaphore : public MVKBaseDeviceObject {
|
||||
|
||||
public:
|
||||
|
||||
/** Indefinitely blocks processing on the current thread until this semaphore is signaled. */
|
||||
void wait();
|
||||
|
||||
/**
|
||||
* Blocks processing on the current thread until this semaphore is
|
||||
* signaled, or until the specified timeout in nanoseconds expires.
|
||||
*
|
||||
* If timeout is the special value UINT64_MAX the timeout is treated as infinite.
|
||||
*
|
||||
* Returns true if this semaphore was signaled, or false if the timeout interval expired.
|
||||
*/
|
||||
bool wait(uint64_t timeout);
|
||||
bool wait(uint64_t timeout = UINT64_MAX);
|
||||
|
||||
/** Signals the semaphore. Unblocks all waiting threads to continue processing. */
|
||||
void signal();
|
||||
@ -195,25 +187,17 @@ class MVKFenceSitter : public MVKBaseObject {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* If this instance has been configured to wait for fences, blocks processing on the
|
||||
* current thread until any or all of the fences that this instance is waiting for are
|
||||
* signaled. If this instance has not been configured to wait for fences, this function
|
||||
* immediately returns true.
|
||||
*
|
||||
* Returns whether the lock timed out while waiting.
|
||||
*/
|
||||
void wait();
|
||||
|
||||
/**
|
||||
* If this instance has been configured to wait for fences, blocks processing on the
|
||||
* current thread until any or all of the fences that this instance is waiting for are
|
||||
* signaled, or until the specified timeout in nanoseconds expires. If this instance
|
||||
* has not been configured to wait for fences, this function immediately returns true.
|
||||
*
|
||||
* If timeout is the special value UINT64_MAX the timeout is treated as infinite.
|
||||
*
|
||||
* Returns true if the required fences were triggered, or false if the timeout interval expired.
|
||||
*/
|
||||
bool wait(uint64_t timeout);
|
||||
bool wait(uint64_t timeout = UINT64_MAX);
|
||||
|
||||
|
||||
#pragma mark Construction
|
||||
@ -248,6 +232,6 @@ VkResult mvkResetFences(uint32_t fenceCount, const VkFence* pFences);
|
||||
VkResult mvkWaitForFences(uint32_t fenceCount,
|
||||
const VkFence* pFences,
|
||||
VkBool32 waitAll,
|
||||
uint64_t timeout);
|
||||
uint64_t timeout = UINT64_MAX);
|
||||
|
||||
|
||||
|
@ -44,23 +44,20 @@ void MVKSemaphoreImpl::reserve() {
|
||||
reserveImpl();
|
||||
}
|
||||
|
||||
void MVKSemaphoreImpl::wait(bool reserveAgain) {
|
||||
unique_lock<mutex> lock(_lock);
|
||||
_blocker.wait(lock, [this]{ return isClear(); });
|
||||
if (reserveAgain) { reserveImpl(); }
|
||||
}
|
||||
|
||||
bool MVKSemaphoreImpl::wait(uint64_t timeout, bool reserveAgain) {
|
||||
unique_lock<mutex> lock(_lock);
|
||||
|
||||
bool isDone;
|
||||
if (timeout > 0) {
|
||||
if (timeout == 0) {
|
||||
isDone = isClear();
|
||||
} else if (timeout == UINT64_MAX) {
|
||||
_blocker.wait(lock, [this]{ return isClear(); });
|
||||
isDone = true;
|
||||
} else {
|
||||
// Limit timeout to avoid overflow since wait_for() uses wait_until()
|
||||
uint64_t nanoTimeout = min(timeout, numeric_limits<uint64_t>::max() >> 4);
|
||||
chrono::nanoseconds nanos(nanoTimeout);
|
||||
isDone = _blocker.wait_for(lock, nanos, [this]{ return isClear(); });
|
||||
} else {
|
||||
isDone = isClear();
|
||||
}
|
||||
|
||||
if (reserveAgain) { reserveImpl(); }
|
||||
@ -71,23 +68,14 @@ bool MVKSemaphoreImpl::wait(uint64_t timeout, bool reserveAgain) {
|
||||
#pragma mark -
|
||||
#pragma mark MVKSemaphore
|
||||
|
||||
void MVKSemaphore::wait() {
|
||||
// MVKLogDebug("Waiting on semaphore %p. Elapsed time: %.6f ms.", this, mvkGetElapsedMilliseconds());
|
||||
_blocker.wait(true);
|
||||
// MVKLogDebug("Done waiting on semaphore %p. Elapsed time: %.6f ms.", this, mvkGetElapsedMilliseconds());
|
||||
}
|
||||
|
||||
bool MVKSemaphore::wait(uint64_t timeout) {
|
||||
// MVKLogDebug("Waiting on semaphore %p for max timeout %llu. Elapsed time: %.6f ms.", this, timeout, mvkGetElapsedMilliseconds());
|
||||
bool isDone = _blocker.wait(timeout, true);
|
||||
// MVKLogDebug("Done waiting on semaphore %p. Elapsed time: %.6f ms.", this, mvkGetElapsedMilliseconds());
|
||||
if ( !isDone && timeout > 0 ) { mvkNotifyErrorWithText(VK_TIMEOUT, "Vulkan semaphore timeout after %llu nanoseconds.", timeout); }
|
||||
return isDone;
|
||||
}
|
||||
|
||||
void MVKSemaphore::signal() {
|
||||
_blocker.release();
|
||||
// MVKLogDebug("Signalled semaphore %p. Elapsed time: %.6f ms.", this, mvkGetElapsedMilliseconds());
|
||||
}
|
||||
|
||||
|
||||
@ -99,21 +87,15 @@ void MVKFence::addSitter(MVKFenceSitter* fenceSitter) {
|
||||
|
||||
// Sitters only care about unsignaled fences. If already signaled,
|
||||
// don't add myself to the sitter and don't notify the sitter.
|
||||
if (_isSignaled) {
|
||||
// MVKLogDebug("Fence %p already signaled. Sitter not added. Elapsed time: %.6f ms.", this, mvkGetElapsedMilliseconds());
|
||||
return;
|
||||
}
|
||||
if (_isSignaled) { return; }
|
||||
|
||||
// Ensure each fence only added once to each fence sitter
|
||||
auto addRslt = _fenceSitters.insert(fenceSitter); // pair with second element true if was added
|
||||
if (addRslt.second) { fenceSitter->addUnsignaledFence(this); }
|
||||
|
||||
// MVKLogDebug("Fence %p adding sitter %d. Elapsed time: %.6f ms.", this, _fenceSitters.size(), mvkGetElapsedMilliseconds());
|
||||
}
|
||||
|
||||
void MVKFence::removeSitter(MVKFenceSitter* fenceSitter) {
|
||||
lock_guard<mutex> lock(_lock);
|
||||
// MVKLogDebug("Fence %p removing sitter %d. Elapsed time: %.6f ms.", this, _fenceSitters.size(), mvkGetElapsedMilliseconds());
|
||||
_fenceSitters.erase(fenceSitter);
|
||||
}
|
||||
|
||||
@ -123,8 +105,6 @@ void MVKFence::signal() {
|
||||
if (_isSignaled) { return; } // Only signal once
|
||||
_isSignaled = true;
|
||||
|
||||
// MVKLogDebug("Fence %p with %d sitters signaled. Elapsed time: %.6f ms.", this , _fenceSitters.size(), mvkGetElapsedMilliseconds());
|
||||
|
||||
// Notify all the fence sitters, and clear them from this instance.
|
||||
for (auto& fs : _fenceSitters) {
|
||||
fs->fenceSignaled(this);
|
||||
@ -136,12 +116,10 @@ void MVKFence::reset() {
|
||||
lock_guard<mutex> lock(_lock);
|
||||
_isSignaled = false;
|
||||
_fenceSitters.clear();
|
||||
// MVKLogDebug("Reset fence %p. Elapsed time: %.6f ms.", this, mvkGetElapsedMilliseconds());
|
||||
}
|
||||
|
||||
bool MVKFence::getIsSignaled() {
|
||||
lock_guard<mutex> lock(_lock);
|
||||
// MVKLogDebug("Checking fence %p status: %ssignaled. Elapsed time: %.6f ms.", this, (_isSignaled ? "" : "un"), mvkGetElapsedMilliseconds());
|
||||
return _isSignaled;
|
||||
}
|
||||
|
||||
@ -172,8 +150,6 @@ void MVKFenceSitter::fenceSignaled(MVKFence* fence) {
|
||||
if (_unsignaledFences.erase(fence)) { _blocker.release(); }
|
||||
}
|
||||
|
||||
void MVKFenceSitter::wait() { _blocker.wait(); }
|
||||
|
||||
bool MVKFenceSitter::wait(uint64_t timeout) {
|
||||
bool isDone = _blocker.wait(timeout);
|
||||
if ( !isDone && timeout > 0 ) { mvkNotifyErrorWithText(VK_TIMEOUT, "Vulkan fence timeout after %llu nanoseconds.", timeout); }
|
||||
@ -206,19 +182,13 @@ VkResult mvkWaitForFences(uint32_t fenceCount,
|
||||
VkBool32 waitAll,
|
||||
uint64_t timeout) {
|
||||
|
||||
// MVKLogDebug("Waiting for fences. Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
|
||||
|
||||
// Create a blocking fence sitter and add it to each fence
|
||||
MVKFenceSitter fenceSitter(waitAll);
|
||||
for (uint32_t i = 0; i < fenceCount; i++) {
|
||||
MVKFence* mvkFence = (MVKFence*)pFences[i];
|
||||
mvkFence->addSitter(&fenceSitter);
|
||||
}
|
||||
VkResult rslt = fenceSitter.wait(timeout) ? VK_SUCCESS : VK_TIMEOUT;
|
||||
|
||||
// MVKLogDebug("Fences done. Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
|
||||
|
||||
return rslt;
|
||||
return fenceSitter.wait(timeout) ? VK_SUCCESS : VK_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user