diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index bb82cefffd..cf7f8aef57 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -546,6 +546,11 @@ error_code sceNpTrophyDestroyContext(u32 context) return CELL_OK; } +struct register_context_thread_name +{ + static constexpr std::string_view thread_name = "Trophy Register Thread"; +}; + error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, vm::ptr statusCb, vm::ptr arg, u64 options) { sceNpTrophy.warning("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options); @@ -709,57 +714,77 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, ensure(tropusr->Load(trophyUsrPath, trophyConfPath).success); - // This emulates vsh sending the events and ensures that not 2 events are processed at once - const std::pair statuses[] = - { - { SCE_NP_TROPHY_STATUS_PROCESSING_SETUP, 3 }, - { SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS, ::narrow(tropusr->GetTrophiesCount()) - 1 }, - { SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE, 4 }, - { SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 0 } - }; - lock2.unlock(); + struct register_context_thread : register_context_thread_name + { + void operator()(s32 progress_cb_count, u32 context, vm::ptr statusCb, vm::ptr arg) const + { + // This emulates vsh sending the events and ensures that not 2 events are processed at once + const std::pair statuses[] = + { + { SCE_NP_TROPHY_STATUS_PROCESSING_SETUP, 3 }, + { SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS, progress_cb_count }, + { SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE, std::max(progress_cb_count, 9) - 5 }, // Seems varying, little bit less than progress_cb_count + { SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE, 0 } + }; + + // Create a counter which is destroyed after the function ends + const auto queued = std::make_shared>(0); + + for (auto status : statuses) + { + for (s32 completed = 0; completed <= status.second; completed++) + { + // One status max per cellSysutilCheckCallback call + *queued += 1; + + sysutil_register_cb([statusCb, status, context, completed, arg, queued](ppu_thread& cb_ppu) -> s32 + { + // TODO: it is possible that we need to check the return value here as well. + statusCb(cb_ppu, context, status.first, completed, status.second, arg); + + if (queued && (*queued)-- == 1) + { + queued->notify_one(); + } + + return 0; + }); + + u64 current = get_system_time(); + + const u64 until_max = current + 300'000; + const u64 until_min = current + 100'000; + + // If too much time passes just send the rest of the events anyway + for (u32 old_value = *queued; current < (old_value ? until_max : until_min); + current = get_system_time(), old_value = *queued) + { + if (!old_value) + { + thread_ctrl::wait_for(until_min - current); + } + else + { + thread_ctrl::wait_on(*queued, old_value, until_max - current); + } + + if (thread_ctrl::state() == thread_state::aborting) + { + return; + } + } + } + } + } + }; + lv2_obj::sleep(ppu); - // Create a counter which is destroyed after the function ends - const auto queued = std::make_shared>(0); + g_fxo->get>()(::narrow(tropusr->GetTrophiesCount()) - 1, context, statusCb, arg); - for (auto status : statuses) - { - // One status max per cellSysutilCheckCallback call - *queued += status.second; - for (s32 completed = 0; completed <= status.second; completed++) - { - sysutil_register_cb([statusCb, status, context, completed, arg, queued](ppu_thread& cb_ppu) -> s32 - { - // TODO: it is possible that we need to check the return value here as well. - statusCb(cb_ppu, context, status.first, completed, status.second, arg); - - if (queued && (*queued)-- == 1) - { - queued->notify_one(); - } - - return 0; - }); - } - - u64 current = get_system_time(); - const u64 until = current + 300'000; - - // If too much time passes just send the rest of the events anyway - for (u32 old_value; current < until && (old_value = *queued); - current = get_system_time()) - { - thread_ctrl::wait_on(*queued, old_value, until - current); - - if (ppu.is_stopped()) - { - return {}; - } - } - } + thread_ctrl::wait_for(200'000); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.h b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h index 941727648d..0c48623fda 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.h +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h @@ -135,7 +135,7 @@ struct SceNpTrophyFlagArray be_t flag_bits[SCE_NP_TROPHY_FLAG_SETSIZE >> SCE_NP_TROPHY_FLAG_BITS_SHIFT]; }; -enum +enum SceNpTrophyStatus : u32 { SCE_NP_TROPHY_STATUS_UNKNOWN = 0, SCE_NP_TROPHY_STATUS_NOT_INSTALLED = 1,