diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 288d1b54ee..7b4fa6b7e3 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -40,6 +40,7 @@ #include "GS.h" #include "GS/GS.h" #include "SPU2/spu2.h" +#include "StateWrapper.h" #include "PAD/Gamepad.h" #include "USB/USB.h" #include "VMManager.h" @@ -355,7 +356,6 @@ static int SysState_MTGSFreeze(FreezeAction mode, freezeData* fP) static constexpr SysState_Component SPU2{ "SPU2", SPU2freeze }; static constexpr SysState_Component PAD_{ "PAD", PADfreeze }; -static constexpr SysState_Component USB_{ "USB", USBfreeze }; static constexpr SysState_Component GS{ "GS", SysState_MTGSFreeze }; @@ -404,6 +404,43 @@ static void SysState_ComponentFreezeOut(SaveStateBase& writer, SysState_Componen return; } +static void SysState_ComponentFreezeInNew(zip_file_t* zf, const char* name, bool(*do_state_func)(StateWrapper&)) +{ + // TODO: We could decompress on the fly here for a little bit more speed. + std::vector data; + if (zf) + { + std::optional> optdata(ReadBinaryFileInZip(zf)); + if (optdata.has_value()) + data = std::move(optdata.value()); + } + + StateWrapper::ReadOnlyMemoryStream stream(data.empty() ? nullptr : data.data(), data.size()); + StateWrapper sw(&stream, StateWrapper::Mode::Read, g_SaveVersion); + + // TODO: Get rid of the bloody exceptions. + if (!do_state_func(sw)) + throw std::runtime_error(fmt::format(" * {}: Error loading state!", name)); +} + +static void SysState_ComponentFreezeOutNew(SaveStateBase& writer, const char* name, u32 reserve, bool (*do_state_func)(StateWrapper&)) +{ + StateWrapper::VectorMemoryStream stream(reserve); + StateWrapper sw(&stream, StateWrapper::Mode::Write, g_SaveVersion); + + // TODO: Get rid of the bloody exceptions. + if (!do_state_func(sw)) + throw std::runtime_error(fmt::format(" * {}: Error saving state!", name)); + + const int size = static_cast(stream.GetBuffer().size()); + if (size > 0) + { + writer.PrepBlock(size); + std::memcpy(writer.GetBlockPtr(), stream.GetBuffer().data(), size); + writer.CommitBlock(size); + } +} + // -------------------------------------------------------------------------------------- // BaseSavestateEntry // -------------------------------------------------------------------------------------- @@ -575,8 +612,8 @@ public: virtual ~SavestateEntry_USB() = default; const char* GetFilename() const { return "USB.bin"; } - void FreezeIn(zip_file_t* zf) const { return SysState_ComponentFreezeIn(zf, USB_); } - void FreezeOut(SaveStateBase& writer) const { return SysState_ComponentFreezeOut(writer, USB_); } + void FreezeIn(zip_file_t* zf) const { return SysState_ComponentFreezeInNew(zf, "USB", &USB::DoState); } + void FreezeOut(SaveStateBase& writer) const { return SysState_ComponentFreezeOutNew(writer, "USB", 16 * 1024, &USB::DoState); } bool IsRequired() const { return false; } }; diff --git a/pcsx2/StateWrapper.h b/pcsx2/StateWrapper.h index c4813f3c02..0631848352 100644 --- a/pcsx2/StateWrapper.h +++ b/pcsx2/StateWrapper.h @@ -85,6 +85,8 @@ public: VectorMemoryStream(); VectorMemoryStream(u32 reserve); + const std::vector& GetBuffer() const { return m_buf; } + u32 Read(void* buf, u32 count) override; u32 Write(const void* buf, u32 count) override; u32 GetPosition() override; diff --git a/pcsx2/USB/USB.cpp b/pcsx2/USB/USB.cpp index f4b0f26334..7f3cf05996 100644 --- a/pcsx2/USB/USB.cpp +++ b/pcsx2/USB/USB.cpp @@ -41,7 +41,7 @@ namespace USB static void DestroyDevice(u32 port); static void UpdateDevice(u32 port); - static void DoOHCIState(StateWrapper& sw); + static bool DoOHCIState(StateWrapper& sw); static void DoEndpointState(USBEndpoint* ep, StateWrapper& sw); static void DoDeviceState(USBDevice* dev, StateWrapper& sw); static void DoPacketState(USBPacket* p, StateWrapper& sw, const std::array& valid_devices); @@ -199,10 +199,10 @@ void USBwrite32(u32 addr, u32 value) ohci_mem_write(s_qemu_ohci, addr, value); } -void USB::DoOHCIState(StateWrapper& sw) +bool USB::DoOHCIState(StateWrapper& sw) { if (!sw.DoMarker("USBOHCI")) - return; + return false; sw.Do(&g_usb_last_cycle); sw.Do(&s_usb_clocks); @@ -243,6 +243,7 @@ void USB::DoOHCIState(StateWrapper& sw) sw.DoArray(s_qemu_ohci->usb_buf, sizeof(s_qemu_ohci->usb_buf)); sw.Do(&s_qemu_ohci->async_td); sw.Do(&s_qemu_ohci->async_complete); + return true; } void USB::DoDeviceState(USBDevice* dev, StateWrapper& sw) @@ -378,24 +379,19 @@ void USB::DoPacketState(USBPacket* p, StateWrapper& sw, const std::array valid_devices = {}; - if (mode == FreezeAction::Load) + if (!sw.DoMarker("USB") || !USB::DoOHCIState(sw)) { - StateWrapper::ReadOnlyMemoryStream swstream(data->data, data->size); - StateWrapper sw(&swstream, StateWrapper::Mode::Read, g_SaveVersion); - - if (!sw.DoMarker("USB")) - { - Console.Error("USB state is invalid, resetting."); - USBreset(); - return 0; - } - - USB::DoOHCIState(sw); + Console.Error("USB state is invalid, resetting."); + USBreset(); + return false; + } + if (sw.IsReading()) + { for (u32 port = 0; port < USB::NUM_PORTS; port++) { s32 state_devtype; @@ -443,21 +439,11 @@ s32 USBfreeze(FreezeAction mode, freezeData* data) { Console.WriteLn("Failed to read USB packet, resetting all devices."); USBreset(); - return 0; + return true; } } - else if (mode == FreezeAction::Save) + else { - std::memset(data->data, 0, data->size); - - StateWrapper::MemoryStream swstream(data->data, data->size); - StateWrapper sw(&swstream, StateWrapper::Mode::Write, g_SaveVersion); - - if (!sw.DoMarker("USB")) - return -1; - - USB::DoOHCIState(sw); - for (u32 port = 0; port < USB::NUM_PORTS; port++) { s32 state_devtype = EmuConfig.USB.Ports[port].DeviceType; @@ -465,12 +451,12 @@ s32 USBfreeze(FreezeAction mode, freezeData* data) sw.Do(&state_devtype); sw.Do(&state_devsubtype); - const u32 size_pos = swstream.GetPosition(); + const u32 size_pos = sw.GetStream()->GetPosition(); u32 state_size = 0; sw.Do(&state_size); if (sw.HasError()) - return -1; + return false; if (!s_usb_device[port]) { @@ -478,33 +464,28 @@ s32 USBfreeze(FreezeAction mode, freezeData* data) continue; } - const u32 start_pos = swstream.GetPosition(); + const u32 start_pos = sw.GetStream()->GetPosition(); USB::DoDeviceState(s_usb_device[port], sw); if (!s_usb_device_proxy[port]->Freeze(s_usb_device[port], sw) || sw.HasError()) { Console.Error("Failed to serialize USB port %u.", port); - return -1; + return false; } - const u32 end_pos = swstream.GetPosition(); + const u32 end_pos = sw.GetStream()->GetPosition(); state_size = end_pos - start_pos; - if (!swstream.SeekAbsolute(size_pos) || (sw.Do(&state_size), sw.HasError()) || !swstream.SeekAbsolute(end_pos)) - return -1; + if (!sw.GetStream()->SeekAbsolute(size_pos) || (sw.Do(&state_size), sw.HasError()) || !sw.GetStream()->SeekAbsolute(end_pos)) + return false; valid_devices[port] = true; } USB::DoPacketState(&s_qemu_ohci->usb_packet, sw, valid_devices); if (sw.HasError()) - return -1; - } - else if (mode == FreezeAction::Size) - { - // I don't like this, but until we move everything over to state wrapper, it'll have to do. - data->size = 0x10000; + return false; } - return 0; + return true; } void USBasync(u32 cycles) diff --git a/pcsx2/USB/USB.h b/pcsx2/USB/USB.h index 05a143529f..77794ff720 100644 --- a/pcsx2/USB/USB.h +++ b/pcsx2/USB/USB.h @@ -24,9 +24,9 @@ #include "gsl/span" #include "Config.h" -#include "SaveState.h" class SettingsInterface; +class StateWrapper; namespace USB { @@ -84,6 +84,9 @@ namespace USB /// Reads a device-specific configuration string. std::string GetConfigString(SettingsInterface& si, u32 port, const char* devname, const char* key, const char* default_value = ""); + + /// Handles loading/saving save state. + bool DoState(StateWrapper& sw); } // namespace USB struct WindowInfo; @@ -96,7 +99,6 @@ void USBshutdown(); void USBclose(); bool USBopen(); void USBreset(); -s32 USBfreeze(FreezeAction mode, freezeData* data); u8 USBread8(u32 addr); u16 USBread16(u32 addr);