Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop repeated frame IDs #244

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ buildDir
build.layer
out
winsysroot
.idea/**
.vscode/**
.idea
.vscode
version.h
config.h
layer/version.h
Expand Down
47 changes: 31 additions & 16 deletions src/nvapi/nvapi_d3d_low_latency_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace dxvk {
LowLatencyFrameIdGenerator::LowLatencyFrameIdGenerator()
: m_nextLowLatencyDeviceFrameId(1),
m_applicationIdList({0}) {}
m_applicationIdList({0}) {
m_lastFrameId.fill(std::numeric_limits<uint64_t>::max());
}

LowLatencyFrameIdGenerator::~LowLatencyFrameIdGenerator() = default;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -99,17 +106,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 All @@ -127,23 +142,23 @@ namespace dxvk {
static_assert(static_cast<int>(OUT_OF_BAND_PRESENT_END) - 1 == static_cast<int>(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;
}

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::array<uint64_t, 13> 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, 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);
Expand Down
Loading