diff --git a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp index 5b870c6316..a8499c198e 100644 --- a/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp @@ -187,7 +187,7 @@ audio_out_configuration::audio_out_configuration(utils::serial& ar) void audio_out_configuration::save(utils::serial& ar) { - USING_SERIALIZATION_VERSION_COND(ar.is_writing(), cellAudioOut); + GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellAudioOut); for (auto& state : out) { diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp index 32ab185702..e071ad126c 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -145,7 +145,7 @@ void camera_context::save(utils::serial& ar) return; } - USING_SERIALIZATION_VERSION_COND(ar.is_writing(), cellCamera); + GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera); ar(notify_data_map, start_timestamp, read_mode, is_streaming, is_attached, is_open, info, attr, frame_num); } diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index e2142025f1..82dbc9107c 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -244,7 +244,7 @@ public: return; } - USING_SERIALIZATION_VERSION_COND(ar.is_writing(), cellGem); + GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellGem); ar(attribute, vc_attribute, status_flags, enable_pitch_correction, inertial_counter, controllers , connected_controllers, update_started, camera_frame, memory_ptr, start_timestamp); diff --git a/rpcs3/Emu/Cell/Modules/cellMusic.cpp b/rpcs3/Emu/Cell/Modules/cellMusic.cpp index e9edc9d2e0..1a93b0b806 100644 --- a/rpcs3/Emu/Cell/Modules/cellMusic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusic.cpp @@ -96,7 +96,7 @@ struct music_state return; } - USING_SERIALIZATION_VERSION_COND(ar.is_writing(), cellMusic); + GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellMusic); ar(userData); } diff --git a/rpcs3/Emu/Cell/Modules/cellVoice.cpp b/rpcs3/Emu/Cell/Modules/cellVoice.cpp index 5472361056..48b495d96f 100644 --- a/rpcs3/Emu/Cell/Modules/cellVoice.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVoice.cpp @@ -48,7 +48,7 @@ void voice_manager::reset() void voice_manager::save(utils::serial& ar) { - USING_SERIALIZATION_VERSION_COND(ar.is_writing(), cellVoice); + GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellVoice); ar(id_ctr, port_source, ports, queue_keys, voice_service_started); } diff --git a/rpcs3/Emu/RSX/RSXFIFO.cpp b/rpcs3/Emu/RSX/RSXFIFO.cpp index dff8a598bf..650936f5cd 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.cpp +++ b/rpcs3/Emu/RSX/RSXFIFO.cpp @@ -30,6 +30,16 @@ namespace rsx m_ctrl->get.release(m_internal_get); } + void FIFO_control::restore_state(u32 cmd, u32 count) + { + m_cmd = cmd; + m_command_inc = ((m_cmd & RSX_METHOD_NON_INCREMENT_CMD_MASK) == RSX_METHOD_NON_INCREMENT_CMD) ? 0 : 4; + m_remaining_commands = count - 1; + m_internal_get = m_ctrl->get; + m_args_ptr = m_iotable->get_addr(m_internal_get); + m_command_reg = (m_cmd & 0xffff) + m_command_inc * (((m_cmd >> 18) - count) & 0x7ff); + } + void FIFO_control::inc_get(bool wait) { m_internal_get += 4; @@ -806,13 +816,16 @@ namespace rsx if (auto method = methods[reg]) { method(this, reg, value); + + if (state & cpu_flag::again) + { + method_registers.decode(reg, method_registers.register_previous_value); + break; + } } } while (fifo_ctrl->read_unsafe(command)); - if (cpu_flag::again - state) - { - fifo_ctrl->sync_get(); - } + fifo_ctrl->sync_get(); } } diff --git a/rpcs3/Emu/RSX/RSXFIFO.h b/rpcs3/Emu/RSX/RSXFIFO.h index 4f4588fefb..65a9d66e16 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.h +++ b/rpcs3/Emu/RSX/RSXFIFO.h @@ -141,6 +141,7 @@ namespace rsx void sync_get() const; std::span get_current_arg_ptr() const; u32 get_remaining_args_count() const { return m_remaining_commands; } + void restore_state(u32 cmd, u32 count); void inc_get(bool wait); void set_get(u32 get, u32 spin_cmd = 0); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 7e8e05ce52..d81486089c 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -438,7 +438,7 @@ namespace rsx void thread::save(utils::serial& ar) { - USING_SERIALIZATION_VERSION_COND(ar.is_writing(), rsx); + [[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), rsx); ar(rsx::method_registers); @@ -454,6 +454,27 @@ namespace rsx ar(in_begin_end); ar(display_buffers, display_buffers_count, current_display_buffer); ar(unsent_gcm_events, rsx::method_registers.current_draw_clause); + + if (ar.is_writing()) + { + if (fifo_ctrl && state & cpu_flag::again) + { + ar(fifo_ctrl->get_remaining_args_count() + 1); + ar(fifo_ctrl->last_cmd()); + } + else + { + ar(u32{0}); + } + } + else if (version > 1) + { + if (u32 count = ar) + { + restore_fifo_count = count; + ar(restore_fifo_cmd); + } + } } thread::thread(utils::serial* _ar) @@ -726,6 +747,8 @@ namespace rsx performance_counters.state = FIFO_state::empty; + const u64 event_flags = unsent_gcm_events.exchange(0); + Emu.CallFromMainThread([]{ Emu.RunPPU(); }); // Wait for startup (TODO) @@ -751,11 +774,6 @@ namespace rsx thread_ctrl::wait_for(1000); } - if (is_stopped()) - { - return; - } - performance_counters.state = FIFO_state::running; fifo_ctrl = std::make_unique<::rsx::FIFO::FIFO_control>(this); @@ -765,12 +783,14 @@ namespace rsx vblank_count = 0; - if (u64 event_flags = unsent_gcm_events.exchange(0)) + if (restore_fifo_count) { - if (!send_event(0, event_flags, 0)) - { - return; - } + fifo_ctrl->restore_state(restore_fifo_cmd, restore_fifo_count); + } + + if (!send_event(0, event_flags, 0)) + { + return; } g_fxo->init("VBlank Thread", [this]() diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 850ad60e86..414ff2844e 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -478,6 +478,8 @@ namespace rsx FIFO::flattening_helper m_flattener; u32 fifo_ret_addr = RSX_CALL_STACK_EMPTY; u32 saved_fifo_ret = RSX_CALL_STACK_EMPTY; + u32 restore_fifo_cmd = 0; + u32 restore_fifo_count = 0; // Occlusion query bool zcull_surface_active = false; diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 6ade67cb0a..7d2c2de506 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -115,6 +115,7 @@ namespace rsx { if (rsx->test_stopped()) { + rsx->state += cpu_flag::again; return; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index f97cab3c99..62951208cf 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -101,7 +101,7 @@ SERIALIZATION_VER(lv2_config, 9, 1) namespace rsx { - SERIALIZATION_VER(rsx, 10, 1) + SERIALIZATION_VER(rsx, 10, 1, 2) } namespace np diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index 7ce7e36446..721c2020e9 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -1168,10 +1168,11 @@ extern bool serialize(utils::serial& ar, T& obj); using_##name##_serialization();\ }() -#define USING_SERIALIZATION_VERSION_COND(cond, name) [&]()\ +#define GET_OR_USE_SERIALIZATION_VERSION(cond, name) [&]()\ {\ extern void using_##name##_serialization();\ - if (static_cast(cond)) using_##name##_serialization();\ + extern s32 get_##name##_serialization_version();\ + return (static_cast(cond) ? (using_##name##_serialization(), 0) : get_##name##_serialization_version());\ }() #define GET_SERIALIZATION_VERSION(name) []()\