diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index a33379f966e..2ffc50e26ed 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -3062,7 +3062,10 @@ namespace dxvk { D3D11DXGIDevice* pContainer, D3D11Device* pDevice) : m_container(pContainer), m_device(pDevice) { + auto dxvkDevice = pDevice->GetDXVKDevice(); + m_reflexEnabled = dxvkDevice->features().nvLowLatency2 + && dxvkDevice->config().latencySleep == Tristate::Auto; } @@ -3089,12 +3092,25 @@ namespace dxvk { BOOL STDMETHODCALLTYPE D3D11ReflexDevice::SupportsLowLatency() { - return FALSE; + return m_reflexEnabled; } HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::LatencySleep() { - return E_NOTIMPL; + if (!m_reflexEnabled) + return DXGI_ERROR_INVALID_CALL; + + // Don't keep object locked while sleeping + Rc tracker; + + { std::lock_guard lock(m_mutex); + tracker = m_tracker; + } + + if (tracker) + tracker->latencySleep(); + + return S_OK; } @@ -3102,21 +3118,133 @@ namespace dxvk { BOOL LowLatencyEnable, BOOL LowLatencyBoost, UINT32 MinIntervalUs) { - return E_NOTIMPL; + if (!m_reflexEnabled) + return DXGI_ERROR_INVALID_CALL; + + std::lock_guard lock(m_mutex); + + if (m_tracker) { + m_tracker->setLatencySleepMode( + LowLatencyEnable, LowLatencyBoost, MinIntervalUs); + } + + // Write back in case we have no swapchain yet + m_enableLowLatency = LowLatencyEnable; + m_enableBoost = LowLatencyBoost; + m_minIntervalUs = MinIntervalUs; + return S_OK; } HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::SetLatencyMarker( UINT64 FrameId, UINT32 MarkerType) { - return E_NOTIMPL; + if (!m_reflexEnabled) + return DXGI_ERROR_INVALID_CALL; + + std::lock_guard lock(m_mutex); + + if (m_tracker) { + auto marker = VkLatencyMarkerNV(MarkerType); + m_tracker->setLatencyMarker(FrameId, marker); + + if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_START_NV) { + m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [ + cTracker = m_tracker, + cFrameId = FrameId + ] (DxvkContext* ctx) { + uint64_t frameId = cTracker->frameIdFromAppFrameId(cFrameId); + + if (frameId) + ctx->beginLatencyTracking(cTracker, frameId); + }); + } else if (marker == VK_LATENCY_MARKER_RENDERSUBMIT_END_NV) { + m_device->GetContext()->InjectCs(DxvkCsQueue::Ordered, [ + cTracker = m_tracker + ] (DxvkContext* ctx) { + ctx->endLatencyTracking(cTracker); + }); + } + } + + return S_OK; } HRESULT STDMETHODCALLTYPE D3D11ReflexDevice::GetLatencyInfo( D3D_LOW_LATENCY_RESULTS* pLowLatencyResults) { - *pLowLatencyResults = D3D_LOW_LATENCY_RESULTS(); - return E_NOTIMPL; + constexpr static size_t FrameCount = 64; + + if (!pLowLatencyResults) + return E_INVALIDARG; + + for (size_t i = 0; i < FrameCount; i++) + pLowLatencyResults->frameReports[i] = D3D_LOW_LATENCY_FRAME_REPORT(); + + if (!m_reflexEnabled) + return DXGI_ERROR_INVALID_CALL; + + std::lock_guard lock(m_mutex); + + if (!m_tracker) + return S_OK; + + // Apparently we have to report all 64 frames, or nothing + std::array reports = { }; + uint32_t reportCount = m_tracker->getFrameReports(FrameCount, reports.data()); + + if (reportCount < FrameCount) + return S_OK; + + for (uint32_t i = 0; i < FrameCount; i++) { + auto& src = reports[i]; + auto& dst = pLowLatencyResults->frameReports[i]; + + dst.frameID = src.report.presentID; + dst.inputSampleTime = src.report.inputSampleTimeUs; + dst.simStartTime = src.report.simStartTimeUs; + dst.simEndTime = src.report.simEndTimeUs; + dst.renderSubmitStartTime = src.report.renderSubmitStartTimeUs; + dst.renderSubmitEndTime = src.report.renderSubmitEndTimeUs; + dst.presentStartTime = src.report.presentStartTimeUs; + dst.presentEndTime = src.report.presentEndTimeUs; + dst.driverStartTime = src.report.driverStartTimeUs; + dst.driverEndTime = src.report.driverEndTimeUs; + dst.osRenderQueueStartTime = src.report.osRenderQueueStartTimeUs; + dst.osRenderQueueEndTime = src.report.osRenderQueueEndTimeUs; + dst.gpuRenderStartTime = src.report.gpuRenderStartTimeUs; + dst.gpuRenderEndTime = src.report.gpuRenderEndTimeUs; + dst.gpuActiveRenderTimeUs = src.gpuActiveTimeUs; + dst.gpuFrameTimeUs = 0; + + if (i) { + dst.gpuFrameTimeUs = reports[i - 0].report.gpuRenderEndTimeUs + - reports[i - 1].report.gpuRenderEndTimeUs; + } + } + + return S_OK; + } + + + void D3D11ReflexDevice::RegisterLatencyTracker( + Rc Tracker) { + std::lock_guard lock(m_mutex); + + if (m_tracker) + return; + + if ((m_tracker = dynamic_cast(Tracker.ptr()))) + m_tracker->setLatencySleepMode(m_enableLowLatency, m_enableBoost, m_minIntervalUs); + } + + + void D3D11ReflexDevice::UnregisterLatencyTracker( + Rc Tracker) { + std::lock_guard lock(m_mutex); + + if (m_tracker == Tracker) + m_tracker = nullptr; } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 7adcf0db694..48356f8b446 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -9,6 +9,7 @@ #include "../dxgi/dxgi_interfaces.h" #include "../dxvk/dxvk_cs.h" +#include "../dxvk/dxvk_latency_reflex.h" #include "../d3d10/d3d10_device.h" @@ -788,11 +789,26 @@ namespace dxvk { HRESULT STDMETHODCALLTYPE GetLatencyInfo( D3D_LOW_LATENCY_RESULTS* pLowLatencyResults); + void RegisterLatencyTracker( + Rc Tracker); + + void UnregisterLatencyTracker( + Rc Tracker); + private: D3D11DXGIDevice* m_container; D3D11Device* m_device; + bool m_reflexEnabled = false; + + dxvk::mutex m_mutex; + + bool m_enableLowLatency = false; + bool m_enableBoost = false; + uint64_t m_minIntervalUs = 0u; + + Rc m_tracker; }; diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 6219f3985e5..da0ebcb9c24 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -517,6 +517,9 @@ namespace dxvk { m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency()); m_latency = m_device->createLatencyTracker(m_presenter); + + Com reflex = GetReflexDevice(); + reflex->RegisterLatencyTracker(m_latency); } @@ -617,6 +620,9 @@ namespace dxvk { ] (DxvkContext* ctx) { ctx->endLatencyTracking(cLatency); }); + + Com reflex = GetReflexDevice(); + reflex->UnregisterLatencyTracker(m_latency); } @@ -678,6 +684,14 @@ namespace dxvk { } + Com D3D11SwapChain::GetReflexDevice() { + Com llDevice; + m_parent->QueryInterface(__uuidof(ID3DLowLatencyDevice), reinterpret_cast(&llDevice)); + + return static_cast(llDevice.ptr()); + } + + std::string D3D11SwapChain::GetApiName() const { Com device; m_parent->QueryInterface(__uuidof(IDXGIDXVKDevice), reinterpret_cast(&device)); diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h index cb51182d034..99f09450c7a 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -148,9 +148,11 @@ namespace dxvk { void SyncFrameLatency(); uint32_t GetActualFrameLatency(); - + VkSurfaceFormatKHR GetSurfaceFormat(DXGI_FORMAT Format); - + + Com GetReflexDevice(); + std::string GetApiName() const; };