mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-19 19:15:26 +00:00
sceNpTrophy: Send signals asynchronously
This commit is contained in:
parent
746b438500
commit
75e7a31979
2 changed files with 72 additions and 47 deletions
|
@ -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<SceNpTrophyStatusCallback> statusCb, vm::ptr<void> 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<u32, s32> statuses[] =
|
||||
{
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_SETUP, 3 },
|
||||
{ SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS, ::narrow<s32>(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<SceNpTrophyStatusCallback> statusCb, vm::ptr<void> arg) const
|
||||
{
|
||||
// This emulates vsh sending the events and ensures that not 2 events are processed at once
|
||||
const std::pair<SceNpTrophyStatus, s32> 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<s32>(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<atomic_t<u32>>(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<atomic_t<u32>>(0);
|
||||
g_fxo->get<named_thread<register_context_thread>>()(::narrow<s32>(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;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ struct SceNpTrophyFlagArray
|
|||
be_t<u32> 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,
|
||||
|
|
Loading…
Add table
Reference in a new issue