diff --git a/src/common/archives.h b/src/common/archives.h index 76aa71054..490710d3c 100644 --- a/src/common/archives.h +++ b/src/common/archives.h @@ -1,11 +1,14 @@ #include "boost/archive/binary_iarchive.hpp" #include "boost/archive/binary_oarchive.hpp" -#define SERIALIZE_IMPL(A) template void A::serialize( \ - boost::archive::binary_iarchive & ar, \ +using iarchive = boost::archive::binary_iarchive; +using oarchive = boost::archive::binary_oarchive; + +#define SERIALIZE_IMPL(A) template void A::serialize( \ + iarchive & ar, \ const unsigned int file_version \ ); \ -template void A::serialize( \ - boost::archive::binary_oarchive & ar, \ +template void A::serialize( \ + oarchive & ar, \ const unsigned int file_version \ ); diff --git a/src/core/core.cpp b/src/core/core.cpp index cee6a3866..63730214f 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -397,22 +397,28 @@ void System::Reset() { template void System::serialize(Archive & ar, const unsigned int file_version) { - ar & memory; ar & GPU::g_regs; ar & LCD::g_regs; ar & dsp_core->GetDspMemory(); + ar & memory; } void System::Save(std::ostream &stream) const { - boost::archive::binary_oarchive oa{stream}; - oa & *this; + { + oarchive oa{stream}; + oa & *this; + } + VideoCore::Save(stream); } void System::Load(std::istream &stream) { - boost::archive::binary_iarchive ia{stream}; - ia & *this; + { + iarchive ia{stream}; + ia & *this; + } + VideoCore::Load(stream); } } // namespace Core diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index fcb60e6fe..b283b7d91 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -472,14 +472,7 @@ inline void Write(u32 addr, const T data) { if (config.trigger & 1) { MICROPROFILE_SCOPE(GPU_CmdlistProcessing); - u32* buffer = (u32*)g_memory->GetPhysicalPointer(config.GetPhysicalAddress()); - - if (Pica::g_debug_context && Pica::g_debug_context->recorder) { - Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size, - config.GetPhysicalAddress()); - } - - Pica::CommandProcessor::ProcessCommandList(buffer, config.size); + Pica::CommandProcessor::ProcessCommandList(config.GetPhysicalAddress(), config.size); g_regs.command_processor_config.trigger = 0; } diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 4cb976354..8dbf5d8e0 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -94,7 +94,7 @@ endif() create_target_directory_groups(video_core) target_link_libraries(video_core PUBLIC common core) -target_link_libraries(video_core PRIVATE glad nihstro-headers) +target_link_libraries(video_core PRIVATE glad nihstro-headers boost_libs) if (ARCHITECTURE_x86_64) target_link_libraries(video_core PUBLIC xbyak) diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 72f6f2161..3a5b35236 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -640,8 +640,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { reinterpret_cast(&id)); } -void ProcessCommandList(const u32* list, u32 size) { - g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list; +void ProcessCommandList(PAddr list, u32 size) { + + u32* buffer = (u32*)VideoCore::g_memory->GetPhysicalPointer(list); + + if (Pica::g_debug_context && Pica::g_debug_context->recorder) { + Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, size, + list); + } + + g_state.cmd_list.addr = list; + g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = buffer; g_state.cmd_list.length = size / sizeof(u32); while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) { diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h index 82b154327..3b4e05519 100644 --- a/src/video_core/command_processor.h +++ b/src/video_core/command_processor.h @@ -32,6 +32,6 @@ static_assert(std::is_standard_layout::value == true, "CommandHeader does not use standard layout"); static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); -void ProcessCommandList(const u32* list, u32 size); +void ProcessCommandList(PAddr list, u32 size); } // namespace Pica::CommandProcessor diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h index 5a97ae952..1e5b1ecd2 100644 --- a/src/video_core/pica_state.h +++ b/src/video_core/pica_state.h @@ -5,6 +5,7 @@ #pragma once #include +#include "boost/serialization/split_member.hpp" #include "common/bit_field.h" #include "common/common_types.h" #include "common/vector_math.h" @@ -13,6 +14,18 @@ #include "video_core/regs.h" #include "video_core/shader/shader.h" +// NB, by defining this we can't use the built-in std::array serializer in this file +namespace boost::serialization { + +template +void serialize(Archive & ar, std::array &array, const unsigned int version) +{ + static_assert(sizeof(Value) == sizeof(u32)); + ar & *static_cast(static_cast(array.data())); +} + +} + namespace Pica { /// Struct used to describe current Pica state @@ -79,6 +92,18 @@ struct State { std::array alpha_map_table; std::array color_table; std::array color_diff_table; + + private: + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int file_version) + { + ar & noise_table; + ar & color_map_table; + ar & alpha_map_table; + ar & color_table; + ar & color_diff_table; + } } proctex; struct Lighting { @@ -101,6 +126,12 @@ struct State { float diff = static_cast(difference) / 2047.f; return neg_difference ? -diff : diff; } + + template + void serialize(Archive & ar, const unsigned int file_version) + { + ar & raw; + } }; std::array, 24> luts; @@ -126,8 +157,11 @@ struct State { std::array lut; } fog; +#undef SERIALIZE_RAW + /// Current Pica command list struct { + PAddr addr; // This exists only for serialization const u32* head_ptr; const u32* current_ptr; u32 length; @@ -141,6 +175,17 @@ struct State { u32 current_attribute = 0; // Indicates the immediate mode just started and the geometry pipeline needs to reconfigure bool reset_geometry_pipeline = true; + + private: + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int file_version) + { + // ar & input_vertex; + ar & current_attribute; + ar & reset_geometry_pipeline; + } + } immediate; // the geometry shader needs to be kept in the global state because some shaders relie on @@ -161,6 +206,51 @@ struct State { int default_attr_counter = 0; u32 default_attr_write_buffer[3]{}; + +private: + + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int file_version) + { + ar & regs.reg_array; + // ar & vs; + // ar & gs; + // ar & input_default_attributes; + ar & proctex; + for (auto i = 0; i < lighting.luts.size(); i++) { + ar & lighting.luts[i]; + } + ar & fog.lut; + ar & cmd_list.addr; + ar & cmd_list.length; + ar & immediate; + // ar & gs_unit; + // ar & geometry_pipeline; + // ar & primitive_assembler; + ar & vs_float_regs_counter; + ar & vs_uniform_write_buffer; + ar & gs_float_regs_counter; + ar & gs_uniform_write_buffer; + ar & default_attr_counter; + ar & default_attr_write_buffer; + boost::serialization::split_member(ar, *this, file_version); + } + + template + void save(Archive & ar, const unsigned int file_version) const + { + ar << static_cast(cmd_list.current_ptr - cmd_list.head_ptr); + } + + template + void load(Archive & ar, const unsigned int file_version) + { + u32 offset{}; + ar >> offset; + cmd_list.head_ptr = (u32*)VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr); + cmd_list.current_ptr = cmd_list.head_ptr + offset; + } }; extern State g_state; ///< Current Pica state diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index b7e1d4885..5bc1e8702 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -3,9 +3,11 @@ // Refer to the license.txt file included. #include +#include "common/archives.h" #include "common/logging/log.h" #include "core/settings.h" #include "video_core/pica.h" +#include "video_core/pica_state.h" #include "video_core/renderer_base.h" #include "video_core/renderer_opengl/gl_vars.h" #include "video_core/renderer_opengl/renderer_opengl.h" @@ -85,4 +87,18 @@ u16 GetResolutionScaleFactor() { } } +void Save(std::ostream &stream) +{ + oarchive oa{stream}; + oa & Pica::g_state; +} + +void Load(std::istream &stream) +{ + iarchive ia{stream}; + ia & Pica::g_state; + // TODO: Flush/reset things + +} + } // namespace VideoCore diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index f11b67839..1ec69f802 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include "core/frontend/emu_window.h" @@ -61,4 +62,7 @@ void RequestScreenshot(void* data, std::function callback, u16 GetResolutionScaleFactor(); +void Save(std::ostream &stream); +void Load(std::istream &stream); + } // namespace VideoCore