From 60e21e2530e7af150ab1c9dfd2ffa78e1c31704e Mon Sep 17 00:00:00 2001 From: KamFretoZ <14798312+kamfretoz@users.noreply.github.com> Date: Wed, 25 Sep 2024 23:10:02 +0700 Subject: [PATCH] SaveState: Add configurable compression type and level --- pcsx2-qt/Settings/AdvancedSettingsWidget.cpp | 22 +++ pcsx2-qt/Settings/AdvancedSettingsWidget.h | 2 +- pcsx2-qt/Settings/AdvancedSettingsWidget.ui | 139 ++++++++++++++----- pcsx2/Config.h | 30 +++- pcsx2/ImGui/FullscreenUI.cpp | 42 +++++- pcsx2/Pcsx2Config.cpp | 25 +++- pcsx2/SaveState.cpp | 50 ++++++- 7 files changed, 264 insertions(+), 46 deletions(-) diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp index bfc7dfd63f..eaa6f6ac48 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.cpp @@ -56,6 +56,15 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.ntscFrameRate, "EmuCore/GS", "FramerateNTSC", 59.94f); SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.palFrameRate, "EmuCore/GS", "FrameratePAL", 50.00f); + SettingWidgetBinder::BindWidgetToIntSetting( + sif, m_ui.savestateCompressionMethod, "EmuCore", "SavestateCompressionType", static_cast(SavestateCompressionMethod::Zstandard)); + + SettingWidgetBinder::BindWidgetToIntSetting( + sif, m_ui.savestateCompressionLevel, "EmuCore", "SavestateCompressionRatio", static_cast(SavestateCompressionLevel::Medium)); + + connect(m_ui.savestateCompressionMethod, QOverload::of(&QComboBox::currentIndexChanged), this, + &AdvancedSettingsWidget::onSavestateCompressionTypeChanged); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pineEnable, "EmuCore", "EnablePINE", false); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.pineSlot, "EmuCore", "PINESlot", 28011); @@ -123,6 +132,12 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* dialog->registerWidgetHelp(m_ui.patches, tr("Enable Compatibility Patches"), tr("Checked"), tr("Automatically loads and applies compatibility patches to known problematic games.")); + + dialog->registerWidgetHelp(m_ui.savestateCompressionMethod, tr("Savestate Compression Method"), tr("Zstandard"), + tr("Determines the algorithm to be used when compressing savestates.")); + + dialog->registerWidgetHelp(m_ui.savestateCompressionLevel, tr("Savestate Compression Level"), tr("Medium"), + tr("Determines the level to be used when compressing savestates.")); } AdvancedSettingsWidget::~AdvancedSettingsWidget() = default; @@ -189,3 +204,10 @@ void AdvancedSettingsWidget::setClampingMode(int vunum, int index) m_dialog->setBoolSettingValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0Overflow" : "vu1Overflow") : "fpuOverflow"), first); } + +void AdvancedSettingsWidget::onSavestateCompressionTypeChanged() +{ + const bool uncompressed = (m_dialog->getEffectiveIntValue("EmuCore", "SavestateCompressionType", static_cast(SavestateCompressionMethod::Zstandard)) == + static_cast(SavestateCompressionMethod::Uncompressed)); + m_ui.savestateCompressionLevel->setDisabled(uncompressed); +} \ No newline at end of file diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.h b/pcsx2-qt/Settings/AdvancedSettingsWidget.h index d1d7f5f124..40e2b8903e 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.h +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.h @@ -21,8 +21,8 @@ private: int getGlobalClampingModeIndex(int vunum) const; int getClampingModeIndex(int vunum) const; void setClampingMode(int vunum, int index); + void onSavestateCompressionTypeChanged(); SettingsWindow* m_dialog; - Ui::AdvancedSystemSettingsWidget m_ui; }; diff --git a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui index 689376166d..7a8c20a165 100644 --- a/pcsx2-qt/Settings/AdvancedSettingsWidget.ui +++ b/pcsx2-qt/Settings/AdvancedSettingsWidget.ui @@ -32,9 +32,9 @@ 0 - 0 + -272 790 - 765 + 997 @@ -48,7 +48,7 @@ 0 - + Changing these options may cause games to become non-functional. Modify at your own risk, the PCSX2 team will not provide support for configurations with these settings changed. @@ -58,13 +58,13 @@ - + EmotionEngine (MIPS-IV) - + Rounding Mode: @@ -95,7 +95,7 @@ - + Division Rounding Mode: @@ -126,7 +126,7 @@ - + Clamping Mode: @@ -157,7 +157,7 @@ - + @@ -213,13 +213,13 @@ - + Vector Units (VU) - + VU1 Rounding Mode: @@ -250,7 +250,7 @@ - + @@ -306,21 +306,21 @@ - + VU0 Clamping Mode: - + VU0 Rounding Mode: - + VU1 Clamping Mode: @@ -378,7 +378,7 @@ - + I/O Processor (IOP, MIPS-I) @@ -394,7 +394,7 @@ - + Game Settings @@ -417,24 +417,24 @@ - + Frame Rate Control - + hz - - 0.010000000000000 - - 10.0 + 10.000000000000000 - 300.0 + 300.000000000000000 + + + 0.010000000000000 @@ -443,26 +443,26 @@ hz - - 0.010000000000000 - - 10.0 + 10.000000000000000 - 300.0 + 300.000000000000000 + + + 0.010000000000000 - + PAL Frame Rate: - + NTSC Frame Rate: @@ -472,11 +472,82 @@ - + + + Savestate Settings + + + + + + Compression Level: + + + + + + + Compression Method: + + + + + + + + Uncompressed + + + + + Deflate64 + + + + + Zstandard + + + + + LZMA2 + + + + + + + + + Low (Fast) + + + + + Medium (Recommended) + + + + + High + + + + + Very High (Slow, Not Recommended) + + + + + + + + + PINE Settings - + @@ -488,7 +559,7 @@ - + 0 @@ -511,7 +582,7 @@ - + Qt::Orientation::Vertical diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 6f4b995747..9bf084c372 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -342,6 +342,22 @@ enum class GSDumpCompressionMethod : u8 Zstandard, }; +enum class SavestateCompressionMethod : u8 +{ + Uncompressed = 0, + Deflate64 = 1, + Zstandard = 2, + LZMA2 = 3 +}; + +enum class SavestateCompressionLevel : u8 +{ + Low = 0, + Medium = 1, + High = 2, + VeryHigh = 3, +}; + enum class GSHardwareDownloadMode : u8 { Enabled, @@ -1129,6 +1145,18 @@ struct Pcsx2Config bool operator!=(const AchievementsOptions& right) const; }; + struct SavestateOptions + { + SavestateOptions(); + void LoadSave(SettingsWrapper& wrap); + + SavestateCompressionMethod CompressionType = SavestateCompressionMethod::Zstandard; + SavestateCompressionLevel CompressionRatio = SavestateCompressionLevel::Medium; + + bool operator==(const SavestateOptions& right) const; + bool operator!=(const SavestateOptions& right) const; + }; + // ------------------------------------------------------------------------ BITFIELD32() @@ -1151,7 +1179,6 @@ struct Pcsx2Config EnableDiscordPresence : 1, // enables discord rich presence integration InhibitScreensaver : 1, BackupSavestate : 1, - SavestateZstdCompression : 1, McdFolderAutoManage : 1, HostFs : 1, @@ -1166,6 +1193,7 @@ struct Pcsx2Config ProfilerOptions Profiler; DebugOptions Debugger; EmulationSpeedOptions EmulationSpeed; + SavestateOptions Savestate; SPU2Options SPU2; DEV9Options DEV9; USBOptions USB; diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index 67b9974e8f..15734ebc67 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -3938,7 +3938,11 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad s_tv_shaders, std::size(s_tv_shaders), true); } - static constexpr const char* s_gsdump_compression[] = {FSUI_NSTR("Uncompressed"), FSUI_NSTR("LZMA (xz)"), FSUI_NSTR("Zstandard (zst)")}; + static constexpr const char* s_gsdump_compression[] = { + FSUI_NSTR("Uncompressed"), + FSUI_NSTR("LZMA (xz)"), + FSUI_NSTR("Zstandard (zst)") + }; if (show_advanced_settings) { @@ -4723,6 +4727,20 @@ void FullscreenUI::DrawAdvancedSettingsPage() bsi, FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "CDVD Verbose Reads"), FSUI_CSTR("Logs disc reads from games."), "EmuCore", "CdvdVerboseReads", false); } + static constexpr const char* s_savestate_compression_type[] = { + FSUI_NSTR("Uncompressed"), + FSUI_NSTR("Deflate64"), + FSUI_NSTR("Zstandard"), + FSUI_NSTR("LZMA2") + }; + + static constexpr const char* s_savestate_compression_ratio[] = { + FSUI_NSTR("Low (Fast)"), + FSUI_NSTR("Medium (Recommended)"), + FSUI_NSTR("High"), + FSUI_NSTR("Very High (Slow, Not Recommended)") + }; + if (show_advanced_settings) { MenuHeading(FSUI_CSTR("Emotion Engine")); @@ -4781,6 +4799,12 @@ void FullscreenUI::DrawAdvancedSettingsPage() FSUI_CSTR("Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code."), "EmuCore/CPU/Recompiler", "EnableIOP", true); + MenuHeading(FSUI_CSTR("Savestate")); + DrawIntListSetting(bsi, FSUI_CSTR("Compression Method"), FSUI_CSTR("Sets the compression algorithm for savestate."), "EmuCore", + "SavestateCompressionType", static_cast(SavestateCompressionMethod::Zstandard), s_savestate_compression_type, std::size(s_savestate_compression_type), true); + DrawIntListSetting(bsi, FSUI_CSTR("Compression Level"), FSUI_CSTR("Sets the compression level for savestate."), "EmuCore", + "SavestateCompressionRatio", static_cast(SavestateCompressionLevel::Medium), s_savestate_compression_ratio, std::size(s_savestate_compression_ratio), true); + MenuHeading(FSUI_CSTR("Graphics")); DrawToggleSetting(bsi, FSUI_CSTR("Use Debug Device"), FSUI_CSTR("Enables API-level validation of graphics commands."), "EmuCore/GS", "UseDebugDevice", false); @@ -6854,7 +6878,6 @@ TRANSLATE_NOOP("FullscreenUI", "Game region copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game compatibility copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game path copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Automatic"); -TRANSLATE_NOOP("FullscreenUI", "Per-game controller configuration initialized with global settings."); TRANSLATE_NOOP("FullscreenUI", "Controller settings reset to default."); TRANSLATE_NOOP("FullscreenUI", "No input profiles available."); TRANSLATE_NOOP("FullscreenUI", "Create New..."); @@ -7024,8 +7047,6 @@ TRANSLATE_NOOP("FullscreenUI", "Dithering"); TRANSLATE_NOOP("FullscreenUI", "Selects the type of dithering applies when the game requests it."); TRANSLATE_NOOP("FullscreenUI", "Blending Accuracy"); TRANSLATE_NOOP("FullscreenUI", "Determines the level of accuracy when emulating blend modes not supported by the host graphics API."); -TRANSLATE_NOOP("FullscreenUI", "Texture Preloading"); -TRANSLATE_NOOP("FullscreenUI", "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games."); TRANSLATE_NOOP("FullscreenUI", "Mipmapping"); TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's texture mipmapping."); TRANSLATE_NOOP("FullscreenUI", "Software Rendering Threads"); @@ -7142,6 +7163,8 @@ TRANSLATE_NOOP("FullscreenUI", "Disable Shader Cache"); TRANSLATE_NOOP("FullscreenUI", "Prevents the loading and saving of shaders/pipelines to disk."); TRANSLATE_NOOP("FullscreenUI", "Disable Vertex Shader Expand"); TRANSLATE_NOOP("FullscreenUI", "Falls back to the CPU for expanding sprites/lines."); +TRANSLATE_NOOP("FullscreenUI", "Texture Preloading"); +TRANSLATE_NOOP("FullscreenUI", "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games."); TRANSLATE_NOOP("FullscreenUI", "Audio Control"); TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host."); TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host when fast forwarding."); @@ -7222,6 +7245,11 @@ TRANSLATE_NOOP("FullscreenUI", "Runs VU1 instantly. Provides a modest speed impr TRANSLATE_NOOP("FullscreenUI", "I/O Processor"); TRANSLATE_NOOP("FullscreenUI", "Enable IOP Recompiler"); TRANSLATE_NOOP("FullscreenUI", "Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code."); +TRANSLATE_NOOP("FullscreenUI", "Savestate"); +TRANSLATE_NOOP("FullscreenUI", "Compression Method"); +TRANSLATE_NOOP("FullscreenUI", "Sets the compression algorithm for savestate."); +TRANSLATE_NOOP("FullscreenUI", "Compression Level"); +TRANSLATE_NOOP("FullscreenUI", "Sets the compression level for savestate."); TRANSLATE_NOOP("FullscreenUI", "Graphics"); TRANSLATE_NOOP("FullscreenUI", "Use Debug Device"); TRANSLATE_NOOP("FullscreenUI", "Enables API-level validation of graphics commands."); @@ -7517,6 +7545,12 @@ TRANSLATE_NOOP("FullscreenUI", "PS1"); TRANSLATE_NOOP("FullscreenUI", "Negative"); TRANSLATE_NOOP("FullscreenUI", "Positive"); TRANSLATE_NOOP("FullscreenUI", "Chop/Zero (Default)"); +TRANSLATE_NOOP("FullscreenUI", "Deflate64"); +TRANSLATE_NOOP("FullscreenUI", "Zstandard"); +TRANSLATE_NOOP("FullscreenUI", "LZMA2"); +TRANSLATE_NOOP("FullscreenUI", "Low (Fast)"); +TRANSLATE_NOOP("FullscreenUI", "Medium (Recommended)"); +TRANSLATE_NOOP("FullscreenUI", "Very High (Slow, Not Recommended)"); TRANSLATE_NOOP("FullscreenUI", "Game Grid"); TRANSLATE_NOOP("FullscreenUI", "Type"); TRANSLATE_NOOP("FullscreenUI", "Serial"); diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index c78c8dfe1e..9c5deebc60 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -1460,6 +1460,28 @@ bool Pcsx2Config::DebugOptions::operator==(const DebugOptions& right) const return OpEqu(bitset) && OpEqu(FontWidth) && OpEqu(FontHeight) && OpEqu(WindowWidth) && OpEqu(WindowHeight) && OpEqu(MemoryViewBytesPerRow); } +Pcsx2Config::SavestateOptions::SavestateOptions() +{ +} + +void Pcsx2Config::SavestateOptions::LoadSave(SettingsWrapper& wrap) +{ + SettingsWrapSection("EmuCore"); + + SettingsWrapIntEnumEx(CompressionType, "SavestateCompressionType"); + SettingsWrapIntEnumEx(CompressionRatio, "SavestateCompressionRatio"); +} + +bool Pcsx2Config::SavestateOptions::operator!=(const SavestateOptions& right) const +{ + return !this->operator==(right); +} + +bool Pcsx2Config::SavestateOptions::operator==(const SavestateOptions& right) const +{ + return OpEqu(CompressionType) && OpEqu(CompressionRatio); +}; + Pcsx2Config::FilenameOptions::FilenameOptions() { } @@ -1702,7 +1724,6 @@ Pcsx2Config::Pcsx2Config() EnableGameFixes = true; InhibitScreensaver = true; BackupSavestate = true; - SavestateZstdCompression = true; WarnAboutUnsafeSettings = true; // To be moved to FileMemoryCard pluign (someday) @@ -1741,7 +1762,6 @@ void Pcsx2Config::LoadSaveCore(SettingsWrapper& wrap) SettingsWrapBitBool(HostFs); SettingsWrapBitBool(BackupSavestate); - SettingsWrapBitBool(SavestateZstdCompression); SettingsWrapBitBool(McdFolderAutoManage); SettingsWrapBitBool(WarnAboutUnsafeSettings); @@ -1755,6 +1775,7 @@ void Pcsx2Config::LoadSaveCore(SettingsWrapper& wrap) DEV9.LoadSave(wrap); Gamefixes.LoadSave(wrap); Profiler.LoadSave(wrap); + Savestate.LoadSave(wrap); Debugger.LoadSave(wrap); Trace.LoadSave(wrap); diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 4583e23bc9..eef7f23420 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -914,9 +914,51 @@ static bool SaveState_ReadScreenshot(zip_t* zf, u32* out_width, u32* out_height, // -------------------------------------------------------------------------------------- static bool SaveState_AddToZip(zip_t* zf, ArchiveEntryList* srclist, SaveStateScreenshotData* screenshot) { - // use zstd compression, it can be 10x+ faster for saving. - const u32 compression = EmuConfig.SavestateZstdCompression ? ZIP_CM_ZSTD : ZIP_CM_DEFLATE; - const u32 compression_level = 0; + u32 compression; + u32 compression_level; + + if (EmuConfig.Savestate.CompressionType == SavestateCompressionMethod::Zstandard) + { + compression = ZIP_CM_ZSTD; + + if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::Low) + compression_level = 1; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::Medium) + compression_level = 3; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::High) + compression_level = 10; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::VeryHigh) + compression_level = 22; + } + else if (EmuConfig.Savestate.CompressionType == SavestateCompressionMethod::Deflate64) + { + compression = ZIP_CM_DEFLATE64; + if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::Low) + compression_level = 1; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::Medium) + compression_level = 3; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::High) + compression_level = 7; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::VeryHigh) + compression_level = 9; + } + else if (EmuConfig.Savestate.CompressionType == SavestateCompressionMethod::LZMA2) + { + compression = ZIP_CM_LZMA2; + if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::Low) + compression_level = 1; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::Medium) + compression_level = 3; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::High) + compression_level = 7; + else if (EmuConfig.Savestate.CompressionRatio == SavestateCompressionLevel::VeryHigh) + compression_level = 9; + } + else if (EmuConfig.Savestate.CompressionType == SavestateCompressionMethod::Uncompressed) + { + compression = ZIP_CM_STORE; + compression_level = 0; + } // version indicator { @@ -949,7 +991,7 @@ static bool SaveState_AddToZip(zip_t* zf, ArchiveEntryList* srclist, SaveStateSc return false; } - zip_set_file_compression(zf, fi, ZIP_CM_STORE, 0); + zip_set_file_compression(zf, fi, compression, compression_level); } const uint listlen = srclist->GetLength();