WIP: XeLL inputs cont.

This commit is contained in:
FakeMichau
2026-05-19 23:09:07 +02:00
parent fcf81b7ab3
commit aeefd5307a
19 changed files with 487 additions and 175 deletions
+74 -23
View File
@@ -2,6 +2,7 @@
#include "input_common.h"
#include <low_latency/low_latency_tech/ll_xell.h>
// private
bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional<LowLatencyMode> mode)
{
LowLatencyMode desiredMode = LowLatencyMode::None;
@@ -24,7 +25,18 @@ bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional<LowLa
return true;
}
// TODO: Add system for selecting input
if (activeInput == LowLatencyInput::XeLL)
return true;
activeInput = LowLatencyInput::XeLL;
// TODO: init correct currently_active_tech, desiredMode == None -> Auto
auto new_tech_xell = std::make_shared<XeLL>();
if (new_tech_xell->init(pDevice))
{
LOG_INFO("LowLatency algo: XeLL");
currently_active_tech.store(std::move(new_tech_xell));
}
if (auto current_tech = currently_active_tech.load())
{
@@ -36,19 +48,19 @@ bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional<LowLa
return false;
}
void InputCommon::add_marker_to_report(MarkerParams* marker_params)
void InputCommon::add_marker_to_report(const 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];
auto current_report = &frame_reports[marker_params.frame_id % FRAME_REPORTS_BUFFER_SIZE];
if (current_report->frameID != marker_params->frame_id)
if (current_report->frameID != marker_params.frame_id)
{
*current_report = FrameReport {};
}
current_report->frameID = marker_params->frame_id;
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;
@@ -57,7 +69,7 @@ void InputCommon::add_marker_to_report(MarkerParams* marker_params)
current_report->gpuRenderEndTime = current_timestamp + 100;
current_report->osRenderQueueStartTime = current_timestamp;
current_report->osRenderQueueEndTime = current_timestamp + 100;
switch (marker_params->marker_type)
switch (marker_params.marker_type)
{
case MarkerType::SIMULATION_START:
_2nd_last_sim_start = last_sim_start;
@@ -87,6 +99,7 @@ void InputCommon::add_marker_to_report(MarkerParams* marker_params)
}
}
// public
InputResult InputCommon::set_low_latency_tech(IUnknown* pDevice, LowLatencyMode mode)
{
if (!update_low_latency_tech(pDevice, mode))
@@ -95,11 +108,14 @@ InputResult InputCommon::set_low_latency_tech(IUnknown* pDevice, LowLatencyMode
return InputResult::Ok;
}
InputResult InputCommon::sleep(IUnknown* pDevice, const InputContext& inputContext, std::optional<uint32_t> frame_id)
InputResult InputCommon::sleep(const InputContext& inputContext, IUnknown* pDevice, std::optional<uint32_t> frame_id)
{
if (!update_low_latency_tech(pDevice))
return InputResult::LowLatencyUpdateFail;
if (inputContext.caller != activeInput)
return InputResult::UsingDifferentInput;
if (auto current_tech = currently_active_tech.load())
current_tech->sleep(frame_id);
else
@@ -108,20 +124,21 @@ InputResult InputCommon::sleep(IUnknown* pDevice, const InputContext& inputConte
return InputResult::Ok;
}
InputResult InputCommon::set_marker(const InputContext& inputContext, IUnknown* pDevice, MarkerParams* marker_params)
InputResult InputCommon::set_marker(const InputContext& inputContext, IUnknown* pDevice,
const MarkerParams& marker_params)
{
if (!update_low_latency_tech(pDevice))
return InputResult::LowLatencyUpdateFail;
if (!marker_params)
return InputResult::InvalidParameter;
if (inputContext.caller != activeInput)
return InputResult::UsingDifferentInput;
if (inputContext.markerMode == InputMarkerMode::NoMarkers)
{
return InputResult::InputNotSupported;
}
else if (inputContext.markerMode == InputMarkerMode::PresentStartOnly &&
marker_params->marker_type != MarkerType::PRESENT_START)
marker_params.marker_type != MarkerType::PRESENT_START)
{
return InputResult::InputNotSupported;
}
@@ -137,26 +154,26 @@ InputResult InputCommon::set_marker(const InputContext& inputContext, IUnknown*
else
return InputResult::GenericError;
LOG_TRACE_LOWLATENCY("{}: {}", magic_enum::enum_name(marker_params->marker_type), marker_params->frame_id);
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)
const MarkerParams& marker_params)
{
if (inputContext.caller != activeInput)
return InputResult::UsingDifferentInput;
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)
marker_params.marker_type != MarkerType::OUT_OF_BAND_PRESENT_START)
{
return InputResult::InputNotSupported;
}
@@ -169,7 +186,7 @@ InputResult InputCommon::set_async_marker(const InputContext& inputContext, ID3D
else
return InputResult::GenericError;
LOG_TRACE_LOWLATENCY("{}: {}", magic_enum::enum_name(marker_params->marker_type), marker_params->frame_id);
LOG_TRACE_LOWLATENCY("{}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id);
return InputResult::Ok;
}
@@ -177,6 +194,17 @@ InputResult InputCommon::set_async_marker(const InputContext& inputContext, ID3D
// TODO: impl
InputResult InputCommon::set_sleep_mode(const InputContext& inputContext, IUnknown* pDevice, SleepMode* sleep_mode)
{
if (!update_low_latency_tech(pDevice))
return InputResult::LowLatencyUpdateFail;
if (inputContext.caller != activeInput)
return InputResult::UsingDifferentInput;
if (auto current_tech = currently_active_tech.load())
current_tech->set_sleep_mode(sleep_mode);
else
return InputResult::GenericError;
return InputResult::Ok;
}
@@ -184,11 +212,28 @@ InputResult InputCommon::set_sleep_mode(const InputContext& inputContext, IUnkno
InputResult InputCommon::get_sleep_status(const InputContext& inputContext, IUnknown* pDevice,
SleepParams* sleep_params)
{
if (!update_low_latency_tech(pDevice))
return InputResult::LowLatencyUpdateFail;
if (inputContext.caller != activeInput)
return InputResult::UsingDifferentInput;
if (auto current_tech = currently_active_tech.load())
current_tech->get_sleep_status(sleep_params);
else
return InputResult::GenericError;
return InputResult::Ok;
}
InputResult InputCommon::get_latency(const InputContext& inputContext, IUnknown* pDev, void* latency_params)
{
if (inputContext.caller != activeInput)
return InputResult::UsingDifferentInput;
if (!update_low_latency_tech(pDev))
return InputResult::LowLatencyUpdateFail;
if (!latency_params)
return InputResult::InvalidParameter;
@@ -243,15 +288,21 @@ InputResult InputCommon::get_latency(const InputContext& inputContext, IUnknown*
}
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
if (activeOutput == LowLatencyMode::XeLL)
{
if (auto current_tech = currently_active_tech.load())
{
auto xell_tech = std::static_pointer_cast<XeLL>(current_tech);
auto result = xell_tech->xellGetFramesReports(reports);
if (result == XELL_RESULT_SUCCESS)
return InputResult::Ok;
}
}
// 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++)
+7 -32
View File
@@ -10,38 +10,11 @@ enum class LowLatencyInput
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,
FullMarkers, // TODO: add something about xell's partial async markers
};
struct InputContext
@@ -55,6 +28,7 @@ struct InputContext
enum class InputResult : uint32_t
{
Ok,
UsingDifferentInput,
InputNotSupported,
InvalidParameter,
LowLatencyUpdateFail,
@@ -71,17 +45,18 @@ class InputCommon
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);
static void add_marker_to_report(const 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,
static InputResult sleep(const InputContext& inputContext, IUnknown* pDevice,
std::optional<uint32_t> frame_id = std::nullopt);
static InputResult set_marker(const InputContext& inputContext, IUnknown* pDevice, MarkerParams* marker_params);
static InputResult set_marker(const InputContext& inputContext, IUnknown* pDevice,
const MarkerParams& marker_params);
static InputResult set_async_marker(const InputContext& inputContext, ID3D12CommandQueue* pCommandQueue,
MarkerParams* marker_params);
const 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
+116 -17
View File
@@ -14,32 +14,125 @@ xell_result_t InputXeLL::DestroyContext(xell_input_handle_t context)
}
xell_result_t InputXeLL::SetSleepMode(xell_input_handle_t context, const xell_sleep_params_t* param)
{
// TODO: impl
return XELL_RESULT_SUCCESS;
if (!context)
return XELL_RESULT_ERROR_INVALID_CONTEXT;
if (!param)
return XELL_RESULT_ERROR_INVALID_ARGUMENT;
SleepMode sleepMode {};
sleepMode.low_latency_enabled = param->bLowLatencyMode;
sleepMode.low_latency_boost = param->bLowLatencyBoost;
sleepMode.minimum_interval_us = param->minimumIntervalUs;
// TODO: not fully filled out
auto result = InputCommon::set_sleep_mode(inputContext, context->device, &sleepMode);
if (result == InputResult::Ok)
return XELL_RESULT_SUCCESS;
else
LOG_ERROR("set_sleep_mode result: {}", magic_enum::enum_name(result));
return XELL_RESULT_ERROR_UNKNOWN;
}
xell_result_t InputXeLL::GetSleepMode(xell_input_handle_t context, xell_sleep_params_t* param)
{
// TODO: impl
if (!context)
return XELL_RESULT_ERROR_INVALID_CONTEXT;
param->bLowLatencyMode = true;
if (!param)
return XELL_RESULT_ERROR_INVALID_ARGUMENT;
return XELL_RESULT_SUCCESS;
if (!context->device)
return XELL_RESULT_ERROR_DEVICE;
SleepParams sleepParams {};
auto result = InputCommon::get_sleep_status(inputContext, context->device, &sleepParams);
if (result == InputResult::Ok)
{
param->bLowLatencyMode = sleepParams.low_latency_enabled;
param->bLowLatencyBoost = sleepParams.low_latency_boost;
param->minimumIntervalUs = sleepParams.minimum_interval_us;
// TODO: not fully filled out
return XELL_RESULT_SUCCESS;
}
else
{
LOG_ERROR("get_sleep_status result: {}", magic_enum::enum_name(result));
return XELL_RESULT_ERROR_UNKNOWN;
}
}
xell_result_t InputXeLL::Sleep(xell_input_handle_t context, uint32_t frame_id)
{
// TODO: impl
return XELL_RESULT_SUCCESS;
if (!context)
return XELL_RESULT_ERROR_INVALID_CONTEXT;
if (!context->device)
return XELL_RESULT_ERROR_DEVICE;
auto result = InputCommon::sleep(inputContext, context->device, frame_id);
if (result == InputResult::Ok)
return XELL_RESULT_SUCCESS;
else
LOG_ERROR("sleep result: {}", magic_enum::enum_name(result));
return XELL_RESULT_ERROR_UNKNOWN;
}
xell_result_t InputXeLL::AddMarkerData(xell_input_handle_t context, uint32_t frame_id,
xell_latency_marker_type_t marker)
{
// TODO: impl
return XELL_RESULT_SUCCESS;
if (!context)
return XELL_RESULT_ERROR_INVALID_CONTEXT;
if (marker >= XELL_MARKER_COUNT)
{
// TODO: call async, probably, need to understand the high markers
MarkerParams markerParams {};
markerParams.frame_id = frame_id;
if (marker == 80860000)
markerParams.marker_type = MarkerType::OUT_OF_BAND_RENDERSUBMIT_START;
else if (marker == 80860001)
markerParams.marker_type = MarkerType::OUT_OF_BAND_RENDERSUBMIT_END;
else
return XELL_RESULT_ERROR_UNKNOWN;
auto result = InputCommon::set_async_marker(inputContext, context->d3d12AppQueue, markerParams);
if (result == InputResult::Ok)
return XELL_RESULT_SUCCESS;
else
LOG_ERROR("sleep result: {}", magic_enum::enum_name(result));
return XELL_RESULT_ERROR_UNKNOWN;
}
MarkerParams markerParams {};
markerParams.frame_id = frame_id;
markerParams.marker_type = (MarkerType) marker; // Those should match 1:1
if (marker == XELL_PRESENT_START)
context->lastPresentStartFrameId = frame_id;
auto result = InputCommon::set_marker(inputContext, context->device, markerParams);
if (result == InputResult::Ok)
return XELL_RESULT_SUCCESS;
else
LOG_ERROR("set_marker result: {}", magic_enum::enum_name(result));
return XELL_RESULT_ERROR_UNKNOWN;
}
xell_result_t InputXeLL::GetVersion(xell_version_t* pVersion)
{
if (!pVersion)
return XELL_RESULT_ERROR_INVALID_CONTEXT;
return XELL_RESULT_ERROR_INVALID_ARGUMENT;
// TODO: make this mimic the version of loaded xefg dll so that both are seen as compatible
pVersion->major = 1;
@@ -66,10 +159,14 @@ xell_result_t InputXeLL::GetFramesReports(xell_input_handle_t context, xell_fram
if (!outdata)
return XELL_RESULT_ERROR_INVALID_ARGUMENT;
// outdata should have 64 reports, hopefully the app allocated that much
// TODO: fillout
auto result = InputCommon::get_latency(inputContext, context->device, outdata);
return XELL_RESULT_SUCCESS;
if (result == InputResult::Ok)
return XELL_RESULT_SUCCESS;
else
LOG_ERROR("get_latency result: {}", magic_enum::enum_name(result));
return XELL_RESULT_ERROR_UNKNOWN;
}
// D3D12
@@ -109,7 +206,7 @@ xell_result_t InputXeLL::D3D12SetAppQueue(xell_input_handle_t context, ID3D12Com
context->d3d12AppQueue = appQueue;
return XELL_RESULT_SUCCESS;
return InputCommon::pass_xellD3D12SetAppQueue(inputContext, appQueue);
}
xell_result_t InputXeLL::GetContextParameterP(xell_input_handle_t context, uint32_t param1, uint64_t param2)
{
@@ -200,18 +297,20 @@ xell_result_t InputXeLL::SetDisplayInfo(xell_input_handle_t context, void* displ
context->displayInfo = displayInfo;
return XELL_RESULT_SUCCESS;
return InputCommon::pass_xellSetDisplayInfo(inputContext, displayInfo);
}
xell_result_t InputXeLL::SetFgEnabled(xell_input_handle_t context, uint32_t param1, uint32_t param2)
{
// TODO: figure out params and impl
return XELL_RESULT_SUCCESS;
// This might need to take Opti's FG into account, unsure
return InputCommon::pass_xellSetFgEnabled(inputContext, param1, param2);
}
xell_result_t InputXeLL::SetGeneratedFramesCount(xell_input_handle_t context, uint32_t param1, uint32_t framesCount)
{
// TODO: figure out params and impl
return XELL_RESULT_SUCCESS;
// TODO: store framesCount for the SleepParams::fg_multiplier
return InputCommon::pass_xellSetGeneratedFramesCount(inputContext, param1, framesCount);
}
#ifdef LOW_LATENCY_INPUTS
@@ -2,6 +2,7 @@
#include <xell.h>
#include <xell_d3d12.h>
#include "input_common.h"
class InputXeLL
{
@@ -15,6 +16,10 @@ class InputXeLL
void* displayInfo;
};
const static inline InputContext inputContext { .caller = LowLatencyInput::XeLL,
.noFrameId = false,
.markerMode = InputMarkerMode::FullMarkers };
public:
typedef struct _xell_input_handle_t* xell_input_handle_t;
+27
View File
@@ -26,6 +26,33 @@ enum class LowLatencyMode
Reflex
};
#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];
};
void tonvss(NvAPI_ShortString nvss, std::string str);
#define INSERT_AND_RETURN_WHEN_EQUALS(method) \
@@ -193,9 +193,9 @@ void AntiLag2::sleep(std::optional<uint32_t> frame_id)
al2_sleep();
}
void AntiLag2::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
void AntiLag2::set_marker(IUnknown* pDevice, const MarkerParams& marker_params)
{
switch (marker_params->marker_type)
switch (marker_params.marker_type)
{
case MarkerType::SIMULATION_START:
simulation_framecount++;
@@ -219,12 +219,12 @@ void AntiLag2::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
}
}
void AntiLag2::set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params)
void AntiLag2::set_async_marker(IUnknown* pCommandQueue, const MarkerParams& marker_params)
{
if (marker_params->marker_type == MarkerType::OUT_OF_BAND_PRESENT_START)
if (marker_params.marker_type == MarkerType::OUT_OF_BAND_PRESENT_START)
{
static uint64_t previous_frame_id = marker_params->frame_id;
set_fg_type(previous_frame_id == marker_params->frame_id, marker_params->frame_id);
previous_frame_id = marker_params->frame_id;
static uint64_t previous_frame_id = marker_params.frame_id;
set_fg_type(previous_frame_id == marker_params.frame_id, marker_params.frame_id);
previous_frame_id = marker_params.frame_id;
}
}
@@ -48,6 +48,6 @@ class AntiLag2 : public LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override;
void set_marker(IUnknown* pDevice, const MarkerParams& marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, const MarkerParams& marker_params) override;
};
@@ -38,9 +38,9 @@ void AntiLagVk::sleep(std::optional<uint32_t> frame_id)
return;
}
void AntiLagVk::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
void AntiLagVk::set_marker(IUnknown* pDevice, const MarkerParams& marker_params)
{
if (!pDevice || !marker_params)
if (!pDevice)
{
LOG_ERROR("Invalid pointer");
return;
@@ -55,7 +55,7 @@ void AntiLagVk::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
call_count++;
if (marker_params->marker_type == MarkerType::OUT_OF_BAND_PRESENT_START)
if (marker_params.marker_type == MarkerType::OUT_OF_BAND_PRESENT_START)
{
last_oob_present = call_count;
if (!using_oob_present)
@@ -65,13 +65,13 @@ void AntiLagVk::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
if (using_oob_present && call_count - last_oob_present > allowed_gap)
using_oob_present = false;
if (marker_params->marker_type == MarkerType::SIMULATION_START)
if (marker_params.marker_type == MarkerType::SIMULATION_START)
{
// Before processing user input
VkAntiLagPresentationInfoAMD inputInfo = {};
inputInfo.sType = VK_STRUCTURE_TYPE_ANTI_LAG_PRESENTATION_INFO_AMD;
inputInfo.stage = VK_ANTI_LAG_STAGE_INPUT_AMD;
inputInfo.frameIndex = marker_params->frame_id;
inputInfo.frameIndex = marker_params.frame_id;
VkAntiLagDataAMD antiLagDataInput = {};
antiLagDataInput.sType = VK_STRUCTURE_TYPE_ANTI_LAG_DATA_AMD;
@@ -81,20 +81,21 @@ void AntiLagVk::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
if (VulkanHooks::o_vkAntiLagUpdateAMD)
{
LOG_TRACE_LOWLATENCY("AntiLag Input: {}, status: {}", marker_params->frame_id, is_enabled());
LOG_TRACE_LOWLATENCY("AntiLag Input: {}, status: {}", marker_params.frame_id, is_enabled());
// TODO: somehow confirm that pDevice is actually VkDevice
VulkanHooks::o_vkAntiLagUpdateAMD((VkDevice) pDevice, &antiLagDataInput);
}
}
if ((marker_params->marker_type == MarkerType::PRESENT_START && !using_oob_present) ||
marker_params->marker_type == MarkerType::OUT_OF_BAND_PRESENT_START)
if ((marker_params.marker_type == MarkerType::PRESENT_START && !using_oob_present) ||
marker_params.marker_type == MarkerType::OUT_OF_BAND_PRESENT_START)
{
// Before calling vkQueuePresentKHR
VkAntiLagPresentationInfoAMD presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_ANTI_LAG_PRESENTATION_INFO_AMD;
presentInfo.stage = VK_ANTI_LAG_STAGE_PRESENT_AMD;
presentInfo.frameIndex = marker_params->frame_id;
presentInfo.frameIndex = marker_params.frame_id;
VkAntiLagDataAMD antiLagDataPresent = {};
antiLagDataPresent.sType = VK_STRUCTURE_TYPE_ANTI_LAG_DATA_AMD;
@@ -104,7 +105,7 @@ void AntiLagVk::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
if (VulkanHooks::o_vkAntiLagUpdateAMD)
{
LOG_TRACE_LOWLATENCY("AntiLag Present: {}, status: {}", marker_params->frame_id, is_enabled());
LOG_TRACE_LOWLATENCY("AntiLag Present: {}, status: {}", marker_params.frame_id, is_enabled());
VulkanHooks::o_vkAntiLagUpdateAMD((VkDevice) pDevice, &antiLagDataPresent);
}
@@ -33,6 +33,7 @@ class AntiLagVk : public LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override {}; // Not used by AntiLag VK
void set_marker(IUnknown* pDevice, const MarkerParams& marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, const MarkerParams& marker_params) override {
}; // Not used by AntiLag VK
};
@@ -168,9 +168,9 @@ void LatencyFlex::sleep(std::optional<uint32_t> frame_id)
}
};
void LatencyFlex::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
void LatencyFlex::set_marker(IUnknown* pDevice, const MarkerParams& marker_params)
{
switch (marker_params->marker_type)
switch (marker_params.marker_type)
{
case MarkerType::SIMULATION_START:
simulation_framecount++;
@@ -181,12 +181,12 @@ void LatencyFlex::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
current_call_spot = CallSpot::SleepCall;
if (current_call_spot == CallSpot::SimulationStart)
lfx_sleep(marker_params->frame_id);
lfx_sleep(marker_params.frame_id);
break;
case MarkerType::RENDERSUBMIT_END:
if ((LFXMode) Config::Instance()->FN_LatencyFlexMode.value_or_default() != LFXMode::Conservative)
lfx_end_frame(marker_params->frame_id);
lfx_end_frame(marker_params.frame_id);
break;
}
};
@@ -52,6 +52,6 @@ class LatencyFlex : public LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override {}; // Not used by LFX
void set_marker(IUnknown* pDevice, const MarkerParams& marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, const MarkerParams& marker_params) override {}; // Not used by LFX
};
@@ -13,7 +13,7 @@ void XeLL::xell_sleep(uint32_t frame_id)
if (!inited_using_context || is_enabled())
{
LOG_TRACE_LOWLATENCY("Sleeping with frame_id: {}", frame_id);
XeLLProxy::Sleep()(XeLLProxy::Context(), frame_id);
o_xellSleep(xell_context, frame_id);
}
}
@@ -27,7 +27,7 @@ void XeLL::add_marker(uint32_t frame_id, xell_latency_marker_type_t marker)
}
if (!inited_using_context || is_enabled())
XeLLProxy::AddMarkerData()(XeLLProxy::Context(), frame_id, marker);
o_xellAddMarkerData(xell_context, frame_id, marker);
}
bool XeLL::init(IUnknown* pDevice)
@@ -43,7 +43,7 @@ bool XeLL::init(IUnknown* pDevice)
if (hr != S_OK)
return false;
auto result = XeLLProxy::CreateContext(dx12_pDevice);
auto result = o_xellD3D12CreateContext(dx12_pDevice, &xell_context) == XELL_RESULT_SUCCESS;
if (result)
XellHooks::blockExternalContexts(true);
@@ -59,16 +59,22 @@ bool XeLL::init_using_ctx(void* context)
return false;
}
if (!XeLLProxy::Context())
if (!context)
{
LOG_ERROR("XeLL handed over to fakenvapi but the context is null");
return false;
}
if (xell_context)
{
o_xellDestroyContext(xell_context);
xell_context = (xell_context_handle_t) context;
}
// Context is handled and held inside XeLLProxy
inited_using_context = true;
XellHooks::blockExternalContexts(true);
LOG_INFO("XeLL initialized using existing context: {:X}", (uint64_t) XeLLProxy::Context());
LOG_INFO("XeLL initialized using existing context: {:X}", (uint64_t) xell_context);
return true;
}
@@ -85,17 +91,17 @@ void XeLL::deinit()
}
else
{
XeLLProxy::DestroyXeLLContext();
o_xellDestroyContext(xell_context);
LOG_INFO("XeLL deinitialized");
}
}
void* XeLL::get_tech_context() { return XeLLProxy::Context(); }
void* XeLL::get_tech_context() { return xell_context; }
void XeLL::get_sleep_status(SleepParams* sleep_params)
{
xell_sleep_params_t xell_sleep_params {};
auto result = XeLLProxy::GetSleepMode()(XeLLProxy::Context(), &xell_sleep_params);
auto result = o_xellGetSleepMode(xell_context, &xell_sleep_params) == XELL_RESULT_SUCCESS;
sleep_params->low_latency_enabled = xell_sleep_params.bLowLatencyMode;
sleep_params->fullscreen_vrr = true;
@@ -130,7 +136,7 @@ void XeLL::set_sleep_mode(SleepMode* sleep_mode)
xell_sleep_params.minimumIntervalUs != last_minimumIntervalUs ||
xell_sleep_params.bLowLatencyBoost != last_bLowLatencyBoost)
{
auto result = XeLLProxy::SetSleepMode()(XeLLProxy::Context(), &xell_sleep_params);
auto result = o_xellSetSleepMode(xell_context, &xell_sleep_params) == XELL_RESULT_SUCCESS;
last_bLowLatencyMode = xell_sleep_params.bLowLatencyMode;
last_minimumIntervalUs = xell_sleep_params.minimumIntervalUs;
@@ -138,21 +144,21 @@ void XeLL::set_sleep_mode(SleepMode* sleep_mode)
}
}
void XeLL::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
void XeLL::set_marker(IUnknown* pDevice, const MarkerParams& marker_params)
{
if (!pDevice || !marker_params)
if (!pDevice)
{
LOG_ERROR("Invalid pointer");
return;
}
// XeLL frame ids are uint64_t
auto frame_id = (uint32_t) marker_params->frame_id;
auto frame_id = (uint32_t) marker_params.frame_id;
switch (marker_params->marker_type)
switch (marker_params.marker_type)
{
case MarkerType::SIMULATION_START:
simulation_start_last_id = marker_params->frame_id;
simulation_start_last_id = marker_params.frame_id;
// Call sleep just before simulation start if sleep isn't getting called
if (sleep_last_id + 10 < simulation_start_last_id)
@@ -176,13 +182,37 @@ void XeLL::set_marker(IUnknown* pDevice, MarkerParams* marker_params)
add_marker(frame_id, XELL_PRESENT_END);
break;
// case MarkerType::INPUT_SAMPLE:
// add_marker(marker_params->frame_id, XELL_INPUT_SAMPLE);
// add_marker(marker_params.frame_id, XELL_INPUT_SAMPLE);
// break;
default:
break;
}
}
void XeLL::set_async_marker(IUnknown* pCommandQueue, const MarkerParams& marker_params)
{
if (!pCommandQueue)
{
LOG_ERROR("Invalid pointer");
return;
}
// XeLL frame ids are uint64_t
auto frame_id = (uint32_t) marker_params.frame_id;
switch (marker_params.marker_type)
{
case MarkerType::OUT_OF_BAND_RENDERSUBMIT_START:
add_marker(frame_id, (xell_latency_marker_type_t) 80860000);
break;
case MarkerType::OUT_OF_BAND_RENDERSUBMIT_END:
add_marker(frame_id, (xell_latency_marker_type_t) 80860001);
break;
default:
break;
}
}
void XeLL::sleep(std::optional<uint32_t> frame_id)
{
if (frame_id.has_value())
@@ -201,7 +231,7 @@ xell_result_t XeLL::xellD3D12SetAppQueue(ID3D12CommandQueue* appQueue) const
if (!o_xellD3D12SetAppQueue)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellD3D12SetAppQueue(XeLLProxy::Context(), appQueue);
return o_xellD3D12SetAppQueue(xell_context, appQueue);
}
xell_result_t XeLL::xellSetDisplayInfo(void* displayInfo) const
@@ -209,7 +239,7 @@ xell_result_t XeLL::xellSetDisplayInfo(void* displayInfo) const
if (!o_xellSetDisplayInfo)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellSetDisplayInfo(XeLLProxy::Context(), displayInfo);
return o_xellSetDisplayInfo(xell_context, displayInfo);
}
xell_result_t XeLL::xellSetFgEnabled(uint32_t param1, uint32_t param2) const
@@ -217,7 +247,7 @@ 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);
return o_xellSetFgEnabled(xell_context, param1, param2);
}
xell_result_t XeLL::xellSetGeneratedFramesCount(uint32_t param1, uint32_t framesCount) const
@@ -225,7 +255,7 @@ xell_result_t XeLL::xellSetGeneratedFramesCount(uint32_t param1, uint32_t frames
if (!o_xellSetGeneratedFramesCount)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellSetGeneratedFramesCount(XeLLProxy::Context(), param1, framesCount);
return o_xellSetGeneratedFramesCount(xell_context, param1, framesCount);
}
xell_result_t XeLL::xellGetLastPresentStartFrameId(uint32_t* p_frame_id) const
@@ -233,5 +263,13 @@ 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);
}
return o_xellGetLastPresentStartFrameId(xell_context, p_frame_id);
}
xell_result_t XeLL::xellGetFramesReports(xell_frame_report_t* outdata) const
{
if (!o_xellGetFramesReports)
return XELL_RESULT_ERROR_UNKNOWN;
return o_xellGetFramesReports(xell_context, outdata);
}
@@ -4,6 +4,7 @@
#include <xell_d3d12.h>
#include "low_latency/input/input_xell.h"
#include <proxies/XeLL_Proxy.h>
class XeLL : public LowLatencyTech
{
@@ -11,7 +12,18 @@ class XeLL : public LowLatencyTech
uint64_t simulation_start_last_id {};
uint64_t sleep_last_id {};
// TODO: set those
xell_context_handle_t xell_context {};
decltype(&xellDestroyContext) o_xellDestroyContext = nullptr;
decltype(&xellSetSleepMode) o_xellSetSleepMode = nullptr;
decltype(&xellGetSleepMode) o_xellGetSleepMode = nullptr;
decltype(&xellSleep) o_xellSleep = nullptr;
decltype(&xellAddMarkerData) o_xellAddMarkerData = nullptr;
decltype(&xellGetVersion) o_xellGetVersion = nullptr;
decltype(&xellSetLoggingCallback) o_xellSetLoggingCallback = nullptr;
decltype(&xellGetFramesReports) o_xellGetFramesReports = nullptr;
decltype(&xellD3D12CreateContext) o_xellD3D12CreateContext = nullptr;
decltype(&xellD3D12SetAppQueue) o_xellD3D12SetAppQueue = nullptr;
decltype(&xellSetDisplayInfo) o_xellSetDisplayInfo = nullptr;
decltype(&xellSetFgEnabled) o_xellSetFgEnabled = nullptr;
@@ -22,11 +34,43 @@ class XeLL : public LowLatencyTech
void add_marker(uint32_t frame_id, xell_latency_marker_type_t marker);
public:
XeLL() : LowLatencyTech() {}
XeLL() : LowLatencyTech()
{
if (XeLLProxy::InitXeLL())
{
#ifdef LOW_LATENCY_INPUTS
o_xellDestroyContext = XeLLProxy::RealDestroyContext();
o_xellSetSleepMode = XeLLProxy::RealSetSleepMode();
o_xellGetSleepMode = XeLLProxy::RealGetSleepMode();
o_xellSleep = XeLLProxy::RealSleep();
o_xellAddMarkerData = XeLLProxy::RealAddMarkerData();
o_xellGetVersion = XeLLProxy::RealGetVersion();
o_xellSetLoggingCallback = XeLLProxy::RealSetLoggingCallback();
o_xellGetFramesReports = XeLLProxy::RealGetFramesReports();
o_xellD3D12CreateContext = XeLLProxy::RealD3D12CreateContext();
o_xellD3D12SetAppQueue = XeLLProxy::RealD3D12SetAppQueue();
o_xellSetDisplayInfo = XeLLProxy::RealSetDisplayInfo();
o_xellSetFgEnabled = XeLLProxy::RealSetFgEnabled();
o_xellSetGeneratedFramesCount = XeLLProxy::RealSetGeneratedFramesCount();
o_xellGetLastPresentStartFrameId = XeLLProxy::RealGetLastPresentStartFrameId(); // Maybe not needed
#else
o_xellDestroyContext = XeLLProxy::DestroyContext();
o_xellSetSleepMode = XeLLProxy::SetSleepMode();
o_xellGetSleepMode = XeLLProxy::GetSleepMode();
o_xellSleep = XeLLProxy::Sleep();
o_xellAddMarkerData = XeLLProxy::AddMarkerData();
o_xellGetVersion = XeLLProxy::GetVersion();
o_xellSetLoggingCallback = XeLLProxy::SetLoggingCallback();
o_xellGetFramesReports = XeLLProxy::GetFramesReports();
o_xellD3D12CreateContext = XeLLProxy::D3D12CreateContext();
#endif
}
}
// From LowLatencyTech
bool init(IUnknown* pDevice) override;
bool init_using_ctx(void* context) override; // Context is always held by XeLLProxy
bool init_using_ctx(void* context) override;
void deinit() override;
LowLatencyMode get_mode() override { return LowLatencyMode::XeLL; };
@@ -47,8 +91,8 @@ class XeLL : public LowLatencyTech
void get_sleep_status(SleepParams* sleep_params) override;
void set_sleep_mode(SleepMode* sleep_mode) override;
void sleep(std::optional<uint32_t> frame_id) override;
void set_marker(IUnknown* pDevice, MarkerParams* marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, MarkerParams* marker_params) override {}; // Not used by XeLL
void set_marker(IUnknown* pDevice, const MarkerParams& marker_params) override;
void set_async_marker(IUnknown* pCommandQueue, const MarkerParams& marker_params) override;
// For passthrough
xell_result_t xellD3D12SetAppQueue(ID3D12CommandQueue* appQueue) const;
@@ -56,4 +100,5 @@ class XeLL : public LowLatencyTech
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;
xell_result_t xellGetFramesReports(xell_frame_report_t* outdata) const;
};
@@ -18,8 +18,13 @@ enum class CallSpot
struct SleepParams
{
bool low_latency_enabled;
bool low_latency_boost;
uint32_t minimum_interval_us; // 0 -> no fps limit
bool fullscreen_vrr;
bool control_panel_vsync_override;
bool use_game_sleep;
bool fullscreen_i_flip;
uint8_t fg_multiplier;
};
struct SleepMode
@@ -28,6 +33,7 @@ struct SleepMode
bool low_latency_boost;
uint32_t minimum_interval_us; // 0 -> no fps limit
bool use_markers_to_optimize; // TODO: log this if false
bool use_min_queue_time;
};
enum class MarkerType
@@ -85,6 +91,6 @@ class LowLatencyTech
virtual void get_sleep_status(SleepParams* sleep_params) = 0;
virtual void set_sleep_mode(SleepMode* sleep_mode) = 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(IUnknown* pCommandQueue, MarkerParams* marker_params) = 0;
virtual void set_marker(IUnknown* pDevice, const MarkerParams& marker_params) = 0;
virtual void set_async_marker(IUnknown* pCommandQueue, const MarkerParams& marker_params) = 0;
};
+2 -2
View File
@@ -59,7 +59,7 @@ void UeLowLatency::tickStart(int64_t frameId, float DeltaSeconds, bool bIdleMode
MarkerParams marker {};
marker.marker_type = MarkerType::SIMULATION_START;
marker.frame_id = frameId;
lowLatencyFeature->set_marker(State::Instance().currentD3D12Device, &marker);
lowLatencyFeature->set_marker(State::Instance().currentD3D12Device, marker);
}
void UeLowLatency::tickEnd(int64_t frameId, float DeltaSeconds, bool bIdleMode)
@@ -69,5 +69,5 @@ void UeLowLatency::tickEnd(int64_t frameId, float DeltaSeconds, bool bIdleMode)
MarkerParams marker {};
marker.marker_type = MarkerType::SIMULATION_END;
marker.frame_id = frameId;
lowLatencyFeature->set_marker(State::Instance().currentD3D12Device, &marker);
lowLatencyFeature->set_marker(State::Instance().currentD3D12Device, marker);
}
-24
View File
@@ -8,30 +8,6 @@
#include "low_latency/ll_util.h"
#include <optional>
#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;
uint8_t rsvd[120];
};
class LowLatency
{
private:
@@ -278,7 +278,7 @@ NvAPI_Status LowLatency::SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARA
marker_params.marker_type = (MarkerType) pSetLatencyMarkerParams->markerType; // requires enums to match
if (auto current_tech = currently_active_tech.load())
current_tech->set_marker(pDev, &marker_params);
current_tech->set_marker(pDev, marker_params);
LOG_TRACE_FAKENVAPI("{}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id);
@@ -325,7 +325,7 @@ NvAPI_Status LowLatency::SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue,
}
if (auto current_tech = currently_active_tech.load())
current_tech->set_async_marker(pCommandQueue, &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);
@@ -220,7 +220,7 @@ NvAPI_Status LowLatency::SetLatencyMarker(HANDLE vkDevice, NV_VULKAN_LATENCY_MAR
// This cast is not ideal as it needs to be cast to VkDevice while knowing it's vulkan
if (auto current_tech = currently_active_tech.load())
current_tech->set_marker((IUnknown*) vkDevice, &marker_params);
current_tech->set_marker((IUnknown*) vkDevice, marker_params);
LOG_TRACE_FAKENVAPI("{}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id);
+107 -19
View File
@@ -30,6 +30,13 @@ typedef decltype(&xellGetFramesReports) PFN_xellGetFramesReports;
// Dx12
typedef decltype(&xellD3D12CreateContext) PFN_xellD3D12CreateContext;
// Extra
typedef decltype(&xellD3D12SetAppQueue) PFN_xellD3D12SetAppQueue;
typedef decltype(&xellSetDisplayInfo) PFN_xellSetDisplayInfo;
typedef decltype(&xellSetFgEnabled) PFN_xellSetFgEnabled;
typedef decltype(&xellSetGeneratedFramesCount) PFN_xellSetGeneratedFramesCount;
typedef decltype(&xellGetLastPresentStartFrameId) PFN_xellGetLastPresentStartFrameId;
// This callback runs once for every function exported by the Old DLL
static int ExportCallback(PVOID hNewDll, ULONG nOrdinal, LPCSTR pszName, PVOID pOldFunction)
{
@@ -68,6 +75,7 @@ class XeLLProxy
{
private:
inline static HMODULE _dll = nullptr;
inline static HMODULE _memoryDll = nullptr;
inline static std::wstring _dllPath;
inline static xell_version_t _xellVersion {};
@@ -109,6 +117,13 @@ class XeLLProxy
// Dx12
inline static PFN_xellD3D12CreateContext _xellD3D12CreateContext = nullptr;
// Extra
inline static PFN_xellD3D12SetAppQueue _xellD3D12SetAppQueue = nullptr;
inline static PFN_xellSetDisplayInfo _xellSetDisplayInfo = nullptr;
inline static PFN_xellSetFgEnabled _xellSetFgEnabled = nullptr;
inline static PFN_xellSetGeneratedFramesCount _xellSetGeneratedFramesCount = nullptr;
inline static PFN_xellGetLastPresentStartFrameId _xellGetLastPresentStartFrameId = nullptr;
inline static xell_version_t GetDLLVersion(std::wstring dllPath)
{
xell_version_t xellVersion {};
@@ -141,11 +156,7 @@ class XeLLProxy
return dll;
}
public:
static HMODULE Module() { return _dll; }
static std::wstring Module_Path() { return _dllPath; }
static bool InitXeLL()
static bool InitXeLLProper()
{
if (_dll != nullptr)
return true;
@@ -154,7 +165,7 @@ class XeLLProxy
std::vector<std::wstring> dllNames = { L"libxell.dll" };
auto optiPath = Config::Instance()->MainDllPath.value();
auto& optiPath = Config::Instance()->MainDllPath.value();
for (size_t i = 0; i < dllNames.size(); i++)
{
@@ -162,21 +173,16 @@ class XeLLProxy
auto overridePath = Config::Instance()->XeLLLibrary.value_or(L"");
HMODULE memModule = nullptr;
#ifdef LOW_LATENCY_INPUTS
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCSTR) InputXeLL::D3D12CreateContext, &mainModule);
#else
Util::LoadProxyLibrary(dllNames[i], optiPath, overridePath, &memModule, &mainModule);
#endif
Util::LoadProxyLibrary(dllNames[i], optiPath, overridePath, &_memoryDll, &mainModule);
if (mainModule != nullptr)
{
// We don't control which XeLL dll XeFG will pick
// Detouring GetModuleHandleExA seemingly isn't enough
if (memModule && mainModule != memModule)
RedirectAllExports(memModule, mainModule);
#ifndef LOW_LATENCY_INPUTS
if (_memoryDll && mainModule != _memoryDll)
RedirectAllExports(_memoryDll, mainModule);
#endif
break;
}
@@ -195,6 +201,44 @@ class XeLLProxy
return false;
}
static bool InitXeLLInput()
{
#ifndef LOW_LATENCY_INPUTS
return true;
#endif
HMODULE mainModule = nullptr;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCSTR) InputXeLL::D3D12CreateContext, &mainModule);
if (_dll != nullptr)
{
// If our xell and the one in memory aren't the same then
// hook the in-memory functions with our xell inputs ones
if (_memoryDll && _dll != _memoryDll)
RedirectAllExports(_memoryDll, dllModule);
}
if (mainModule != nullptr)
{
wchar_t modulePath[MAX_PATH];
DWORD len = GetModuleFileNameW(mainModule, modulePath, MAX_PATH);
_dllPath = std::wstring(modulePath);
LOG_INFO("Loaded from {}", wstring_to_string(_dllPath));
return HookXeLL(mainModule);
}
return false;
}
public:
static HMODULE Module() { return _dll; }
static std::wstring Module_Path() { return _dllPath; }
static bool InitXeLL() { return InitXeLLProper() && InitXeLLInput(); }
static bool HookXeLL(HMODULE libxellModule)
{
// if dll already loaded
@@ -228,6 +272,17 @@ class XeLLProxy
_xellD3D12CreateContext =
(PFN_xellD3D12CreateContext) KernelBaseProxy::GetProcAddress_()(_dll, "xellD3D12CreateContext");
_xellD3D12SetAppQueue =
(PFN_xellD3D12SetAppQueue) KernelBaseProxy::GetProcAddress_()(_dll, "xellD3D12SetAppQueue");
_xellSetDisplayInfo =
(PFN_xellSetDisplayInfo) KernelBaseProxy::GetProcAddress_()(_dll, "xellSetDisplayInfo");
_xellSetFgEnabled = (PFN_xellSetFgEnabled) KernelBaseProxy::GetProcAddress_()(_dll, "xellSetFgEnabled");
_xellSetGeneratedFramesCount = (PFN_xellSetGeneratedFramesCount) KernelBaseProxy::GetProcAddress_()(
_dll, "xellSetGeneratedFramesCount");
_xellGetLastPresentStartFrameId =
(PFN_xellGetLastPresentStartFrameId) KernelBaseProxy::GetProcAddress_()(
_dll, "xellGetLastPresentStartFrameId");
}
}
@@ -260,6 +315,37 @@ class XeLLProxy
return _xellVersion;
}
#ifdef LOW_LATENCY_INPUTS
// We export / implement those functions
static PFN_xellDestroyContext DestroyContext() { return xellDestroyContext; }
static PFN_xellSetSleepMode SetSleepMode() { return xellSetSleepMode; }
static PFN_xellGetSleepMode GetSleepMode() { return xellGetSleepMode; }
static PFN_xellSleep Sleep() { return xellSleep; }
static PFN_xellAddMarkerData AddMarkerData() { return xellAddMarkerData; }
static PFN_xellGetVersion GetVersion() { return xellGetVersion; }
static PFN_xellSetLoggingCallback SetLoggingCallback() { return xellSetLoggingCallback; }
static PFN_xellGetFramesReports GetFramesReports() { return xellGetFramesReports; }
static PFN_xellD3D12CreateContext D3D12CreateContext() { return xellD3D12CreateContext; }
// Pointing to the actual DLL
static PFN_xellDestroyContext RealDestroyContext() { return _xellDestroyContext; }
static PFN_xellSetSleepMode RealSetSleepMode() { return _xellSetSleepMode; }
static PFN_xellGetSleepMode RealGetSleepMode() { return _xellGetSleepMode; }
static PFN_xellSleep RealSleep() { return _xellSleep; }
static PFN_xellAddMarkerData RealAddMarkerData() { return _xellAddMarkerData; }
static PFN_xellGetVersion RealGetVersion() { return _xellGetVersion; }
static PFN_xellSetLoggingCallback RealSetLoggingCallback() { return _xellSetLoggingCallback; }
static PFN_xellGetFramesReports RealGetFramesReports() { return _xellGetFramesReports; }
static PFN_xellD3D12CreateContext RealD3D12CreateContext() { return _xellD3D12CreateContext; }
static PFN_xellD3D12SetAppQueue RealD3D12SetAppQueue() { return _xellD3D12SetAppQueue; }
static PFN_xellSetDisplayInfo RealSetDisplayInfo() { return _xellSetDisplayInfo; }
static PFN_xellSetFgEnabled RealSetFgEnabled() { return _xellSetFgEnabled; }
static PFN_xellSetGeneratedFramesCount RealSetGeneratedFramesCount() { return _xellSetGeneratedFramesCount; }
static PFN_xellGetLastPresentStartFrameId RealGetLastPresentStartFrameId()
{
return _xellGetLastPresentStartFrameId;
}
#else
static PFN_xellDestroyContext DestroyContext() { return _xellDestroyContext; }
static PFN_xellSetSleepMode SetSleepMode() { return _xellSetSleepMode; }
static PFN_xellGetSleepMode GetSleepMode() { return _xellGetSleepMode; }
@@ -268,8 +354,8 @@ class XeLLProxy
static PFN_xellGetVersion GetVersion() { return _xellGetVersion; }
static PFN_xellSetLoggingCallback SetLoggingCallback() { return _xellSetLoggingCallback; }
static PFN_xellGetFramesReports GetFramesReports() { return _xellGetFramesReports; }
static PFN_xellD3D12CreateContext D3D12CreateContext() { return _xellD3D12CreateContext; }
#endif
static bool DestroyXeLLContext()
{
@@ -279,7 +365,7 @@ class XeLLProxy
{
auto context = _xellContext;
_xellContext = nullptr;
auto xellResult = _xellDestroyContext(context);
auto xellResult = DestroyContext()(context);
LOG_INFO("XeLL DestroyContext result: {} ({})", magic_enum::enum_name(xellResult), (UINT) xellResult);
@@ -299,11 +385,13 @@ class XeLLProxy
return false;
}
#ifndef LOW_LATENCY_INPUTS
if (!XellHooks::Hook())
{
LOG_ERROR("Couldn't detour XeLL");
return false;
}
#endif
if (_xellContext != nullptr)
DestroyXeLLContext();
@@ -311,7 +399,7 @@ class XeLLProxy
xell_result_t xellResult;
{
ScopedSkipSpoofing skipSpoofing {};
xellResult = _xellD3D12CreateContext(device, &_xellContext);
xellResult = D3D12CreateContext()(device, &_xellContext);
}
if (xellResult != XELL_RESULT_SUCCESS)