From 0d490baab5fdfadc2e0ea723b02e45dffed36010 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Sat, 27 Jun 2026 21:43:13 +0200 Subject: [PATCH] WIP: Improve low latency output switching --- OptiScaler/low_latency/input/input_common.cpp | 115 ++++++++++-------- OptiScaler/low_latency/input/input_common.h | 4 + OptiScaler/low_latency/input/input_reflex.cpp | 30 ++++- .../low_latency/low_latency_tech/ll_xell.cpp | 2 +- 4 files changed, 95 insertions(+), 56 deletions(-) diff --git a/OptiScaler/low_latency/input/input_common.cpp b/OptiScaler/low_latency/input/input_common.cpp index 36dfa48c..c5178ac9 100644 --- a/OptiScaler/low_latency/input/input_common.cpp +++ b/OptiScaler/low_latency/input/input_common.cpp @@ -30,6 +30,60 @@ bool InputCommon::deinit_current_tech() return false; } +bool InputCommon::init_tech(IUnknown* pDevice, LowLatencyMode desiredMode) +{ + if (!currently_active_tech.load() && delay_deinit == 0) + { + auto try_init = [&](auto low_latency_tech, const char* name) -> bool + { + if (low_latency_tech->init(pDevice)) + { + LOG_INFO("LowLatency algo: {}", name); + currently_active_tech.store(std::move(low_latency_tech)); + return true; + } + return false; + }; + + bool isInitialized = false; + switch (desiredMode) + { + case LowLatencyMode::XeLL: + isInitialized = try_init(std::make_shared(), "XeLL"); + break; + case LowLatencyMode::AntiLag2: + isInitialized = try_init(std::make_shared(), "AntiLag2"); + break; + case LowLatencyMode::Reflex: + // isInitialized = try_init(std::make_shared(), "Reflex"); + break; + case LowLatencyMode::LatencyFlex: + isInitialized = try_init(std::make_shared(), "LatencyFlex"); + break; + default: + break; + } + + if (!isInitialized && desiredMode != LowLatencyMode::LatencyFlex) + { + isInitialized = try_init(std::make_shared(), "LatencyFlex (Fallback)"); + if (isInitialized) + { + Config::Instance()->LowLatencyOutput.set_volatile_value(LowLatencyMode::LatencyFlex); + } + } + + if (auto current_tech = currently_active_tech.load(); current_tech && isInitialized) + { + activeOutput = current_tech->get_mode(); + current_tech->set_sleep_mode(&get_sleep_copy(activeInput)); // Restore any potential sleep mode + return true; + } + } + + return false; +} + bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional mode) { if (avaliableInputs.count() == 0) @@ -143,54 +197,17 @@ bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optional bool - { - if (low_latency_tech->init(pDevice)) - { - LOG_INFO("LowLatency algo: {}", name); - currently_active_tech.store(std::move(low_latency_tech)); - return true; - } - return false; - }; + std::scoped_lock lock(create_tech_mutex); - bool isInitialized = false; - switch (desiredMode) - { - case LowLatencyMode::XeLL: - isInitialized = try_init(std::make_shared(), "XeLL"); - break; - case LowLatencyMode::AntiLag2: - isInitialized = try_init(std::make_shared(), "AntiLag2"); - break; - case LowLatencyMode::Reflex: - // isInitialized = try_init(std::make_shared(), "Reflex"); - break; - case LowLatencyMode::LatencyFlex: - isInitialized = try_init(std::make_shared(), "LatencyFlex"); - break; - default: - break; - } - - if (!isInitialized && desiredMode != LowLatencyMode::LatencyFlex) - { - isInitialized = try_init(std::make_shared(), "LatencyFlex (Fallback)"); - } - - if (auto current_tech = currently_active_tech.load(); current_tech && isInitialized) - { - activeOutput = current_tech->get_mode(); - current_tech->set_sleep_mode(&get_sleep_copy(activeInput)); // Restore any potential sleep mode - return true; - } - } + if (init_tech(pDevice, desiredMode)) + return true; auto try_reinit = [&]() -> bool { @@ -200,7 +217,7 @@ bool InputCommon::update_low_latency_tech(IUnknown* pDevice, std::optionalsleep(frame_id); else - return InputResult::GenericError; + return InputResult::NoReadyOutput; return InputResult::Ok; } @@ -348,7 +365,7 @@ InputResult InputCommon::set_marker(const InputContext& inputContext, IUnknown* if (auto current_tech = currently_active_tech.load()) current_tech->set_marker(pDevice, marker_params); else - return InputResult::GenericError; + return InputResult::NoReadyOutput; LOG_TRACE_LOWLATENCY("{}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id); @@ -383,7 +400,7 @@ InputResult InputCommon::set_async_marker(const InputContext& inputContext, ID3D if (auto current_tech = currently_active_tech.load()) current_tech->set_async_marker(pCommandQueue, marker_params); else - return InputResult::GenericError; + return InputResult::NoReadyOutput; LOG_TRACE_LOWLATENCY("{}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id); @@ -407,7 +424,7 @@ InputResult InputCommon::set_sleep_mode(const InputContext& inputContext, IUnkno if (auto current_tech = currently_active_tech.load()) current_tech->set_sleep_mode(sleep_mode); else - return InputResult::GenericError; + return InputResult::NoReadyOutput; return InputResult::Ok; } @@ -429,7 +446,7 @@ InputResult InputCommon::get_sleep_status(const InputContext& inputContext, IUnk if (auto current_tech = currently_active_tech.load()) current_tech->get_sleep_status(sleep_params); else - return InputResult::GenericError; + return InputResult::NoReadyOutput; return InputResult::Ok; } diff --git a/OptiScaler/low_latency/input/input_common.h b/OptiScaler/low_latency/input/input_common.h index 654cee52..01e76bfb 100644 --- a/OptiScaler/low_latency/input/input_common.h +++ b/OptiScaler/low_latency/input/input_common.h @@ -29,6 +29,7 @@ enum class InputResult : uint32_t InvalidParameter, LowLatencyUpdateFail, NotEnoughReports, + NoReadyOutput, GenericError, }; @@ -46,6 +47,8 @@ struct TimingData class InputCommon { inline static std::atomic> currently_active_tech; + inline static std::mutex create_tech_mutex {}; + inline static FrameReport frame_reports[FRAME_REPORTS_BUFFER_SIZE] {}; inline static std::atomic_uint64_t last_present_start_frame_id = 0; inline static std::atomic_uint32_t delay_deinit = 0; @@ -57,6 +60,7 @@ class InputCommon inline static bool enabled = false; static bool deinit_current_tech(); + static bool init_tech(IUnknown* pDevice, LowLatencyMode desiredMode); static bool update_low_latency_tech(IUnknown* pDevice, std::optional mode = std::nullopt); static void add_marker_to_report(const MarkerParams& marker_params); static void set_input_avaliable(LowLatencyInput input) { avaliableInputs.set(input); }; diff --git a/OptiScaler/low_latency/input/input_reflex.cpp b/OptiScaler/low_latency/input/input_reflex.cpp index 41fe0c72..584f3cfc 100644 --- a/OptiScaler/low_latency/input/input_reflex.cpp +++ b/OptiScaler/low_latency/input/input_reflex.cpp @@ -20,7 +20,10 @@ NvAPI_Status InputReflex::D3D_SetSleepMode(IUnknown* pDev, NV_SET_SLEEP_MODE_PAR else LOG_ERROR("set_sleep_mode result: {}", magic_enum::enum_name(result)); - return NVAPI_ERROR; + if (result == InputResult::NoReadyOutput) + return NVAPI_OK; + else + return NVAPI_ERROR; } NvAPI_Status InputReflex::D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) @@ -49,7 +52,10 @@ NvAPI_Status InputReflex::D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STA LOG_ERROR("get_sleep_status result: {}", magic_enum::enum_name(result)); } - return NVAPI_ERROR; + if (result == InputResult::NoReadyOutput) + return NVAPI_OK; + else + return NVAPI_ERROR; } NvAPI_Status InputReflex::D3D_Sleep(IUnknown* pDev) @@ -64,7 +70,10 @@ NvAPI_Status InputReflex::D3D_Sleep(IUnknown* pDev) else LOG_ERROR("sleep result: {}", magic_enum::enum_name(result)); - return NVAPI_ERROR; + if (result == InputResult::NoReadyOutput) + return NVAPI_OK; + else + return NVAPI_ERROR; } NvAPI_Status InputReflex::D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) @@ -81,7 +90,10 @@ NvAPI_Status InputReflex::D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAM else LOG_ERROR("get_latency result: {}", magic_enum::enum_name(result)); - return NVAPI_ERROR; + if (result == InputResult::NoReadyOutput) + return NVAPI_OK; + else + return NVAPI_ERROR; } NvAPI_Status InputReflex::D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) @@ -101,7 +113,10 @@ NvAPI_Status InputReflex::D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER else LOG_ERROR("set_marker result: {}", magic_enum::enum_name(result)); - return NVAPI_ERROR; + if (result == InputResult::NoReadyOutput) + return NVAPI_OK; + else + return NVAPI_ERROR; } NvAPI_Status InputReflex::D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, @@ -122,5 +137,8 @@ NvAPI_Status InputReflex::D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommand else LOG_ERROR("set_async_marker result: {}", magic_enum::enum_name(result)); - return NVAPI_ERROR; + if (result == InputResult::NoReadyOutput) + return NVAPI_OK; + else + return NVAPI_ERROR; } \ 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 230b6a31..41d7cdae 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_xell.cpp +++ b/OptiScaler/low_latency/low_latency_tech/ll_xell.cpp @@ -61,7 +61,7 @@ bool XeLL::init(IUnknown* pDevice) auto xellInputContext = (InputXeLL::xell_input_handle_t) XellHooks::getOurContext(); if (!xellInputContext) - return false; + return true; auto resendResult = XELL_RESULT_SUCCESS;