From f5beaabdedd7abd86253dd3a20ae4c5b47ab665c Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 30 May 2022 16:31:01 +0300 Subject: [PATCH] cellSysutil: Implement DRAWING callbacks Also fixed a minor race in cellUserInfo regarding status of dialog --- rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp | 22 ++++++++++++++++++++-- rpcs3/Emu/Cell/Modules/cellSysutil.cpp | 23 +++++++++++++++++++++-- rpcs3/Emu/Cell/Modules/cellSysutil.h | 2 +- rpcs3/Emu/Cell/Modules/cellUserInfo.cpp | 22 ++++++++++++++++++---- rpcs3/Emu/System.cpp | 2 +- rpcs3/rpcs3qt/main_window.cpp | 2 +- rpcs3/rpcs3qt/save_data_dialog.cpp | 18 ++++++++++++++++++ 7 files changed, 80 insertions(+), 11 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp index 193ace8b1c..d92eadfc6a 100644 --- a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp @@ -155,10 +155,17 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr msgString, return CELL_SYSUTIL_ERROR_BUSY; } + if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0) + { + return CellSysutilError{ret + 0u}; + } + g_last_user_response = CELL_MSGDIALOG_BUTTON_NONE; const auto res = manager->create()->show(is_blocking, msgString.get_ptr(), _type, [callback, userData](s32 status) { + sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); + if (callback) { sysutil_register_cb([=](ppu_thread& ppu) -> s32 @@ -179,6 +186,11 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr msgString, return CELL_SYSUTIL_ERROR_BUSY; } + if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0) + { + return CellSysutilError{ret + 0u}; + } + dlg->type = _type; dlg->on_close = [callback, userData, wptr = std::weak_ptr(dlg)](s32 status) @@ -187,6 +199,8 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr msgString, if (dlg && dlg->state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Close)) { + sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); + if (callback) { sysutil_register_cb([=](ppu_thread& ppu) -> s32 @@ -208,11 +222,14 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr msgString, auto& ppu = *get_current_cpu_thread(); lv2_obj::sleep(ppu); + // PS3 memory must not be accessed by Main thread + std::string msg_string = msgString.get_ptr(); + // Run asynchronously in GUI thread - Emu.CallFromMainThread([&]() + Emu.CallFromMainThread([&, msg_string = std::move(msg_string)]() { g_last_user_response = CELL_MSGDIALOG_BUTTON_NONE; - dlg->Create(msgString.get_ptr()); + dlg->Create(msg_string); lv2_obj::awake(&ppu); }); @@ -487,6 +504,7 @@ error_code cellMsgDialogAbort() g_fxo->get().wait_until = 0; g_fxo->get().remove(); // this shouldn't call on_close input::SetIntercepted(false); // so we need to reenable the pads here + sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index 3b9a96c872..b6da4105f1 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -47,6 +47,8 @@ struct sysutil_cb_manager atomic_t callbacks[4]{}; lf_queue> registered; + + atomic_t draw_cb_started{}; }; extern void sysutil_register_cb(std::function&& cb) @@ -56,12 +58,29 @@ extern void sysutil_register_cb(std::function&& cb) cbm.registered.push(std::move(cb)); } -extern u32 sysutil_send_system_cmd(u64 status, u64 param) +extern s32 sysutil_send_system_cmd(u64 status, u64 param) { - u32 count = 0; + s32 count = 0; if (auto cbm = g_fxo->try_get()) { + if (status == CELL_SYSUTIL_DRAWING_BEGIN) + { + if (cbm->draw_cb_started.exchange(true)) + { + cellSysutil.error("Tried to enqueue a second or more DRAWING_BEGIN callback!"); + return CELL_SYSUTIL_ERROR_BUSY; + } + } + else if (status == CELL_SYSUTIL_DRAWING_END) + { + if (!cbm->draw_cb_started.exchange(false)) + { + cellSysutil.error("Tried to enqueue a DRAWING_END callback without a BEGIN callback!"); + return -1; + } + } + for (sysutil_cb_manager::registered_cb cb : cbm->callbacks) { if (cb.first) diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.h b/rpcs3/Emu/Cell/Modules/cellSysutil.h index c5b631ad4d..aa78c693fd 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.h +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.h @@ -301,5 +301,5 @@ struct CellSysCacheParam }; extern void sysutil_register_cb(std::function&&); -extern u32 sysutil_send_system_cmd(u64 status, u64 param); +extern s32 sysutil_send_system_cmd(u64 status, u64 param); s32 sysutil_check_name_string(const char* src, s32 minlen, s32 maxlen); diff --git a/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp index 960db3b912..4fafded3e0 100644 --- a/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp @@ -157,6 +157,11 @@ error_code cellUserInfoSelectUser_ListType(vm::ptr listType return CELL_USERINFO_ERROR_BUSY; } + if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0) + { + return CELL_USERINFO_ERROR_BUSY; + } + const std::string title = listType->title.get_ptr(); const u32 focused = listType->focus; @@ -178,6 +183,10 @@ error_code cellUserInfoSelectUser_ListType(vm::ptr listType cellUserInfo.warning("cellUserInfoSelectUser_ListType: callback_result=%s, selected_user_id=%d, selected_username='%s'", callback_result, selected_user_id, selected_username); + g_fxo->get().dialog_opened = false; + + sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); + sysutil_register_cb([=](ppu_thread& ppu) -> s32 { vm::var selectUser; @@ -189,8 +198,6 @@ error_code cellUserInfoSelectUser_ListType(vm::ptr listType funcSelect(ppu, callback_result, selectUser, userdata); return CELL_OK; }); - - g_fxo->get().dialog_opened = false; }); return result; @@ -258,6 +265,11 @@ error_code cellUserInfoSelectUser_SetList(vm::ptr setList, return CELL_USERINFO_ERROR_BUSY; } + if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0) + { + return CELL_USERINFO_ERROR_BUSY; + } + const std::string title = setList->title.get_ptr(); const u32 focused = setList->focus; @@ -279,6 +291,10 @@ error_code cellUserInfoSelectUser_SetList(vm::ptr setList, cellUserInfo.warning("cellUserInfoSelectUser_SetList: callback_result=%s, selected_user_id=%d, selected_username='%s'", callback_result, selected_user_id, selected_username); + g_fxo->get().dialog_opened = false; + + sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); + sysutil_register_cb([=](ppu_thread& ppu) -> s32 { vm::var selectUser; @@ -290,8 +306,6 @@ error_code cellUserInfoSelectUser_SetList(vm::ptr setList, funcSelect(ppu, callback_result, selectUser, userdata); return CELL_OK; }); - - g_fxo->get().dialog_opened = false; }); return result; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index c660fc75d0..f0a13d9d06 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1768,7 +1768,7 @@ void Emulator::Resume() } } -u32 sysutil_send_system_cmd(u64 status, u64 param); +s32 sysutil_send_system_cmd(u64 status, u64 param); void process_qt_events(); void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op) diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 61fbbcb1a0..e20e0ee0bc 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -1315,7 +1315,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString& } // This is ugly, but PS3 headers shall not be included there. -extern u32 sysutil_send_system_cmd(u64 status, u64 param); +extern s32 sysutil_send_system_cmd(u64 status, u64 param); void main_window::DecryptSPRXLibraries() { diff --git a/rpcs3/rpcs3qt/save_data_dialog.cpp b/rpcs3/rpcs3qt/save_data_dialog.cpp index 250bf1f452..b5ef615c7b 100644 --- a/rpcs3/rpcs3qt/save_data_dialog.cpp +++ b/rpcs3/rpcs3qt/save_data_dialog.cpp @@ -5,21 +5,37 @@ #include "Emu/IdManager.h" #include "Emu/Io/interception.h" #include "Emu/RSX/Overlays/overlay_save_dialog.h" +#include "Emu/Cell/Modules/cellSysutil.h" #include "Utilities/Thread.h" +#include "util/logs.hpp" + +LOG_CHANNEL(cellSaveData); s32 save_data_dialog::ShowSaveDataList(std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) { + // TODO: Implement proper error checking in savedata_op? + const bool use_end = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0) >= 0; + + if (!use_end) + { + cellSaveData.error("ShowSaveDataList(): Not able to notify DRAWING_BEGIN callback because one has already been sent!"); + } + // TODO: Install native shell as an Emu callback if (auto manager = g_fxo->try_get()) { const s32 result = manager->create()->show(save_entries, focused, op, listSet, enable_overlay); if (result != rsx::overlays::user_interface::selection_code::error) + { + if (use_end) sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); return result; + } } if (!Emu.HasGui()) { + if (use_end) sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); return -2; } @@ -45,5 +61,7 @@ s32 save_data_dialog::ShowSaveDataList(std::vector& save_entries, input::SetIntercepted(false); + if (use_end) sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); + return selection.load(); }