From 3074d3caa0124c219684622f5bdee772412ac0fd Mon Sep 17 00:00:00 2001 From: LibretroAdmin Date: Sat, 7 Nov 2026 05:22:19 +0100 Subject: [PATCH] Riivolution: memory patch values lent, not copied A memory patch's value file is lent through File::LoanFile and handed to the patcher as a span, and a value given inline is used where the parser left it, instead of either being copied into a fresh std::vector each time a patch is applied. --- Source/Core/DiscIO/RiivolutionPatcher.cpp | 62 ++++++++++++++--------- Source/Core/DiscIO/RiivolutionPatcher.h | 7 ++- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index 074e6d078e..0a091a0ceb 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -172,20 +172,14 @@ FileDataLoaderHostFS::GetExternalFileSize(std::string_view external_relative_pat return f.GetSize(); } -std::vector FileDataLoaderHostFS::GetFileContents(std::string_view external_relative_path) +bool FileDataLoaderHostFS::LoanFileContents(std::string_view external_relative_path, + ::File::FileLoan* loan) { auto path = MakeAbsoluteFromRelative(external_relative_path); - if (!path) - return {}; - ::File::IOFile f(*path, "rb"); - if (!f) - return {}; - const u64 length = f.GetSize(); - std::vector value; - value.resize(length); - if (!f.ReadBytes(value.data(), length)) - return {}; - return value; + loan->data = nullptr; + loan->size = 0; + loan->owned = nullptr; + return path && ::File::LoanFile(loan, path->c_str()); } std::vector @@ -524,10 +518,20 @@ static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, u32 offset, } } -static std::vector GetMemoryPatchValue(const Patch& patch, const Memory& memory_patch) +// The patch's value: lent from its value file, or the parsed bytes as they +// are; File::EndLoan(loan) when done either way. +static std::span GetMemoryPatchValue(const Patch& patch, const Memory& memory_patch, + ::File::FileLoan* loan) { + loan->data = nullptr; + loan->size = 0; + loan->owned = nullptr; if (!memory_patch.m_valuefile.empty()) - return patch.m_file_data_loader->GetFileContents(memory_patch.m_valuefile); + { + if (!patch.m_file_data_loader->LoanFileContents(memory_patch.m_valuefile, loan)) + return {}; + return std::span(loan->data, size_t(loan->size)); + } return memory_patch.m_value; } @@ -537,8 +541,10 @@ static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& pat if (memory_patch.m_offset == 0) return; + ::File::FileLoan loan; ApplyMemoryPatch(guard, memory_patch.m_offset | 0x80000000, - GetMemoryPatchValue(patch, memory_patch), memory_patch.m_original); + GetMemoryPatchValue(patch, memory_patch, &loan), memory_patch.m_original); + ::File::EndLoan(&loan); } static void ApplySearchMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch, @@ -553,21 +559,17 @@ static void ApplySearchMemoryPatch(const Core::CPUThreadGuard& guard, const Patc const u32 address = ram_start + i; if (MemoryMatchesAt(guard, address, memory_patch.m_original)) { - ApplyMemoryPatch(guard, address, GetMemoryPatchValue(patch, memory_patch), {}); + ::File::FileLoan loan; + ApplyMemoryPatch(guard, address, GetMemoryPatchValue(patch, memory_patch, &loan), {}); + ::File::EndLoan(&loan); break; } } } -static void ApplyOcarinaMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch, - const Memory& memory_patch, u32 ram_start, u32 length) +static void ApplyOcarinaPattern(const Core::CPUThreadGuard& guard, const Memory& memory_patch, + std::span value, u32 ram_start, u32 length) { - if (memory_patch.m_offset == 0) - return; - const std::vector value = GetMemoryPatchValue(patch, memory_patch); - if (value.empty()) - return; - auto& system = guard.GetSystem(); for (u32 i = 0; i < length; i += 4) { @@ -600,6 +602,18 @@ static void ApplyOcarinaMemoryPatch(const Core::CPUThreadGuard& guard, const Pat } } +static void ApplyOcarinaMemoryPatch(const Core::CPUThreadGuard& guard, const Patch& patch, + const Memory& memory_patch, u32 ram_start, u32 length) +{ + if (memory_patch.m_offset == 0) + return; + ::File::FileLoan loan; + const std::span value = GetMemoryPatchValue(patch, memory_patch, &loan); + if (!value.empty()) + ApplyOcarinaPattern(guard, memory_patch, value, ram_start, length); + ::File::EndLoan(&loan); +} + void ApplyGeneralMemoryPatches(const Core::CPUThreadGuard& guard, std::span patches) { const auto& system = guard.GetSystem(); diff --git a/Source/Core/DiscIO/RiivolutionPatcher.h b/Source/Core/DiscIO/RiivolutionPatcher.h index cac6462970..1ed079022c 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.h +++ b/Source/Core/DiscIO/RiivolutionPatcher.h @@ -9,6 +9,7 @@ #include #include +#include "Common/IOFile.h" #include "DiscIO/DirectoryBlob.h" #include "DiscIO/RiivolutionParser.h" @@ -36,7 +37,9 @@ public: virtual ~FileDataLoader(); virtual std::optional GetExternalFileSize(std::string_view external_relative_path) = 0; - virtual std::vector GetFileContents(std::string_view external_relative_path) = 0; + // The whole file, lent; File::EndLoan() when done. + virtual bool LoanFileContents(std::string_view external_relative_path, + ::File::FileLoan* loan) = 0; virtual std::vector GetFolderContents(std::string_view external_relative_path) = 0; virtual BuilderContentSource MakeContentSource(std::string_view external_relative_path, u64 external_offset, u64 external_size, @@ -55,7 +58,7 @@ public: std::string_view patch_root); std::optional GetExternalFileSize(std::string_view external_relative_path) override; - std::vector GetFileContents(std::string_view external_relative_path) override; + bool LoanFileContents(std::string_view external_relative_path, ::File::FileLoan* loan) override; std::vector GetFolderContents(std::string_view external_relative_path) override; BuilderContentSource MakeContentSource(std::string_view external_relative_path,