From dbf3e4ee44c1a17927def7e386acbc9739ddbf47 Mon Sep 17 00:00:00 2001 From: Jens Peters Date: Mon, 20 Jan 2025 19:48:54 +0100 Subject: [PATCH 1/3] meta: Simplify ignores --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 67aaa4bf..571e666b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,8 @@ buildDir build.layer out winsysroot -.idea/** -.vscode/** +.idea +.vscode version.h config.h layer/version.h From 7df0756c42bab48cfcd5f6d517cf639147a159aa Mon Sep 17 00:00:00 2001 From: Jens Peters Date: Tue, 21 Jan 2025 07:50:38 +0100 Subject: [PATCH 2/3] nvapi-d3d: Formatting --- src/nvapi/nvapi_d3d_low_latency_device.cpp | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/nvapi/nvapi_d3d_low_latency_device.cpp b/src/nvapi/nvapi_d3d_low_latency_device.cpp index 0245bc80..acaa731f 100644 --- a/src/nvapi/nvapi_d3d_low_latency_device.cpp +++ b/src/nvapi/nvapi_d3d_low_latency_device.cpp @@ -127,23 +127,23 @@ namespace dxvk { static_assert(static_cast(OUT_OF_BAND_PRESENT_END) - 1 == static_cast(VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_END_NV)); switch (markerType) { - case (SIMULATION_START): - case (SIMULATION_END): - case (RENDERSUBMIT_START): - case (RENDERSUBMIT_END): - case (PRESENT_START): - case (PRESENT_END): - case (INPUT_SAMPLE): - case (TRIGGER_FLASH): + case SIMULATION_START: + case SIMULATION_END: + case RENDERSUBMIT_START: + case RENDERSUBMIT_END: + case PRESENT_START: + case PRESENT_END: + case INPUT_SAMPLE: + case TRIGGER_FLASH: return markerType; // VkLatencyMarkerNV misses PC_LATENCY_PING and all following enum values are offset // See https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkSetLatencyMarkerInfoNV-marker-parameter - case (PC_LATENCY_PING): + case PC_LATENCY_PING: return {}; - case (OUT_OF_BAND_RENDERSUBMIT_START): - case (OUT_OF_BAND_RENDERSUBMIT_END): - case (OUT_OF_BAND_PRESENT_START): - case (OUT_OF_BAND_PRESENT_END): + case OUT_OF_BAND_RENDERSUBMIT_START: + case OUT_OF_BAND_RENDERSUBMIT_END: + case OUT_OF_BAND_PRESENT_START: + case OUT_OF_BAND_PRESENT_END: return markerType - 1; } From 53c17e911ecfaf5203c861c9fa2443c5c74ad7eb Mon Sep 17 00:00:00 2001 From: Jens Peters Date: Mon, 20 Jan 2025 19:50:30 +0100 Subject: [PATCH 3/3] nvapi-d3d: Drop repeated frame IDs Frame IDs must be monotonic per marker type and device/command queue. --- src/nvapi/nvapi_d3d_low_latency_device.cpp | 21 +++++++++++-- src/nvapi/nvapi_d3d_low_latency_device.h | 5 +++- tests/nvapi_d3d.cpp | 34 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/nvapi/nvapi_d3d_low_latency_device.cpp b/src/nvapi/nvapi_d3d_low_latency_device.cpp index acaa731f..b5662431 100644 --- a/src/nvapi/nvapi_d3d_low_latency_device.cpp +++ b/src/nvapi/nvapi_d3d_low_latency_device.cpp @@ -5,7 +5,9 @@ namespace dxvk { LowLatencyFrameIdGenerator::LowLatencyFrameIdGenerator() : m_nextLowLatencyDeviceFrameId(1), - m_applicationIdList({0}) {} + m_applicationIdList({0}) { + m_lastFrameId.fill(std::numeric_limits::max()); + } LowLatencyFrameIdGenerator::~LowLatencyFrameIdGenerator() = default; @@ -42,6 +44,11 @@ namespace dxvk { return m_applicationIdList[((lowLatencyDeviceFrameId - 1) % applicationIdListSize)]; } + bool LowLatencyFrameIdGenerator::IsRepeatedFrame(uint64_t frameID, uint32_t markerType) { + // Should always be within bounds since we drop unsupported marker types in the entrypoints + return std::exchange(m_lastFrameId[markerType], frameID) == frameID; + } + bool NvapiD3dLowLatencyDevice::SupportsLowLatency(IUnknown* device) { auto d3dLowLatencyDevice = GetLowLatencyDevice(device); if (d3dLowLatencyDevice == nullptr) @@ -99,8 +106,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 +119,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 9e90dc96..1228f1fe 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::array m_lastFrameId; }; class NvapiD3dLowLatencyDevice { diff --git a/tests/nvapi_d3d.cpp b/tests/nvapi_d3d.cpp index 6994e9a1..f6b8f562 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, VK_LATENCY_MARKER_PRESENT_START_NV)) + .IN_SEQUENCE(seq1) + .TIMES(1) + .RETURN(S_OK); + REQUIRE_CALL(lowLatencyDevice, SetLatencyMarker(2ULL, VK_LATENCY_MARKER_PRESENT_START_NV)) + .IN_SEQUENCE(seq2) + .TIMES(1) + .RETURN(S_OK); + REQUIRE_CALL(lowLatencyDevice, SetLatencyMarker(2ULL, VK_LATENCY_MARKER_PRESENT_END_NV)) + .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);