Skip to content

Commit

Permalink
System: Rewrite save state I/O
Browse files Browse the repository at this point in the history
No more ByteStream or virtual calls for every piece of data.
  • Loading branch information
stenzek committed Jul 29, 2024
1 parent dd8bf2c commit a6518ff
Show file tree
Hide file tree
Showing 14 changed files with 687 additions and 478 deletions.
6 changes: 6 additions & 0 deletions src/common/string_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ std::size_t StringUtil::Strlcpy(char* dst, const char* src, std::size_t size)
return len;
}

std::size_t StringUtil::Strnlen(const char* str, std::size_t max_size)
{
const char* loc = static_cast<const char*>(std::memchr(str, 0, max_size));
return loc ? static_cast<size_t>(loc - str) : max_size;
}

std::size_t StringUtil::Strlcpy(char* dst, const std::string_view src, std::size_t size)
{
std::size_t len = src.length();
Expand Down
3 changes: 3 additions & 0 deletions src/common/string_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ std::size_t Strlcpy(char* dst, const char* src, std::size_t size);
/// Strlcpy from string_view.
std::size_t Strlcpy(char* dst, const std::string_view src, std::size_t size);

/// Bounds checked version of strlen.
std::size_t Strnlen(const char* str, std::size_t max_size);

/// Platform-independent strcasecmp
static inline int Strcasecmp(const char* s1, const char* s2)
{
Expand Down
4 changes: 2 additions & 2 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ set(NEWREC_SOURCES
target_precompile_headers(core PRIVATE "pch.h")
target_include_directories(core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(core PUBLIC Threads::Threads common util ZLIB::ZLIB)
target_link_libraries(core PRIVATE xxhash imgui rapidyaml rcheevos cpuinfo::cpuinfo)
target_link_libraries(core PUBLIC Threads::Threads common util)
target_link_libraries(core PRIVATE xxhash imgui rapidyaml rcheevos cpuinfo::cpuinfo ZLIB::ZLIB Zstd::Zstd)

if(CPU_ARCH_X64)
target_compile_definitions(core PUBLIC "ENABLE_RECOMPILER=1" "ENABLE_NEWREC=1" "ENABLE_MMAP_FASTMEM=1")
Expand Down
8 changes: 4 additions & 4 deletions src/core/fullscreen_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5559,11 +5559,11 @@ bool FullscreenUI::InitializeSaveStateListEntryFromPath(SaveStateListEntry* li,
void FullscreenUI::PopulateSaveStateScreenshot(SaveStateListEntry* li, const ExtendedSaveStateInfo* ssi)
{
li->preview_texture.reset();
if (ssi && !ssi->screenshot_data.empty())
if (ssi && ssi->screenshot.IsValid())
{
li->preview_texture = g_gpu_device->FetchTexture(ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1,
li->preview_texture = g_gpu_device->FetchTexture(ssi->screenshot.GetWidth(), ssi->screenshot.GetHeight(), 1, 1, 1,
GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width);
ssi->screenshot.GetPixels(), ssi->screenshot.GetPitch());
}
else
{
Expand Down Expand Up @@ -6112,7 +6112,7 @@ void FullscreenUI::DoLoadState(std::string path)
else
{
Error error;
if (!System::LoadState(path.c_str(), &error))
if (!System::LoadState(path.c_str(), &error, true))
{
ShowToast(std::string(),
fmt::format(TRANSLATE_FS("System", "Failed to load state: {}"), error.GetDescription()));
Expand Down
2 changes: 1 addition & 1 deletion src/core/hotkeys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static void HotkeyLoadStateSlot(bool global, s32 slot)
}

Error error;
if (!System::LoadState(path.c_str(), &error))
if (!System::LoadState(path.c_str(), &error, true))
{
Host::AddKeyedOSDMessage(
"LoadState",
Expand Down
10 changes: 5 additions & 5 deletions src/core/imgui_overlays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -891,11 +891,11 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn
{
g_gpu_device->RecycleTexture(std::move(li->preview_texture));

if (ssi && !ssi->screenshot_data.empty())
if (ssi->screenshot.IsValid())
{
li->preview_texture = g_gpu_device->FetchTexture(
ssi->screenshot_width, ssi->screenshot_height, 1, 1, 1, GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
ssi->screenshot_data.data(), sizeof(u32) * ssi->screenshot_width);
li->preview_texture = g_gpu_device->FetchTexture(ssi->screenshot.GetWidth(), ssi->screenshot.GetHeight(), 1, 1, 1,
GPUTexture::Type::Texture, GPUTexture::Format::RGBA8,
ssi->screenshot.GetPixels(), ssi->screenshot.GetPitch());
if (!li->preview_texture) [[unlikely]]
ERROR_LOG("Failed to upload save state image to GPU");
}
Expand Down Expand Up @@ -1084,7 +1084,7 @@ void SaveStateSelectorUI::LoadCurrentSlot()
if (FileSystem::FileExists(path.c_str()))
{
Error error;
if (!System::LoadState(path.c_str(), &error))
if (!System::LoadState(path.c_str(), &error, true))
{
Host::AddKeyedOSDMessage("LoadState",
fmt::format(TRANSLATE_FS("OSDMessage", "Failed to load state from slot {0}:\n{1}"),
Expand Down
24 changes: 8 additions & 16 deletions src/core/pad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ static bool s_receive_buffer_full = false;
static bool s_transmit_buffer_full = false;

static u32 s_last_memory_card_transfer_frame = 0;
static std::unique_ptr<GrowableMemoryByteStream> s_memory_card_backup;
static DynamicHeapArray<u8> s_memory_card_backup;
static std::unique_ptr<MemoryCard> s_dummy_card;

} // namespace Pad
Expand All @@ -145,7 +145,7 @@ void Pad::Initialize()

void Pad::Shutdown()
{
s_memory_card_backup.reset();
s_memory_card_backup.deallocate();

s_transfer_event.Deactivate();

Expand Down Expand Up @@ -197,7 +197,7 @@ bool Pad::DoStateController(StateWrapper& sw, u32 i)
if (controller_type != state_controller_type)
{
const Controller::ControllerInfo* state_cinfo = Controller::GetControllerInfo(state_controller_type);
Assert(sw.GetMode() == StateWrapper::Mode::Read);
Assert(sw.IsReading());

// UI notification portion is separated from emulation portion (intentional condition check redundancy)
if (g_settings.load_devices_from_save_states)
Expand Down Expand Up @@ -363,16 +363,10 @@ void Pad::BackupMemoryCardState()
{
DEV_LOG("Backing up memory card state.");

if (!s_memory_card_backup)
{
s_memory_card_backup =
std::make_unique<GrowableMemoryByteStream>(nullptr, MemoryCard::STATE_SIZE * NUM_CONTROLLER_AND_CARD_PORTS);
}

s_memory_card_backup->SeekAbsolute(0);

StateWrapper sw(s_memory_card_backup.get(), StateWrapper::Mode::Write, SAVE_STATE_VERSION);
if (s_memory_card_backup.empty())
s_memory_card_backup.resize(MemoryCard::STATE_SIZE * NUM_CONTROLLER_AND_CARD_PORTS);

StateWrapper sw(s_memory_card_backup.span(), StateWrapper::Mode::Write, SAVE_STATE_VERSION);
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
{
if (s_memory_cards[i])
Expand All @@ -382,13 +376,11 @@ void Pad::BackupMemoryCardState()

void Pad::RestoreMemoryCardState()
{
DebugAssert(s_memory_card_backup);
DebugAssert(!s_memory_card_backup.empty());

VERBOSE_LOG("Restoring backed up memory card state.");

s_memory_card_backup->SeekAbsolute(0);
StateWrapper sw(s_memory_card_backup.get(), StateWrapper::Mode::Read, SAVE_STATE_VERSION);

StateWrapper sw(s_memory_card_backup.cspan(), StateWrapper::Mode::Read, SAVE_STATE_VERSION);
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
{
if (s_memory_cards[i])
Expand Down
2 changes: 1 addition & 1 deletion src/core/pine_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ bool PINEServer::PINESocket::HandleCommand(IPCCommand command, BinarySpanReader

Host::RunOnCPUThread([state_filename = std::move(state_filename)] {
Error error;
if (!System::LoadState(state_filename.c_str(), &error))
if (!System::LoadState(state_filename.c_str(), &error, true))
ERROR_LOG("PINE: Load state failed: {}", error.GetDescription());
});

Expand Down
25 changes: 15 additions & 10 deletions src/core/save_state_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,42 @@
#include "types.h"

static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 68;
static constexpr u32 SAVE_STATE_VERSION = 69;
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;

static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);

enum class SaveStateCompression : u32
{
None = 0,
ZLib = 1,
ZStd = 2,
};

#pragma pack(push, 4)
struct SAVE_STATE_HEADER
{
enum : u32
{
MAX_TITLE_LENGTH = 128,
MAX_SERIAL_LENGTH = 32,

COMPRESSION_TYPE_NONE = 0,
COMPRESSION_TYPE_ZLIB = 1,
COMPRESSION_TYPE_ZSTD = 2,
};

u32 magic;
u32 version;
char title[MAX_TITLE_LENGTH];
char serial[MAX_SERIAL_LENGTH];

u32 media_filename_length;
u32 offset_to_media_filename;
u32 media_path_length;
u32 offset_to_media_path;
u32 media_subimage_index;
u32 unused_offset_to_playlist_filename; // Unused as of version 51.


// Screenshot compression added in version 69.
// Uncompressed size not stored, it can be inferred from width/height.
u32 screenshot_compression_type;
u32 screenshot_width;
u32 screenshot_height;
u32 screenshot_size;
u32 screenshot_compressed_size;
u32 offset_to_screenshot;

u32 data_compression_type;
Expand Down
Loading

0 comments on commit a6518ff

Please sign in to comment.