Skip to content

Commit

Permalink
nvapi: Reflex support through LatencyFleX (v2 changes)
Browse files Browse the repository at this point in the history
  • Loading branch information
ishitatsuyuki committed Jan 24, 2022
1 parent bd6d161 commit c985e96
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 73 deletions.
18 changes: 10 additions & 8 deletions src/d3d/nvapi_d3d_instance.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
#include "../util/util_log.h"
#include "nvapi_d3d_instance.h"

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

}

NvapiD3dInstance::~NvapiD3dInstance() {
NvapiD3dInstance::~NvapiD3dInstance() = default;

}

bool NvapiD3dInstance::Initialize() {
void NvapiD3dInstance::Initialize() {
m_lfx = m_resourceFactory.CreateLfx();
return true;
if (m_lfx->IsAvailable())
log::write("LatencyFleX loaded and initialized successfully");
}

bool NvapiD3dInstance::IsReflexAvailable() {
Expand All @@ -31,7 +32,8 @@ namespace dxvk {
m_lfx->WaitAndBeginFrame();
}

void NvapiD3dInstance::SetTargetFrameTime(uint64_t frameTimeNs) {
m_lfx->SetTargetFrameTime(frameTimeNs);
void NvapiD3dInstance::SetTargetFrameTime(uint64_t frameTimeUs) {
constexpr uint64_t kNanoInMicro = 1000;
m_lfx->SetTargetFrameTime(frameTimeUs * kNanoInMicro);
}
}
6 changes: 3 additions & 3 deletions src/d3d/nvapi_d3d_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ namespace dxvk {
explicit NvapiD3dInstance(ResourceFactory &resourceFactory);
~NvapiD3dInstance();

bool Initialize();
bool IsReflexAvailable();
void Initialize();
[[nodiscard]] bool IsReflexAvailable();
[[nodiscard]] bool IsReflexEnabled() const;
void SetReflexEnabled(bool value);
void Sleep();
void SetTargetFrameTime(uint64_t frameTimeNs);
void SetTargetFrameTime(uint64_t frameTimeUs);

private:
ResourceFactory& m_resourceFactory;
Expand Down
6 changes: 1 addition & 5 deletions src/nvapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,7 @@ extern "C" {
}

nvapiD3dInstance = std::make_unique<NvapiD3dInstance>(*resourceFactory);
if (!nvapiD3dInstance->Initialize()) {
nvapiD3dInstance.reset();
--initializationCount;
return NvidiaDeviceNotFound(n);
}
nvapiD3dInstance->Initialize();

return Ok(n);
}
Expand Down
54 changes: 33 additions & 21 deletions src/nvapi_d3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,43 +91,55 @@ extern "C" {

NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown *pDevice) {
constexpr auto n = __func__;
static bool alreadyLogged = false;
if (!nvapiD3dInstance->IsReflexAvailable()) {
return NoImplementation(n, alreadyLogged);
}
static bool alreadyLoggedOk = false;
static bool alreadyLoggedUnavailable = false;

if (pDevice == nullptr)
return InvalidArgument(n);

if (!nvapiD3dInstance->IsReflexAvailable())
return NoImplementation(n, alreadyLoggedUnavailable);

nvapiD3dInstance->Sleep();
return Ok(n, alreadyLogged);

return Ok(n, alreadyLoggedOk);
}

NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown *pDevice,
NV_SET_SLEEP_MODE_PARAMS *pSetSleepModeParams) {
constexpr auto n = __func__;
if (pSetSleepModeParams->version != NV_SET_SLEEP_MODE_PARAMS_VER1) return IncompatibleStructVersion(n);
if (!nvapiD3dInstance->IsReflexAvailable()) {
log::write(str::format(n, ": Wine LFX module unavailable"));
return NoImplementation();
}
auto f = str::format(n, " (", pSetSleepModeParams->bLowLatencyMode ? "Enable" : "Disable", ")");
if (pSetSleepModeParams->bLowLatencyMode && !nvapiD3dInstance->IsReflexAvailable()) {
log::write(str::format(n, ": tried to enable Reflex but Wine LFX module is not available!"));
}
static bool alreadyLoggedUnavailable = false;

if (pDevice == nullptr)
return InvalidArgument(n);

if (pSetSleepModeParams->version != NV_SET_SLEEP_MODE_PARAMS_VER1)
return IncompatibleStructVersion(n);

if (!nvapiD3dInstance->IsReflexAvailable())
return NoImplementation(n, alreadyLoggedUnavailable);

nvapiD3dInstance->SetReflexEnabled(pSetSleepModeParams->bLowLatencyMode);
if (pSetSleepModeParams->bLowLatencyMode) {
log::write(str::format(n, ": interval ", pSetSleepModeParams->minimumIntervalUs, " us"));
constexpr uint64_t kNanoInMicro = 1000;
nvapiD3dInstance->SetTargetFrameTime(pSetSleepModeParams->minimumIntervalUs * kNanoInMicro);
nvapiD3dInstance->SetTargetFrameTime(pSetSleepModeParams->minimumIntervalUs);
}

auto f = str::format(n, " (", pSetSleepModeParams->bLowLatencyMode ? "Enable" : "Disable", ")");
return Ok(f);
}

NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown *pDevice,
NV_GET_SLEEP_STATUS_PARAMS *pGetSleepStatusParams) {
constexpr auto n = __func__;
if (pGetSleepStatusParams->version != NV_GET_SLEEP_STATUS_PARAMS_VER1) return IncompatibleStructVersion(n);
if (!nvapiD3dInstance->IsReflexAvailable()) {
log::write(str::format(n, ": Wine LFX module unavailable"));
return NoImplementation();
}
static bool alreadyLoggedUnavailable = false;

if (pGetSleepStatusParams->version != NV_GET_SLEEP_STATUS_PARAMS_VER1)
return IncompatibleStructVersion(n);

if (!nvapiD3dInstance->IsReflexAvailable())
return NoImplementation(n, alreadyLoggedUnavailable);

pGetSleepStatusParams->bLowLatencyMode = nvapiD3dInstance->IsReflexEnabled();
return Ok(n);
}
Expand Down
73 changes: 37 additions & 36 deletions tests/nvapi_d3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ TEST_CASE("D3D methods succeed", "[.d3d]") {
REQUIRE(NvAPI_D3D1x_GetGraphicsCapabilities(&unknown, NV_D3D1x_GRAPHICS_CAPS_VER+1, reinterpret_cast<NV_D3D1x_GRAPHICS_CAPS*>(&caps)) == NVAPI_INCOMPATIBLE_STRUCT_VERSION);
}
}
TEST_CASE("Reflex method behavior", "[.d3d]"){
TEST_CASE("Reflex methods", "[.d3d]"){
UnknownMock unknown;
auto dxgiFactory = std::make_unique<DXGIFactory1Mock>();
auto vulkan = std::make_unique<VulkanMock>();
Expand All @@ -71,45 +71,46 @@ TEST_CASE("Reflex method behavior", "[.d3d]"){
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_SET_SLEEP_MODE_PARAMS_V1 params {};
params.version = NV_SET_SLEEP_MODE_PARAMS_VER1;
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("GetSleepStatus (V1) returns OK") {
SECTION("Reflex methods work when LFX is available") {
ALLOW_CALL(*lfx, IsAvailable()).RETURN(true); // NOLINT(bugprone-use-after-move)
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_GET_SLEEP_STATUS_PARAMS_V1 params {};
params.version = NV_GET_SLEEP_STATUS_PARAMS_VER1;
REQUIRE(NvAPI_D3D_GetSleepStatus(&unknown, &params) == NVAPI_OK);
}

SECTION("SetSleepMode returns OK") {
ALLOW_CALL(*lfx, IsAvailable()).RETURN(true); // NOLINT(bugprone-use-after-move)
ALLOW_CALL(*lfx, SetTargetFrameTime(UINT64_C(0)));
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_SET_SLEEP_MODE_PARAMS_V1 params {};
params.version = NV_SET_SLEEP_MODE_PARAMS_VER1;
params.bLowLatencyMode = true;
REQUIRE(NvAPI_D3D_SetSleepMode(&unknown, &params) == NVAPI_OK);
}

SECTION("Sleep calls LFX bridge function") {
ALLOW_CALL(*lfx, IsAvailable()).RETURN(true); // NOLINT(bugprone-use-after-move)
ALLOW_CALL(*lfx, SetTargetFrameTime(UINT64_C(0)));
REQUIRE_CALL(*lfx, WaitAndBeginFrame());
SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx));
REQUIRE(NvAPI_Initialize() == NVAPI_OK);

NV_SET_SLEEP_MODE_PARAMS_V1 params {};
params.version = NV_SET_SLEEP_MODE_PARAMS_VER1;
params.bLowLatencyMode = true;
REQUIRE(NvAPI_D3D_SetSleepMode(&unknown, &params) == NVAPI_OK);
REQUIRE(NvAPI_D3D_Sleep(&unknown) == NVAPI_OK);
SECTION("GetSleepStatus returns OK") {
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_OK);
}

SECTION("SetSleepMode returns OK") {
REQUIRE_CALL(*lfx, SetTargetFrameTime(UINT64_C(0))); // NOLINT(bugprone-use-after-move)
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("Sleep calls LFX throttle callback and returns OK") {
REQUIRE_CALL(*lfx, SetTargetFrameTime(UINT64_C(0))); // NOLINT(bugprone-use-after-move)
REQUIRE_CALL(*lfx, WaitAndBeginFrame());
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);
REQUIRE(NvAPI_D3D_Sleep(&unknown) == NVAPI_OK);
}
}
}

0 comments on commit c985e96

Please sign in to comment.