From aeefd5307ae8fde753c38e290e4467e8cc31fb13 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Tue, 19 May 2026 23:09:07 +0200 Subject: [PATCH] WIP: XeLL inputs cont. --- OptiScaler/low_latency/input/input_common.cpp | 97 ++++++++++--- OptiScaler/low_latency/input/input_common.h | 39 +---- OptiScaler/low_latency/input/input_xell.cpp | 133 +++++++++++++++--- OptiScaler/low_latency/input/input_xell.h | 5 + OptiScaler/low_latency/ll_util.h | 27 ++++ .../low_latency_tech/ll_antilag2.cpp | 14 +- .../low_latency_tech/ll_antilag2.h | 4 +- .../low_latency_tech/ll_antilag_vk.cpp | 21 +-- .../low_latency_tech/ll_antilag_vk.h | 5 +- .../low_latency_tech/ll_latencyflex.cpp | 8 +- .../low_latency_tech/ll_latencyflex.h | 4 +- .../low_latency/low_latency_tech/ll_xell.cpp | 80 ++++++++--- .../low_latency/low_latency_tech/ll_xell.h | 55 +++++++- .../low_latency_tech/low_latency_tech.h | 10 +- OptiScaler/misc/UeLowLatency.cpp | 4 +- OptiScaler/nvapi/fakenvapi/low_latency.h | 24 ---- .../nvapi/fakenvapi/low_latency_d3d.cpp | 4 +- OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp | 2 +- OptiScaler/proxies/XeLL_Proxy.h | 126 ++++++++++++++--- 19 files changed, 487 insertions(+), 175 deletions(-) diff --git a/OptiScaler/low_latency/input/input_common.cpp b/OptiScaler/low_latency/input/input_common.cpp index 20372063..bb44afa3 100644 --- a/OptiScaler/low_latency/input/input_common.cpp +++ b/OptiScaler/low_latency/input/input_common.cpp @@ -2,6 +2,7 @@ #include "input_common.h" #include +// private bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional mode) { LowLatencyMode desiredMode = LowLatencyMode::None; @@ -24,7 +25,18 @@ bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional Auto + auto new_tech_xell = std::make_shared(); + 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::optionalframe_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 frame_id) +InputResult InputCommon::sleep(const InputContext& inputContext, IUnknown* pDevice, std::optional 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(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++) diff --git a/OptiScaler/low_latency/input/input_common.h b/OptiScaler/low_latency/input/input_common.h index 6628c01f..ac933471 100644 --- a/OptiScaler/low_latency/input/input_common.h +++ b/OptiScaler/low_latency/input/input_common.h @@ -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 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 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 diff --git a/OptiScaler/low_latency/input/input_xell.cpp b/OptiScaler/low_latency/input/input_xell.cpp index a451ca51..b3adc086 100644 --- a/OptiScaler/low_latency/input/input_xell.cpp +++ b/OptiScaler/low_latency/input/input_xell.cpp @@ -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 diff --git a/OptiScaler/low_latency/input/input_xell.h b/OptiScaler/low_latency/input/input_xell.h index 1a83dcc2..77e4b427 100644 --- a/OptiScaler/low_latency/input/input_xell.h +++ b/OptiScaler/low_latency/input/input_xell.h @@ -2,6 +2,7 @@ #include #include +#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; diff --git a/OptiScaler/low_latency/ll_util.h b/OptiScaler/low_latency/ll_util.h index dd36024a..390931c7 100644 --- a/OptiScaler/low_latency/ll_util.h +++ b/OptiScaler/low_latency/ll_util.h @@ -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) \ diff --git a/OptiScaler/low_latency/low_latency_tech/ll_antilag2.cpp b/OptiScaler/low_latency/low_latency_tech/ll_antilag2.cpp index 8d536abd..a689363e 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_antilag2.cpp +++ b/OptiScaler/low_latency/low_latency_tech/ll_antilag2.cpp @@ -193,9 +193,9 @@ void AntiLag2::sleep(std::optional 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; } } diff --git a/OptiScaler/low_latency/low_latency_tech/ll_antilag2.h b/OptiScaler/low_latency/low_latency_tech/ll_antilag2.h index 819e69c9..71944ea8 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_antilag2.h +++ b/OptiScaler/low_latency/low_latency_tech/ll_antilag2.h @@ -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 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; }; \ No newline at end of file diff --git a/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.cpp b/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.cpp index 98500953..51935f30 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.cpp +++ b/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.cpp @@ -38,9 +38,9 @@ void AntiLagVk::sleep(std::optional 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); } diff --git a/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.h b/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.h index d46ca2dd..21f327f8 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.h +++ b/OptiScaler/low_latency/low_latency_tech/ll_antilag_vk.h @@ -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 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 }; \ No newline at end of file diff --git a/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.cpp b/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.cpp index af8c320a..494a96a4 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.cpp +++ b/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.cpp @@ -168,9 +168,9 @@ void LatencyFlex::sleep(std::optional 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; } }; diff --git a/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.h b/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.h index ce45bdbb..7229ab87 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.h +++ b/OptiScaler/low_latency/low_latency_tech/ll_latencyflex.h @@ -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 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 }; \ No newline at end of file diff --git a/OptiScaler/low_latency/low_latency_tech/ll_xell.cpp b/OptiScaler/low_latency/low_latency_tech/ll_xell.cpp index c2dbc7b2..29c22416 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_xell.cpp +++ b/OptiScaler/low_latency/low_latency_tech/ll_xell.cpp @@ -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 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); -} \ No newline at end of file + 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); +} diff --git a/OptiScaler/low_latency/low_latency_tech/ll_xell.h b/OptiScaler/low_latency/low_latency_tech/ll_xell.h index 14f7726d..edd7907f 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_xell.h +++ b/OptiScaler/low_latency/low_latency_tech/ll_xell.h @@ -4,6 +4,7 @@ #include #include "low_latency/input/input_xell.h" +#include 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 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; }; \ No newline at end of file diff --git a/OptiScaler/low_latency/low_latency_tech/low_latency_tech.h b/OptiScaler/low_latency/low_latency_tech/low_latency_tech.h index f27e5e10..edf88341 100644 --- a/OptiScaler/low_latency/low_latency_tech/low_latency_tech.h +++ b/OptiScaler/low_latency/low_latency_tech/low_latency_tech.h @@ -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 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; }; \ No newline at end of file diff --git a/OptiScaler/misc/UeLowLatency.cpp b/OptiScaler/misc/UeLowLatency.cpp index 6d27a20d..391fb08d 100644 --- a/OptiScaler/misc/UeLowLatency.cpp +++ b/OptiScaler/misc/UeLowLatency.cpp @@ -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); } diff --git a/OptiScaler/nvapi/fakenvapi/low_latency.h b/OptiScaler/nvapi/fakenvapi/low_latency.h index 7d7ef639..aa008928 100644 --- a/OptiScaler/nvapi/fakenvapi/low_latency.h +++ b/OptiScaler/nvapi/fakenvapi/low_latency.h @@ -8,30 +8,6 @@ #include "low_latency/ll_util.h" #include -#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: diff --git a/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp b/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp index d92eade9..64de65f3 100644 --- a/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp +++ b/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp @@ -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); diff --git a/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp b/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp index 99714ce2..51285168 100644 --- a/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp +++ b/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp @@ -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); diff --git a/OptiScaler/proxies/XeLL_Proxy.h b/OptiScaler/proxies/XeLL_Proxy.h index 57713998..a0401e31 100644 --- a/OptiScaler/proxies/XeLL_Proxy.h +++ b/OptiScaler/proxies/XeLL_Proxy.h @@ -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 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)