Skip to content

Commit

Permalink
nvapi: Reflex support through LatencyFleX (v3 changes)
Browse files Browse the repository at this point in the history
  • Loading branch information
ishitatsuyuki committed Feb 8, 2022
1 parent b9b57a5 commit b60b775
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 29 deletions.
41 changes: 29 additions & 12 deletions src/d3d/lfx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,35 @@

namespace dxvk {
Lfx::Lfx() {
const auto lfxModuleName = "latencyflex_wine.dll";
const auto lfxModuleName = "latencyflex_layer.dll";
const auto lfxModuleNameFallback = "latencyflex_wine.dll";
m_lfxModule = ::LoadLibraryA(lfxModuleName);
if (m_lfxModule == nullptr) {
if (m_lfxModule) {
m_lfx_WaitAndBeginFrame = reinterpret_cast<PFN_lfx_WaitAndBeginFrame>(GetProcAddress(m_lfxModule,
"lfx_WaitAndBeginFrame"));
m_lfx_SetTargetFrameTime = reinterpret_cast<PFN_lfx_SetTargetFrameTime>(GetProcAddress(m_lfxModule,
"lfx_SetTargetFrameTime"));
} else {
auto lastError = ::GetLastError();
if (lastError != ERROR_MOD_NOT_FOUND) // Ignore library not found
if (lastError != ERROR_MOD_NOT_FOUND) {
log::write(str::format("Loading ", lfxModuleName, " failed with error code: ", lastError));

return;
} else {
// Try fallback entrypoints. These were used by an older version of LatencyFleX.
m_lfxModule = ::LoadLibraryA(lfxModuleNameFallback);
if (m_lfxModule) {
m_lfx_WaitAndBeginFrame = reinterpret_cast<PFN_lfx_WaitAndBeginFrame>(GetProcAddress(m_lfxModule,
"winelfx_WaitAndBeginFrame"));
m_lfx_SetTargetFrameTime = reinterpret_cast<PFN_lfx_SetTargetFrameTime>(GetProcAddress(m_lfxModule,
"winelfx_SetTargetFrameTime"));
} else {
lastError = ::GetLastError();
if (lastError != ERROR_MOD_NOT_FOUND) // Ignore library not found
log::write(
str::format("Loading ", lfxModuleNameFallback, " failed with error code: ", lastError));
return;
}
}
}

m_winelfx_WaitAndBeginFrame = reinterpret_cast<PFN_winelfx_WaitAndBeginFrame>(reinterpret_cast<void*>(GetProcAddress(m_lfxModule, "winelfx_WaitAndBeginFrame")));
m_winelfx_SetTargetFrameTime = reinterpret_cast<PFN_winelfx_SetTargetFrameTime>(reinterpret_cast<void*>(GetProcAddress(m_lfxModule, "winelfx_SetTargetFrameTime")));
}

Lfx::~Lfx() {
Expand All @@ -31,12 +48,12 @@ namespace dxvk {
}

void Lfx::WaitAndBeginFrame() {
if (m_winelfx_WaitAndBeginFrame)
m_winelfx_WaitAndBeginFrame();
if (m_lfx_WaitAndBeginFrame)
m_lfx_WaitAndBeginFrame();
}

void Lfx::SetTargetFrameTime(uint64_t frame_time_ns) {
if (m_winelfx_SetTargetFrameTime)
m_winelfx_SetTargetFrameTime(static_cast<__int64>(frame_time_ns));
if (m_lfx_SetTargetFrameTime)
m_lfx_SetTargetFrameTime(static_cast<__int64>(frame_time_ns));
}
}
8 changes: 4 additions & 4 deletions src/d3d/lfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ namespace dxvk {
HMODULE m_lfxModule{};
bool m_enabled = false;

typedef void (*PFN_winelfx_WaitAndBeginFrame)();
typedef void (*PFN_winelfx_SetTargetFrameTime)(__int64);
typedef void (*PFN_lfx_WaitAndBeginFrame)();
typedef void (*PFN_lfx_SetTargetFrameTime)(__int64);

PFN_winelfx_WaitAndBeginFrame m_winelfx_WaitAndBeginFrame{};
PFN_winelfx_SetTargetFrameTime m_winelfx_SetTargetFrameTime{};
PFN_lfx_WaitAndBeginFrame m_lfx_WaitAndBeginFrame{};
PFN_lfx_SetTargetFrameTime m_lfx_SetTargetFrameTime{};
};
}
6 changes: 2 additions & 4 deletions src/d3d/nvapi_d3d_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

namespace dxvk {
NvapiD3dInstance::NvapiD3dInstance(ResourceFactory &resourceFactory)
: m_resourceFactory(resourceFactory) {

}
: m_resourceFactory(resourceFactory) {}

NvapiD3dInstance::~NvapiD3dInstance() = default;

Expand All @@ -28,7 +26,7 @@ namespace dxvk {
}

void NvapiD3dInstance::Sleep() {
if(IsReflexAvailable() && m_isLfxEnabled)
if (m_isLfxEnabled)
m_lfx->WaitAndBeginFrame();
}

Expand Down
34 changes: 26 additions & 8 deletions tests/nvapi_d3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,32 @@ TEST_CASE("Reflex methods", "[.d3d]"){

auto e = ConfigureDefaultTestEnvironment(*dxgiFactory, *vulkan, *nvml, *lfx, adapter, output);

SECTION("Enabling Reflex does not return OK when LFX is unavailable") {
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_SET_SLEEP_MODE_PARAMS params {};
params.version = NV_SET_SLEEP_MODE_PARAMS_VER;
params.bLowLatencyMode = true;
REQUIRE(NvAPI_D3D_SetSleepMode(&unknown, &params) != NVAPI_OK);
SECTION("LatencyFleX-depending methods return NoImplementation when LFX is unavailable") {
SECTION("GetSleepStatus returns NoImplementation") {
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_GET_SLEEP_STATUS_PARAMS params{};
params.version = NV_GET_SLEEP_STATUS_PARAMS_VER;
REQUIRE(NvAPI_D3D_GetSleepStatus(&unknown, &params) == NVAPI_NO_IMPLEMENTATION);
}

SECTION("SetSleepMode returns NoImplementation") {
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_SET_SLEEP_MODE_PARAMS params{};
params.version = NV_SET_SLEEP_MODE_PARAMS_VER;
params.bLowLatencyMode = true;
REQUIRE(NvAPI_D3D_SetSleepMode(&unknown, &params) == NVAPI_NO_IMPLEMENTATION);
}

SECTION("Sleep returns NoImplementation") {
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

REQUIRE(NvAPI_D3D_Sleep(&unknown) == NVAPI_NO_IMPLEMENTATION);
}
}

SECTION("Reflex methods work when LFX is available") {
Expand Down
2 changes: 1 addition & 1 deletion tests/nvapi_d3d12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ TEST_CASE("D3D12 methods succeed", "[.d3d12]") {
}

SECTION("GetGraphicsCapabilities with future struct version returns incompatible-struct-version") {
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml));
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_D3D12_GRAPHICS_CAPS graphicsCaps{};
Expand Down

0 comments on commit b60b775

Please sign in to comment.