diff --git a/src/d3d/nvapi_d3d_low_latency_device.cpp b/src/d3d/nvapi_d3d_low_latency_device.cpp index 49214fbd..c756cd3d 100644 --- a/src/d3d/nvapi_d3d_low_latency_device.cpp +++ b/src/d3d/nvapi_d3d_low_latency_device.cpp @@ -48,6 +48,14 @@ namespace dxvk { return d3dLowLatencyDevice->SupportsLowLatency(); } + bool NvapiD3dLowLatencyDevice::SupportsLowLatency(ID3D12CommandQueue* commandQueue) { + auto d3dLowLatencyDevice = GetLowLatencyDevice(commandQueue); + if (d3dLowLatencyDevice == nullptr) + return false; + + return d3dLowLatencyDevice->SupportsLowLatency(); + } + bool NvapiD3dLowLatencyDevice::LatencySleep(IUnknown* device) { auto d3dLowLatencyDevice = GetLowLatencyDevice(device); if (d3dLowLatencyDevice == nullptr) @@ -93,6 +101,15 @@ namespace dxvk { GetFrameIdGenerator(d3dLowLatencyDevice.ptr())->GetLowLatencyDeviceFrameId(frameID), markerType)); } + bool NvapiD3dLowLatencyDevice::SetLatencyMarker(ID3D12CommandQueue* commandQueue, uint64_t frameID, uint32_t markerType) { + auto d3dLowLatencyDevice = GetLowLatencyDevice(commandQueue); + if (d3dLowLatencyDevice == nullptr) + return false; + + return SUCCEEDED(d3dLowLatencyDevice->SetLatencyMarker( + GetFrameIdGenerator(d3dLowLatencyDevice.ptr())->GetLowLatencyDeviceFrameId(frameID), markerType)); + } + void NvapiD3dLowLatencyDevice::ClearCacheMaps() { std::scoped_lock lock(m_lowLatencyDeviceMutex, m_lowLatencyFrameIdGeneratorMutex); @@ -118,6 +135,26 @@ namespace dxvk { return d3dLowLatencyDevice; } + Com NvapiD3dLowLatencyDevice::GetLowLatencyDevice(ID3D12CommandQueue* commandQueue) { + if (commandQueue == nullptr) + return nullptr; + + auto unknown = static_cast(commandQueue); + + std::scoped_lock lock(m_lowLatencyDeviceMutex); + auto it = m_lowLatencyDeviceMap.find(unknown); + if (it != m_lowLatencyDeviceMap.end()) + return it->second; + + Com d3dLowLatencyDevice; + if (FAILED(commandQueue->GetDevice(IID_PPV_ARGS(&d3dLowLatencyDevice)))) + return nullptr; + + m_lowLatencyDeviceMap.emplace(unknown, d3dLowLatencyDevice.ptr()); + + return d3dLowLatencyDevice; + } + LowLatencyFrameIdGenerator* NvapiD3dLowLatencyDevice::GetFrameIdGenerator(ID3DLowLatencyDevice* device) { std::scoped_lock lock(m_lowLatencyFrameIdGeneratorMutex); auto it = m_frameIdGeneratorMap.find(device); diff --git a/src/d3d/nvapi_d3d_low_latency_device.h b/src/d3d/nvapi_d3d_low_latency_device.h index 09f0e4b1..93f10eb1 100644 --- a/src/d3d/nvapi_d3d_low_latency_device.h +++ b/src/d3d/nvapi_d3d_low_latency_device.h @@ -26,10 +26,12 @@ namespace dxvk { class NvapiD3dLowLatencyDevice { public: static bool SupportsLowLatency(IUnknown* device); + static bool SupportsLowLatency(ID3D12CommandQueue* commandQueue); static bool LatencySleep(IUnknown* device); static bool SetLatencySleepMode(IUnknown* device, bool lowLatencyMode, bool lowLatencyBoost, uint32_t minimumIntervalUs); static bool GetLatencyInfo(IUnknown* device, D3D_LATENCY_RESULTS* latencyResults); static bool SetLatencyMarker(IUnknown* device, uint64_t frameID, uint32_t markerType); + static bool SetLatencyMarker(ID3D12CommandQueue* commandQueue, uint64_t frameID, uint32_t markerType); static void ClearCacheMaps(); @@ -41,6 +43,7 @@ namespace dxvk { inline static std::mutex m_lowLatencyFrameIdGeneratorMutex; [[nodiscard]] static Com GetLowLatencyDevice(IUnknown* device); + [[nodiscard]] static Com GetLowLatencyDevice(ID3D12CommandQueue* commandQueue); [[nodiscard]] static LowLatencyFrameIdGenerator* GetFrameIdGenerator(ID3DLowLatencyDevice* device); }; } \ No newline at end of file diff --git a/src/nvapi_d3d12.cpp b/src/nvapi_d3d12.cpp index 3310a491..8e851cd9 100644 --- a/src/nvapi_d3d12.cpp +++ b/src/nvapi_d3d12.cpp @@ -471,11 +471,7 @@ extern "C" { if (pCommandQueue == nullptr) return InvalidPointer(n); - ID3D12Device* pDevice; - if (FAILED(pCommandQueue->GetDevice(IID_PPV_ARGS(&pDevice)))) - return InvalidArgument(n); - - if (nvapiD3dInstance->IsUsingLfx() || !NvapiD3dLowLatencyDevice::SupportsLowLatency(pDevice)) + if (nvapiD3dInstance->IsUsingLfx() || !NvapiD3dLowLatencyDevice::SupportsLowLatency(pCommandQueue)) return NoImplementation(n); if (!NvapiD3d12Device::NotifyOutOfBandCommandQueue(pCommandQueue, static_cast(cqType))) @@ -501,14 +497,10 @@ extern "C" { if (pSetLatencyMarkerParams->version != NV_LATENCY_MARKER_PARAMS_VER1) return IncompatibleStructVersion(n); - ID3D12Device* pDevice; - if (FAILED(pCommandQueue->GetDevice(IID_PPV_ARGS(&pDevice)))) - return InvalidArgument(n); - - if (nvapiD3dInstance->IsUsingLfx() || !NvapiD3dLowLatencyDevice::SupportsLowLatency(pDevice)) + if (nvapiD3dInstance->IsUsingLfx() || !NvapiD3dLowLatencyDevice::SupportsLowLatency(pCommandQueue)) return NoImplementation(n); - if (!NvapiD3dLowLatencyDevice::SetLatencyMarker(pDevice, pSetLatencyMarkerParams->frameID, pSetLatencyMarkerParams->markerType)) + if (!NvapiD3dLowLatencyDevice::SetLatencyMarker(pCommandQueue, pSetLatencyMarkerParams->frameID, pSetLatencyMarkerParams->markerType)) return Error(n, alreadyLoggedError); return Ok(n, alreadyLoggedOk); diff --git a/tests/nvapi_d3d12.cpp b/tests/nvapi_d3d12.cpp index 71dfed72..889bd038 100644 --- a/tests/nvapi_d3d12.cpp +++ b/tests/nvapi_d3d12.cpp @@ -803,6 +803,10 @@ TEST_CASE("D3D12 methods succeed", "[.d3d12]") { auto e = ConfigureDefaultTestEnvironment(*dxgiFactory, *vulkan, *nvml, *lfx, adapter, output); + ALLOW_CALL(commandQueue, GetDevice(__uuidof(ID3DLowLatencyDevice), _)) + .LR_SIDE_EFFECT(*_2 = static_cast(&lowLatencyDevice)) + .LR_SIDE_EFFECT(lowLatencyDeviceRefCount++) + .RETURN(S_OK); ALLOW_CALL(device, QueryInterface(__uuidof(ID3DLowLatencyDevice), _)) .LR_SIDE_EFFECT(*_2 = static_cast(&lowLatencyDevice)) .LR_SIDE_EFFECT(lowLatencyDeviceRefCount++)