Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 152 additions & 36 deletions rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,64 @@ struct msg_dlg_thread_info

using msg_dlg_thread = named_thread<msg_dlg_thread_info>;

// Forward decleration for opened_dialog_context
error_code open_msg_dialog(bool is_blocking, u32 type, std::string msg_string, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code);

struct opened_dialog_context
{
bool is_opened = false;
u32 type{};
std::string msg_string;
msg_dialog_source source{};
vm::ptr<CellMsgDialogCallback> callback{};
vm::ptr<void> userData{};
vm::ptr<void> extParam{};

SAVESTATE_INIT_POS(54);

opened_dialog_context(const opened_dialog_context&) = delete;
opened_dialog_context& operator=(const opened_dialog_context&) = delete;

opened_dialog_context() noexcept
{
g_fxo->need<msg_dlg_thread>();
}

opened_dialog_context(utils::serial& ar) noexcept
: opened_dialog_context()
{
save(ar);

if (is_opened)
{
g_fxo->get<msg_dlg_thread>().wait_until = ar.pop<u64>();

Emu.PostponeInitCode([=]()
{
ensure(open_msg_dialog(false, type, msg_string, source, callback, userData, extParam, nullptr) == CELL_OK);
});
}
}

void save(utils::serial& ar)
{
ar(is_opened);

if (!is_opened)
{
return;
}

ar(type, msg_string, source, callback, userData, extParam, +g_fxo->get<msg_dlg_thread>().wait_until);
}
};

// forward declaration for open_msg_dialog
error_code cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam);

// wrapper to call for other hle dialogs
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code)
error_code open_msg_dialog(bool is_blocking, u32 type, std::string msg_string, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code)
{
cellSysutil.notice("open_msg_dialog(is_blocking=%d, type=0x%x, msgString=%s, source=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x, return_code=*0x%x)", is_blocking, type, msgString, source, callback, userData, extParam, return_code);
cellSysutil.notice("open_msg_dialog(is_blocking=%d, type=0x%x, msg_string=%s, source=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x, return_code=*0x%x)", is_blocking, type, msg_string, source, callback, userData, extParam, return_code);

const MsgDialogType _type{ type };

Expand All @@ -173,21 +224,39 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
*return_code = CELL_MSGDIALOG_BUTTON_NONE;
}

const auto ppu = cpu_thread::get_current<ppu_thread>();
const bool loaded_from_savestate = ppu && ppu->loaded_from_savestate;

if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{
if (manager->get<rsx::overlays::message_dialog>())
{
return CELL_SYSUTIL_ERROR_BUSY;
}

if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0)
if (s32 ret = loaded_from_savestate ? 0 : sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0)
{
return CellSysutilError{ret + 0u};
}

const auto notify = std::make_shared<atomic_t<u32>>(0);

const auto res = manager->create<rsx::overlays::message_dialog>()->show(is_blocking, msgString.get_ptr(), _type, source, [callback, userData, &return_code, is_blocking, notify](s32 status)
auto dlg = manager->create<rsx::overlays::message_dialog>();

if (!is_blocking)
{
auto& ctxt = g_fxo->get<opened_dialog_context>();
ctxt.is_opened = true;

ctxt.type = type;
ctxt.msg_string = msg_string;
ctxt.source = source;
ctxt.callback = callback;
ctxt.userData = userData;
ctxt.extParam = extParam;
}

const auto res = dlg->show(is_blocking, msg_string, _type, source, [callback, userData, &return_code, is_blocking, notify](s32 status)
{
if (is_blocking && return_code)
{
Expand All @@ -210,12 +279,28 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
*notify = 1;
notify->notify_one();
}

auto& ctxt = g_fxo->get<opened_dialog_context>();
ctxt.is_opened = false;
});

// Wait for on_close
while (is_blocking && !Emu.IsStopped() && !*notify)
while (!*notify)
{
notify->wait(false, atomic_wait_timeout{1'000'000});
if (ppu)
{
if (ppu->is_stopped())
{
ppu->state += cpu_flag::again;
return {};
}
}
else if (Emu.IsStopped())
{
return {};
}

thread_ctrl::wait_on(*notify, 0);
}

return res;
Expand All @@ -228,15 +313,30 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
return CELL_SYSUTIL_ERROR_BUSY;
}

