From 52edef0867a7145b107cf9eee99f9f495416c2fa Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Fri, 14 Feb 2025 16:59:16 +0200 Subject: [PATCH] Remove xxHash submodule --- .gitmodules | 4 - 3rdparty/CMakeLists.txt | 14 ---- 3rdparty/xxHash | 1 - 3rdparty/xxhash.vcxproj | 65 --------------- buildfiles/msvc/rpcs3_default.props | 4 +- rpcs3.sln | 8 -- rpcs3/Emu/CMakeLists.txt | 2 +- rpcs3/Emu/RSX/Capture/rsx_capture.cpp | 71 ++++++++++------- rpcs3/Emu/RSX/Capture/rsx_replay.cpp | 17 ++-- rpcs3/Emu/RSX/Capture/rsx_replay.h | 61 +++++++++++--- rpcs3/util/serialization.hpp | 109 ++++++++++++++++++++------ 11 files changed, 187 insertions(+), 169 deletions(-) delete mode 160000 3rdparty/xxHash delete mode 100644 3rdparty/xxhash.vcxproj diff --git a/.gitmodules b/.gitmodules index 50cdb67ab6..9f453de899 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,10 +28,6 @@ path = 3rdparty/pugixml url = ../../zeux/pugixml.git ignore = dirty -[submodule "3rdparty/xxHash"] - path = 3rdparty/xxHash - url = ../../Cyan4973/xxHash.git - ignore = dirty [submodule "3rdparty/yaml-cpp"] path = 3rdparty/yaml-cpp/yaml-cpp url = ../../RPCS3/yaml-cpp.git diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 4c2c6a35ac..4625c0e81e 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -97,19 +97,6 @@ target_link_libraries(3rdparty_glslang INTERFACE SPIRV) add_subdirectory(yaml-cpp) -# xxHash -if (USE_SYSTEM_XXHASH) - pkg_check_modules(XXHASH REQUIRED IMPORTED_TARGET libxxhash) - add_library(xxhash INTERFACE) - target_link_libraries(xxhash INTERFACE PkgConfig::XXHASH) -else() - set(XXHASH_BUNDLED_MODE ON) - set(XXHASH_BUILD_XXHSUM OFF) - set(BUILD_SHARED_LIBS OFF CACHE BOOL "Make xxHash build static libs") - add_subdirectory(xxHash/cmake_unofficial EXCLUDE_FROM_ALL) - target_include_directories(xxhash INTERFACE xxHash) -endif() - # OpenGL find_package(OpenGL REQUIRED OPTIONAL_COMPONENTS EGL) @@ -364,7 +351,6 @@ add_library(3rdparty::flatbuffers ALIAS 3rdparty_flatbuffers) add_library(3rdparty::pugixml ALIAS pugixml) add_library(3rdparty::glslang ALIAS 3rdparty_glslang) 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::opengl ALIAS 3rdparty_opengl) diff --git a/3rdparty/xxHash b/3rdparty/xxHash deleted file mode 160000 index e626a72bc2..0000000000 --- a/3rdparty/xxHash +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e626a72bc2321cd320e953a0ccf1584cad60f363 diff --git a/3rdparty/xxhash.vcxproj b/3rdparty/xxhash.vcxproj deleted file mode 100644 index 6985e3205a..0000000000 --- a/3rdparty/xxhash.vcxproj +++ /dev/null @@ -1,65 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {939FE206-1182-ABC3-1234-FEAB88E98404} - - - - - - StaticLibrary - Unicode - - - true - - - false - - - - x64 - - - - - - - - - - - - - - - - - - MaxSpeed - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/buildfiles/msvc/rpcs3_default.props b/buildfiles/msvc/rpcs3_default.props index 77aca3d0dd..4f5862ca84 100644 --- a/buildfiles/msvc/rpcs3_default.props +++ b/buildfiles/msvc/rpcs3_default.props @@ -3,7 +3,7 @@ - .\;..\;..\3rdparty\asmjit\asmjit\src;..\..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\stb;..\3rdparty\openal\openal-soft\include\AL;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi;..\3rdparty\Optional;..\3rdparty\xxhash + .\;..\;..\3rdparty\asmjit\asmjit\src;..\..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\libpng\libpng;..\3rdparty\GL;..\3rdparty\stblib\stb;..\3rdparty\openal\openal-soft\include\AL;..\3rdparty\pugixml\src;..\3rdparty\hidapi\hidapi $(SolutionDir)build\lib\$(Configuration)-$(Platform)\ $(SolutionDir)build\lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\ @@ -23,7 +23,7 @@ /utf-8 /Zc:throwingNew- /constexpr:steps16777216 %(AdditionalOptions) - xxhash.lib;ws2_32.lib;Iphlpapi.lib;Bcrypt.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib + ws2_32.lib;Iphlpapi.lib;Bcrypt.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib ..\3rdparty\ffmpeg\lib\windows\x86_64 8388608 1048576 diff --git a/rpcs3.sln b/rpcs3.sln index 26bc66179b..4b920a68e0 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -10,7 +10,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vc {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} {5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0} = {5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0} {8846A9AA-5539-4C91-8301-F54260E1A07A} = {8846A9AA-5539-4C91-8301-F54260E1A07A} - {939FE206-1182-ABC3-1234-FEAB88E98404} = {939FE206-1182-ABC3-1234-FEAB88E98404} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build", "3rdparty\llvm\llvm_build.vcxproj", "{8BC303AB-25BE-4276-8E57-73F171B2D672}" @@ -67,8 +66,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi", "3rdparty\hidapi\hidapi.vcxproj", "{A107C21C-418A-4697-BB10-20C3AA60E2E4}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "3rdparty\xxhash.vcxproj", "{939FE206-1182-ABC3-1234-FEAB88E98404}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "3rdparty\libusb\libusb_static.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wolfssl", "3rdparty\wolfssl\wolfssl.vcxproj", "{73973223-5EE8-41CA-8E88-1D60E89A237B}" @@ -161,10 +158,6 @@ Global {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64 {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.ActiveCfg = Release|x64 {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64 - {939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.ActiveCfg = Debug|x64 - {939FE206-1182-ABC3-1234-FEAB88E98404}.Debug|x64.Build.0 = Debug|x64 - {939FE206-1182-ABC3-1234-FEAB88E98404}.Release|x64.ActiveCfg = Release|x64 - {939FE206-1182-ABC3-1234-FEAB88E98404}.Release|x64.Build.0 = Release|x64 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 @@ -236,7 +229,6 @@ Global {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {FDC361C5-7734-493B-8CFB-037308B35122} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {A107C21C-418A-4697-BB10-20C3AA60E2E4} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} - {939FE206-1182-ABC3-1234-FEAB88E98404} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {73973223-5EE8-41CA-8E88-1D60E89A237B} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 0b78942ac9..cd4cdb2a46 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -641,7 +641,7 @@ target_link_libraries(rpcs3_emu 3rdparty::vulkan 3rdparty::glew 3rdparty::libusb 3rdparty::wolfssl PRIVATE - 3rdparty::glslang 3rdparty::xxhash + 3rdparty::glslang ) if(APPLE) diff --git a/rpcs3/Emu/RSX/Capture/rsx_capture.cpp b/rpcs3/Emu/RSX/Capture/rsx_capture.cpp index bfd47df73d..3ac2dd929e 100644 --- a/rpcs3/Emu/RSX/Capture/rsx_capture.cpp +++ b/rpcs3/Emu/RSX/Capture/rsx_capture.cpp @@ -6,33 +6,33 @@ #include "Emu/RSX/RSXThread.h" #include "Emu/Memory/vm.h" -#include "xxhash.h" - namespace rsx { namespace capture { - void insert_mem_block_in_map(std::unordered_set& mem_changes, frame_capture_data::memory_block&& block, frame_capture_data::memory_block_data&& data) + void insert_mem_block_in_map(u64& indexer, std::unordered_set& mem_changes, frame_capture_data::memory_block&& block, frame_capture_data::memory_block_data&& data) { if (!data.data.empty()) { - u64 data_hash = XXH64(data.data.data(), data.data.size(), 0); + const auto [it, inserted] = frame_capture.memory_data_map.try_emplace(data, 0); + u64& data_hash = it->second; + + if (inserted) + { + data_hash = ++indexer; + } + block.data_state = data_hash; - auto it = frame_capture.memory_data_map.find(data_hash); - if (it != frame_capture.memory_data_map.end()) - { - if (it->second.data != data.data) - // screw this - fmt::throw_exception("Memory map hash collision detected...cant capture"); - } - else - frame_capture.memory_data_map.insert(std::make_pair(data_hash, std::move(data))); + const auto [block_it, inserted_block] = frame_capture.memory_map.try_emplace(block, 0); + u64& block_hash = block_it->second; + + if (inserted_block) + { + block_hash = ++indexer; + } - u64 block_hash = XXH64(&block, sizeof(frame_capture_data::memory_block), 0); mem_changes.insert(block_hash); - if (frame_capture.memory_map.find(block_hash) == frame_capture.memory_map.end()) - frame_capture.memory_map.insert(std::make_pair(block_hash, std::move(block))); } } @@ -48,6 +48,7 @@ namespace rsx // shove the mem_changes onto the last issued command std::unordered_set& mem_changes = frame_capture.replay_commands.back().memory_state; + u64& mem_indexer = frame_capture.memory_indexer; // capture fragment shader mem const auto [program_offset, program_location] = method_registers.shader_program_address(); @@ -63,7 +64,7 @@ namespace rsx frame_capture_data::memory_block_data block_data; block_data.data.resize(ucode_size + program_start); std::memcpy(block_data.data.data(), vm::base(addr), ucode_size + program_start); - insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data)); + insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data)); // vertex shader is passed in registers, so it can be ignored @@ -90,7 +91,7 @@ namespace rsx frame_capture_data::memory_block_data block_data; block_data.data.resize(texSize); std::memcpy(block_data.data.data(), vm::base(texaddr), texSize); - insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data)); + insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data)); } // save vertex texture mem @@ -116,7 +117,7 @@ namespace rsx frame_capture_data::memory_block_data block_data; block_data.data.resize(texSize); std::memcpy(block_data.data.data(), vm::base(texaddr), texSize); - insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data)); + insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data)); } // save vertex buffer memory @@ -154,7 +155,7 @@ namespace rsx frame_capture_data::memory_block_data block_data; block_data.data.resize(bufferSize); std::memcpy(block_data.data.data(), vm::base(addr + (range.first * vertStride)), bufferSize); - insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data)); + insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data)); } while (method_registers.current_draw_clause.next()); } @@ -193,7 +194,7 @@ namespace rsx frame_capture_data::memory_block_data block_data; block_data.data.resize(bufferSize); std::memcpy(block_data.data.data(), vm::base(idxAddr), bufferSize); - insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data)); + insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data)); switch (index_type) { @@ -256,7 +257,7 @@ namespace rsx frame_capture_data::memory_block_data block_data; block_data.data.resize(bufferSize); std::memcpy(block_data.data.data(), vm::base(addr + (min_index * vertStride)), bufferSize); - insert_mem_block_in_map(mem_changes, std::move(block), std::move(block_data)); + insert_mem_block_in_map(mem_indexer, mem_changes, std::move(block), std::move(block_data)); } } } @@ -308,7 +309,7 @@ namespace rsx frame_capture_data::memory_block_data block_data; block_data.data.resize(src_size); std::memcpy(block_data.data.data(), pixels_src, src_size); - insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data)); + insert_mem_block_in_map(frame_capture.memory_indexer, replay_command.memory_state, std::move(block), std::move(block_data)); capture_display_tile_state(rsx, replay_command); } @@ -340,14 +341,17 @@ namespace rsx src += in_pitch; } - insert_mem_block_in_map(replay_command.memory_state, std::move(block), std::move(block_data)); + insert_mem_block_in_map(frame_capture.memory_indexer, replay_command.memory_state, std::move(block), std::move(block_data)); capture_display_tile_state(rsx, replay_command); } void capture_display_tile_state(thread* rsx, frame_capture_data::replay_command& replay_command) { + u64& mem_indexer = frame_capture.memory_indexer; + frame_capture_data::display_buffers_state dbstate; dbstate.count = rsx->display_buffers_count; + // should this only happen on flip? for (u32 i = 0; i < rsx->display_buffers_count; ++i) { @@ -358,9 +362,13 @@ namespace rsx dbstate.buffers[i].pitch = db.pitch; } - const u64 dbnum = XXH64(&dbstate, sizeof(frame_capture_data::display_buffers_state), 0); - if (frame_capture.display_buffers_map.find(dbnum) == frame_capture.display_buffers_map.end()) - frame_capture.display_buffers_map.insert(std::make_pair(dbnum, std::move(dbstate))); + const auto [db_it, db_inserted] = frame_capture.display_buffers_map.try_emplace(dbstate, 0); + u64& dbnum = db_it->second; + + if (db_inserted) + { + dbnum = ++mem_indexer; + } // todo: hook tile call sys_rsx call or something frame_capture_data::tile_state tilestate; @@ -386,10 +394,13 @@ namespace rsx zcstate.status1 = rsx->zculls[i].bound ? u32{zc.status1} : 0; } - const u64 tsnum = XXH64(&tilestate, sizeof(frame_capture_data::tile_state), 0); + const auto [ts_it, ts_inserted] = frame_capture.tile_map.try_emplace(tilestate, 0); + u64& tsnum = ts_it->second; - if (frame_capture.tile_map.find(tsnum) == frame_capture.tile_map.end()) - frame_capture.tile_map.insert(std::make_pair(tsnum, std::move(tilestate))); + if (ts_inserted) + { + tsnum = ++mem_indexer; + } replay_command.display_buffer_state = dbnum; replay_command.tile_state = tsnum; diff --git a/rpcs3/Emu/RSX/Capture/rsx_replay.cpp b/rpcs3/Emu/RSX/Capture/rsx_replay.cpp index 88bd6f9028..bb558744aa 100644 --- a/rpcs3/Emu/RSX/Capture/rsx_replay.cpp +++ b/rpcs3/Emu/RSX/Capture/rsx_replay.cpp @@ -106,26 +106,26 @@ namespace rsx // apply memory needed for command for (const auto& state : replay_cmd.memory_state) { - auto it = frame->memory_map.find(state); + auto it = std::find_if(frame->memory_map.begin(), frame->memory_map.end(), FN(x.second == state)); if (it == frame->memory_map.end()) fmt::throw_exception("requested memory state for command not found in memory_map"); - const auto& memblock = it->second; - auto it_data = frame->memory_data_map.find(it->second.data_state); + const auto& memblock = it->first; + auto it_data = std::find_if(frame->memory_data_map.begin(), frame->memory_data_map.end(), FN(x.second == memblock.data_state)); if (it_data == frame->memory_data_map.end()) fmt::throw_exception("requested memory data state for command not found in memory_data_map"); - const auto& data_block = it_data->second; + const auto& data_block = it_data->first; std::memcpy(vm::base(get_address(memblock.offset, memblock.location)), data_block.data.data(), data_block.data.size()); } if (replay_cmd.display_buffer_state != 0 && replay_cmd.display_buffer_state != cs.display_buffer_hash) { - auto it = frame->display_buffers_map.find(replay_cmd.display_buffer_state); + auto it = std::find_if(frame->display_buffers_map.begin(), frame->display_buffers_map.end(), FN(x.second == replay_cmd.display_buffer_state)); if (it == frame->display_buffers_map.end()) fmt::throw_exception("requested display buffer for command not found"); - const auto& dbstate = it->second; + const auto& dbstate = it->first; for (u32 i = 0; i < dbstate.count; ++i) { const auto& buf = dbstate.buffers[i]; @@ -136,16 +136,17 @@ namespace rsx sys_rsx_context_attribute(context_id, 0x104, i, u64{dbstate.buffers[i].width} << 32 | dbstate.buffers[i].height, u64{dbstate.buffers[i].pitch} << 32 | dbstate.buffers[i].offset, 0); } + cs.display_buffer_hash = replay_cmd.display_buffer_state; } if (replay_cmd.tile_state != 0 && replay_cmd.tile_state != cs.tile_hash) { - auto it = frame->tile_map.find(replay_cmd.tile_state); + auto it = std::find_if(frame->tile_map.begin(), frame->tile_map.end(), FN(x.second == replay_cmd.tile_state)); if (it == frame->tile_map.end()) fmt::throw_exception("requested tile state command not found"); - const auto& tstate = it->second; + const auto& tstate = it->first; for (u32 i = 0; i < limits::tiles_count; ++i) { const auto& ti = tstate.tiles[i]; diff --git a/rpcs3/Emu/RSX/Capture/rsx_replay.h b/rpcs3/Emu/RSX/Capture/rsx_replay.h index 891542f5c5..f11f2e08e9 100644 --- a/rpcs3/Emu/RSX/Capture/rsx_replay.h +++ b/rpcs3/Emu/RSX/Capture/rsx_replay.h @@ -11,7 +11,7 @@ namespace rsx enum : u32 { c_fc_magic = "RRC"_u32, - c_fc_version = 0x5, + c_fc_version = 0x6, }; struct frame_capture_data @@ -92,19 +92,60 @@ namespace rsx u32 version = c_fc_version; u32 LE_format = std::endian::little == std::endian::native; - // hashmap of holding various states for tile - std::unordered_map tile_map; - // hashmap of various memory 'changes' that can be applied to ps3 memory - std::unordered_map memory_map; - // hashmap of memory blocks that can be applied, this is split from above for size decrease - std::unordered_map memory_data_map; - // display buffer state map - std::unordered_map display_buffers_map; - // actual command queue to hold everything above + struct bitwise_hasher + { + template + usz operator()(const T& key) const noexcept + { + if constexpr (!!(requires (const T& a) { a.data[0]; })) + { + return std::hash{}(std::string_view{ reinterpret_cast(key.data.data()), key.data.size() * sizeof(key.data[0]) }); + } + + return std::hash{}(std::string_view{ reinterpret_cast(&key), sizeof(key) }); + } + + template + bool operator()(const T& keya, const T& keyb) const noexcept + { + if constexpr (!!(requires (const T& a) { a.data[0]; })) + { + if (keya.data.size() != keyb.data.size()) + { + return false; + } + + return std::equal(keya.data.begin(), keya.data.end(), keyb.data.begin()); + } + + return std::equal(reinterpret_cast(&keya), reinterpret_cast(&keya) + sizeof(T), reinterpret_cast(&keyb)); + } + }; + + template + using uno_bit_map = std::unordered_map; + + // Hashmap of holding various states for tile + uno_bit_map tile_map; + + // Hashmap of various memory 'changes' that can be applied to ps3 memory + uno_bit_map memory_map; + + // Hashmap of memory blocks that can be applied, this is split from above for size decrease + uno_bit_map memory_data_map; + + // Display buffer state map + uno_bit_map display_buffers_map; + + // Actual command queue to hold everything above std::vector replay_commands; + // Initial registers state at the beginning of the capture rsx::rsx_state reg_state; + // Indexer for memory blocks + u64 memory_indexer = 0x1234; + void reset() { magic = c_fc_magic; diff --git a/rpcs3/util/serialization.hpp b/rpcs3/util/serialization.hpp index 120c70c606..5e139e05f8 100644 --- a/rpcs3/util/serialization.hpp +++ b/rpcs3/util/serialization.hpp @@ -6,7 +6,7 @@ namespace utils { template - concept FastRandomAccess = requires (T& obj) + concept FastRandomAccess = requires (const T& obj) { std::data(obj)[std::size(obj)]; }; @@ -24,13 +24,13 @@ namespace utils }; template - concept TupleAlike = requires () + concept TupleAlike = (!FastRandomAccess) && requires () { - std::tuple_size>::value; + std::tuple_size>::value; }; template - concept ListAlike = requires (T& obj) { obj.insert(obj.end(), std::declval()); }; + concept ListAlike = requires (std::remove_cvref_t& obj) { obj.insert(obj.end(), std::declval()); }; struct serial; @@ -249,6 +249,15 @@ public: return raw_serialize(std::addressof(obj), sizeof(obj)); } + template + static constexpr usz c_tup_size = std::tuple_size_v, std::remove_cvref_t, std::tuple<>>>; + + template + static std::remove_cvref_t& as_nonconst(T&& arg) noexcept + { + return const_cast&>(static_cast(arg)); + } + // std::vector, std::basic_string // Discourage using std::pair/tuple with vectors because it eliminates the possibility of bitwise optimization template requires FastRandomAccess && ListAlike && (!TupleAlike) @@ -327,9 +336,24 @@ public: { for (auto&& value : obj) { - if (!serialize(value)) + if constexpr (c_tup_size == 2) { - return false; + if (!serialize(as_nonconst(std::get<0>(value)))) + { + return false; + } + + if (!serialize(as_nonconst(std::get<1>(value)))) + { + return false; + } + } + else + { + if (!serialize(value)) + { + return false; + } } } @@ -347,9 +371,24 @@ public: for (auto&& value : obj) { - if (!serialize(value)) + if constexpr (c_tup_size == 2) { - return false; + if (!serialize(as_nonconst(std::get<0>(value)))) + { + return false; + } + + if (!serialize(as_nonconst(std::get<1>(value)))) + { + return false; + } + } + else + { + if (!serialize(value)) + { + return false; + } } } @@ -412,7 +451,7 @@ public: } // std::pair, std::tuple - template requires TupleAlike && (!FastRandomAccess) + template requires TupleAlike bool serialize(T& obj) { return serialize_tuple(obj); @@ -423,7 +462,7 @@ public: bool operator()(Args&&... args) noexcept { return ((AUDIT(!std::is_const_v> || is_writing()) - , serialize(const_cast&>(static_cast(args)))), ...); + , serialize(as_nonconst(args))), ...); } // Code style utility, for when utils::serial is a pointer for example @@ -519,30 +558,48 @@ public: AUDIT(!is_writing()); using type = std::remove_const_t; + using not_tuple_t = std::conditional_t, char, type>; if constexpr (Bitcopy) { - u8 buf[sizeof(type)]{}; + u8 buf[sizeof(not_tuple_t)]{}; ensure(raw_serialize(buf, sizeof(buf))); - return std::bit_cast(buf); - } - else if constexpr (std::is_constructible_v>) - { - return type(stx::exact_t(*this)); - } - else if constexpr (std::is_constructible_v) - { - type value{}; - ensure(serialize(value)); - return value; + return std::bit_cast(buf); } else if constexpr (TupleAlike) { - static_assert(std::tuple_size_v == 2, "Unimplemented tuple serialization!"); + constexpr usz tup_size = c_tup_size; - auto first = operator std::remove_cvref_t(std::declval()))>(); - return type{ std::move(first) - , operator std::remove_cvref_t(std::declval()))> }; + static_assert(tup_size == 2 || tup_size == 4, "Unimplemented tuple serialization!"); + + using first_t = std::remove_cvref_t(0, tup_size - 1)>(std::declval()))>; + using second_t = std::remove_cvref_t(1, tup_size - 1)>(std::declval()))>; + using third_t = std::remove_cvref_t(2, tup_size - 1)>(std::declval()))>; + using fourth_t = std::remove_cvref_t(3, tup_size - 1)>(std::declval()))>; + + first_t first = this->operator first_t(); + + if constexpr (tup_size == 4) + { + second_t second = this->operator second_t(); + third_t third = this->operator third_t(); + + return type{ std::move(first), std::move(second), std::move(third), this->operator fourth_t() }; + } + else + { + return type{ std::move(first), this->operator second_t() }; + } + } + else if constexpr (std::is_constructible_v>) + { + return not_tuple_t(stx::exact_t(*this)); + } + else if constexpr (std::is_constructible_v) + { + not_tuple_t value{}; + ensure(serialize(value)); + return value; } }