1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-31 05:52:11 +01:00

[d3d11] Implement ID3DLowLatencyDevice

This commit is contained in:
Philip Rebohle 2025-01-20 21:24:50 +01:00 committed by Philip Rebohle
parent 4f9b106d40
commit 736ee20eb5
4 changed files with 168 additions and 8 deletions

View File

@ -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<DxvkReflexLatencyTrackerNv> 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<DxvkReflexFrameReport, FrameCount> 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<DxvkLatencyTracker> Tracker) {
std::lock_guard lock(m_mutex);
if (m_tracker)
return;
if ((m_tracker = dynamic_cast<DxvkReflexLatencyTrackerNv*>(Tracker.ptr())))
m_tracker->setLatencySleepMode(m_enableLowLatency, m_enableBoost, m_minIntervalUs);
}
void D3D11ReflexDevice::UnregisterLatencyTracker(
Rc<DxvkLatencyTracker> Tracker) {
std::lock_guard lock(m_mutex);
if (m_tracker == Tracker)
m_tracker = nullptr;
}

View File

@ -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<DxvkLatencyTracker> Tracker);
void UnregisterLatencyTracker(
Rc<DxvkLatencyTracker> 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<DxvkReflexLatencyTrackerNv> m_tracker;
};

View File

@ -517,6 +517,9 @@ namespace dxvk {
m_presenter->setFrameRateLimit(m_targetFrameRate, GetActualFrameLatency());
m_latency = m_device->createLatencyTracker(m_presenter);
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
reflex->RegisterLatencyTracker(m_latency);
}
@ -617,6 +620,9 @@ namespace dxvk {
] (DxvkContext* ctx) {
ctx->endLatencyTracking(cLatency);
});
Com<D3D11ReflexDevice> reflex = GetReflexDevice();
reflex->UnregisterLatencyTracker(m_latency);
}
@ -678,6 +684,14 @@ namespace dxvk {
}
Com<D3D11ReflexDevice> D3D11SwapChain::GetReflexDevice() {
Com<ID3DLowLatencyDevice> llDevice;
m_parent->QueryInterface(__uuidof(ID3DLowLatencyDevice), reinterpret_cast<void**>(&llDevice));
return static_cast<D3D11ReflexDevice*>(llDevice.ptr());
}
std::string D3D11SwapChain::GetApiName() const {
Com<IDXGIDXVKDevice> device;
m_parent->QueryInterface(__uuidof(IDXGIDXVKDevice), reinterpret_cast<void**>(&device));

View File

@ -148,9 +148,11 @@ namespace dxvk {
void SyncFrameLatency();
uint32_t GetActualFrameLatency();
VkSurfaceFormatKHR GetSurfaceFormat(DXGI_FORMAT Format);
Com<D3D11ReflexDevice> GetReflexDevice();
std::string GetApiName() const;
};