if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0)
if (s32 ret = loaded_from_savestate ? 0 : sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0); ret < 0)
{
return CellSysutilError{ret + 0u};
}

if (!is_blocking)
{
auto& ctxt = g_fxo->get<opened_dialog_context>();
ctxt.is_opened = true;

ctxt.type = type;
ctxt.msg_string = msg_string;
ctxt.source = source;
ctxt.callback = callback;
ctxt.userData = userData;
ctxt.extParam = extParam;
}

dlg->type = _type;
dlg->source = source;

dlg->on_close = [callback, userData, is_blocking, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
const auto notify = std::make_shared<atomic_t<u32>>(0);

dlg->on_close = [notify, callback, userData, is_blocking, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
{
if (is_blocking && return_code)
{
Expand All @@ -245,7 +345,9 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,

const auto dlg = wptr.lock();

if (dlg && dlg->state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Close))
const bool closed = dlg && dlg->state.compare_and_swap_test(MsgDialogState::Open, MsgDialogState::Close);

if (closed)
{
sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0);

Expand All @@ -263,53 +365,67 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
}

input::SetIntercepted(false);

auto& ctxt = g_fxo->get<opened_dialog_context>();
ctxt.is_opened = false;

if (closed)
{
*notify = 1;
notify->notify_one();
}
};

input::SetIntercepted(true);

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();
if (ppu)
{
lv2_obj::sleep(*ppu);
}

// Run asynchronously in GUI thread
Emu.CallFromMainThread([&, msg_string = std::move(msg_string)]()
Emu.CallFromMainThread([&, is_blocking, notify, msg_string = std::move(msg_string)]()
{
dlg->Create(msg_string);
lv2_obj::awake(&ppu);
});

while (auto state = ppu.state.fetch_sub(cpu_flag::signal))
{
if (is_stopped(state))
if (!is_blocking)
{
return {};
*notify = 1;
notify->notify_one();
}
});

if (state & cpu_flag::signal)
{
break;
}

ppu.state.wait(state);
}

if (is_blocking)
while (!*notify)
{
while (auto dlg = g_fxo->get<msg_info>().get())
if (ppu)
{
if (Emu.IsStopped() || dlg->state != MsgDialogState::Open)
if (ppu->is_stopped())
{
break;
ppu->state += cpu_flag::again;
return {};
}
std::this_thread::yield();
}
else if (Emu.IsStopped())
{
return {};
}

thread_ctrl::wait_on(*notify, 0);
}

return CELL_OK;
}

// wrapper to call for other hle dialogs
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code)
{
// PS3 memory must not be accessed by Main thread
std::string msg_string;
ensure(vm::read_string(msgString.addr(), CELL_MSGDIALOG_STRING_SIZE, msg_string, true), "Secret access violation");

return open_msg_dialog(is_blocking, type, std::move(msg_string), source, callback, userData, extParam, return_code);
}

