From 6f25cf31a76932e5f7ca82e40a979716425e73d4 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Mon, 17 Feb 2025 21:33:50 +1000 Subject: [PATCH] CDROM: Add randomness to repeated seek times I hate it, but it fixes lockups in Dino Crisis 2, and probably other games with dodgy code too. Also Simple 1500 Series Vol. 57 - The Meiro. --- src/core/cdrom.cpp | 16 ++++++++++++++++ src/core/save_state_version.h | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 2b23e4752..3ec87f68e 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -25,6 +25,7 @@ #include "common/gsvector.h" #include "common/heap_array.h" #include "common/log.h" +#include "common/xorshift_prng.h" #include "fmt/format.h" #include "imgui.h" @@ -52,6 +53,7 @@ enum : u32 XA_RESAMPLE_RING_BUFFER_SIZE = 32, XA_RESAMPLE_ZIGZAG_TABLE_SIZE = 29, XA_RESAMPLE_NUM_ZIGZAG_TABLES = 7, + PRNG_SEED = 0x4B435544u, PARAM_FIFO_SIZE = 16, RESPONSE_FIFO_SIZE = 16, @@ -460,6 +462,8 @@ struct CDROMState InlineFIFOQueue response_fifo; InlineFIFOQueue async_response_fifo; + XorShift128PlusPlus prng; + std::array sector_buffers; u32 current_read_sector_buffer = 0; u32 current_write_sector_buffer = 0; @@ -608,6 +612,7 @@ void CDROM::Reset() s_state.param_fifo.Clear(); s_state.response_fifo.Clear(); s_state.async_response_fifo.Clear(); + s_state.prng.Reset(PRNG_SEED); UpdateStatusRegister(); @@ -758,6 +763,11 @@ bool CDROM::DoState(StateWrapper& sw) sw.Do(&s_state.response_fifo); sw.Do(&s_state.async_response_fifo); + if (sw.GetVersion() >= 79) + sw.DoPOD(s_state.prng.GetMutableStatePtr()); + else + s_state.prng.Reset(PRNG_SEED); + if (sw.GetVersion() < 65) { // Skip over the "copied out data", we don't care about it. @@ -1637,6 +1647,12 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change) seek_type = (new_lba > current_lba) ? "sled forward" : "sled backward"; } + // I hate this so much. There's some games that are extremely timing sensitive in their disc code, and if we return + // the same seek times repeatedly, end up locking up in an infinite loop. e.g. Resident Evil, Dino Crisis, etc. + // Add some randomness to timing if we detect them repeatedly seeking, otherwise don't. This somewhat simulates how + // the real hardware behaves, by adding an additional 0.5-1ms to every seek. + ticks += s_state.prng.NextRange(System::MASTER_CLOCK / 2000, System::MASTER_CLOCK / 1000); + if (g_settings.cdrom_seek_speedup > 1) ticks = std::max(ticks / g_settings.cdrom_seek_speedup, MIN_SEEK_TICKS); diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index bf2f0a108..e21c74a15 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -6,7 +6,7 @@ #include "common/types.h" static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; -static constexpr u32 SAVE_STATE_VERSION = 78; +static constexpr u32 SAVE_STATE_VERSION = 79; static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42; static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);