diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index d5f04b230..3a6d46d67 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -25,6 +25,7 @@ struct SAVE_STATE_HEADER { MAX_TITLE_LENGTH = 128, MAX_SERIAL_LENGTH = 32, + MAX_SAVE_STATE_SIZE = 32 * 1024 * 1024, }; u32 magic; diff --git a/src/core/system.cpp b/src/core/system.cpp index 43b1ff1db..5a2f01e49 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -122,7 +122,7 @@ static void InternalReset(); static void ClearRunningGame(); static void DestroySystem(); static std::string GetMediaPathFromSaveState(const char* path); -static bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state); + static bool CreateGPU(GPURenderer renderer, bool is_switching, Error* error); static bool SaveUndoLoadState(); static void WarnAboutUnsafeSettings(); @@ -174,6 +174,10 @@ struct MemorySaveState #endif }; } // namespace + +/// Returns the maximum size of a save state, considering the current configuration. +static size_t GetMaxSaveStateSize(); + static bool SaveMemoryState(MemorySaveState* mss); static bool LoadMemoryState(const MemorySaveState& mss); static bool LoadStateFromBuffer(const SaveStateBuffer& buffer, Error* error, bool update_display); @@ -186,6 +190,7 @@ static bool SaveStateBufferToFile(const SaveStateBuffer& buffer, std::FILE* fp, SaveStateCompression screenshot_compression = SaveStateCompression::ZLib, SaveStateCompression data_compression = SaveStateCompression::ZStd); static u32 CompressAndWriteStateData(std::FILE* fp, std::span src, SaveStateCompression method, Error* error); +static bool DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_display, bool is_memory_state); static void UpdateSessionTime(const std::string& prev_serial); @@ -1103,7 +1108,7 @@ bool System::RecreateGPU(GPURenderer renderer, bool force_recreate_device, bool g_gpu->RestoreDeviceContext(); // save current state - DynamicHeapArray state_data(MAX_SAVE_STATE_SIZE); + DynamicHeapArray state_data(GetMaxSaveStateSize()); { StateWrapper sw(state_data.span(), StateWrapper::Mode::Write, SAVE_STATE_VERSION); if (!g_gpu->DoState(sw, nullptr, false) || !TimingEvents::DoState(sw)) @@ -2434,6 +2439,15 @@ void System::ResetBootMode() } } +size_t System::GetMaxSaveStateSize() +{ + // 5 megabytes is sufficient for now, at the moment they're around 4.3MB, or 10.3MB with 8MB RAM enabled. + static constexpr u32 MAX_2MB_SAVE_STATE_SIZE = 5 * 1024 * 1024; + static constexpr u32 MAX_8MB_SAVE_STATE_SIZE = 11 * 1024 * 1024; + const bool is_8mb_ram = (System::IsValid() ? (Bus::g_ram_size > Bus::RAM_2MB_SIZE) : g_settings.enable_8mb_ram); + return is_8mb_ram ? MAX_8MB_SAVE_STATE_SIZE : MAX_2MB_SAVE_STATE_SIZE; +} + std::string System::GetMediaPathFromSaveState(const char* path) { SaveStateBuffer buffer; @@ -2634,7 +2648,7 @@ bool System::LoadStateBufferFromFile(SaveStateBuffer* buffer, std::FILE* fp, Err (static_cast(header.offset_to_screenshot) + header.screenshot_compressed_size) > file_size || header.screenshot_width >= 32768 || header.screenshot_height >= 32768 || (static_cast(header.offset_to_data) + header.data_compressed_size) > file_size || - header.data_uncompressed_size > MAX_SAVE_STATE_SIZE) [[unlikely]] + header.data_uncompressed_size > SAVE_STATE_HEADER::MAX_SAVE_STATE_SIZE) [[unlikely]] { Error::SetStringView(error, "Save state header is corrupted."); return false; @@ -2885,7 +2899,7 @@ bool System::SaveStateToBuffer(SaveStateBuffer* buffer, Error* error, u32 screen // write data if (buffer->state_data.empty()) - buffer->state_data.resize(MAX_SAVE_STATE_SIZE); + buffer->state_data.resize(GetMaxSaveStateSize()); g_gpu->RestoreDeviceContext(); StateWrapper sw(buffer->state_data.span(), StateWrapper::Mode::Write, SAVE_STATE_VERSION); @@ -4476,7 +4490,7 @@ void System::LogUnsafeSettingsToConsole(const SmallStringBase& messages) void System::CalculateRewindMemoryUsage(u32 num_saves, u32 resolution_scale, u64* ram_usage, u64* vram_usage) { const u64 real_resolution_scale = std::max(g_settings.gpu_resolution_scale, 1u); - *ram_usage = MAX_SAVE_STATE_SIZE * static_cast(num_saves); + *ram_usage = GetMaxSaveStateSize() * static_cast(num_saves); *vram_usage = ((VRAM_WIDTH * real_resolution_scale) * (VRAM_HEIGHT * real_resolution_scale) * 4) * static_cast(g_settings.gpu_multisamples) * static_cast(num_saves); } @@ -4536,7 +4550,7 @@ bool System::LoadMemoryState(const MemorySaveState& mss) bool System::SaveMemoryState(MemorySaveState* mss) { if (mss->state_data.empty()) - mss->state_data.resize(MAX_SAVE_STATE_SIZE); + mss->state_data.resize(GetMaxSaveStateSize()); GPUTexture* host_texture = mss->vram_texture.release(); StateWrapper sw(mss->state_data.span(), StateWrapper::Mode::Write, SAVE_STATE_VERSION); diff --git a/src/core/system.h b/src/core/system.h index 6bddb1077..804d9a9ac 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -77,12 +77,6 @@ struct ExtendedSaveStateInfo namespace System { -enum : u32 -{ - // 5 megabytes is sufficient for now, at the moment they're around 4.3MB, or 10.3MB with 8MB RAM enabled. - MAX_SAVE_STATE_SIZE = 11 * 1024 * 1024, -}; - enum : s32 { PER_GAME_SAVE_STATE_SLOTS = 10,