WIP: Common Low Latency inputs

This commit is contained in:
FakeMichau
2026-05-19 02:24:30 +02:00
parent 733567616b
commit cc721bfdaa
15 changed files with 555 additions and 26 deletions
+2
View File
@@ -328,6 +328,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClInclude Include="hooks\Hook_Utils.h" />
<ClInclude Include="hooks\LibraryLoad_Hooks.h" />
<ClInclude Include="hooks\CommandBuffer_StateTracker.h" />
<ClInclude Include="low_latency\input\input_common.h" />
<ClInclude Include="low_latency\input\input_reflex.h" />
<ClInclude Include="low_latency\input\input_xell.h" />
<ClInclude Include="low_latency\input\input_antilag2.h" />
@@ -592,6 +593,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClCompile Include="hooks\LibraryLoad_Hooks.cpp" />
<ClCompile Include="hooks\VulkanwDx12_Hooks.cpp" />
<ClCompile Include="hooks\Xell_Hooks.cpp" />
<ClCompile Include="low_latency\input\input_common.cpp" />
<ClCompile Include="low_latency\input\input_reflex.cpp" />
<ClCompile Include="low_latency\input\input_xell.cpp" />
<ClCompile Include="low_latency\input\input_antilag2.cpp" />
+6
View File
@@ -872,6 +872,9 @@
<ClInclude Include="shaders\rcas\shaders\RCAS_Shader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="low_latency\input\input_common.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Config.cpp">
@@ -1355,6 +1358,9 @@
<ClCompile Include="low_latency\input\input_reflex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="low_latency\input\input_common.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="OptiScaler.rc" />
@@ -0,0 +1,353 @@
#include "pch.h"
#include "input_common.h"
#include <low_latency/low_latency_tech/ll_xell.h>
bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional<LowLatencyMode> mode)
{
LowLatencyMode desiredMode = LowLatencyMode::None;
if (!pDevice)
{
// Some outputs might call sleep with nullptr
if (activeOutput != LowLatencyMode::None && !mode.has_value())
return true; // Allow it if we already have an output and not trying to set manually
else
return false;
}
if (mode.has_value())
desiredMode = mode.value();
if (desiredMode != LowLatencyMode::None && desiredMode == activeOutput)
{
// No need to do anything
return true;
}
// TODO: init correct currently_active_tech, desiredMode == None -> Auto
if (auto current_tech = currently_active_tech.load())
{
activeOutput = current_tech->get_mode();
return true;
}
LOG_ERROR("No Low Latency Tech selected");
return false;
}
void InputCommon::add_marker_to_report(MarkerParams* marker_params)
{
auto current_timestamp = get_timestamp() / 1000;
static auto last_sim_start = current_timestamp;
static auto _2nd_last_sim_start = current_timestamp;
auto current_report = &frame_reports[marker_params->frame_id % FRAME_REPORTS_BUFFER_SIZE];
if (current_report->frameID != marker_params->frame_id)
{
*current_report = FrameReport {};
}
current_report->frameID = marker_params->frame_id;
current_report->gpuFrameTimeUs = (uint32_t) (last_sim_start - _2nd_last_sim_start);
current_report->gpuActiveRenderTimeUs = 100;
current_report->driverStartTime = current_timestamp;
current_report->driverEndTime = current_timestamp + 100;
current_report->gpuRenderStartTime = current_timestamp;
current_report->gpuRenderEndTime = current_timestamp + 100;
current_report->osRenderQueueStartTime = current_timestamp;
current_report->osRenderQueueEndTime = current_timestamp + 100;
switch (marker_params->marker_type)
{
case MarkerType::SIMULATION_START:
_2nd_last_sim_start = last_sim_start;
last_sim_start = get_timestamp() / 1000;
current_report->simStartTime = last_sim_start;
break;
case MarkerType::SIMULATION_END:
current_report->simEndTime = get_timestamp() / 1000;
break;
case MarkerType::RENDERSUBMIT_START:
current_report->renderSubmitStartTime = get_timestamp() / 1000;
break;
case MarkerType::RENDERSUBMIT_END:
current_report->renderSubmitEndTime = get_timestamp() / 1000;
break;
case MarkerType::PRESENT_START:
current_report->presentStartTime = get_timestamp() / 1000;
break;
case MarkerType::PRESENT_END:
current_report->presentEndTime = get_timestamp() / 1000;
break;
case MarkerType::INPUT_SAMPLE:
current_report->inputSampleTime = get_timestamp() / 1000;
break;
default:
break;
}
}
InputResult InputCommon::set_low_latency_tech(IUnknown* pDevice, LowLatencyMode mode)
{
if (!update_low_latency_tech(pDevice, mode))
return InputResult::LowLatencyUpdateFail;
return InputResult::Ok;
}
InputResult InputCommon::sleep(IUnknown* pDevice, const InputContext& inputContext, std::optional<uint32_t> frame_id)
{
if (!update_low_latency_tech(pDevice))
return InputResult::LowLatencyUpdateFail;
if (auto current_tech = currently_active_tech.load())
current_tech->sleep(frame_id);
else
return InputResult::GenericError;
return InputResult::Ok;
}
InputResult InputCommon::set_marker(const InputContext& inputContext, IUnknown* pDevice, MarkerParams* marker_params)
{
if (!update_low_latency_tech(pDevice))
return InputResult::LowLatencyUpdateFail;
if (!marker_params)
return InputResult::InvalidParameter;
if (inputContext.markerMode == InputMarkerMode::NoMarkers)
{
return InputResult::InputNotSupported;
}
else if (inputContext.markerMode == InputMarkerMode::PresentStartOnly &&
marker_params->marker_type != MarkerType::PRESENT_START)
{
return InputResult::InputNotSupported;
}
// update_effective_fg_state();
// update_enabled_override();
add_marker_to_report(marker_params);
if (auto current_tech = currently_active_tech.load())
current_tech->set_marker(pDevice, marker_params);
else
return InputResult::GenericError;
LOG_TRACE_LOWLATENCY("{}: {}", magic_enum::enum_name(marker_params->marker_type), marker_params->frame_id);
return InputResult::Ok;
}
InputResult InputCommon::set_async_marker(const InputContext& inputContext, ID3D12CommandQueue* pCommandQueue,
MarkerParams* marker_params)
{
if (!currently_active_tech.load()) // can't init using ID3D12CommandQueue, can only check if available
return InputResult::LowLatencyUpdateFail;
if (!marker_params)
return InputResult::InvalidParameter;
if (inputContext.markerMode == InputMarkerMode::NoMarkers)
{
return InputResult::InputNotSupported;
}
else if (inputContext.markerMode == InputMarkerMode::PresentStartOnly &&
marker_params->marker_type != MarkerType::OUT_OF_BAND_PRESENT_START)
{
return InputResult::InputNotSupported;
}
// TODO: could consider adding async markers to the report but would require some rewriting
// add_marker_to_report(marker_params);
if (auto current_tech = currently_active_tech.load())
current_tech->set_async_marker(pCommandQueue, marker_params);
else
return InputResult::GenericError;
LOG_TRACE_LOWLATENCY("{}: {}", magic_enum::enum_name(marker_params->marker_type), marker_params->frame_id);
return InputResult::Ok;
}
// TODO: impl
InputResult InputCommon::set_sleep_mode(const InputContext& inputContext, IUnknown* pDevice, SleepMode* sleep_mode)
{
return InputResult::Ok;
}
// TODO: impl
InputResult InputCommon::get_sleep_status(const InputContext& inputContext, IUnknown* pDevice,
SleepParams* sleep_params)
{
return InputResult::Ok;
}
InputResult InputCommon::get_latency(const InputContext& inputContext, IUnknown* pDev, void* latency_params)
{
if (!latency_params)
return InputResult::InvalidParameter;
if (inputContext.caller == LowLatencyInput::Reflex)
{
if (activeOutput == LowLatencyMode::Reflex)
{
// TODO: passthrough call, if success return InputResult::Ok;
// return InputResult::Ok;
}
NV_LATENCY_RESULT_PARAMS* reports = (NV_LATENCY_RESULT_PARAMS*) latency_params;
if (reports->version != NV_LATENCY_RESULT_PARAMS_VER1)
{
LOG_ERROR("Unsupported version {}", reports->version);
return InputResult::InvalidParameter;
}
// Assume no frame reports collected yet, report all zeros
if (frame_reports[FRAME_REPORTS_BUFFER_SIZE - 1].frameID == 0)
{
std::memset(reports->frameReport, 0, sizeof(reports->frameReport));
// spdlog::warn("GetLatency: Not enough data to report");
return InputResult::GenericError;
}
// Sort frame reports, find the oldest
size_t minIdx = 0;
uint64_t minID = frame_reports[0].frameID;
for (size_t i = 1; i < FRAME_REPORTS_BUFFER_SIZE; i++)
{
if (frame_reports[i].frameID < minID)
{
minID = frame_reports[i].frameID;
minIdx = i;
}
}
// Copy starting from older before wrapping around
size_t firstChunk = std::min<uint64_t>(NVAPI_BUFFER_SIZE, FRAME_REPORTS_BUFFER_SIZE - minIdx);
std::memcpy(reports->frameReport, frame_reports + minIdx, firstChunk * sizeof(FrameReport));
// Copy the rest after wrapping around
if (firstChunk < NVAPI_BUFFER_SIZE)
{
std::memcpy(reports->frameReport + firstChunk, frame_reports,
(NVAPI_BUFFER_SIZE - firstChunk) * sizeof(FrameReport));
}
return InputResult::Ok;
}
else if (inputContext.caller == LowLatencyInput::XeLL)
{
if (activeOutput == LowLatencyMode::XeLL)
{
// TODO: passthrough call, if success return InputResult::Ok;
// return InputResult::Ok;
}
xell_frame_report_t* reports = (xell_frame_report_t*) latency_params;
constexpr size_t reportCount = 64; // 64 reports, if the app allocated less then it's on them
// Hopefully not too slow
// XeLL doesn't seem to make any guarantees about ordering so no sort needed
for (auto i = 0; i < reportCount; i++)
{
auto& reportOut = reports[i];
auto& reportIn = frame_reports[i];
reportOut.m_frame_id = reportIn.frameID & 0xFFFFFFFF;
reportOut.m_sim_start_ts = reportIn.simStartTime;
reportOut.m_sim_end_ts = reportIn.simEndTime;
reportOut.m_render_submit_start_ts = reportIn.renderSubmitStartTime;
reportOut.m_render_submit_end_ts = reportIn.renderSubmitEndTime;
reportOut.m_present_start_ts = reportIn.presentStartTime;
reportOut.m_present_end_ts = reportIn.presentEndTime;
}
return InputResult::Ok;
}
else
{
return InputResult::InputNotSupported;
}
}
xell_result_t InputCommon::pass_xellD3D12SetAppQueue(const InputContext& inputContext, void* appQueue)
{
if (inputContext.caller == LowLatencyInput::XeLL && activeInput == LowLatencyInput::XeLL &&
activeOutput == LowLatencyMode::XeLL)
{
if (auto current_tech = currently_active_tech.load())
{
auto xell_tech = std::static_pointer_cast<XeLL>(current_tech);
return xell_tech->xellD3D12SetAppQueue(appQueue);
}
}
return XELL_RESULT_ERROR_UNKNOWN;
}
xell_result_t InputCommon::pass_xellSetDisplayInfo(const InputContext& inputContext, void* displayInfo)
{
if (inputContext.caller == LowLatencyInput::XeLL && activeInput == LowLatencyInput::XeLL &&
activeOutput == LowLatencyMode::XeLL)
{
if (auto current_tech = currently_active_tech.load())
{
auto xell_tech = std::static_pointer_cast<XeLL>(current_tech);
return xell_tech->xellSetDisplayInfo(displayInfo);
}
}
return XELL_RESULT_ERROR_UNKNOWN;
}
xell_result_t InputCommon::pass_xellSetFgEnabled(const InputContext& inputContext, uint32_t param1, uint32_t param2)
{
if (inputContext.caller == LowLatencyInput::XeLL && activeInput == LowLatencyInput::XeLL &&
activeOutput == LowLatencyMode::XeLL)
{
if (auto current_tech = currently_active_tech.load())
{
auto xell_tech = std::static_pointer_cast<XeLL>(current_tech);
return xell_tech->xellSetFgEnabled(param1, param2);
}
}
return XELL_RESULT_ERROR_UNKNOWN;
}
xell_result_t InputCommon::pass_xellSetGeneratedFramesCount(const InputContext& inputContext, uint32_t param1,
uint32_t framesCount)
{
if (inputContext.caller == LowLatencyInput::XeLL && activeInput == LowLatencyInput::XeLL &&
activeOutput == LowLatencyMode::XeLL)
{
if (auto current_tech = currently_active_tech.load())
{
auto xell_tech = std::static_pointer_cast<XeLL>(current_tech);
return xell_tech->xellSetGeneratedFramesCount(param1, framesCount);
}
}
return XELL_RESULT_ERROR_UNKNOWN;
}
xell_result_t InputCommon::pass_xellGetLastPresentStartFrameId(const InputContext& inputContext, uint32_t* p_frame_id)
{
if (inputContext.caller == LowLatencyInput::XeLL && activeInput == LowLatencyInput::XeLL &&
activeOutput == LowLatencyMode::XeLL)
{
if (auto current_tech = currently_active_tech.load())
{
auto xell_tech = std::static_pointer_cast<XeLL>(current_tech);
return xell_tech->xellGetLastPresentStartFrameId(p_frame_id);
}
}
return XELL_RESULT_ERROR_UNKNOWN;
}
+102
View File
@@ -0,0 +1,102 @@
#pragma once
#include <low_latency/low_latency_tech/low_latency_tech.h>
#include <xell.h>
enum class LowLatencyInput
{
None,
AntiLag2,
Reflex,
XeLL
};
#define FRAME_REPORTS_BUFFER_SIZE 70
#define NVAPI_BUFFER_SIZE 64
struct FrameReport
{
uint64_t frameID;
uint64_t inputSampleTime;
uint64_t simStartTime;
uint64_t simEndTime;
uint64_t renderSubmitStartTime;
uint64_t renderSubmitEndTime;
uint64_t presentStartTime;
uint64_t presentEndTime;
uint64_t driverStartTime;
uint64_t driverEndTime;
uint64_t osRenderQueueStartTime;
uint64_t osRenderQueueEndTime;
uint64_t gpuRenderStartTime;
uint64_t gpuRenderEndTime;
uint32_t gpuActiveRenderTimeUs;
uint32_t gpuFrameTimeUs;
uint64_t cameraConstructedTime;
uint32_t crossAdapterCopyTimeUs;
uint32_t aiFrameTimeUs;
uint8_t rsvd[104];
};
enum class InputMarkerMode
{
NoMarkers,
PresentStartOnly,
FullMarkers,
};
struct InputContext
{
LowLatencyInput caller;
// bool sleepWithFrameId;
bool noFrameId;
InputMarkerMode markerMode;
};
enum class InputResult : uint32_t
{
Ok,
InputNotSupported,
InvalidParameter,
LowLatencyUpdateFail,
GenericError,
};
class InputCommon
{
inline static std::atomic<std::shared_ptr<LowLatencyTech>> currently_active_tech;
inline static FrameReport frame_reports[FRAME_REPORTS_BUFFER_SIZE] {};
inline static LowLatencyInput activeInput = LowLatencyInput::None;
inline static LowLatencyMode activeOutput = LowLatencyMode::None;
inline static bool enabled = false;
static bool update_low_latency_tech(IUnknown* pDevice, std::optional<LowLatencyMode> mode = std::nullopt);
static void add_marker_to_report(MarkerParams* marker_params);
public:
static InputResult set_low_latency_tech(IUnknown* pDevice, LowLatencyMode mode);
// TODO: Ignore all calls that are not coming for the activeInput
static InputResult sleep(IUnknown* pDevice, const InputContext& inputContext,
std::optional<uint32_t> frame_id = std::nullopt);
static InputResult set_marker(const InputContext& inputContext, IUnknown* pDevice, MarkerParams* marker_params);
static InputResult set_async_marker(const InputContext& inputContext, ID3D12CommandQueue* pCommandQueue,
MarkerParams* marker_params);
static InputResult set_sleep_mode(const InputContext& inputContext, IUnknown* pDevice, SleepMode* sleep_mode);
static InputResult get_sleep_status(const InputContext& inputContext, IUnknown* pDevice, SleepParams* sleep_params);
static InputResult
get_latency(const InputContext& inputContext, IUnknown* pDev,
void* latency_params); // NV_LATENCY_RESULT_PARAMS* for reflex, xell_frame_report_t* for xell,
// passthrough when possible, fillout with local frame_reports if not
// XeLL-specific calls for passthrough, TODO: only allow when caller == activeOutput == activeInput == XeLL
static xell_result_t pass_xellD3D12SetAppQueue(
const InputContext& inputContext,
void* appQueue); // if it's ID3D12CommandQueue* then some translation with async markers can be made
static xell_result_t pass_xellSetDisplayInfo(const InputContext& inputContext, void* displayInfo);
static xell_result_t pass_xellSetFgEnabled(const InputContext& inputContext, uint32_t param1, uint32_t param2);
static xell_result_t pass_xellSetGeneratedFramesCount(const InputContext& inputContext, uint32_t param1,
uint32_t framesCount);
static xell_result_t pass_xellGetLastPresentStartFrameId(const InputContext& inputContext,
uint32_t* p_frame_id); // Maybe not needed
};
+2 -1
View File
@@ -22,7 +22,8 @@ enum class LowLatencyMode
LatencyFlex,
AntiLag2,
XeLL,
AntiLagVk
AntiLagVk,
Reflex
};
void tonvss(NvAPI_ShortString nvss, std::string str);
@@ -185,7 +185,7 @@ void AntiLag2::set_sleep_mode(SleepMode* sleep_mode)
sleep_mode->minimum_interval_us; // don't convert to fps due to fg fps limit fallback using intervals
}
void AntiLag2::sleep()
void AntiLag2::sleep(std::optional<uint32_t> frame_id)
{
last_sleep_framecount = simulation_framecount;
@@ -219,7 +219,7 @@ void AntiLag2::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
}
}
void AntiLag2::set_async_marker(MarkerParams* marker_params)
void AntiLag2::set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params)
{
if (marker_params->marker_type == MarkerType::OUT_OF_BAND_PRESENT_START)
{
@@ -5,7 +5,7 @@
#include <ffx_antilag2_dx12.h>
#include <ffx_antilag2_dx11.h>
class AntiLag2 : public virtual LowLatencyTech
class AntiLag2 : public LowLatencyTech
{
private:
AMD::AntiLag2DX12::Context dx12_ctx = {};
@@ -47,7 +47,7 @@ class AntiLag2 : public virtual LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override;
};
@@ -32,7 +32,7 @@ void AntiLagVk::set_sleep_mode(SleepMode* sleep_mode)
sleep_mode->minimum_interval_us > 0 ? (uint32_t) std::round(1000000.0f / sleep_mode->minimum_interval_us) : 0;
}
void AntiLagVk::sleep()
void AntiLagVk::sleep(std::optional<uint32_t> frame_id)
{
// This can be supported but prefer using markers with frame ids instead
return;
@@ -2,7 +2,7 @@
#include "low_latency_tech.h"
class AntiLagVk : public virtual LowLatencyTech
class AntiLagVk : public LowLatencyTech
{
private:
uint32_t max_fps = 0;
@@ -32,7 +32,7 @@ class AntiLagVk : public virtual LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override {}; // Not used by AntiLag VK
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override {}; // Not used by AntiLag VK
};
@@ -152,14 +152,19 @@ void LatencyFlex::set_sleep_mode(SleepMode* sleep_mode)
minimum_interval_us = sleep_mode->minimum_interval_us;
};
void LatencyFlex::sleep()
void LatencyFlex::sleep(std::optional<uint32_t> frame_id)
{
if ((LFXMode) Config::Instance()->FN_LatencyFlexMode.value_or_default() != LFXMode::ReflexIDs)
{
last_sleep_framecount = simulation_framecount;
if (current_call_spot == CallSpot::SleepCall)
lfx_sleep(INVALID_ID);
{
if (frame_id.has_value())
lfx_sleep(frame_id.value());
else
lfx_sleep(INVALID_ID);
}
}
};
@@ -3,7 +3,7 @@
#include "low_latency_tech.h"
#include <latencyflex.h>
class LatencyFlex : public virtual LowLatencyTech
class LatencyFlex : public LowLatencyTech
{
private:
lfx::LatencyFleX* ctx = nullptr;
@@ -51,7 +51,7 @@ class LatencyFlex : public virtual LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override {}; // Not used by LFX
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override {}; // Not used by LFX
};
@@ -183,10 +183,55 @@ void XeLL::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
}
}
void XeLL::sleep()
void XeLL::sleep(std::optional<uint32_t> frame_id)
{
// This can either be better than sleeping in XELL_SIMULATION_START
// or be a total mess if +1 is not correct
sleep_last_id = simulation_start_last_id + 1;
xell_sleep((uint32_t) sleep_last_id);
if (frame_id.has_value())
xell_sleep(frame_id.value());
else
{
// This can either be better than sleeping in XELL_SIMULATION_START
// or be a total mess if +1 is not correct
sleep_last_id = simulation_start_last_id + 1;
xell_sleep((uint32_t) sleep_last_id);
}
}
xell_result_t XeLL::xellD3D12SetAppQueue(void* appQueue) const
{
if (!o_xellD3D12SetAppQueue)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellD3D12SetAppQueue(XeLLProxy::Context(), appQueue);
}
xell_result_t XeLL::xellSetDisplayInfo(void* displayInfo) const
{
if (!o_xellSetDisplayInfo)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellSetDisplayInfo(XeLLProxy::Context(), displayInfo);
}
xell_result_t XeLL::xellSetFgEnabled(uint32_t param1, uint32_t param2) const
{
if (!o_xellSetFgEnabled)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellSetFgEnabled(XeLLProxy::Context(), param1, param2);
}
xell_result_t XeLL::xellSetGeneratedFramesCount(uint32_t param1, uint32_t framesCount) const
{
if (!o_xellSetGeneratedFramesCount)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellSetGeneratedFramesCount(XeLLProxy::Context(), param1, framesCount);
}
xell_result_t XeLL::xellGetLastPresentStartFrameId(uint32_t* p_frame_id) const
{
if (!o_xellGetLastPresentStartFrameId)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellGetLastPresentStartFrameId(XeLLProxy::Context(), p_frame_id);
}
@@ -3,13 +3,21 @@
#include "low_latency_tech.h"
#include <xell_d3d12.h>
#include "low_latency/input/input_xell.h"
class XeLL : public virtual LowLatencyTech
class XeLL : public LowLatencyTech
{
bool sent_sleep_frame_ids[64] {};
uint64_t simulation_start_last_id {};
uint64_t sleep_last_id {};
// TODO: set those
decltype(&xellD3D12SetAppQueue) o_xellD3D12SetAppQueue = nullptr;
decltype(&xellSetDisplayInfo) o_xellSetDisplayInfo = nullptr;
decltype(&xellSetFgEnabled) o_xellSetFgEnabled = nullptr;
decltype(&xellSetGeneratedFramesCount) o_xellSetGeneratedFramesCount = nullptr;
decltype(&xellGetLastPresentStartFrameId) o_xellGetLastPresentStartFrameId = nullptr; // Maybe not needed
void xell_sleep(uint32_t frame_id);
void add_marker(uint32_t frame_id, xell_latency_marker_type_t marker);
@@ -38,7 +46,14 @@ class XeLL : public virtual LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep() override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(MarkerParams* marker_params) override {}; // Not used by XeLL
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override {}; // Not used by XeLL
// For passthrough
xell_result_t xellD3D12SetAppQueue(void* appQueue) const;
xell_result_t xellSetDisplayInfo(void* displayInfo) const;
xell_result_t xellSetFgEnabled(uint32_t param1, uint32_t param2) const;
xell_result_t xellSetGeneratedFramesCount(uint32_t param1, uint32_t framesCount) const;
xell_result_t xellGetLastPresentStartFrameId(uint32_t* p_frame_id) const;
};
@@ -84,7 +84,7 @@ class LowLatencyTech
virtual void get_sleep_status(SleepParams* sleep_params) = 0;
virtual void set_sleep_mode(SleepMode* sleep_mode) = 0;
virtual void sleep() = 0;
virtual void sleep(std::optional<uint32_t> frame_id = std::nullopt) = 0;
virtual void set_marker(IUnknown* pDevice, MarkerParams* marker_params) = 0;
virtual void set_async_marker(MarkerParams* marker_params) = 0;
virtual void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) = 0;
};
@@ -325,7 +325,7 @@ NvAPI_Status LowLatency::SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue,
}
if (auto current_tech = currently_active_tech.load())
current_tech->set_async_marker(&marker_params);
current_tech->set_async_marker(pCommandQueue, &marker_params);
LOG_TRACE_FAKENVAPI("Async {}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id);