diff --git a/src/nvapi/nvapi_d3d_low_latency_device.cpp b/src/nvapi/nvapi_d3d_low_latency_device.cpp index 187d33f9..45abda27 100644 --- a/src/nvapi/nvapi_d3d_low_latency_device.cpp +++ b/src/nvapi/nvapi_d3d_low_latency_device.cpp @@ -42,6 +42,15 @@ namespace dxvk { return m_applicationIdList[((lowLatencyDeviceFrameId - 1) % applicationIdListSize)]; } + bool LowLatencyFrameIdGenerator::IsRepeatedFrame(uint64_t frameID, uint32_t markerType) { + if (m_lastFrameId.contains(markerType) && m_lastFrameId[markerType] == frameID) { + return true; + } + + m_lastFrameId[markerType] = frameID; + return false; + } + bool NvapiD3dLowLatencyDevice::SupportsLowLatency(IUnknown* device) { auto d3dLowLatencyDevice = GetLowLatencyDevice(device); if (d3dLowLatencyDevice == nullptr) @@ -99,8 +108,12 @@ namespace dxvk { if (d3dLowLatencyDevice == nullptr) return false; + auto frameIdGenerator = GetFrameIdGenerator(d3dLowLatencyDevice.ptr()); + if (frameIdGenerator->IsRepeatedFrame(frameID, markerType)) + return true; // Silently drop repeated frame IDs + return SUCCEEDED(d3dLowLatencyDevice->SetLatencyMarker( - GetFrameIdGenerator(d3dLowLatencyDevice.ptr())->GetLowLatencyDeviceFrameId(frameID), markerType)); + frameIdGenerator->GetLowLatencyDeviceFrameId(frameID), markerType)); } bool NvapiD3dLowLatencyDevice::SetLatencyMarker(ID3D12CommandQueue* commandQueue, uint64_t frameID, uint32_t markerType) { @@ -108,8 +121,12 @@ namespace dxvk { if (d3dLowLatencyDevice == nullptr) return false; + auto frameIdGenerator = GetFrameIdGenerator(d3dLowLatencyDevice.ptr()); + if (frameIdGenerator->IsRepeatedFrame(frameID, markerType)) + return true; // Silently drop repeated frame IDs + return SUCCEEDED(d3dLowLatencyDevice->SetLatencyMarker( - GetFrameIdGenerator(d3dLowLatencyDevice.ptr())->GetLowLatencyDeviceFrameId(frameID), markerType)); + frameIdGenerator->GetLowLatencyDeviceFrameId(frameID), markerType)); } std::optional NvapiD3dLowLatencyDevice::ToMarkerType(NV_LATENCY_MARKER_TYPE markerType) { diff --git a/src/nvapi/nvapi_d3d_low_latency_device.h b/src/nvapi/nvapi_d3d_low_latency_device.h index 5fbca359..829f1365 100644 --- a/src/nvapi/nvapi_d3d_low_latency_device.h +++ b/src/nvapi/nvapi_d3d_low_latency_device.h @@ -9,9 +9,10 @@ namespace dxvk { public: LowLatencyFrameIdGenerator(); virtual ~LowLatencyFrameIdGenerator(); - bool LowLatencyDeviceFrameIdInWindow(uint64_t lowLatencyDeviceFrameId) const; + [[nodiscard]] bool LowLatencyDeviceFrameIdInWindow(uint64_t lowLatencyDeviceFrameId) const; uint64_t GetLowLatencyDeviceFrameId(uint64_t applicationFrameId); uint64_t GetApplicationFrameId(uint64_t lowLatencyDeviceFrameId); + [[nodiscard]] bool IsRepeatedFrame(uint64_t frameID, uint32_t markerType); private: std::mutex m_frameIdGeneratorMutex; @@ -21,6 +22,8 @@ namespace dxvk { static constexpr uint32_t applicationIdListSize = 1000; std::array m_applicationIdList; + + std::unordered_map m_lastFrameId; }; class NvapiD3dLowLatencyDevice { diff --git a/tests/nvapi_d3d.cpp b/tests/nvapi_d3d.cpp index 7b039bed..e4d88b05 100644 --- a/tests/nvapi_d3d.cpp +++ b/tests/nvapi_d3d.cpp @@ -415,6 +415,40 @@ TEST_CASE("D3D Reflex/LatencyFleX depending methods succeed", "[.d3d]") { REQUIRE(NvAPI_D3D_SetLatencyMarker(&unknown, &latencyMarkerParams) == NVAPI_OK); } + SECTION("SetLatencyMarker drops repeated frame IDs and returns OK") { + sequence seq1, seq2, seq3; + + REQUIRE_CALL(lowLatencyDevice, SetLatencyMarker(1ULL, PRESENT_START)) + .IN_SEQUENCE(seq1) + .TIMES(1) + .RETURN(S_OK); + REQUIRE_CALL(lowLatencyDevice, SetLatencyMarker(2ULL, PRESENT_START)) + .IN_SEQUENCE(seq2) + .TIMES(1) + .RETURN(S_OK); + REQUIRE_CALL(lowLatencyDevice, SetLatencyMarker(2ULL, PRESENT_END)) + .IN_SEQUENCE(seq3) + .TIMES(1) + .RETURN(S_OK); + + SetupResourceFactory(std::move(dxgiFactory), std::move(vk), std::move(nvml), std::move(lfx)); + REQUIRE(NvAPI_Initialize() == NVAPI_OK); + + NV_LATENCY_MARKER_PARAMS latencyMarkerParams{}; + latencyMarkerParams.version = NV_LATENCY_MARKER_PARAMS_VER1; + latencyMarkerParams.frameID = 1; + latencyMarkerParams.markerType = PRESENT_START; + REQUIRE(NvAPI_D3D_SetLatencyMarker(&unknown, &latencyMarkerParams) == NVAPI_OK); + REQUIRE(NvAPI_D3D_SetLatencyMarker(&unknown, &latencyMarkerParams) == NVAPI_OK); + latencyMarkerParams.frameID = 2; + REQUIRE(NvAPI_D3D_SetLatencyMarker(&unknown, &latencyMarkerParams) == NVAPI_OK); + REQUIRE(NvAPI_D3D_SetLatencyMarker(&unknown, &latencyMarkerParams) == NVAPI_OK); + latencyMarkerParams.frameID = 2; + latencyMarkerParams.markerType = PRESENT_END; + REQUIRE(NvAPI_D3D_SetLatencyMarker(&unknown, &latencyMarkerParams) == NVAPI_OK); + REQUIRE(NvAPI_D3D_SetLatencyMarker(&unknown, &latencyMarkerParams) == NVAPI_OK); + } + SECTION("SetLatencyMarker correctly produces monotonic frame ids for a sequence of unique application frame ids") { REQUIRE_CALL(lowLatencyDevice, SetLatencySleepMode(true, false, 750U)) .RETURN(S_OK);