1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-05 01:24:14 +01:00

[dxvk] Implement waiting for specific present requests

This commit is contained in:
Philip Rebohle 2023-06-15 16:46:47 +02:00
parent ca3492570c
commit 5d1196733b
7 changed files with 71 additions and 29 deletions

View File

@ -414,7 +414,7 @@ namespace dxvk {
if (cHud != nullptr && !cFrameId) if (cHud != nullptr && !cFrameId)
cHud->update(); cHud->update();
m_device->presentImage(m_presenter, cPresentMode, &m_presentStatus); m_device->presentImage(m_presenter, cPresentMode, 0, &m_presentStatus);
}); });
pContext->FlushCsChunk(); pContext->FlushCsChunk();

View File

@ -833,7 +833,7 @@ namespace dxvk {
if (cHud != nullptr && !cFrameId) if (cHud != nullptr && !cFrameId)
cHud->update(); cHud->update();
m_device->presentImage(m_presenter, cPresentMode, &m_presentStatus); m_device->presentImage(m_presenter, cPresentMode, 0, &m_presentStatus);
}); });
m_parent->FlushCsChunk(); m_parent->FlushCsChunk();

View File

@ -254,12 +254,14 @@ namespace dxvk {
void DxvkDevice::presentImage( void DxvkDevice::presentImage(
const Rc<Presenter>& presenter, const Rc<Presenter>& presenter,
VkPresentModeKHR presentMode, VkPresentModeKHR presentMode,
uint64_t frameId,
DxvkSubmitStatus* status) { DxvkSubmitStatus* status) {
status->result = VK_NOT_READY; status->result = VK_NOT_READY;
DxvkPresentInfo presentInfo = { }; DxvkPresentInfo presentInfo = { };
presentInfo.presenter = presenter; presentInfo.presenter = presenter;
presentInfo.presentMode = presentMode; presentInfo.presentMode = presentMode;
presentInfo.frameId = frameId;
m_submissionQueue.present(presentInfo, status); m_submissionQueue.present(presentInfo, status);
std::lock_guard<sync::Spinlock> statLock(m_statLock); std::lock_guard<sync::Spinlock> statLock(m_statLock);
@ -310,10 +312,13 @@ namespace dxvk {
void DxvkDevice::waitForIdle() { void DxvkDevice::waitForIdle() {
this->lockSubmission(); m_submissionQueue.waitForIdle();
m_submissionQueue.lockDeviceQueue();
if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS) if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS)
Logger::err("DxvkDevice: waitForIdle: Operation failed"); Logger::err("DxvkDevice: waitForIdle: Operation failed");
this->unlockSubmission();
m_submissionQueue.unlockDeviceQueue();
} }

View File

@ -455,11 +455,13 @@ namespace dxvk {
* can be retrieved with \ref waitForSubmission. * can be retrieved with \ref waitForSubmission.
* \param [in] presenter The presenter * \param [in] presenter The presenter
* \param [in] presenteMode Present mode * \param [in] presenteMode Present mode
* \param [in] frameId Optional frame ID
* \param [out] status Present status * \param [out] status Present status
*/ */
void presentImage( void presentImage(
const Rc<Presenter>& presenter, const Rc<Presenter>& presenter,
VkPresentModeKHR presentMode, VkPresentModeKHR presentMode,
uint64_t frameId,
DxvkSubmitStatus* status); DxvkSubmitStatus* status);
/** /**

View File

@ -74,6 +74,19 @@ namespace dxvk {
} }
void DxvkSubmissionQueue::waitForIdle() {
std::unique_lock<dxvk::mutex> lock(m_mutex);
m_submitCond.wait(lock, [this] {
return m_submitQueue.empty();
});
m_finishCond.wait(lock, [this] {
return m_finishQueue.empty();
});
}
void DxvkSubmissionQueue::lockDeviceQueue() { void DxvkSubmissionQueue::lockDeviceQueue() {
m_mutexQueue.lock(); m_mutexQueue.lock();
@ -107,8 +120,6 @@ namespace dxvk {
lock.unlock(); lock.unlock();
// Submit command buffer to device // Submit command buffer to device
VkResult status = VK_NOT_READY;
if (m_lastError != VK_ERROR_DEVICE_LOST) { if (m_lastError != VK_ERROR_DEVICE_LOST) {
std::lock_guard<dxvk::mutex> lock(m_mutexQueue); std::lock_guard<dxvk::mutex> lock(m_mutexQueue);
@ -116,30 +127,34 @@ namespace dxvk {
m_callback(true); m_callback(true);
if (entry.submit.cmdList != nullptr) if (entry.submit.cmdList != nullptr)
status = entry.submit.cmdList->submit(); entry.result = entry.submit.cmdList->submit();
else if (entry.present.presenter != nullptr) else if (entry.present.presenter != nullptr)
status = entry.present.presenter->presentImage(entry.present.presentMode, 0); entry.result = entry.present.presenter->presentImage(entry.present.presentMode, entry.present.frameId);
if (m_callback) if (m_callback)
m_callback(false); m_callback(false);
} else { } else {
// Don't submit anything after device loss // Don't submit anything after device loss
// so that drivers get a chance to recover // so that drivers get a chance to recover
status = VK_ERROR_DEVICE_LOST; entry.result = VK_ERROR_DEVICE_LOST;
} }
if (entry.status) if (entry.status)
entry.status->result = status; entry.status->result = entry.result;
// On success, pass it on to the queue thread // On success, pass it on to the queue thread
lock = std::unique_lock<dxvk::mutex>(m_mutex); lock = std::unique_lock<dxvk::mutex>(m_mutex);
if (status == VK_SUCCESS) { bool doForward = (entry.result == VK_SUCCESS) ||
if (entry.submit.cmdList != nullptr) (entry.present.presenter != nullptr && entry.result != VK_ERROR_DEVICE_LOST);
if (doForward) {
m_finishQueue.push(std::move(entry)); m_finishQueue.push(std::move(entry));
} else if (status == VK_ERROR_DEVICE_LOST || entry.submit.cmdList != nullptr) { } else {
Logger::err(str::format("DxvkSubmissionQueue: Command submission failed: ", status)); Logger::err(str::format("DxvkSubmissionQueue: Command submission failed: ", entry.result));
m_lastError = status; m_lastError = entry.result;
if (m_lastError != VK_ERROR_DEVICE_LOST)
m_device->waitForIdle(); m_device->waitForIdle();
} }
@ -172,6 +187,7 @@ namespace dxvk {
DxvkSubmitEntry entry = std::move(m_finishQueue.front()); DxvkSubmitEntry entry = std::move(m_finishQueue.front());
lock.unlock(); lock.unlock();
if (entry.submit.cmdList != nullptr) {
VkResult status = m_lastError.load(); VkResult status = m_lastError.load();
if (status != VK_ERROR_DEVICE_LOST) if (status != VK_ERROR_DEVICE_LOST)
@ -179,12 +195,22 @@ namespace dxvk {
if (status != VK_SUCCESS) { if (status != VK_SUCCESS) {
m_lastError = status; m_lastError = status;
if (status != VK_ERROR_DEVICE_LOST)
m_device->waitForIdle(); m_device->waitForIdle();
} }
} else if (entry.present.presenter != nullptr) {
// Signal the frame and then immediately destroy the reference.
// This is necessary since the front-end may want to explicitly
// destroy the presenter object.
entry.present.presenter->signalFrame(entry.result, entry.present.frameId);
entry.present.presenter = nullptr;
}
// Release resources and signal events, then immediately wake // Release resources and signal events, then immediately wake
// up any thread that's currently waiting on a resource in // up any thread that's currently waiting on a resource in
// order to reduce delays as much as possible. // order to reduce delays as much as possible.
if (entry.submit.cmdList != nullptr)
entry.submit.cmdList->notifyObjects(); entry.submit.cmdList->notifyObjects();
lock.lock(); lock.lock();
@ -195,9 +221,11 @@ namespace dxvk {
lock.unlock(); lock.unlock();
// Free the command list and associated objects now // Free the command list and associated objects now
if (entry.submit.cmdList != nullptr) {
entry.submit.cmdList->reset(); entry.submit.cmdList->reset();
m_device->recycleCommandList(entry.submit.cmdList); m_device->recycleCommandList(entry.submit.cmdList);
} }
} }
}
} }

View File

@ -44,6 +44,7 @@ namespace dxvk {
struct DxvkPresentInfo { struct DxvkPresentInfo {
Rc<Presenter> presenter; Rc<Presenter> presenter;
VkPresentModeKHR presentMode; VkPresentModeKHR presentMode;
uint64_t frameId;
}; };
@ -51,6 +52,7 @@ namespace dxvk {
* \brief Submission queue entry * \brief Submission queue entry
*/ */
struct DxvkSubmitEntry { struct DxvkSubmitEntry {
VkResult result;
DxvkSubmitStatus* status; DxvkSubmitStatus* status;
DxvkSubmitInfo submit; DxvkSubmitInfo submit;
DxvkPresentInfo present; DxvkPresentInfo present;
@ -160,6 +162,11 @@ namespace dxvk {
m_finishCond.wait(lock, pred); m_finishCond.wait(lock, pred);
} }
/**
* \brief Waits for all submissions to complete
*/
void waitForIdle();
/** /**
* \brief Locks device queue * \brief Locks device queue
* *