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:
Bill Hollings 2018-04-06 00:07:04 -04:00 committed by GitHub
commit 9c8117efe6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 36 additions and 103 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -1 +1 @@
d435e00dc9f614155621cdadd2f00fbd0585cda6
8dc54f70b2f11858b422477e7a9eaa7fb455dee2

View File

@ -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()

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}