mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-21 18:22:33 +01:00
Implement serialization.hpp, remove cereal submodule
Bump RSX capture version, use new serializer.
This commit is contained in:
parent
ddbe496097
commit
2169e8d935
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -23,10 +23,6 @@
|
||||
path = 3rdparty/SPIRV/SPIRV-Headers
|
||||
url = ../../KhronosGroup/SPIRV-Headers.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/cereal"]
|
||||
path = 3rdparty/cereal
|
||||
url = ../../RPCS3/cereal.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/zlib"]
|
||||
path = 3rdparty/zlib/zlib
|
||||
url = ../../madler/zlib
|
||||
|
7
3rdparty/CMakeLists.txt
vendored
7
3rdparty/CMakeLists.txt
vendored
@ -103,12 +103,6 @@ else()
|
||||
target_include_directories(xxhash INTERFACE xxHash)
|
||||
endif()
|
||||
|
||||
|
||||
# cereal
|
||||
add_library(3rdparty_cereal INTERFACE)
|
||||
target_include_directories(3rdparty_cereal INTERFACE cereal/include)
|
||||
|
||||
|
||||
# OpenGL
|
||||
|
||||
# Prefer GLVND for OpenGL rather than legacy, unless it's been defined elsewhere, in the case of AppImage builds
|
||||
@ -351,7 +345,6 @@ add_library(3rdparty::yaml-cpp ALIAS yaml-cpp)
|
||||
add_library(3rdparty::xxhash ALIAS xxhash)
|
||||
add_library(3rdparty::hidapi ALIAS 3rdparty_hidapi)
|
||||
add_library(3rdparty::libpng ALIAS ${LIBPNG_TARGET})
|
||||
add_library(3rdparty::cereal ALIAS 3rdparty_cereal)
|
||||
add_library(3rdparty::opengl ALIAS 3rdparty_opengl)
|
||||
add_library(3rdparty::stblib ALIAS 3rdparty_stblib)
|
||||
add_library(3rdparty::discordRPC ALIAS 3rdparty_discordRPC)
|
||||
|
1
3rdparty/cereal
vendored
1
3rdparty/cereal
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 60c69df968d1c72c998cd5f23ba34e2e3718a84b
|
@ -3,7 +3,7 @@
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<IncludePath>.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash</IncludePath>
|
||||
<IncludePath>.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash</IncludePath>
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
|
@ -38,7 +38,6 @@ target_sources(rpcs3_emu PRIVATE
|
||||
../util/atomic.cpp
|
||||
../util/logs.cpp
|
||||
../util/yaml.cpp
|
||||
../util/cereal.cpp
|
||||
../util/vm_native.cpp
|
||||
../util/dyn_lib.cpp
|
||||
../util/sysinfo.cpp
|
||||
@ -76,12 +75,6 @@ else()
|
||||
set_source_files_properties("../util/yaml.cpp" PROPERTIES COMPILE_FLAGS -fexceptions)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties("../util/cereal.cpp" PROPERTIES COMPILE_FLAGS /GR)
|
||||
else()
|
||||
set_source_files_properties("../util/cereal.cpp" PROPERTIES COMPILE_FLAGS -frtti)
|
||||
endif()
|
||||
|
||||
# Crypto
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
../Crypto/aes.cpp
|
||||
@ -499,7 +492,7 @@ endif()
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
PUBLIC
|
||||
3rdparty::ffmpeg 3rdparty::cereal
|
||||
3rdparty::ffmpeg
|
||||
3rdparty::opengl 3rdparty::stblib
|
||||
3rdparty::vulkan 3rdparty::glew
|
||||
3rdparty::libusb 3rdparty::wolfssl
|
||||
|
@ -8,35 +8,27 @@
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
constexpr u32 FRAME_CAPTURE_MAGIC = 0x52524300; // ascii 'RRC/0'
|
||||
constexpr u32 FRAME_CAPTURE_VERSION = 0x4;
|
||||
enum : u32
|
||||
{
|
||||
c_fc_magic = "RRC"_u32,
|
||||
c_fc_version = 0x5,
|
||||
};
|
||||
|
||||
struct frame_capture_data
|
||||
{
|
||||
struct memory_block_data
|
||||
{
|
||||
std::vector<u8> data{};
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive& ar)
|
||||
{
|
||||
ar(data);
|
||||
}
|
||||
};
|
||||
|
||||
// simple block to hold ps3 address and data
|
||||
struct memory_block
|
||||
{
|
||||
static constexpr bool enable_bitcopy = true;
|
||||
|
||||
u32 offset; // Offset in rsx address space
|
||||
u32 location; // rsx memory location of the block
|
||||
u64 data_state;
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(offset);
|
||||
ar(location);
|
||||
ar(data_state);
|
||||
}
|
||||
};
|
||||
|
||||
struct replay_command
|
||||
@ -45,101 +37,61 @@ namespace rsx
|
||||
std::unordered_set<u64> memory_state{}; // index into memory_map for the various memory blocks that need applying before this command can run
|
||||
u64 tile_state{0}; // tile state for this command
|
||||
u64 display_buffer_state{0};
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(rsx_command);
|
||||
ar(memory_state);
|
||||
ar(tile_state);
|
||||
ar(display_buffer_state);
|
||||
}
|
||||
};
|
||||
|
||||
struct tile_info
|
||||
{
|
||||
static constexpr bool enable_bitcopy = true;
|
||||
|
||||
u32 tile;
|
||||
u32 limit;
|
||||
u32 pitch;
|
||||
u32 format;
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(tile);
|
||||
ar(limit);
|
||||
ar(pitch);
|
||||
ar(format);
|
||||
}
|
||||
};
|
||||
|
||||
struct zcull_info
|
||||
{
|
||||
static constexpr bool enable_bitcopy = true;
|
||||
|
||||
u32 region;
|
||||
u32 size;
|
||||
u32 start;
|
||||
u32 offset;
|
||||
u32 status0;
|
||||
u32 status1;
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(region);
|
||||
ar(size);
|
||||
ar(start);
|
||||
ar(offset);
|
||||
ar(status0);
|
||||
ar(status1);
|
||||
}
|
||||
};
|
||||
|
||||
// bleh, may need to break these out, might be unnecessary to do both always
|
||||
struct tile_state
|
||||
{
|
||||
static constexpr bool enable_bitcopy = true;
|
||||
|
||||
tile_info tiles[15]{};
|
||||
zcull_info zculls[8]{};
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(tiles);
|
||||
ar(zculls);
|
||||
}
|
||||
};
|
||||
|
||||
struct buffer_state
|
||||
{
|
||||
static constexpr bool enable_bitcopy = true;
|
||||
|
||||
u32 width{0};
|
||||
u32 height{0};
|
||||
u32 pitch{0};
|
||||
u32 offset{0};
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(width);
|
||||
ar(height);
|
||||
ar(pitch);
|
||||
ar(offset);
|
||||
}
|
||||
};
|
||||
|
||||
struct display_buffers_state
|
||||
{
|
||||
static constexpr bool enable_bitcopy = true;
|
||||
|
||||
std::array<buffer_state, 8> buffers{};
|
||||
u32 count{0};
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(buffers);
|
||||
ar(count);
|
||||
}
|
||||
};
|
||||
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 magic = c_fc_magic;
|
||||
u32 version = c_fc_version;
|
||||
u32 LE_format = std::endian::little == std::endian::native;
|
||||
|
||||
// hashmap of holding various states for tile
|
||||
std::unordered_map<u64, tile_state> tile_map;
|
||||
// hashmap of various memory 'changes' that can be applied to ps3 memory
|
||||
@ -153,23 +105,10 @@ namespace rsx
|
||||
// Initial registers state at the beginning of the capture
|
||||
rsx::rsx_state reg_state;
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(magic);
|
||||
ar(version);
|
||||
ar(tile_map);
|
||||
ar(memory_map);
|
||||
ar(memory_data_map);
|
||||
ar(display_buffers_map);
|
||||
ar(replay_commands);
|
||||
ar(reg_state);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
magic = FRAME_CAPTURE_MAGIC;
|
||||
version = FRAME_CAPTURE_VERSION;
|
||||
magic = c_fc_magic;
|
||||
version = c_fc_version;
|
||||
tile_map.clear();
|
||||
memory_map.clear();
|
||||
replay_commands.clear();
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "Utilities/date_time.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include "util/cereal.hpp"
|
||||
#include "util/serialization.hpp"
|
||||
#include "util/asm.hpp"
|
||||
|
||||
#include <span>
|
||||
@ -39,6 +39,37 @@ rsx::frame_capture_data frame_capture;
|
||||
extern CellGcmOffsetTable offsetTable;
|
||||
extern thread_local std::string(*g_tls_log_prefix)();
|
||||
|
||||
template <>
|
||||
bool serialize<rsx::rsx_state>(utils::serial& ar, rsx::rsx_state& o)
|
||||
{
|
||||
return ar(o.transform_program, /*o.transform_constants,*/ o.registers);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool serialize<rsx::frame_capture_data>(utils::serial& ar, rsx::frame_capture_data& o)
|
||||
{
|
||||
ar(o.magic, o.version, o.LE_format);
|
||||
|
||||
if (o.magic != rsx::c_fc_magic || o.version != rsx::c_fc_version || o.LE_format != (std::endian::little == std::endian::native))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ar(o.tile_map, o.memory_map, o.memory_data_map, o.display_buffers_map, o.replay_commands, o.reg_state);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool serialize<rsx::frame_capture_data::memory_block_data>(utils::serial& ar, rsx::frame_capture_data::memory_block_data& o)
|
||||
{
|
||||
return ar(o.data);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool serialize<rsx::frame_capture_data::replay_command>(utils::serial& ar, rsx::frame_capture_data::replay_command& o)
|
||||
{
|
||||
return ar(o.rsx_command, o.memory_state, o.tile_state, o.display_buffer_state);
|
||||
}
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
@ -2861,11 +2892,14 @@ namespace rsx
|
||||
const std::string file_path = fs::get_config_dir() + "captures/" + Emu.GetTitleID() + "_" + date_time::current_time_narrow() + "_capture.rrc";
|
||||
|
||||
// todo: may want to compress this data?
|
||||
const std::string file_data = cereal_serialize(frame_capture);
|
||||
utils::serial save_manager;
|
||||
save_manager.reserve(0x800'0000); // 128MB
|
||||
|
||||
save_manager(frame_capture);
|
||||
|
||||
fs::pending_file temp(file_path);
|
||||
|
||||
if (temp.file && (temp.file.write(file_data), temp.commit(false)))
|
||||
if (temp.file && (temp.file.write(save_manager.data), temp.commit(false)))
|
||||
{
|
||||
rsx_log.success("Capture successful: %s", file_path);
|
||||
}
|
||||
|
@ -554,15 +554,6 @@ namespace rsx
|
||||
|
||||
void init();
|
||||
|
||||
template<typename Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(transform_program,
|
||||
// transform_constants,
|
||||
registers
|
||||
);
|
||||
}
|
||||
|
||||
u16 viewport_width() const
|
||||
{
|
||||
return decode<NV4097_SET_VIEWPORT_HORIZONTAL>().width();
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "../Crypto/unself.h"
|
||||
#include "util/yaml.hpp"
|
||||
#include "util/logs.hpp"
|
||||
#include "util/cereal.hpp"
|
||||
#include "util/serialization.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
@ -380,18 +380,31 @@ bool Emulator::BootRsxCapture(const std::string& path)
|
||||
}
|
||||
|
||||
std::unique_ptr<rsx::frame_capture_data> frame = std::make_unique<rsx::frame_capture_data>();
|
||||
cereal_deserialize(*frame, in_file.to_string());
|
||||
utils::serial load_manager;
|
||||
load_manager.set_reading_state(in_file.to_vector<u8>());
|
||||
|
||||
load_manager(*frame);
|
||||
in_file.close();
|
||||
|
||||
if (frame->magic != rsx::FRAME_CAPTURE_MAGIC)
|
||||
if (frame->magic != rsx::c_fc_magic)
|
||||
{
|
||||
sys_log.error("Invalid rsx capture file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frame->version != rsx::FRAME_CAPTURE_VERSION)
|
||||
if (frame->version != rsx::c_fc_version)
|
||||
{
|
||||
sys_log.error("Rsx capture file version not supported! Expected %d, found %d", rsx::FRAME_CAPTURE_VERSION, frame->version);
|
||||
sys_log.error("Rsx capture file version not supported! Expected %d, found %d", +rsx::c_fc_version, frame->version);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frame->LE_format != (std::endian::little == std::endian::native))
|
||||
{
|
||||
static constexpr std::string_view machines[2]{"Big-Endian", "Little-Endian"};
|
||||
|
||||
sys_log.error("Rsx capture byte endianness not supported! Expected %s format, found %s format"
|
||||
, machines[frame->LE_format ^ 1], machines[frame->LE_format]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -100,10 +100,6 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\cereal.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Utilities\bin_patch.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
@ -490,6 +486,7 @@
|
||||
<ClInclude Include="Emu\system_config_types.h" />
|
||||
<ClInclude Include="Loader\mself.hpp" />
|
||||
<ClInclude Include="util\atomic.hpp" />
|
||||
<ClInclude Include="util\serialization.hpp" />
|
||||
<ClInclude Include="util\v128.hpp" />
|
||||
<ClInclude Include="util\v128sse.hpp" />
|
||||
<ClInclude Include="util\to_endian.hpp" />
|
||||
|
@ -843,9 +843,6 @@
|
||||
<ClCompile Include="util\yaml.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\cereal.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\cpu_stats.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
@ -1962,6 +1959,9 @@
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_progress_bar.hpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util\serialization.hpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Common\Interpreter\FragmentInterpreter.glsl">
|
||||
|
@ -62,12 +62,12 @@
|
||||
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib</IncludePath>
|
||||
<IncludePath>..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LibraryPath>$(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;..\3rdparty\cereal\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib</IncludePath>
|
||||
<IncludePath>..\3rdparty\7z\src;..\3rdparty\hidapi\hidapi\hidapi;.\;..\;..\3rdparty\asmjit\asmjit\src;..\3rdparty\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\XAudio2Redist\include;..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\include;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src;..\3rdparty\Optional;..\3rdparty\discord-rpc\include;..\3rdparty\zlib\zlib</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
|
@ -1,49 +0,0 @@
|
||||
#include "util/cereal.hpp"
|
||||
#include <string>
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Emu/RSX/RSXThread.h"
|
||||
#include "Emu/RSX/Capture/rsx_capture.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#endif
|
||||
|
||||
#include "cereal/archives/binary.hpp"
|
||||
#include <cereal/types/vector.hpp>
|
||||
#include <cereal/types/array.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
#include <cereal/types/utility.hpp>
|
||||
#include <cereal/types/unordered_set.hpp>
|
||||
#include <cereal/types/unordered_map.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
[[noreturn]] void throw_exception(const std::string& err)
|
||||
{
|
||||
fmt::throw_exception("%s", err);
|
||||
}
|
||||
|
||||
[[noreturn]] void throw_exception(const char* err)
|
||||
{
|
||||
fmt::throw_exception("%s", err);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string cereal_serialize<rsx::frame_capture_data>(const rsx::frame_capture_data& data)
|
||||
{
|
||||
std::ostringstream os;
|
||||
cereal::BinaryOutputArchive archive(os);
|
||||
archive(data);
|
||||
return os.str();
|
||||
}
|
||||
|
||||
template <>
|
||||
void cereal_deserialize<rsx::frame_capture_data>(rsx::frame_capture_data& data, const std::string& src)
|
||||
{
|
||||
std::istringstream is(src);
|
||||
cereal::BinaryInputArchive archive(is);
|
||||
archive(data);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
template <typename T>
|
||||
std::string cereal_serialize(const T&);
|
||||
|
||||
template <typename T>
|
||||
void cereal_deserialize(T& data, const std::string& src);
|
346
rpcs3/util/serialization.hpp
Normal file
346
rpcs3/util/serialization.hpp
Normal file
@ -0,0 +1,346 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace stx
|
||||
{
|
||||
template <typename T>
|
||||
struct exact_t
|
||||
{
|
||||
T obj;
|
||||
|
||||
exact_t(T&& _obj) : obj(std::forward<T>(_obj)) {}
|
||||
|
||||
// TODO: More conversions
|
||||
template <typename U> requires (std::is_same_v<U&, T>)
|
||||
operator U&() const { return obj; };
|
||||
};
|
||||
}
|
||||
|
||||
namespace utils
|
||||
{
|
||||
template <typename T>
|
||||
concept FastRandomAccess = requires (T& obj)
|
||||
{
|
||||
std::data(obj)[0];
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept Reservable = requires (T& obj)
|
||||
{
|
||||
obj.reserve(0);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept Bitcopy = (std::is_arithmetic_v<T>) || (std::is_enum_v<T>) || requires (T& obj)
|
||||
{
|
||||
std::enable_if_t<static_cast<bool>(std::remove_cv_t<T>::enable_bitcopy)>();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept TupleAlike = requires ()
|
||||
{
|
||||
std::tuple_size<std::remove_cv_t<T>>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept ListAlike = requires (T& obj) { obj.insert(obj.end(), std::declval<typename T::value_type>()); };
|
||||
|
||||
struct serial
|
||||
{
|
||||
std::vector<u8> data;
|
||||
usz pos = umax;
|
||||
|
||||
// Checks if this strcuture is currently used for serialization
|
||||
bool is_writing() const
|
||||
{
|
||||
return pos == umax;
|
||||
}
|
||||
|
||||
// Reserve memory for serialization
|
||||
void reserve(usz size)
|
||||
{
|
||||
// Is a NO-OP for deserialization in order to allow usage from serialization specializations regardless
|
||||
if (is_writing())
|
||||
{
|
||||
data.reserve(data.size() + size);
|
||||
}
|
||||
}
|
||||
|
||||
bool raw_serialize(const void* ptr, usz size)
|
||||
{
|
||||
if (is_writing())
|
||||
{
|
||||
data.insert(data.end(), static_cast<const u8*>(ptr), static_cast<const u8*>(ptr) + size);
|
||||
return true;
|
||||
}
|
||||
|
||||
ensure(data.size() - pos >= size);
|
||||
std::memcpy(const_cast<void*>(ptr), data.data() + pos, size);
|
||||
pos += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
// (De)serialization function
|
||||
template <typename T>
|
||||
bool serialize(T& obj)
|
||||
{
|
||||
// Fallback to global overload
|
||||
return ::serialize(*this, obj);
|
||||
}
|
||||
|
||||
// Enabled for fundamental types, enumerations and if specfied explicitly that type can be saved in pure bitwise manner
|
||||
template <typename T> requires Bitcopy<T>
|
||||
bool serialize(T& obj)
|
||||
{
|
||||
return raw_serialize(std::addressof(obj), sizeof(obj));
|
||||
}
|
||||
|
||||
// std::vector, std::basic_string
|
||||
template <typename T> requires FastRandomAccess<T> && ListAlike<T>
|
||||
bool serialize(T& obj)
|
||||
{
|
||||
if (is_writing())
|
||||
{
|
||||
for (usz i = obj.size();;)
|
||||
{
|
||||
const usz i_old = std::exchange(i, i >> 7);
|
||||
operator()<u8>(static_cast<u8>(i_old % 0x80) | (u8{!!i} << 7));
|
||||
if (!i)
|
||||
break;
|
||||
}
|
||||
|
||||
if constexpr (std::is_trivially_copyable_v<typename std::remove_reference_t<T>::value_type>)
|
||||
{
|
||||
raw_serialize(obj.data(), sizeof(obj[0]) * obj.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto&& value : obj)
|
||||
{
|
||||
if (!serialize(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
obj.clear();
|
||||
|
||||
usz size = 0;
|
||||
|
||||
for (u32 i = 0;; i += 7)
|
||||
{
|
||||
u8 byte_data = 0;
|
||||
|
||||
if (!raw_serialize(&byte_data, 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size |= static_cast<usz>(byte_data % 0x80) << i;
|
||||
|
||||
if (!(byte_data >> 7))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
obj.resize(size);
|
||||
|
||||
if constexpr (std::is_trivially_copyable_v<typename T::value_type>)
|
||||
{
|
||||
if (!raw_serialize(obj.data(), sizeof(obj[0]) * size))
|
||||
{
|
||||
obj.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto&& value : obj)
|
||||
{
|
||||
if (!serialize(value))
|
||||
{
|
||||
obj.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// C-array, std::array, std::span
|
||||
template <typename T> requires FastRandomAccess<T> && (!ListAlike<T>) && (!Bitcopy<T>)
|
||||
bool serialize(T& obj)
|
||||
{
|
||||
if constexpr (std::is_trivially_copyable_v<std::remove_reference_t<decltype(std::declval<T>()[0])>>)
|
||||
{
|
||||
return raw_serialize(std::data(obj), sizeof(obj[0]) * std::size(obj));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto&& value : obj)
|
||||
{
|
||||
if (!serialize(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// std::deque, std::list, std::(unordered_)set, std::(unordered_)map, std::(unordered_)multiset, std::(unordered_)multimap
|
||||
template <typename T> requires (!FastRandomAccess<T>) && ListAlike<T>
|
||||
bool serialize(T& obj)
|
||||
{
|
||||
if (is_writing())
|
||||
{
|
||||
for (usz i = obj.size();;)
|
||||
{
|
||||
const usz i_old = std::exchange(i, i >> 7);
|
||||
operator()<u8>(static_cast<u8>(i_old % 0x80) | (u8{!!i} << 7));
|
||||
if (!i)
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto&& value : obj)
|
||||
{
|
||||
if (!serialize(value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
obj.clear();
|
||||
|
||||
usz size = 0;
|
||||
|
||||
for (u32 i = 0;; i += 7)
|
||||
{
|
||||
u8 byte_data = 0;
|
||||
|
||||
if (!raw_serialize(&byte_data, 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size |= static_cast<usz>(byte_data % 0x80) << i;
|
||||
|
||||
if (!(byte_data >> 7))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (Reservable<T>)
|
||||
{
|
||||
obj.reserve(size);
|
||||
}
|
||||
|
||||
for (usz i = 0; i < size; i++)
|
||||
{
|
||||
obj.insert(obj.end(), static_cast<typename T::value_type>(*this));
|
||||
|
||||
if (!is_valid())
|
||||
{
|
||||
obj.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <usz i = 0, typename T>
|
||||
bool serialize_tuple(T& obj)
|
||||
{
|
||||
const bool res = serialize(std::get<i>(obj));
|
||||
constexpr usz next_i = std::min<usz>(i + 1, std::tuple_size_v<T> - 1);
|
||||
|
||||
if constexpr (next_i == i)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
return res && serialize_tuple<next_i>(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// std::pair, std::tuple
|
||||
template <typename T> requires TupleAlike<T> && (!FastRandomAccess<T>)
|
||||
bool serialize(T& obj)
|
||||
{
|
||||
return serialize_tuple(obj);
|
||||
}
|
||||
|
||||
// Wrapper for serialize(T&), allows to pass multiple objects at once
|
||||
template <typename... Args>
|
||||
bool operator()(Args&&... args)
|
||||
{
|
||||
return ((AUDIT(!std::is_const_v<std::remove_reference_t<Args>> || is_writing())
|
||||
, serialize(const_cast<Args&>(static_cast<const Args&>(args)))), ...);
|
||||
}
|
||||
|
||||
// Convert serialization manager to deserializion manager (can't go the other way)
|
||||
// If no arg provided reuse saved buffer
|
||||
void set_reading_state(std::vector<u8>&& _data = std::vector<u8>{})
|
||||
{
|
||||
if (!_data.empty())
|
||||
{
|
||||
data = std::move(_data);
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
template <typename T> requires (std::is_constructible_v<std::remove_const_t<T>> || Bitcopy<std::remove_const_t<T>> ||
|
||||
std::is_constructible_v<std::remove_const_t<T>, stx::exact_t<serial&>> || TupleAlike<std::remove_const_t<T>>)
|
||||
operator T()
|
||||
{
|
||||
AUDIT(!is_writing());
|
||||
|
||||
using type = std::remove_const_t<T>;
|
||||
|
||||
if constexpr (Bitcopy<T>)
|
||||
{
|
||||
u8 buf[sizeof(type)]{};
|
||||
ensure(raw_serialize(buf, sizeof(buf)));
|
||||
return std::bit_cast<type>(buf);
|
||||
}
|
||||
else if constexpr (std::is_constructible_v<type, stx::exact_t<serial&>>)
|
||||
{
|
||||
return type(stx::exact_t<serial&>(*this));
|
||||
}
|
||||
else if constexpr (std::is_constructible_v<type>)
|
||||
{
|
||||
type value{};
|
||||
ensure(serialize(value));
|
||||
return value;
|
||||
}
|
||||
else if constexpr (TupleAlike<T>)
|
||||
{
|
||||
static_assert(std::tuple_size_v<type> == 2, "Unimplemented tuple serialization!");
|
||||
return type{ operator std::remove_cvref_t<decltype(std::get<0>(std::declval<type&>()))>
|
||||
, operator std::remove_cvref_t<decltype(std::get<1>(std::declval<type&>()))> };
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if writable or readable and valid
|
||||
bool is_valid() const
|
||||
{
|
||||
return is_writing() || pos < data.size();
|
||||
}
|
||||
};
|
||||
}
|
@ -1070,3 +1070,11 @@ constexpr bool is_same_ptr(const volatile Y* ptr)
|
||||
|
||||
template <typename X, typename Y>
|
||||
concept PtrSame = (is_same_ptr<X, Y>());
|
||||
|
||||
namespace utils
|
||||
{
|
||||
struct serial;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
extern bool serialize(utils::serial& ar, T& obj);
|
||||
|
Loading…
Reference in New Issue
Block a user