System: Add 'Runahead for Analog Input' option

Mitigates the performance impact of serializing PGXP state.
pull/3582/head
Stenzek 3 weeks ago
parent cf0b602476
commit e6788b313e
No known key found for this signature in database

@ -262,7 +262,7 @@ void AnalogController::SetBindState(u32 index, float value)
}
if (std::memcmp(m_axis_state.data(), prev_axis_state.data(), m_axis_state.size()) != 0)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(true);
#undef MERGE
@ -274,14 +274,14 @@ void AnalogController::SetBindState(u32 index, float value)
if (value >= m_button_deadzone)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state &= ~(bit);
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state |= bit;
}

@ -101,8 +101,8 @@ void AnalogJoystick::SetBindState(u32 index, float value)
return;
const u8 u8_value = static_cast<u8>(std::clamp(value * m_analog_sensitivity * 255.0f, 0.0f, 255.0f));
if (u8_value != m_half_axis_state[sub_index])
System::SetRunaheadReplayFlag();
if (m_half_axis_state[sub_index] == u8_value)
return;
m_half_axis_state[sub_index] = u8_value;
@ -181,7 +181,7 @@ void AnalogJoystick::SetBindState(u32 index, float value)
}
if (std::memcmp(m_axis_state.data(), prev_axis_state.data(), m_axis_state.size()) != 0)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(true);
#undef MERGE
@ -193,14 +193,14 @@ void AnalogJoystick::SetBindState(u32 index, float value)
if (value >= 0.5f)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state &= ~(bit);
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state |= bit;
}

@ -114,14 +114,14 @@ void DDGoController::SetBindState(u32 index, float value)
if (pressed)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state &= ~bit;
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state |= bit;
}
@ -215,7 +215,7 @@ void DDGoController::SetPowerLevel(u32 level)
m_power_level = Truncate8(level);
m_power_transition_frames_remaining = m_power_transition_frames;
UpdatePowerBits();
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
}
void DDGoController::UpdatePowerBits()
@ -251,7 +251,7 @@ void DDGoController::SetBrakeLevel(u32 level)
m_brake_level = Truncate8(level);
m_brake_transition_frames_remaining = m_brake_transition_frames;
UpdateBrakeBits();
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
}
void DDGoController::UpdateBrakeBits()

@ -64,14 +64,14 @@ void DigitalController::SetBindState(u32 index, float value)
if (pressed)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state &= ~bit;
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state |= bit;
}

