From 98e4c181ca3f98633b2d94f536aee900c2ea5372 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 23 May 2021 13:35:10 +1000 Subject: [PATCH] CDROM: Add seek speedup enhancement --- src/core/cdrom.cpp | 21 ++++-- src/core/host_interface.cpp | 4 +- src/core/settings.cpp | 2 + src/core/settings.h | 1 + src/core/system.cpp | 24 +++++- src/duckstation-qt/consolesettingswidget.cpp | 5 ++ src/duckstation-qt/consolesettingswidget.ui | 77 +++++++++++++++++++- src/frontend-common/fullscreen_ui.cpp | 24 +++++- 8 files changed, 144 insertions(+), 14 deletions(-) diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 5a8f124e0..d3a4105d3 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -684,24 +684,30 @@ TickCount CDROM::GetTicksForRead() TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba) { + static constexpr TickCount MIN_TICKS = 20000; + + if (g_settings.cdrom_seek_speedup == 0) + return MIN_TICKS; + const TickCount tps = System::GetTicksPerSecond(); const CDImage::LBA current_lba = m_secondary_status.motor_on ? m_current_lba : 0; const u32 lba_diff = static_cast((new_lba > current_lba) ? (new_lba - current_lba) : (current_lba - new_lba)); - // Formula from Mednafen. - TickCount ticks = std::max( + // Original formula based on Mednafen. Still not accurate, doesn't consider the varying number of sectors per track. + // TODO: Replace with algorithm based on mechacon behavior. + u32 ticks = std::max( 20000, static_cast( ((static_cast(lba_diff) * static_cast(tps) * static_cast(1000)) / (72 * 60 * 75)) / 1000)); if (!m_secondary_status.motor_on) ticks += tps; if (lba_diff >= 2550) - ticks += static_cast((u64(tps) * 300) / 1000); + ticks += static_cast((u64(tps) * 300) / 1000); else { // When paused, the CDC seems to keep reading the disc until it hits the position it's set to, then skip 10-15 // sectors back (depending on how far into the disc it is). We'll be generous and use 4 sectors, since on average // it's probably closer. - ticks += GetTicksForRead() * 4u; + ticks += static_cast(GetTicksForRead()) * 4u; } if (m_mode.double_speed != m_current_double_speed) @@ -714,8 +720,11 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba) ticks += static_cast(static_cast(tps) * 0.1); } - Log_DevPrintf("Seek time for %u LBAs: %d", lba_diff, ticks); - return ticks; + if (g_settings.cdrom_seek_speedup > 1) + ticks = std::min(ticks / g_settings.cdrom_seek_speedup, MIN_TICKS); + + Log_DevPrintf("Seek time for %u LBAs: %u", lba_diff, ticks); + return static_cast(ticks); } TickCount CDROM::GetTicksForStop(bool motor_was_on) diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index e2d504530..ae7c4ceee 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -558,6 +558,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetBoolValue("CDROM", "LoadImageToRAM", false); si.SetBoolValue("CDROM", "MuteCDAudio", false); si.SetIntValue("CDROM", "ReadSpeedup", 1); + si.SetIntValue("CDROM", "SeekSpeedup", 1); si.SetStringValue("Audio", "Backend", Settings::GetAudioBackendName(Settings::DEFAULT_AUDIO_BACKEND)); si.SetIntValue("Audio", "OutputVolume", 100); @@ -638,7 +639,8 @@ void HostInterface::FixIncompatibleSettings(bool display_osd_messages) g_settings.gpu_widescreen_hack = false; g_settings.gpu_pgxp_enable = false; g_settings.gpu_24bit_chroma_smoothing = false; - g_settings.cdrom_read_speedup = false; + g_settings.cdrom_read_speedup = 1; + g_settings.cdrom_seek_speedup = 1; g_settings.cdrom_mute_cd_audio = false; g_settings.texture_replacements.enable_vram_write_replacements = false; g_settings.bios_patch_fast_boot = false; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 0e6a84e14..c06568237 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -255,6 +255,7 @@ void Settings::Load(SettingsInterface& si) cdrom_load_image_to_ram = si.GetBoolValue("CDROM", "LoadImageToRAM", false); cdrom_mute_cd_audio = si.GetBoolValue("CDROM", "MuteCDAudio", false); cdrom_read_speedup = si.GetIntValue("CDROM", "ReadSpeedup", 1); + cdrom_seek_speedup = si.GetIntValue("CDROM", "SeekSpeedup", 1); audio_backend = ParseAudioBackend(si.GetStringValue("Audio", "Backend", GetAudioBackendName(DEFAULT_AUDIO_BACKEND)).c_str()) @@ -430,6 +431,7 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("CDROM", "LoadImageToRAM", cdrom_load_image_to_ram); si.SetBoolValue("CDROM", "MuteCDAudio", cdrom_mute_cd_audio); si.SetIntValue("CDROM", "ReadSpeedup", cdrom_read_speedup); + si.SetIntValue("CDROM", "SeekSpeedup", cdrom_seek_speedup); si.SetStringValue("Audio", "Backend", GetAudioBackendName(audio_backend)); si.SetIntValue("Audio", "OutputVolume", audio_output_volume); diff --git a/src/core/settings.h b/src/core/settings.h index c30f3fa88..6933c8377 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -156,6 +156,7 @@ struct Settings bool cdrom_load_image_to_ram = false; bool cdrom_mute_cd_audio = false; u32 cdrom_read_speedup = 1; + u32 cdrom_seek_speedup = 1; AudioBackend audio_backend = AudioBackend::Cubeb; s32 audio_output_volume = 100; diff --git a/src/core/system.cpp b/src/core/system.cpp index e29a0290f..00404f2db 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -885,10 +885,12 @@ bool Initialize(bool force_software_renderer) g_mdec.Initialize(); g_sio.Initialize(); + static constexpr float WARNING_DURATION = 15.0f; + if (g_settings.cpu_overclock_active) { g_host_interface->AddFormattedOSDMessage( - 10.0f, + WARNING_DURATION, g_host_interface->TranslateString("OSDMessage", "CPU clock speed is set to %u%% (%u / %u). This may result in instability."), g_settings.GetCPUOverclockPercent(), g_settings.cpu_overclock_numerator, g_settings.cpu_overclock_denominator); @@ -896,11 +898,29 @@ bool Initialize(bool force_software_renderer) if (g_settings.cdrom_read_speedup > 1) { g_host_interface->AddFormattedOSDMessage( - 10.0f, + WARNING_DURATION, g_host_interface->TranslateString( "OSDMessage", "CD-ROM read speedup set to %ux (effective speed %ux). This may result in instability."), g_settings.cdrom_read_speedup, g_settings.cdrom_read_speedup * 2); } + if (g_settings.cdrom_seek_speedup != 1) + { + if (g_settings.cdrom_seek_speedup == 0) + { + g_host_interface->AddOSDMessage( + g_host_interface->TranslateStdString("OSDMessage", + "CD-ROM seek speedup set to instant. This may result in instability."), + WARNING_DURATION); + } + else + { + g_host_interface->AddFormattedOSDMessage( + WARNING_DURATION, + g_host_interface->TranslateString("OSDMessage", + "CD-ROM seek speedup set to %ux. This may result in instability."), + g_settings.cdrom_seek_speedup); + } + } UpdateThrottlePeriod(); UpdateMemorySaveStateSettings(); diff --git a/src/duckstation-qt/consolesettingswidget.cpp b/src/duckstation-qt/consolesettingswidget.cpp index 86822a76a..98349cdb5 100644 --- a/src/duckstation-qt/consolesettingswidget.cpp +++ b/src/duckstation-qt/consolesettingswidget.cpp @@ -41,6 +41,7 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.cdromRegionCheck, "CDROM", "RegionCheck", false); SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.cdromLoadImageToRAM, "CDROM", "LoadImageToRAM", false); + SettingWidgetBinder::BindWidgetToIntSetting(m_host_interface, m_ui.cdromSeekSpeedup, "CDROM", "SeekSpeedup", 1); SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.multitapMode, "ControllerPorts", "MultitapMode", &Settings::ParseMultitapModeName, &Settings::GetMultitapModeName, Settings::DEFAULT_MULTITAP_MODE); @@ -67,6 +68,10 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW m_ui.cdromReadSpeedup, tr("CDROM Read Speedup"), tr("None (Double Speed)"), tr("Speeds up CD-ROM reads by the specified factor. Only applies to double-speed reads, and is ignored when audio " "is playing. May improve loading speeds in some games, at the cost of breaking others.")); + dialog->registerWidgetHelp( + m_ui.cdromReadSpeedup, tr("CDROM Seek Speedup"), tr("None (Normal Speed)"), + tr("Reduces the simulated time for the CD-ROM sled to move to different areas of the disc. Can improve loading " + "times, but crash games which do not expect the CD-ROM to operate faster.")); dialog->registerWidgetHelp( m_ui.cdromReadThread, tr("Use Read Thread (Asynchronous)"), tr("Checked"), tr("Reduces hitches in emulation by reading/decompressing CD data asynchronously on a worker thread.")); diff --git a/src/duckstation-qt/consolesettingswidget.ui b/src/duckstation-qt/consolesettingswidget.ui index 7f38ff665..b905e3c54 100644 --- a/src/duckstation-qt/consolesettingswidget.ui +++ b/src/duckstation-qt/consolesettingswidget.ui @@ -43,11 +43,11 @@ - + - Enable 8MB RAM (Dev Console) + Enable 8MB RAM (Dev Console) - + @@ -198,7 +198,7 @@ - + @@ -223,6 +223,75 @@ + + + + Seek Speedup: + + + + + + + 1 + + + + Infinite/Instantaneous + + + + + None (Normal Speed) + + + + + 2x + + + + + 3x + + + + + 4x + + + + + 5x + + + + + 6x + + + + + 7x + + + + + 8x + + + + + 9x + + + + + 10x + + + + diff --git a/src/frontend-common/fullscreen_ui.cpp b/src/frontend-common/fullscreen_ui.cpp index 8150eeba8..c20d718e4 100644 --- a/src/frontend-common/fullscreen_ui.cpp +++ b/src/frontend-common/fullscreen_ui.cpp @@ -1425,6 +1425,9 @@ void DrawSettingsWindow() make_array("None (Double Speed)", "2x (Quad Speed)", "3x (6x Speed)", "4x (8x Speed)", "5x (10x Speed)", "6x (12x Speed)", "7x (14x Speed)", "8x (16x Speed)", "9x (18x Speed)", "10x (20x Speed)"); + static constexpr auto cdrom_seek_speeds = make_array("Infinite/Instantaneous", "None (Normal Speed)", "2x", + "3x", "4x", "5x", "6x", "7x", "8x", "9x", "10x"); + BeginMenuButtons(); MenuHeading("Console Settings"); @@ -1456,7 +1459,7 @@ void DrawSettingsWindow() MenuHeading("CD-ROM Emulation"); const u32 read_speed_index = - std::min(s_settings_copy.cdrom_read_speedup, static_cast(cdrom_read_speeds.size() + 1)) - 1; + std::clamp(s_settings_copy.cdrom_read_speedup, 1u, static_cast(cdrom_read_speeds.size())) - 1u; if (MenuButtonWithValue("Read Speedup", "Speeds up CD-ROM reads by the specified factor. May improve loading speeds in some " "games, and break others.", @@ -1474,6 +1477,25 @@ void DrawSettingsWindow() }); } + const u32 seek_speed_index = + std::min(s_settings_copy.cdrom_seek_speedup, static_cast(cdrom_seek_speeds.size())); + if (MenuButtonWithValue("Seek Speedup", + "Speeds up CD-ROM seeks by the specified factor. May improve loading speeds in some " + "games, and break others.", + cdrom_seek_speeds[seek_speed_index])) + { + ImGuiFullscreen::ChoiceDialogOptions options; + options.reserve(cdrom_seek_speeds.size()); + for (u32 i = 0; i < static_cast(cdrom_seek_speeds.size()); i++) + options.emplace_back(cdrom_seek_speeds[i], i == seek_speed_index); + OpenChoiceDialog("CD-ROM Seek Speedup", false, std::move(options), + [](s32 index, const std::string& title, bool checked) { + if (index >= 0) + s_settings_copy.cdrom_seek_speedup = static_cast(index); + CloseChoiceDialog(); + }); + } + settings_changed |= ToggleButton( "Enable Read Thread", "Reduces hitches in emulation by reading/decompressing CD data asynchronously on a worker thread.",