From e2d5a54e206313414b0862161c7f4cd127790bc1 Mon Sep 17 00:00:00 2001 From: Ty Lamontagne Date: Sun, 12 Jan 2025 17:51:15 -0500 Subject: [PATCH] Memory Cards: Use file memory mapping instead of explicit file I/O --- pcsx2/SIO/Memcard/MemoryCardFile.cpp | 53 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/pcsx2/SIO/Memcard/MemoryCardFile.cpp b/pcsx2/SIO/Memcard/MemoryCardFile.cpp index 032cef212a44f..b89083ce5851b 100644 --- a/pcsx2/SIO/Memcard/MemoryCardFile.cpp +++ b/pcsx2/SIO/Memcard/MemoryCardFile.cpp @@ -24,6 +24,11 @@ #include +#ifdef _WIN32 +#include +#include +#endif + static constexpr int MCD_SIZE = 1024 * 8 * 16; // Legacy PSX card default size static constexpr int MC2_MBSIZE = 1024 * 528 * 2; // Size of a single megabyte of card data @@ -157,6 +162,8 @@ class FileMemoryCard { protected: std::FILE* m_file[8] = {}; + u8* m_mappings[8] = {}; + s64 m_fileSize[8] = {}; std::string m_filenames[8] = {}; std::vector m_currentdata; @@ -337,6 +344,21 @@ void FileMemoryCard::Open() if (read_result == 0) Host::ReportErrorAsync("Memory Card Read Failed", "Error reading memory card."); } + +#ifdef _WIN32 + const int fd = _fileno(m_file[slot]); + // Doesn't leak, refcounted based on views + const HANDLE hMapping = CreateFileMapping(reinterpret_cast(_get_osfhandle(fd)), nullptr, PAGE_READWRITE, 0, 0, nullptr); + if (!hMapping) + { + Console.Warning("CreateFileMapping failed: %d", GetLastError()); + } + m_mappings[slot] = reinterpret_cast(MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0)); + if (!m_mappings[slot]) + { + Console.Warning("MapViewOfFile failed: %d", GetLastError()); + } +#endif } } } @@ -364,6 +386,13 @@ void FileMemoryCard::Close() m_filenames[slot] = {}; m_fileSize[slot] = -1; +#ifdef _WIN32 + if (m_mappings[slot]) + { + UnmapViewOfFile(m_mappings[slot]); + m_mappings[slot] = nullptr; + } +#endif } } @@ -430,9 +459,20 @@ s32 FileMemoryCard::Read(uint slot, u8* dest, u32 adr, int size) memset(dest, 0, size); return 1; } + +#ifdef _WIN32 + if (adr + size > static_cast(m_fileSize[slot])) + { + Console.Warning("(FileMcd) Warning: read past end of file. (%d) [%08X]", slot, adr); + } + + std::memcpy(dest, m_mappings[slot] + adr, size); + return 1; +#else if (!Seek(mcfp, adr)) return 0; return std::fread(dest, size, 1, mcfp) == 1; +#endif } s32 FileMemoryCard::Save(uint slot, const u8* src, u32 adr, int size) @@ -516,10 +556,15 @@ s32 FileMemoryCard::EraseBlock(uint slot, u32 adr) if (!Seek(mcfp, adr)) return 0; - - u8 buf[MC2_ERASE_SIZE]; - std::memset(buf, 0xff, sizeof(buf)); - return std::fwrite(buf, sizeof(buf), 1, mcfp) == 1; +#ifdef _WIN32 + std::memset(m_mappings[slot] + adr, 0xff, MC2_ERASE_SIZE); + + return 1; +#else + std::array buffer; + std::memset(buffer.data(), 0xff, buffer.size()); + return std::fwrite(buffer.data(), buffer.size(), 1, mcfp) == 1; +#endif } u64 FileMemoryCard::GetCRC(uint slot)