@ -4662,6 +4662,11 @@ void FullscreenUI::DrawEmulationSettingsPage()
"high system requirements."),
"Main", "RunaheadFrameCount", 0, runahead_options);
DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_PF_ANALOG_ANY, "Runahead for Analog Input"),
FSUI_VSTR("Activates runahead when analog input changes, which significantly increases system requirements."),
"Main", "RunaheadForAnalogInput", false, runahead_enabled);
TinyString rewind_summary;
if (runahead_enabled)
{
@ -9559,6 +9564,7 @@ TRANSLATE_NOOP("FullscreenUI", "Achievements");
TRANSLATE_NOOP("FullscreenUI", "Achievements Settings");
TRANSLATE_NOOP("FullscreenUI", "Achievements are not enabled.");
TRANSLATE_NOOP("FullscreenUI", "Achievements: ");
TRANSLATE_NOOP("FullscreenUI", "Activates runahead when analog input changes, which significantly increases system requirements.");
TRANSLATE_NOOP("FullscreenUI", "Add Search Directory");
TRANSLATE_NOOP("FullscreenUI", "Add Shader");
TRANSLATE_NOOP("FullscreenUI", "Adds a new directory to the game search list.");
@ -9770,7 +9776,6 @@ TRANSLATE_NOOP("FullscreenUI", "Enable VRAM Write Replacement");
TRANSLATE_NOOP("FullscreenUI", "Enable XInput Input Source");
TRANSLATE_NOOP("FullscreenUI", "Enable debugging when supported by the host's renderer API. Only for developer use.");
TRANSLATE_NOOP("FullscreenUI", "Enable/Disable the Player LED on DualSense controllers.");
TRANSLATE_NOOP("FullscreenUI", "Enable/Disable using the DualSense controller's Mic Mute LED to indicate when Analog Mode is active.");
TRANSLATE_NOOP("FullscreenUI", "Enables alignment and bus exceptions. Not needed for any known games.");
TRANSLATE_NOOP("FullscreenUI", "Enables an additional 6MB of RAM to obtain a total of 2+6 = 8MB, usually present on dev consoles.");
TRANSLATE_NOOP("FullscreenUI", "Enables an additional three controller slots on each port. Not supported in all games.");
@ -9941,6 +9946,7 @@ TRANSLATE_NOOP("FullscreenUI", "Mute CD Audio");
TRANSLATE_NOOP("FullscreenUI", "Navigate");
TRANSLATE_NOOP("FullscreenUI", "No");
TRANSLATE_NOOP("FullscreenUI", "No Game Selected");
TRANSLATE_NOOP("FullscreenUI", "No LED");
TRANSLATE_NOOP("FullscreenUI", "No Vibration");
TRANSLATE_NOOP("FullscreenUI", "No cheats are available for this game.");
TRANSLATE_NOOP("FullscreenUI", "No devices with vibration motors were detected.");
@ -10056,10 +10062,10 @@ TRANSLATE_NOOP("FullscreenUI", "Right: ");
TRANSLATE_NOOP("FullscreenUI", "Round Upscaled Texture Coordinates");
TRANSLATE_NOOP("FullscreenUI", "Rounds texture coordinates instead of flooring when upscaling. Can fix misaligned textures in some games, but break others, and is incompatible with texture filtering.");
TRANSLATE_NOOP("FullscreenUI", "Runahead");
TRANSLATE_NOOP("FullscreenUI", "Runahead for Analog Input");
TRANSLATE_NOOP("FullscreenUI", "Runahead/Rewind");
TRANSLATE_NOOP("FullscreenUI", "Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result in greater performance when using graphical enhancements with the hardware renderer.");
TRANSLATE_NOOP("FullscreenUI", "SDL DualSense Player LED");
TRANSLATE_NOOP("FullscreenUI", "SDL DualSense Mic Mute LED for Analog Mode");
TRANSLATE_NOOP("FullscreenUI", "SDL DualShock 4 / DualSense Enhanced Mode");
TRANSLATE_NOOP("FullscreenUI", "Safe Mode");
TRANSLATE_NOOP("FullscreenUI", "Save Controller Preset");

@ -561,7 +561,7 @@ void ImGuiManager::DrawEnhancementsOverlay(const GPUBackend* gpu)
if (g_settings.rewind_enable)
text.append_format(" RW={}/{}", g_settings.rewind_save_frequency, g_settings.rewind_save_slots);
if (g_settings.IsRunaheadEnabled())
text.append_format(" RA={}", g_settings.runahead_frames);
text.append_format(" RA={}{}", g_settings.runahead_frames, g_settings.runahead_for_analog_input ? "+A" : "");
if (g_settings.cpu_overclock_active)
text.append_format(" CPU={}%", g_settings.GetCPUOverclockPercent());

@ -126,7 +126,7 @@ void JogCon::SetBindState(u32 index, float value)
-static_cast<s8>((static_cast<u32>(m_half_axis_state[static_cast<u32>(HalfAxis::SteeringLeft)]) + 1) / 2);
if (m_steering_state != prev_steering_state)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(true);
}
const u16 bit = u16(1) << static_cast<u8>(index);
@ -134,14 +134,14 @@ void JogCon::SetBindState(u32 index, float value)
if (value >= m_button_deadzone)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state &= ~(bit);
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state |= bit;
}

@ -137,14 +137,14 @@ void NeGcon::SetBindState(u32 index, float value)
if (value >= 0.5f)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state &= ~bit;
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state |= bit;
}

@ -194,14 +194,14 @@ void NeGconRumble::SetBindState(u32 index, float value)
if (value >= 0.5f)
{
if (m_button_state & bit)
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state &= ~bit;
}
else
{
if (!(m_button_state & bit))
System::SetRunaheadReplayFlag();
System::SetRunaheadReplayFlag(false);
m_button_state |= bit;
}