void close_msg_dialog()
{
cellSysutil.notice("close_msg_dialog()");
Expand Down Expand Up @@ -376,7 +492,7 @@ error_code cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMs
{
cellSysutil.warning("cellMsgDialogOpen2(type=0x%x, msgString=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x)", type, msgString, callback, userData, extParam);

if (!msgString || std::strlen(msgString.get_ptr()) >= CELL_MSGDIALOG_STRING_SIZE || type & -0x33f8)
if (!msgString || !std::memchr(msgString.get_ptr(), '\0', CELL_MSGDIALOG_STRING_SIZE - 1) || type & -0x33f8)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
Expand Down
21 changes: 17 additions & 4 deletions rpcs3/Emu/Cell/PPUModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,26 +94,34 @@ void ppu_module_manager::register_module(ppu_static_module* _module)
ppu_module_manager::get().emplace(_module->name, _module);
}

ppu_static_function& ppu_module_manager::access_static_function(const char* _module, u32 fnid)
ppu_static_function& ppu_module_manager::access_static_function(const char* _module, u32 fnid, bool for_creation)
{
auto& res = ::at32(ppu_module_manager::get(), _module)->functions[fnid];

if (res.name)
if (for_creation && res.name)
{
fmt::throw_exception("PPU FNID duplication in module %s (%s, 0x%x)", _module, res.name, fnid);
}
else if (!for_creation && !res.name)
{
fmt::throw_exception("PPU FNID unregistered in module %s (%s, 0x%x)", _module, res.name, fnid);
}

return res;
}

ppu_static_variable& ppu_module_manager::access_static_variable(const char* _module, u32 vnid)
ppu_static_variable& ppu_module_manager::access_static_variable(const char* _module, u32 vnid, bool for_creation)
{
auto& res = ::at32(ppu_module_manager::get(), _module)->variables[vnid];

if (res.name)
if (for_creation && res.name)
{
fmt::throw_exception("PPU VNID duplication in module %s (%s, 0x%x)", _module, res.name, vnid);
}
else if (!for_creation && !res.name)
{
fmt::throw_exception("PPU VNID unregistered in module %s (%s, 0x%x)", _module, res.name, vnid);
}

return res;
}
Expand All @@ -133,6 +141,11 @@ void ppu_module_manager::initialize_modules()
}
}

u32 ppu_symbol_addr(std::string_view _module, std::string_view nid) noexcept
{
return *ppu_module_manager::find_static_function(_module.data(), ppu_generate_id(nid)).export_addr;
}

// Global linkage information
struct ppu_linkage_info
{
Expand Down
15 changes: 11 additions & 4 deletions rpcs3/Emu/Cell/PPUModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ class ppu_module_manager final

static void register_module(ppu_static_module*);

static ppu_static_function& access_static_function(const char* _module, u32 fnid);
static ppu_static_function& access_static_function(const char* _module, u32 fnid, bool for_creation);

static ppu_static_variable& access_static_variable(const char* _module, u32 vnid);
static ppu_static_variable& access_static_variable(const char* _module, u32 vnid, bool for_creation);

// Global variable for each registered function
template <auto* Func>
Expand All @@ -125,7 +125,7 @@ class ppu_module_manager final
template <auto* Func>
static auto& register_static_function(const char* _module, const char* name, ppu_intrp_func_t func, u32 fnid)
{
auto& info = access_static_function(_module, fnid);
auto& info = access_static_function(_module, fnid, true);

info.name = name;
info.index = ppu_function_manager::register_function<decltype(Func), Func>(func);
Expand All @@ -142,14 +142,19 @@ class ppu_module_manager final
return *registered<Func>::info;
}

static auto& find_static_function(const char* _module, u32 fnid)
{
return access_static_function(_module, fnid, false);
}

template <auto* Var>
static auto& register_static_variable(const char* _module, const char* name, u32 vnid)
{
using gvar = std::decay_t<decltype(*Var)>;

static_assert(std::is_same_v<u32, typename gvar::addr_type>, "Static variable registration: vm::gvar<T> expected");

auto& info = access_static_variable(_module, vnid);
auto& info = access_static_variable(_module, vnid, true);

info.name = name;
info.var = &Var->raw();
Expand Down Expand Up @@ -313,6 +318,8 @@ inline RT ppu_execute(ppu_thread& ppu, Args... args)
return func(ppu, args...);
}

u32 ppu_symbol_addr(std::string_view _module, std::string_view name) noexcept;

#define BIND_FUNC_WITH_BLR(func, _module) BIND_FUNC(func, if (cpu_flag::again - ppu.state) ppu.cia = static_cast<u32>(ppu.lr) & ~3; else ppu.current_module = _module)

#define REG_FNID(_module, nid, func) ppu_module_manager::register_static_function<&func>(#_module, ppu_select_name(#func, nid), BIND_FUNC_WITH_BLR(func, #_module), ppu_generate_id(nid))
Expand Down
Loading