From c40e13228494667fc88b2f62cea7c2c5f6967fd8 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Fri, 23 Jun 2023 03:05:36 +0100 Subject: [PATCH] SIO/MCD: hugely improved memcard swapping + reinsertion --- pcsx2-qt/Translations/pcsx2-qt_en.ts | 253 +++++++++++++-------------- pcsx2/CDVD/CDVD.cpp | 2 + pcsx2/MemoryCardFile.cpp | 37 ++-- pcsx2/MemoryCardFile.h | 4 +- pcsx2/Pcsx2Config.cpp | 1 - pcsx2/Sio.cpp | 50 +++--- pcsx2/Sio.h | 3 +- pcsx2/VMManager.cpp | 43 +++-- 8 files changed, 205 insertions(+), 188 deletions(-) diff --git a/pcsx2-qt/Translations/pcsx2-qt_en.ts b/pcsx2-qt/Translations/pcsx2-qt_en.ts index 54866da7e3..c0cf2bf23e 100644 --- a/pcsx2-qt/Translations/pcsx2-qt_en.ts +++ b/pcsx2-qt/Translations/pcsx2-qt_en.ts @@ -3673,42 +3673,42 @@ Achievements: %5 (%6) - + Saving screenshot to '{}'. - + Saved screenshot to '{}'. - + Failed to save screenshot to '{}'. - + Host GPU device encountered an error and was recovered. This may have broken rendering. - + CAS is not available, your graphics driver does not support the required functionality. - + Saving {0} GS dump {1} to '{2}' - + Failed to render/download screenshot. - + Saved GS dump to '{}'. @@ -3728,7 +3728,7 @@ Achievements: %5 (%6) - + Spin GPU During Readbacks is enabled, but calibrated timestamps are unavailable. This might be really slow. @@ -6695,272 +6695,272 @@ Swap chain: see Microsoft's Terminology Portal. - + Target speed set to {:.0f}%. - + Volume: Muted - + Volume: {}% - + Save slot {} selected (last save: {}). - + Save slot {} selected (no save yet). - + No save state found in slot {}. - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + System - + Open Pause Menu - + Open Achievements List - + Open Leaderboards List - + Toggle Pause - + Toggle Fullscreen - + Toggle Frame Limit - + Toggle Turbo / Fast Forward - + Toggle Slow Motion - + Turbo / Fast Forward (Hold) - + Increase Target Speed - + Decrease Target Speed - + Increase Volume - + Decrease Volume - + Toggle Mute - + Frame Advance - + Shut Down Virtual Machine - + Reset Virtual Machine - + Toggle Input Recording Mode - - - - + + + + Save States - + Select Previous Save Slot - + Select Next Save Slot - + Save State To Selected Slot - + Load State From Selected Slot - + Save State To Slot 1 - + Load State From Slot 1 - + Save State To Slot 2 - + Load State From Slot 2 - + Save State To Slot 3 - + Load State From Slot 3 - + Save State To Slot 4 - + Load State From Slot 4 - + Save State To Slot 5 - + Load State From Slot 5 - + Save State To Slot 6 - + Load State From Slot 6 - + Save State To Slot 7 - + Load State From Slot 7 - + Save State To Slot 8 - + Load State From Slot 8 - + Save State To Slot 9 - + Load State From Slot 9 - + Save State To Slot 10 - + Load State From Slot 10 @@ -8324,18 +8324,13 @@ The saves will not be recoverable. - - Memory Card in port %d / slot %d reinserted + + Memory card in port {} / slot {} reinserted - - Memory Card in port {} / slot {} reinserted. - - - - - Force ejecting all Memory Cards. + + Force ejecting all Memory Cards. Reinserting in 1 second. @@ -10861,207 +10856,207 @@ The URL was: %1 VMManager - + Failed to back up old save state {}. - + Failed to save save state: {}. - + State saved to slot {}. - + Failed to save save state to slot {}. - + There is no save state in slot {}. - + Loading state from slot {}... - + Saving state to slot {}... - + Disc removed. - + Disc changed to '{}'. - + Failed to open new disc image '{}'. Reverting to old image. - + Failed to switch back to old disc image. Removing disc. - + Cheats have been disabled due to achievements hardcore mode. - + Fast CDVD is enabled, this may break games. - + Cycle rate/skip is not at default, this may crash or make games run too slow. - + Audio is using async mix, expect desynchronization in FMVs. - + Upscale multiplier is below native, this will break rendering. - + Mipmapping is not set to automatic. This may break rendering in some games. - + Texture filtering is not set to Bilinear (PS2). This will break rendering in some games. - + Trilinear filtering is not set to automatic. This may break rendering in some games. - + Blending is below basic, this may break effects in some games. - + Hardware Download Mode is not set to Accurate, this may break rendering in some games. - + EE FPU Round Mode is not set to default, this may break some games. - + EE FPU Clamp Mode is not set to default, this may break some games. - + VU Round Mode is not set to default, this may break some games. - + VU Clamp Mode is not set to default, this may break some games. - + Game Fixes are not enabled. Compatibility with some games may be affected. - + Compatibility Patches are not enabled. Compatibility with some games may be affected. - + Frame rate for NTSC is not default. This may break some games. - + Frame rate for PAL is not default. This may break some games. - + EE Recompiler is not enabled, this will significantly reduce performance. - + VU0 Recompiler is not enabled, this will significantly reduce performance. - + VU1 Recompiler is not enabled, this will significantly reduce performance. - + IOP Recompiler is not enabled, this will significantly reduce performance. - + EE Cache is enabled, this will significantly reduce performance. - + EE Wait Loop Detection is not enabled, this may reduce performance. - + INTC Spin Detection is not enabled, this may reduce performance. - + Instant VU1 is disabled, this may reduce performance. - + mVU Flag Hack is not enabled, this may reduce performance. - + GPU Palette Conversion is enabled, this may reduce performance. - + Texture Preloading is not Full, this may reduce performance. - + Estimate texture region is enabled, this may reduce performance. diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 30b3c09aaa..4c37387aa5 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -19,6 +19,7 @@ #include "IopHw.h" #include "IopDma.h" #include "VMManager.h" +#include "Sio.h" #include #include @@ -1528,6 +1529,7 @@ void cdvdVsync() cdvd.RTCcount = 0; cdvdUpdateTrayState(); + AutoEject::CountDownTicks(); cdvd.RTC.second++; if (cdvd.RTC.second < 60) diff --git a/pcsx2/MemoryCardFile.cpp b/pcsx2/MemoryCardFile.cpp index a0c85a75ad..70f7310f18 100644 --- a/pcsx2/MemoryCardFile.cpp +++ b/pcsx2/MemoryCardFile.cpp @@ -24,6 +24,7 @@ #include "MemoryCardFile.h" #include "MemoryCardFolder.h" +#include "Sio.h" #include "System.h" #include "Config.h" @@ -292,14 +293,11 @@ void FileMemoryCard::Open() cont = true; } - if (EmuConfig.Mcd[slot].Type != MemoryCardType::File) - { - str = "[is not memcard file]"; + if (EmuConfig.Mcd[slot].Type == MemoryCardType::File) + Console.WriteLn(cont ? Color_Gray : Color_Green, fmt::format("McdSlot {} [File]: {}", slot, str)); + else cont = true; - } - Console.WriteLn(cont ? Color_Gray : Color_Green, "McdSlot %u [File]: %.*s", slot, - static_cast(str.size()), str.data()); if (cont) continue; @@ -660,6 +658,20 @@ void FileMcd_EmuClose() Mcd::impl.Close(); } +void FileMcd_CancelEject() +{ + AutoEject::ClearAll(); +} + +void FileMcd_Reopen(std::string new_serial) +{ + Console.WriteLn("Reopening memory cards..."); + FileMcd_EmuClose(); + FileMcd_EmuOpen(); + + sioSetGameSerial(new_serial); +} + s32 FileMcd_IsPresent(uint port, uint slot) { const uint combinedSlot = FileMcd_ConvertToSlot(port, slot); @@ -776,20 +788,25 @@ void FileMcd_NextFrame(uint port, uint slot) } } -bool FileMcd_ReIndex(uint port, uint slot, const std::string& filter) +int FileMcd_ReIndex(uint port, uint slot, const std::string& filter) { - const uint combinedSlot = FileMcd_ConvertToSlot(port, slot); + const int combinedSlot = FileMcd_ConvertToSlot(port, slot); + switch (EmuConfig.Mcd[combinedSlot].Type) { //case MemoryCardType::File: // return Mcd::impl.ReIndex( combinedSlot, filter ); // break; case MemoryCardType::Folder: - return Mcd::implFolder.ReIndex(combinedSlot, EmuConfig.McdFolderAutoManage, filter); + if (!Mcd::implFolder.ReIndex(combinedSlot, EmuConfig.McdFolderAutoManage, filter)) + return -1; break; default: - return false; + return -1; + break; } + + return combinedSlot; } // -------------------------------------------------------------------------------------- diff --git a/pcsx2/MemoryCardFile.h b/pcsx2/MemoryCardFile.h index a0ad382de5..ea95f0589c 100644 --- a/pcsx2/MemoryCardFile.h +++ b/pcsx2/MemoryCardFile.h @@ -47,6 +47,8 @@ extern std::string FileMcd_GetDefaultName(uint slot); uint FileMcd_ConvertToSlot(uint port, uint slot); void FileMcd_EmuOpen(); void FileMcd_EmuClose(); +void FileMcd_CancelEject(); +void FileMcd_Reopen(std::string new_serial); s32 FileMcd_IsPresent(uint port, uint slot); void FileMcd_GetSizeInfo(uint port, uint slot, McdSizeInfo* outways); bool FileMcd_IsPSX(uint port, uint slot); @@ -55,7 +57,7 @@ s32 FileMcd_Save(uint port, uint slot, const u8* src, u32 adr, int size); s32 FileMcd_EraseBlock(uint port, uint slot, u32 adr); u64 FileMcd_GetCRC(uint port, uint slot); void FileMcd_NextFrame(uint port, uint slot); -bool FileMcd_ReIndex(uint port, uint slot, const std::string& filter); +int FileMcd_ReIndex(uint port, uint slot, const std::string& filter); std::vector FileMcd_GetAvailableCards(bool include_in_use_cards); std::optional FileMcd_GetCardInfo(const std::string_view& name); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index d4c386a141..e5e7400eb8 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -1373,7 +1373,6 @@ Pcsx2Config::Pcsx2Config() { Mcd[slot].Enabled = !FileMcd_IsMultitapSlot(slot); // enables main 2 slots Mcd[slot].Filename = FileMcd_GetDefaultName(slot); - // Folder memory card is autodetected later. Mcd[slot].Type = MemoryCardType::File; } diff --git a/pcsx2/Sio.cpp b/pcsx2/Sio.cpp index 967846785e..678b51d197 100644 --- a/pcsx2/Sio.cpp +++ b/pcsx2/Sio.cpp @@ -204,15 +204,6 @@ void Sio0::SetTxData(u8 value) if (mcd->autoEjectTicks) { SetRxData(0x00); - mcd->autoEjectTicks--; - - if (mcd->autoEjectTicks == 0) - { - Host::AddKeyedOSDMessage(fmt::format("AutoEjectSlotClear{}{}", port, slot), - fmt::format(TRANSLATE_SV("MemoryCard", "Memory Card in port %d / slot %d reinserted"), - port + 1, slot + 1), - Host::OSD_INFO_DURATION); - } return; } @@ -585,16 +576,6 @@ void Sio2::Memcard() fifoOut.push_back(0x00); } - mcd->autoEjectTicks--; - - if (mcd->autoEjectTicks == 0) - { - Host::AddKeyedOSDMessage(fmt::format("AutoEjectSlotClear{}{}", port, slot), - fmt::format( - TRANSLATE_SV("MemoryCard", "Memory Card in port {} / slot {} reinserted."), port + 1, slot + 1), - Host::OSD_INFO_DURATION); - } - return; } @@ -833,7 +814,8 @@ void sioNextFrame() { void sioSetGameSerial( const std::string& serial ) { for ( uint port = 0; port < 2; ++port ) { for ( uint slot = 0; slot < 4; ++slot ) { - if ( mcds[port][slot].ReIndex( serial ) ) { + if ( int index = mcds[port][slot].ReIndex( serial ) >= 0 ) { + Console.WriteLn("Ejecting Memory Card %u (port %u slot %u) due to source change. Reinsert in 1 second.", index, port, slot); AutoEject::Set( port, slot ); } } @@ -915,11 +897,33 @@ bool sioPortAndSlotIsMultitap(u32 port, u32 slot) return (slot != 0); } +void AutoEject::CountDownTicks() +{ + bool reinserted = false; + for (size_t port = 0; port < SIO::PORTS; port++) + { + for (size_t slot = 0; slot < SIO::SLOTS; slot++) + { + if (mcds[port][slot].autoEjectTicks > 0) + { + if (--mcds[port][slot].autoEjectTicks == 0) + { + Host::AddKeyedOSDMessage(fmt::format("AutoEjectSlotClear{}{}", port, slot), + fmt::format(TRANSLATE_SV("MemoryCard", "Memory card in port {} / slot {} reinserted"), + port + 1, slot + 1), + Host::OSD_INFO_DURATION); + } + } + } + } +} + void AutoEject::Set(size_t port, size_t slot) { - if (EmuConfig.McdEnableEjection) + if (EmuConfig.McdEnableEjection && mcds[port][slot].autoEjectTicks == 0) { - mcds[port][slot].autoEjectTicks = 60; + mcds[port][slot].autoEjectTicks = 1; // 1 second is enough. + mcds[port][slot].term = 0x55; // Reset terminator to default (0x55), forces the PS2 to recheck the memcard. } } @@ -931,7 +935,7 @@ void AutoEject::Clear(size_t port, size_t slot) void AutoEject::SetAll() { Host::AddIconOSDMessage("AutoEjectAllSet", ICON_FA_SD_CARD, - TRANSLATE_SV("MemoryCard", "Force ejecting all Memory Cards."), Host::OSD_INFO_DURATION); + TRANSLATE_SV("MemoryCard", "Force ejecting all Memory Cards. Reinserting in 1 second."), Host::OSD_INFO_DURATION); for (size_t port = 0; port < SIO::PORTS; port++) { diff --git a/pcsx2/Sio.h b/pcsx2/Sio.h index 0445db7350..8525abf97a 100644 --- a/pcsx2/Sio.h +++ b/pcsx2/Sio.h @@ -99,7 +99,7 @@ struct _mcd FileMcd_NextFrame( port, slot ); } - bool ReIndex(const std::string& filter) { + int ReIndex(const std::string& filter) { return FileMcd_ReIndex(port, slot, filter); } }; @@ -243,6 +243,7 @@ extern void sioSetGameSerial(const std::string& serial); namespace AutoEject { + extern void CountDownTicks(); extern void Set(size_t port, size_t slot); extern void Clear(size_t port, size_t slot); extern void SetAll(); diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index 685af1f6b9..88e5b48d1b 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -627,9 +627,16 @@ void VMManager::Internal::UpdateEmuFolders() if (EmuFolders::MemoryCards != old_memcards_directory) { - FileMcd_EmuClose(); - FileMcd_EmuOpen(); + std::string memcardFilters = ""; + if (const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(s_disc_serial)) + { + memcardFilters = game->memcardFiltersAsString(); + } + AutoEject::SetAll(); + + if(!GSDumpReplayer::IsReplayingDump()) + FileMcd_Reopen(memcardFilters.empty() ? s_disc_serial : memcardFilters); } if (EmuFolders::Textures != old_textures_directory) @@ -882,13 +889,6 @@ void VMManager::UpdateDiscDetails(bool booting) Console.WriteLn(Color_StrongGreen, fmt::format(" Version: {}", s_disc_version)); Console.WriteLn(Color_StrongGreen, fmt::format(" CRC: {:08X}", s_disc_crc)); - sioSetGameSerial(memcardFilters.empty() ? s_disc_serial : memcardFilters); - - // If we don't reset the timer here, when using folder memcards the reindex will cause an eject, - // which a bunch of games don't like since they access the memory card on boot. - if (booting) - AutoEject::ClearAll(); - UpdateGameSettingsLayer(); ApplySettings(); @@ -903,6 +903,9 @@ void VMManager::UpdateDiscDetails(bool booting) Achievements::GameChanged(s_disc_crc, s_current_crc); ReloadPINE(); UpdateDiscordPresence(Achievements::GetRichPresenceString()); + + if (!GSDumpReplayer::IsReplayingDump()) + FileMcd_Reopen(memcardFilters.empty() ? s_disc_serial : memcardFilters); } void VMManager::ClearDiscDetails() @@ -1145,17 +1148,11 @@ bool VMManager::Initialize(VMBootParameters boot_params) } ScopedGuard close_cdvd(&DoCDVDclose); - // Must be before updating serial because of folder memcards. - if (!GSDumpReplayer::IsReplayingDump()) - { - Console.WriteLn("Opening Memory cards..."); - FileMcd_EmuOpen(); - } - ScopedGuard close_memcards(&FileMcd_EmuClose); - // Figure out which game we're running! This also loads game settings. UpdateDiscDetails(true); + ScopedGuard close_memcards(&FileMcd_EmuClose); + // Read fast boot setting late so it can be overridden per-game. // ELFs must be fast booted, and GS dumps are never fast booted. s_fast_boot_requested = @@ -1958,7 +1955,9 @@ void VMManager::Internal::EntryPointCompilingOnCPUThread() HandleELFChange(true); Patch::ApplyLoadedPatches(Patch::PPT_ONCE_ON_LOAD); - + // If the config changes at this point, it's a reset, so the game doesn't currently know about the memcard + // so there's no need to leave the eject running. + FileMcd_CancelEject(); // Toss all the recs, we're going to be executing new code. SysClearExecutionCache(); } @@ -2113,9 +2112,6 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config) Console.WriteLn("Updating memory card configuration"); - FileMcd_EmuClose(); - FileMcd_EmuOpen(); - // force card eject when files change for (u32 port = 0; port < 2; port++) { @@ -2130,7 +2126,6 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config) } } } - // force reindexing, mc folder code is janky std::string sioSerial; { @@ -2140,7 +2135,9 @@ void VMManager::CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config) if (sioSerial.empty()) sioSerial = s_disc_serial; } - sioSetGameSerial(sioSerial); + + if (!GSDumpReplayer::IsReplayingDump()) + FileMcd_Reopen(sioSerial); } void VMManager::CheckForMiscConfigChanges(const Pcsx2Config& old_config)