diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 4566b1e8f..ee60e5da7 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -425,7 +425,7 @@ namespace dxvk { ctx->synchronizeWsi(cSync); ctx->flushCommandList(nullptr); - cDevice->presentImage(cPresenter, cFrameId, nullptr); + cDevice->presentImage(cPresenter, cFrameId, nullptr, 0, nullptr); }); if (m_backBuffers.size() > 1u) diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 8771e4894..2117cb1cb 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -876,7 +876,7 @@ namespace dxvk { uint64_t frameId = cRepeat ? 0 : cFrameId; - cDevice->presentImage(cPresenter, frameId, nullptr); + cDevice->presentImage(cPresenter, frameId, nullptr, 0, nullptr); }); m_parent->FlushCsChunk(); diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 1451226c0..dfb7760b7 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -111,9 +111,9 @@ namespace dxvk { void DxvkContext::flushCommandList(DxvkSubmitStatus* status) { - m_device->submitCommandList( - this->endRecording(), status); - + m_device->submitCommandList(this->endRecording(), + nullptr, 0, status); + this->beginRecording( m_device->createCommandList()); } diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index c029949aa..9544bb2d6 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -319,11 +319,18 @@ namespace dxvk { void DxvkDevice::presentImage( const Rc& presenter, uint64_t frameId, + const Rc& tracker, + uint64_t trackedId, DxvkSubmitStatus* status) { DxvkPresentInfo presentInfo = { }; presentInfo.presenter = presenter; presentInfo.frameId = frameId; - m_submissionQueue.present(presentInfo, status); + + DxvkLatencyInfo latencyInfo; + latencyInfo.tracker = tracker; + latencyInfo.trackedId = trackedId; + + m_submissionQueue.present(presentInfo, latencyInfo, status); std::lock_guard statLock(m_statLock); m_statCounters.addCtr(DxvkStatCounter::QueuePresentCount, 1); @@ -332,10 +339,17 @@ namespace dxvk { void DxvkDevice::submitCommandList( const Rc& commandList, + const Rc& tracker, + uint64_t trackedId, DxvkSubmitStatus* status) { DxvkSubmitInfo submitInfo = { }; submitInfo.cmdList = commandList; - m_submissionQueue.submit(submitInfo, status); + + DxvkLatencyInfo latencyInfo; + latencyInfo.tracker = tracker; + latencyInfo.trackedId = trackedId; + + m_submissionQueue.submit(submitInfo, latencyInfo, status); std::lock_guard statLock(m_statLock); m_statCounters.merge(commandList->statCounters()); diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 5d8b4e37b..e53890354 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -496,12 +496,16 @@ namespace dxvk { * the submission thread. The status of this operation * can be retrieved with \ref waitForSubmission. * \param [in] presenter The presenter - * \param [in] frameId Optional frame ID + * \param [in] frameId Presenter frame ID + * \param [in] tracker Latency tracker + * \param [in] trackedId Latency frame ID * \param [out] status Present status */ void presentImage( const Rc& presenter, uint64_t frameId, + const Rc& tracker, + uint64_t trackedId, DxvkSubmitStatus* status); /** @@ -510,10 +514,14 @@ namespace dxvk { * Submits the given command list to the device using * the given set of optional synchronization primitives. * \param [in] commandList The command list to submit + * \param [in] tracker Latency tracker + * \param [in] trackedId Latency frame ID * \param [out] status Submission feedback */ void submitCommandList( const Rc& commandList, + const Rc& tracker, + uint64_t trackedId, DxvkSubmitStatus* status); /** diff --git a/src/dxvk/dxvk_queue.cpp b/src/dxvk/dxvk_queue.cpp index d9d8b6c30..84108a925 100644 --- a/src/dxvk/dxvk_queue.cpp +++ b/src/dxvk/dxvk_queue.cpp @@ -42,7 +42,10 @@ namespace dxvk { } - void DxvkSubmissionQueue::submit(DxvkSubmitInfo submitInfo, DxvkSubmitStatus* status) { + void DxvkSubmissionQueue::submit( + DxvkSubmitInfo submitInfo, + DxvkLatencyInfo latencyInfo, + DxvkSubmitStatus* status) { std::unique_lock lock(m_mutex); m_finishCond.wait(lock, [this] { @@ -52,18 +55,23 @@ namespace dxvk { DxvkSubmitEntry entry = { }; entry.status = status; entry.submit = std::move(submitInfo); + entry.latency = std::move(latencyInfo); m_submitQueue.push(std::move(entry)); m_appendCond.notify_all(); } - void DxvkSubmissionQueue::present(DxvkPresentInfo presentInfo, DxvkSubmitStatus* status) { + void DxvkSubmissionQueue::present( + DxvkPresentInfo presentInfo, + DxvkLatencyInfo latencyInfo, + DxvkSubmitStatus* status) { std::unique_lock lock(m_mutex); DxvkSubmitEntry entry = { }; entry.status = status; entry.present = std::move(presentInfo); + entry.latency = std::move(latencyInfo); m_submitQueue.push(std::move(entry)); m_appendCond.notify_all(); @@ -142,10 +150,21 @@ namespace dxvk { m_callback(true); if (entry.submit.cmdList != nullptr) { + if (entry.latency.tracker) + entry.latency.tracker->notifyQueueSubmit(entry.latency.trackedId); + entry.result = entry.submit.cmdList->submit(m_semaphores, m_timelines); entry.timelines = m_timelines; } else if (entry.present.presenter != nullptr) { + if (entry.latency.tracker) + entry.latency.tracker->notifyQueuePresentBegin(entry.latency.trackedId); + entry.result = entry.present.presenter->presentImage(entry.present.frameId); + + if (entry.latency.tracker) { + entry.latency.tracker->notifyQueuePresentEnd( + entry.latency.trackedId, entry.result); + } } if (m_callback) @@ -217,12 +236,18 @@ namespace dxvk { std::array semaphores = { m_semaphores.graphics, m_semaphores.transfer }; std::array timelines = { entry.timelines.graphics, entry.timelines.transfer }; + if (entry.latency.tracker) + entry.latency.tracker->notifyGpuExecutionBegin(entry.latency.trackedId); + VkSemaphoreWaitInfo waitInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO }; waitInfo.semaphoreCount = semaphores.size(); waitInfo.pSemaphores = semaphores.data(); waitInfo.pValues = timelines.data(); status = vk->vkWaitSemaphores(vk->device(), &waitInfo, ~0ull); + + if (entry.latency.tracker && status == VK_SUCCESS) + entry.latency.tracker->notifyGpuExecutionEnd(entry.latency.trackedId); } if (status != VK_SUCCESS) { diff --git a/src/dxvk/dxvk_queue.h b/src/dxvk/dxvk_queue.h index 8ef6a7148..15b0e3d35 100644 --- a/src/dxvk/dxvk_queue.h +++ b/src/dxvk/dxvk_queue.h @@ -7,6 +7,7 @@ #include "../util/thread.h" #include "dxvk_cmdlist.h" +#include "dxvk_latency.h" #include "dxvk_presenter.h" namespace dxvk { @@ -47,6 +48,18 @@ namespace dxvk { }; + /** + * \brief Latency info + * + * Optionally stores a latency tracker + * and the associated frame ID. + */ + struct DxvkLatencyInfo { + Rc tracker; + uint64_t trackedId = 0; + }; + + /** * \brief Submission queue entry */ @@ -55,6 +68,7 @@ namespace dxvk { DxvkSubmitStatus* status; DxvkSubmitInfo submit; DxvkPresentInfo present; + DxvkLatencyInfo latency; DxvkTimelineSemaphoreValues timelines; }; @@ -102,10 +116,12 @@ namespace dxvk { * dedicated submission thread. Use this to take * the submission overhead off the calling thread. * \param [in] submitInfo Submission parameters + * \param [in] latencyInfo Latency tracker info * \param [out] status Submission feedback */ void submit( DxvkSubmitInfo submitInfo, + DxvkLatencyInfo latencyInfo, DxvkSubmitStatus* status); /** @@ -115,10 +131,12 @@ namespace dxvk { * and then presents the current swap chain image * of the presenter. May stall the calling thread. * \param [in] present Present parameters + * \param [in] latencyInfo Latency tracker info * \param [out] status Submission feedback */ void present( DxvkPresentInfo presentInfo, + DxvkLatencyInfo latencyInfo, DxvkSubmitStatus* status); /**