mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-23 19:54:16 +01:00
[dxvk] Avoid locking Reflex latency tracker when calling into presenter
There are complex deadlock conditions during swap chain destruction.
This commit is contained in:
parent
efeb15edbd
commit
b1174a1bdf
@ -82,20 +82,30 @@ namespace dxvk {
|
|||||||
|
|
||||||
void DxvkReflexLatencyTrackerNv::notifyCsRenderBegin(
|
void DxvkReflexLatencyTrackerNv::notifyCsRenderBegin(
|
||||||
uint64_t frameId) {
|
uint64_t frameId) {
|
||||||
std::lock_guard lock(m_mutex);
|
bool setMarker = false;
|
||||||
auto& frame = getFrameData(frameId);
|
|
||||||
|
|
||||||
if (frame.appFrameId && frameId >= m_nextValidFrameId)
|
{ std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
|
auto& frame = getFrameData(frameId);
|
||||||
|
setMarker = frame.appFrameId && frameId >= m_nextValidFrameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setMarker)
|
||||||
m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_RENDERSUBMIT_START_NV);
|
m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_RENDERSUBMIT_START_NV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkReflexLatencyTrackerNv::notifyCsRenderEnd(
|
void DxvkReflexLatencyTrackerNv::notifyCsRenderEnd(
|
||||||
uint64_t frameId) {
|
uint64_t frameId) {
|
||||||
std::lock_guard lock(m_mutex);
|
bool setMarker = false;
|
||||||
auto& frame = getFrameData(frameId);
|
|
||||||
|
|
||||||
if (frame.appFrameId && frameId >= m_nextValidFrameId)
|
{ std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
|
auto& frame = getFrameData(frameId);
|
||||||
|
setMarker = frame.appFrameId && frameId >= m_nextValidFrameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setMarker)
|
||||||
m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_RENDERSUBMIT_END_NV);
|
m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_RENDERSUBMIT_END_NV);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,10 +122,15 @@ namespace dxvk {
|
|||||||
|
|
||||||
void DxvkReflexLatencyTrackerNv::notifyQueuePresentBegin(
|
void DxvkReflexLatencyTrackerNv::notifyQueuePresentBegin(
|
||||||
uint64_t frameId) {
|
uint64_t frameId) {
|
||||||
std::lock_guard lock(m_mutex);
|
bool setMarker = false;
|
||||||
auto& frame = getFrameData(frameId);
|
|
||||||
|
|
||||||
if (frame.appFrameId && frameId >= m_nextValidFrameId)
|
{ std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
|
auto& frame = getFrameData(frameId);
|
||||||
|
setMarker = frame.appFrameId && frameId >= m_nextValidFrameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setMarker)
|
||||||
m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_PRESENT_START_NV);
|
m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_PRESENT_START_NV);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,17 +138,29 @@ namespace dxvk {
|
|||||||
void DxvkReflexLatencyTrackerNv::notifyQueuePresentEnd(
|
void DxvkReflexLatencyTrackerNv::notifyQueuePresentEnd(
|
||||||
uint64_t frameId,
|
uint64_t frameId,
|
||||||
VkResult status) {
|
VkResult status) {
|
||||||
std::lock_guard lock(m_mutex);
|
bool setMarker = false;
|
||||||
auto& frame = getFrameData(frameId);
|
|
||||||
|
|
||||||
if (frame.appFrameId && frameId >= m_nextValidFrameId) {
|
{ std::lock_guard lock(m_mutex);
|
||||||
frame.queuePresent = m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_PRESENT_END_NV);
|
|
||||||
|
auto& frame = getFrameData(frameId);
|
||||||
|
setMarker = frame.appFrameId && frameId >= m_nextValidFrameId;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_point cpuTime = time_point();
|
||||||
|
|
||||||
|
if (setMarker)
|
||||||
|
cpuTime = m_presenter->setLatencyMarkerNv(frameId, VK_LATENCY_MARKER_PRESENT_END_NV);
|
||||||
|
|
||||||
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
|
if (setMarker) {
|
||||||
|
auto& frame = getFrameData(frameId);
|
||||||
frame.presentStatus = status;
|
frame.presentStatus = status;
|
||||||
|
frame.queuePresent = cpuTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore errors or we might never wake up a waiting thread
|
// Ignore errors or we might never wake up a waiting thread
|
||||||
m_lastPresentComplete = frameId;
|
m_lastPresentComplete = frameId;
|
||||||
|
|
||||||
m_cond.notify_all();
|
m_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +168,6 @@ namespace dxvk {
|
|||||||
void DxvkReflexLatencyTrackerNv::notifyGpuExecutionBegin(
|
void DxvkReflexLatencyTrackerNv::notifyGpuExecutionBegin(
|
||||||
uint64_t frameId) {
|
uint64_t frameId) {
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
auto now = dxvk::high_resolution_clock::now();
|
auto now = dxvk::high_resolution_clock::now();
|
||||||
|
|
||||||
auto& frame = getFrameData(frameId);
|
auto& frame = getFrameData(frameId);
|
||||||
@ -158,7 +184,6 @@ namespace dxvk {
|
|||||||
void DxvkReflexLatencyTrackerNv::notifyGpuExecutionEnd(
|
void DxvkReflexLatencyTrackerNv::notifyGpuExecutionEnd(
|
||||||
uint64_t frameId) {
|
uint64_t frameId) {
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
auto now = dxvk::high_resolution_clock::now();
|
auto now = dxvk::high_resolution_clock::now();
|
||||||
|
|
||||||
auto& frame = getFrameData(frameId);
|
auto& frame = getFrameData(frameId);
|
||||||
@ -248,7 +273,7 @@ namespace dxvk {
|
|||||||
void DxvkReflexLatencyTrackerNv::setLatencyMarker(
|
void DxvkReflexLatencyTrackerNv::setLatencyMarker(
|
||||||
uint64_t appFrameId,
|
uint64_t appFrameId,
|
||||||
VkLatencyMarkerNV marker) {
|
VkLatencyMarkerNV marker) {
|
||||||
std::lock_guard lock(m_mutex);
|
std::unique_lock lock(m_mutex);
|
||||||
|
|
||||||
// Find frame ID. If this is the first marker in a new frame,
|
// Find frame ID. If this is the first marker in a new frame,
|
||||||
// try to map it to a new internal frame ID.
|
// try to map it to a new internal frame ID.
|
||||||
@ -274,38 +299,52 @@ namespace dxvk {
|
|||||||
if (frameId < m_nextValidFrameId)
|
if (frameId < m_nextValidFrameId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Need to unlock here so we don't deadlock with the presenter
|
||||||
|
auto cpuTime = dxvk::high_resolution_clock::now();
|
||||||
|
|
||||||
|
if (marker == VK_LATENCY_MARKER_INPUT_SAMPLE_NV
|
||||||
|
|| marker == VK_LATENCY_MARKER_SIMULATION_START_NV
|
||||||
|
|| marker == VK_LATENCY_MARKER_SIMULATION_END_NV) {
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
cpuTime = m_presenter->setLatencyMarkerNv(frameId, marker);
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store CPU timestamp to correlate times
|
||||||
auto& frame = getFrameData(frameId);
|
auto& frame = getFrameData(frameId);
|
||||||
|
|
||||||
switch (marker) {
|
switch (marker) {
|
||||||
case VK_LATENCY_MARKER_INPUT_SAMPLE_NV:
|
case VK_LATENCY_MARKER_INPUT_SAMPLE_NV:
|
||||||
frame.cpuInputSample = m_presenter->setLatencyMarkerNv(frameId, marker);
|
frame.cpuInputSample = cpuTime;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VK_LATENCY_MARKER_SIMULATION_START_NV:
|
case VK_LATENCY_MARKER_SIMULATION_START_NV:
|
||||||
frame.cpuSimBegin = m_presenter->setLatencyMarkerNv(frameId, marker);
|
frame.cpuSimBegin = cpuTime;
|
||||||
|
|
||||||
if (m_lastSleepDuration != duration(0u))
|
if (m_lastSleepDuration != duration(0u))
|
||||||
frame.sleepDuration = std::exchange(m_lastSleepDuration, duration(0u));
|
frame.sleepDuration = std::exchange(m_lastSleepDuration, duration(0u));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VK_LATENCY_MARKER_SIMULATION_END_NV:
|
case VK_LATENCY_MARKER_SIMULATION_END_NV:
|
||||||
frame.cpuSimEnd = m_presenter->setLatencyMarkerNv(frameId, marker);
|
frame.cpuSimEnd = cpuTime;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VK_LATENCY_MARKER_RENDERSUBMIT_START_NV:
|
case VK_LATENCY_MARKER_RENDERSUBMIT_START_NV:
|
||||||
frame.cpuRenderBegin = dxvk::high_resolution_clock::now();
|
frame.cpuRenderBegin = cpuTime;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VK_LATENCY_MARKER_RENDERSUBMIT_END_NV:
|
case VK_LATENCY_MARKER_RENDERSUBMIT_END_NV:
|
||||||
frame.cpuRenderEnd = dxvk::high_resolution_clock::now();
|
frame.cpuRenderEnd = cpuTime;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VK_LATENCY_MARKER_PRESENT_START_NV:
|
case VK_LATENCY_MARKER_PRESENT_START_NV:
|
||||||
frame.cpuPresentBegin = dxvk::high_resolution_clock::now();
|
frame.cpuPresentBegin = cpuTime;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VK_LATENCY_MARKER_PRESENT_END_NV:
|
case VK_LATENCY_MARKER_PRESENT_END_NV:
|
||||||
frame.cpuPresentEnd = dxvk::high_resolution_clock::now();
|
frame.cpuPresentEnd = cpuTime;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -346,8 +385,6 @@ namespace dxvk {
|
|||||||
uint32_t DxvkReflexLatencyTrackerNv::getFrameReports(
|
uint32_t DxvkReflexLatencyTrackerNv::getFrameReports(
|
||||||
uint32_t maxCount,
|
uint32_t maxCount,
|
||||||
DxvkReflexFrameReport* reports) {
|
DxvkReflexFrameReport* reports) {
|
||||||
std::lock_guard lock(m_mutex);
|
|
||||||
|
|
||||||
small_vector<VkLatencyTimingsFrameReportNV, 64> nvReports(maxCount);
|
small_vector<VkLatencyTimingsFrameReportNV, 64> nvReports(maxCount);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < maxCount; i++)
|
for (uint32_t i = 0; i < maxCount; i++)
|
||||||
@ -357,6 +394,9 @@ namespace dxvk {
|
|||||||
// correct timestamps for the application-defined markers
|
// correct timestamps for the application-defined markers
|
||||||
uint32_t count = m_presenter->getLatencyTimingsNv(maxCount, nvReports.data());
|
uint32_t count = m_presenter->getLatencyTimingsNv(maxCount, nvReports.data());
|
||||||
|
|
||||||
|
// Only lock after calling into the presenter to avoid deadlocks
|
||||||
|
std::lock_guard lock(m_mutex);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
auto& report = nvReports[i];
|
auto& report = nvReports[i];
|
||||||
const auto& currFrame = m_frames[report.presentID % FrameCount];
|
const auto& currFrame = m_frames[report.presentID % FrameCount];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user