@ -216,6 +216,7 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
rewind_save_frequency = si.GetFloatValue("Main", "RewindFrequency", 10.0f);
rewind_save_slots = static_cast<u16>(std::min(si.GetUIntValue("Main", "RewindSaveSlots", 10u), 65535u));
runahead_frames = static_cast<u8>(std::min(si.GetUIntValue("Main", "RunaheadFrameCount", 0u), 255u));
runahead_for_analog_input = si.GetBoolValue("Main", "RunaheadForAnalogInput", false);
cpu_execution_mode =
ParseCPUExecutionMode(
@ -598,6 +599,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
si.SetFloatValue("Main", "RewindFrequency", rewind_save_frequency);
si.SetUIntValue("Main", "RewindSaveSlots", rewind_save_slots);
si.SetUIntValue("Main", "RunaheadFrameCount", runahead_frames);
si.SetBoolValue("Main", "RunaheadForAnalogInput", runahead_for_analog_input);
si.SetStringValue("CPU", "ExecutionMode", GetCPUExecutionModeName(cpu_execution_mode));
si.SetBoolValue("CPU", "OverclockEnable", cpu_overclock_enable);
@ -1061,6 +1063,7 @@ void Settings::ApplySettingRestrictions()
g_settings.mdec_use_old_routines = false;
g_settings.bios_patch_fast_boot = false;
g_settings.runahead_frames = 0;
g_settings.runahead_for_analog_input = false;
g_settings.rewind_enable = false;
g_settings.pio_device_type = PIODeviceType::None;
g_settings.pcdrv_enable = false;

@ -322,6 +322,7 @@ struct Settings : public GPUSettings
bool bios_fast_forward_boot : 1 = false;
bool rewind_enable : 1 = false;
bool runahead_for_analog_input : 1 = false;
bool apply_compatibility_settings : 1 = true;
bool apply_game_settings : 1 = true;

@ -5149,11 +5149,14 @@ bool System::DoRunahead()
return false;
}
void System::SetRunaheadReplayFlag()
void System::SetRunaheadReplayFlag(bool is_analog_input)
{
if (s_state.runahead_frames == 0 || s_state.memory_save_state_count == 0)
return;
if (is_analog_input && !g_settings.runahead_for_analog_input)
return;
#ifdef PROFILE_MEMORY_SAVE_STATES
DEV_LOG("Runahead rewind pending...");
#endif

@ -437,7 +437,7 @@ std::string GetImageForLoadingScreen(const std::string& game_path);
//////////////////////////////////////////////////////////////////////////
void CalculateRewindMemoryUsage(u32 num_saves, u32 resolution_scale, u64* ram_usage, u64* vram_usage);
void ClearMemorySaveStates(bool reallocate_resources, bool recycle_textures);
void SetRunaheadReplayFlag();
void SetRunaheadReplayFlag(bool is_analog_input);
/// Asynchronous work tasks, complete on worker thread.
void QueueAsyncTask(std::function<void()> function);

@ -31,6 +31,8 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.rewindSaveFrequency, "Main", "RewindFrequency", 10.0f);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.rewindSaveSlots, "Main", "RewindSaveSlots", 10);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.runaheadFrames, "Main", "RunaheadFrameCount", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.runaheadForAnalogInput, "Main", "RunaheadForAnalogInput",
false);
const float effective_emulation_speed = m_dialog->getEffectiveFloatValue("Main", "EmulationSpeed", 1.0f);
fillComboBoxWithEmulationSpeeds(m_ui.emulationSpeed, effective_emulation_speed);
@ -144,6 +146,9 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
m_ui.runaheadFrames, tr("Runahead"), tr("Disabled"),
tr(
"Simulates the system ahead of time and rolls back/replays to reduce input lag. Very high system requirements."));
dialog->registerWidgetHelp(
m_ui.runaheadForAnalogInput, tr("Enable for Analog Input"), tr("Unchecked"),
tr("Activates runahead when analog input changes, which significantly increases system requirements."));
onOptimalFramePacingChanged();
updateSkipDuplicateFramesEnabled();
@ -239,6 +244,7 @@ void EmulationSettingsWidget::updateRewind()
const bool rewind_enabled = m_dialog->getEffectiveBoolValue("Main", "RewindEnable", false);
const bool runahead_enabled = m_dialog->getIntValue("Main", "RunaheadFrameCount", 0) > 0;
m_ui.rewindEnable->setEnabled(!runahead_enabled);
m_ui.runaheadForAnalogInput->setEnabled(runahead_enabled);
if (!runahead_enabled && rewind_enabled)
{

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>618</width>
<height>440</height>
<height>481</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -133,16 +133,9 @@
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Rewind/Runahead</string>
<string>Rewind</string>
</property>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="0,1">
<item row="0" column="0">
<widget class="QCheckBox" name="rewindEnable">
<property name="text">
<string>Enable Rewinding</string>
</property>
</widget>
</item>
<layout class="QGridLayout" name="gridLayout_3" columnstretch="0,0">
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
@ -150,16 +143,26 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="rewindSaveFrequency">
<item row="2" column="1">
<widget class="QSpinBox" name="rewindSaveSlots">
<property name="suffix">
<string> Seconds</string>
<string> Frames</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<double>3600.000000000000000</double>
<number>10000</number>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="rewindSummary">
<property name="text">
<string>TextLabel</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
@ -170,27 +173,43 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="rewindSaveSlots">
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="rewindSaveFrequency">
<property name="suffix">
<string> Frames</string>
</property>
<property name="minimum">
<number>1</number>
<string> Seconds</string>
</property>
<property name="maximum">
<number>10000</number>
<double>3600.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="rewindEnable">
<property name="text">
<string>Enable Rewinding</string>
</property>
</widget>
</item>
<item row="3" column="0">
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Runahead</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Runahead:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="0" column="1">
<widget class="QComboBox" name="runaheadFrames">
<item>
<property name="text">
@ -249,13 +268,10 @@
</item>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="rewindSummary">
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="runaheadForAnalogInput">
<property name="text">
<string>TextLabel</string>
</property>
<property name="wordWrap">
<bool>true</bool>
<string>Enable for Analog Input</string>
</property>
</widget>
</item>
@ -269,8 +285,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>

Loading…
Cancel
Save