Skip to content

Commit

Permalink
nvapi-d3d: Drop repeated frame IDs
Browse files Browse the repository at this point in the history
Frame IDs must be monotonic per marker type and
device/command queue.
  • Loading branch information
jp7677 committed Jan 21, 2025
1 parent c3a8121 commit 652e56a
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 3 deletions.
21 changes: 19 additions & 2 deletions src/nvapi/nvapi_d3d_low_latency_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -99,17 +108,25 @@ 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) {
auto d3dLowLatencyDevice = GetLowLatencyDevice(commandQueue);
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<uint32_t> NvapiD3dLowLatencyDevice::ToMarkerType(NV_LATENCY_MARKER_TYPE markerType) {
Expand Down
5 changes: 4 additions & 1 deletion src/nvapi/nvapi_d3d_low_latency_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,6 +22,8 @@ namespace dxvk {

static constexpr uint32_t applicationIdListSize = 1000;
std::array<uint64_t, applicationIdListSize> m_applicationIdList;

std::unordered_map<uint32_t, uint64_t> m_lastFrameId;
};

class NvapiD3dLowLatencyDevice {
Expand Down
34 changes: 34 additions & 0 deletions tests/nvapi_d3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 652e56a

Please sign in to comment.