diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 65922c212..7bc963f98 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -3266,6 +3266,11 @@ void FullscreenUI::DrawBIOSSettingsPage() DrawToggleSetting(bsi, FSUI_CSTR("Enable Fast Boot"), FSUI_CSTR("Patches the BIOS to skip the boot animation. Safe to enable."), "BIOS", "PatchFastBoot", Settings::DEFAULT_FAST_BOOT_VALUE); + DrawToggleSetting(bsi, FSUI_CSTR("Fast Forward Boot"), + FSUI_CSTR("Fast forwards through the early loading process when fast booting, saving time. Results " + "may vary between games."), + "BIOS", "FastForwardBoot", false, + GetEffectiveBoolSetting(bsi, "BIOS", "PatchFastBoot", Settings::DEFAULT_FAST_BOOT_VALUE)); DrawToggleSetting(bsi, FSUI_CSTR("Enable TTY Logging"), FSUI_CSTR("Logs BIOS calls to printf(). Not all games contain debugging messages."), "BIOS", "TTYLogging", false); @@ -7399,8 +7404,10 @@ TRANSLATE_NOOP("FullscreenUI", "Failed to load '{}'."); TRANSLATE_NOOP("FullscreenUI", "Failed to load shader {}. It may be invalid.\nError was:"); TRANSLATE_NOOP("FullscreenUI", "Failed to save input profile '{}'."); TRANSLATE_NOOP("FullscreenUI", "Fast Boot"); +TRANSLATE_NOOP("FullscreenUI", "Fast Forward Boot"); TRANSLATE_NOOP("FullscreenUI", "Fast Forward Speed"); TRANSLATE_NOOP("FullscreenUI", "Fast Forward Volume"); +TRANSLATE_NOOP("FullscreenUI", "Fast forwards through the early loading process when fast booting, saving time. Results may vary between games."); TRANSLATE_NOOP("FullscreenUI", "File Size"); TRANSLATE_NOOP("FullscreenUI", "File Size: %.2f MB"); TRANSLATE_NOOP("FullscreenUI", "File Title"); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 80df935cc..e9c3febe2 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -360,6 +360,7 @@ void Settings::Load(SettingsInterface& si, SettingsInterface& controller_si) bios_tty_logging = si.GetBoolValue("BIOS", "TTYLogging", false); bios_patch_fast_boot = si.GetBoolValue("BIOS", "PatchFastBoot", DEFAULT_FAST_BOOT_VALUE); + bios_fast_forward_boot = si.GetBoolValue("BIOS", "FastForwardBoot", false); multitap_mode = ParseMultitapModeName( @@ -618,6 +619,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const si.SetBoolValue("BIOS", "TTYLogging", bios_tty_logging); si.SetBoolValue("BIOS", "PatchFastBoot", bios_patch_fast_boot); + si.SetBoolValue("BIOS", "FastForwardBoot", bios_fast_forward_boot); for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { @@ -747,6 +749,9 @@ void Settings::FixIncompatibleSettings(bool display_osd_messages) g_settings.bios_patch_fast_boot = false; } + // fast forward boot requires fast boot + g_settings.bios_fast_forward_boot = g_settings.bios_patch_fast_boot && g_settings.bios_fast_forward_boot; + if (g_settings.pcdrv_enable && g_settings.pcdrv_root.empty()) { Host::AddKeyedOSDMessage("pcdrv_disabled_no_root", diff --git a/src/core/settings.h b/src/core/settings.h index 3cda6718e..feecd8c16 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -258,6 +258,7 @@ struct Settings bool bios_tty_logging : 1 = false; bool bios_patch_fast_boot : 1 = DEFAULT_FAST_BOOT_VALUE; + bool bios_fast_forward_boot : 1 = false; bool enable_8mb_ram : 1 = false; std::array controller_types{}; diff --git a/src/core/system.cpp b/src/core/system.cpp index 8a1d76976..fe22a26c4 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -162,6 +162,12 @@ static bool CreateGPU(GPURenderer renderer, bool is_switching, Error* error); static bool RecreateGPU(GPURenderer renderer, bool force_recreate_device = false, bool update_display = true); static void HandleHostGPUDeviceLost(); +/// Returns true if fast forwarding or slow motion is currently active. +static bool IsRunningAtNonStandardSpeed(); + +/// Returns true if boot is being fast forwarded. +static bool IsFastForwardingBoot(); + /// Updates the throttle period, call when target emulation speed changes. static void UpdateThrottlePeriod(); static void ResetThrottler(); @@ -1497,6 +1503,10 @@ void System::ResetSystem() if (Error error; !SetBootMode(new_boot_mode, &error)) ERROR_LOG("Failed to reload BIOS on boot mode change, the system may be unstable: {}", error.GetDescription()); + // Have to turn on turbo if fast forwarding boot. + if (IsFastForwardingBoot()) + UpdateSpeedLimiterState(); + Host::AddIconOSDMessage("SystemReset", ICON_FA_POWER_OFF, TRANSLATE_STR("OSDMessage", "System reset."), Host::OSD_QUICK_DURATION); @@ -1837,7 +1847,7 @@ bool System::Initialize(bool force_software_renderer, Error* error) g_ticks_per_second = ScaleTicksToOverclock(MASTER_CLOCK); s_max_slice_ticks = ScaleTicksToOverclock(MASTER_CLOCK / 10); s_frame_number = 1; - s_internal_frame_number = 1; + s_internal_frame_number = 0; s_target_speed = g_settings.emulation_speed; s_throttle_frequency = 60.0f; @@ -2333,6 +2343,14 @@ void System::SingleStepCPU() void System::IncrementInternalFrameNumber() { + if (IsFastForwardingBoot()) [[unlikely]] + { + // Need to turn off present throttle. + s_internal_frame_number++; + UpdateSpeedLimiterState(); + return; + } + s_internal_frame_number++; } @@ -3368,9 +3386,11 @@ void System::UpdateSpeedLimiterState() { DebugAssert(IsValid()); - s_target_speed = s_turbo_enabled ? - g_settings.turbo_speed : - (s_fast_forward_enabled ? g_settings.fast_forward_speed : g_settings.emulation_speed); + s_target_speed = + IsFastForwardingBoot() ? + 0.0f : + (s_turbo_enabled ? g_settings.turbo_speed : + (s_fast_forward_enabled ? g_settings.fast_forward_speed : g_settings.emulation_speed)); s_throttler_enabled = (s_target_speed != 0.0f); s_optimal_frame_pacing = (s_throttler_enabled && g_settings.display_optimal_frame_pacing); s_skip_presenting_duplicate_frames = s_throttler_enabled && g_settings.display_skip_presenting_duplicate_frames; @@ -5090,6 +5110,11 @@ bool System::IsRunningAtNonStandardSpeed() return (s_target_speed != 1.0f && !s_syncing_to_host); } +bool System::IsFastForwardingBoot() +{ + return (g_settings.bios_fast_forward_boot && s_internal_frame_number == 0 && s_boot_mode == BootMode::FastBoot); +} + s32 System::GetAudioOutputVolume() { return g_settings.GetAudioOutputVolume(IsRunningAtNonStandardSpeed()); diff --git a/src/core/system.h b/src/core/system.h index c7f55672e..fed3eaaa1 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -430,9 +430,6 @@ void ApplyCheatCode(u32 index); /// Toggle Widescreen Hack and Aspect Ratio void ToggleWidescreen(); -/// Returns true if fast forwarding or slow motion is currently active. -bool IsRunningAtNonStandardSpeed(); - /// Returns true if vsync should be used. GPUVSyncMode GetEffectiveVSyncMode(); bool ShouldAllowPresentThrottle(); diff --git a/src/duckstation-qt/biossettingswidget.cpp b/src/duckstation-qt/biossettingswidget.cpp index e5f0db883..78c0de9f0 100644 --- a/src/duckstation-qt/biossettingswidget.cpp +++ b/src/duckstation-qt/biossettingswidget.cpp @@ -21,6 +21,11 @@ BIOSSettingsWidget::BIOSSettingsWidget(SettingsWindow* dialog, QWidget* parent) SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableTTYLogging, "BIOS", "TTYLogging", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "BIOS", "PatchFastBoot", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastForwardBoot, "BIOS", "FastForwardBoot", false); + + connect(m_ui.fastBoot, &QCheckBox::checkStateChanged, this, &BIOSSettingsWidget::onFastBootChanged); + + onFastBootChanged(); dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"), tr("Patches the BIOS to skip the console's boot animation. Does not work with all games, " @@ -84,6 +89,14 @@ BIOSSettingsWidget::BIOSSettingsWidget(SettingsWindow* dialog, QWidget* parent) } refreshList(); + + m_dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"), + tr("Patches the BIOS to skip the boot animation. Safe to enable.")); + m_dialog->registerWidgetHelp(m_ui.fastForwardBoot, tr("Fast Forward Boot"), tr("Unchecked"), + tr("Fast forwards through the early loading process when fast booting, saving time. " + "Results may vary between games.")); + m_dialog->registerWidgetHelp(m_ui.enableTTYLogging, tr("Enable TTY Logging"), tr("Unchecked"), + tr("Logs BIOS calls to printf(). Not all games contain debugging messages.")); } BIOSSettingsWidget::~BIOSSettingsWidget() = default; @@ -103,6 +116,13 @@ void BIOSSettingsWidget::refreshList() m_dialog->isPerGameSettings()); } +void BIOSSettingsWidget::onFastBootChanged() +{ + const bool fast_boot_enabled = + m_dialog->getEffectiveBoolValue("BIOS", "PatchFastBoot", Settings::DEFAULT_FAST_BOOT_VALUE); + m_ui.fastForwardBoot->setEnabled(fast_boot_enabled); +} + void BIOSSettingsWidget::populateDropDownForRegion(ConsoleRegion region, QComboBox* cb, std::vector>& images, bool per_game) diff --git a/src/duckstation-qt/biossettingswidget.h b/src/duckstation-qt/biossettingswidget.h index 3ee9cc7d7..e6ad8d54d 100644 --- a/src/duckstation-qt/biossettingswidget.h +++ b/src/duckstation-qt/biossettingswidget.h @@ -29,6 +29,7 @@ public: private Q_SLOTS: void refreshList(); + void onFastBootChanged(); private: Ui::BIOSSettingsWidget m_ui; diff --git a/src/duckstation-qt/biossettingswidget.ui b/src/duckstation-qt/biossettingswidget.ui index c87b7fa5a..1273796c1 100644 --- a/src/duckstation-qt/biossettingswidget.ui +++ b/src/duckstation-qt/biossettingswidget.ui @@ -85,7 +85,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -152,28 +152,35 @@ Options and Patches - - + + Fast Boot - + Enable TTY Logging + + + + Fast Forward Boot + + + - Qt::Vertical + Qt::Orientation::Vertical