Dialog: Respect accessThread priority on shutdown.

This influences shutdown timing.
This commit is contained in:
Unknown W. Brackets 2021-02-27 13:15:12 -08:00
parent d066b39334
commit 52c5f4bf95
4 changed files with 118 additions and 25 deletions

View file

@ -41,15 +41,10 @@ PSPDialog::DialogStatus PSPDialog::GetStatus() {
if (pendingStatusTicks != 0 && CoreTiming::GetTicks() >= pendingStatusTicks) {
bool changeAllowed = true;
if (pendingStatus == SCE_UTILITY_STATUS_NONE && status == SCE_UTILITY_STATUS_SHUTDOWN) {
if (volatileLocked_) {
FinishVolatile();
UtilityCancelVolatileUnlock();
volatileLocked_ = false;
}
FinishVolatile();
} else if (pendingStatus == SCE_UTILITY_STATUS_RUNNING && status == SCE_UTILITY_STATUS_INITIALIZE) {
if (!volatileLocked_) {
volatileLocked_ = KernelVolatileMemLock(0, 0, 0) == 0;
UtilityCancelVolatileUnlock();
changeAllowed = volatileLocked_;
}
}
@ -72,16 +67,11 @@ PSPDialog::DialogStatus PSPDialog::GetStatus() {
void PSPDialog::ChangeStatus(DialogStatus newStatus, int delayUs) {
if (delayUs <= 0) {
if (newStatus == SCE_UTILITY_STATUS_NONE && status == SCE_UTILITY_STATUS_SHUTDOWN) {
if (volatileLocked_) {
FinishVolatile();
UtilityCancelVolatileUnlock();
volatileLocked_ = false;
}
FinishVolatile();
} else if (newStatus == SCE_UTILITY_STATUS_RUNNING && status == SCE_UTILITY_STATUS_INITIALIZE) {
if (!volatileLocked_) {
// TODO: Should probably make the status pending instead?
volatileLocked_ = KernelVolatileMemLock(0, 0, 0) == 0;
UtilityCancelVolatileUnlock();
}
}
status = newStatus;
@ -89,20 +79,27 @@ void PSPDialog::ChangeStatus(DialogStatus newStatus, int delayUs) {
} else {
pendingStatus = newStatus;
pendingStatusTicks = CoreTiming::GetTicks() + usToCycles(delayUs);
if (volatileLocked_ && newStatus == SCE_UTILITY_STATUS_NONE && status == SCE_UTILITY_STATUS_SHUTDOWN) {
UtilityScheduleVolatileUnlock(usToCycles(delayUs));
}
}
}
void PSPDialog::FinishVolatile() {
if (volatileLocked_ && KernelVolatileMemUnlock(0) == 0) {
if (!volatileLocked_)
return;
if (KernelVolatileMemUnlock(0) == 0) {
volatileLocked_ = false;
// Simulate modifications to volatile memory.
Memory::Memset(PSP_GetVolatileMemoryStart(), 0, PSP_GetVolatileMemoryEnd() - PSP_GetVolatileMemoryStart());
}
}
int PSPDialog::FinishShutdown() {
if (ReadStatus() != SCE_UTILITY_STATUS_SHUTDOWN)
return -1;
ChangeStatus(SCE_UTILITY_STATUS_NONE, 0);
return 0;
}
void PSPDialog::ChangeStatusInit(int delayUs) {
status = SCE_UTILITY_STATUS_INITIALIZE;
ChangeStatus(SCE_UTILITY_STATUS_RUNNING, delayUs);
@ -110,7 +107,11 @@ void PSPDialog::ChangeStatusInit(int delayUs) {
void PSPDialog::ChangeStatusShutdown(int delayUs) {
status = SCE_UTILITY_STATUS_SHUTDOWN;
ChangeStatus(SCE_UTILITY_STATUS_NONE, delayUs);
auto params = GetCommonParam();
if (params)
UtilityDialogShutdown(DialogType(), delayUs, params->accessThread);
else
ChangeStatus(SCE_UTILITY_STATUS_NONE, delayUs);
}
void PSPDialog::StartDraw()

View file

@ -86,6 +86,7 @@ public:
void EndDraw();
void FinishVolatile();
int FinishShutdown();
protected:
PPGeStyle FadedStyle(PPGeAlign align, float scale);

View file

@ -27,8 +27,10 @@
#include "Core/Config.h"
#include "Core/CoreTiming.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/HLEHelperThread.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/MIPSCodeUtils.h"
#include "Core/Reporting.h"
#include "Core/System.h"
@ -142,18 +144,28 @@ static PSPGamedataInstallDialog gamedataInstallDialog(UTILITY_DIALOG_GAMEDATAINS
static int oldStatus = 100; //random value
static std::map<int, u32> currentlyLoadedModules;
static int volatileUnlockEvent = -1;
static HLEHelperThread *accessThread = nullptr;
static void CleanupDialogThreads() {
if (accessThread && accessThread->Stopped()) {
delete accessThread;
accessThread = nullptr;
}
}
static void ActivateDialog(UtilityDialogType type) {
if (!currentDialogActive) {
currentDialogType = type;
currentDialogActive = true;
}
CleanupDialogThreads();
}
static void DeactivateDialog() {
if (currentDialogActive) {
currentDialogActive = false;
}
CleanupDialogThreads();
}
static void UtilityVolatileUnlock(u64 userdata, int cyclesLate) {
@ -175,7 +187,7 @@ void __UtilityInit() {
}
void __UtilityDoState(PointerWrap &p) {
auto s = p.Section("sceUtility", 1, 3);
auto s = p.Section("sceUtility", 1, 4);
if (!s) {
return;
}
@ -205,6 +217,22 @@ void __UtilityDoState(PointerWrap &p) {
volatileUnlockEvent = -1;
}
CoreTiming::RestoreRegisterEvent(volatileUnlockEvent, "UtilityVolatileUnlock", UtilityVolatileUnlock);
bool hasAccessThread = accessThread != nullptr;
if (s >= 4) {
Do(p, hasAccessThread);
if (hasAccessThread) {
Do(p, accessThread);
}
} else {
hasAccessThread = false;
}
if (!hasAccessThread && accessThread) {
accessThread->Forget();
delete accessThread;
accessThread = nullptr;
}
}
void __UtilityShutdown() {
@ -214,14 +242,67 @@ void __UtilityShutdown() {
netDialog.Shutdown(true);
screenshotDialog.Shutdown(true);
gamedataInstallDialog.Shutdown(true);
if (accessThread) {
delete accessThread;
accessThread = nullptr;
}
}
void UtilityScheduleVolatileUnlock(s64 cyclesIntoFuture) {
CoreTiming::ScheduleEvent(cyclesIntoFuture, volatileUnlockEvent, 0);
void UtilityDialogShutdown(int type, int delayUs, int priority) {
// Break it up so better-priority rescheduling happens.
// The windows aren't this regular, but close.
int partDelay = delayUs / 4;
const u32_le insts[] = {
// Make sure we don't discard/deadbeef 'em.
(u32_le)MIPS_MAKE_ORI(MIPS_REG_S0, MIPS_REG_A0, 0),
(u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityWorkUs"),
(u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_S0, 0),
(u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityWorkUs"),
(u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_S0, 0),
(u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityWorkUs"),
(u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_S0, 0),
(u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityWorkUs"),
(u32_le)MIPS_MAKE_ORI(MIPS_REG_A0, MIPS_REG_ZERO, type),
(u32_le)MIPS_MAKE_JR_RA(),
(u32_le)MIPS_MAKE_SYSCALL("sceUtility", "__UtilityFinishDialog"),
};
CleanupDialogThreads();
_assert_(accessThread == nullptr);
accessThread = new HLEHelperThread("ScePafJob", insts, (uint32_t)ARRAY_SIZE(insts), priority, 0x200);
accessThread->Start(partDelay, 0);
}
void UtilityCancelVolatileUnlock() {
CoreTiming::UnscheduleEvent(volatileUnlockEvent, 0);
static int UtilityWorkUs(int us) {
// This blocks, but other better priority threads can get time.
// Simulate this by allowing a reschedule.
hleEatMicro(us);
hleReSchedule("utility work");
return 0;
}
static int UtilityFinishDialog(int type) {
switch (type) {
case UTILITY_DIALOG_NONE:
break;
case UTILITY_DIALOG_SAVEDATA:
return hleLogSuccessI(SCEUTILITY, saveDialog.FinishShutdown());
case UTILITY_DIALOG_MSG:
return hleLogSuccessI(SCEUTILITY, msgDialog.FinishShutdown());
case UTILITY_DIALOG_OSK:
return hleLogSuccessI(SCEUTILITY, oskDialog.FinishShutdown());
case UTILITY_DIALOG_NET:
return hleLogSuccessI(SCEUTILITY, netDialog.FinishShutdown());
case UTILITY_DIALOG_SCREENSHOT:
return hleLogSuccessI(SCEUTILITY, screenshotDialog.FinishShutdown());
case UTILITY_DIALOG_GAMESHARING:
return hleLogError(SCEUTILITY, -1, "unimplemented");
case UTILITY_DIALOG_GAMEDATAINSTALL:
return hleLogSuccessI(SCEUTILITY, gamedataInstallDialog.FinishShutdown());
}
return hleLogError(SCEUTILITY, 0, "invalid dialog type?");
}
static int sceUtilitySavedataInitStart(u32 paramAddr)
@ -251,7 +332,7 @@ static int sceUtilitySavedataShutdownStart() {
DeactivateDialog();
int ret = saveDialog.Shutdown();
hleEatCycles(90000);
hleEatCycles(30000);
return hleLogSuccessX(SCEUTILITY, ret);
}
@ -270,6 +351,7 @@ static int sceUtilitySavedataGetStatus()
DEBUG_LOG(SCEUTILITY, "%08x=sceUtilitySavedataGetStatus()", status);
}
hleEatCycles(200);
CleanupDialogThreads();
return status;
}
@ -429,6 +511,7 @@ static int sceUtilityMsgDialogGetStatus()
oldStatus = status;
DEBUG_LOG(SCEUTILITY, "%08x=sceUtilityMsgDialogGetStatus()", status);
}
CleanupDialogThreads();
return status;
}
@ -502,6 +585,7 @@ static int sceUtilityOskGetStatus()
oldStatus = status;
DEBUG_LOG(SCEUTILITY, "%08x=sceUtilityOskGetStatus()", status);
}
CleanupDialogThreads();
return status;
}
@ -544,6 +628,7 @@ static int sceUtilityNetconfGetStatus() {
oldStatus = status;
return hleLogSuccessI(SCEUTILITY, status);
}
CleanupDialogThreads();
return hleLogSuccessVerboseI(SCEUTILITY, status);
}
@ -613,6 +698,7 @@ static int sceUtilityScreenshotGetStatus()
oldStatus = status;
WARN_LOG(SCEUTILITY, "%08x=sceUtilityScreenshotGetStatus()", status);
}
CleanupDialogThreads();
return status;
}
@ -678,6 +764,7 @@ static int sceUtilityGamedataInstallGetStatus()
int status = gamedataInstallDialog.GetStatus();
DEBUG_LOG(SCEUTILITY, "%08x=sceUtilityGamedataInstallGetStatus()", status);
CleanupDialogThreads();
return status;
}
@ -893,6 +980,7 @@ static int sceUtilityGameSharingGetStatus()
}
ERROR_LOG(SCEUTILITY, "UNIMPL sceUtilityGameSharingGetStatus()");
CleanupDialogThreads();
return 0;
}
@ -1055,6 +1143,10 @@ const HLEFunction sceUtility[] =
{0X70267ADF, nullptr, "sceUtility_70267ADF", '?', "" },
{0XECE1D3E5, nullptr, "sceUtility_ECE1D3E5", '?', "" },
{0XEF3582B2, nullptr, "sceUtility_EF3582B2", '?', "" },
// Fake functions for PPSSPP's use.
{0xC0DE0001, &WrapI_I<UtilityFinishDialog>, "__UtilityFinishDialog", 'i', "i" },
{0xC0DE0002, &WrapI_I<UtilityWorkUs>, "__UtilityWorkUs", 'i', "i" },
};
void Register_sceUtility()

View file

@ -83,7 +83,6 @@ void __UtilityInit();
void __UtilityDoState(PointerWrap &p);
void __UtilityShutdown();
void UtilityScheduleVolatileUnlock(s64 cyclesIntoFuture);
void UtilityCancelVolatileUnlock();
void UtilityDialogShutdown(int type, int delayUs, int priority);
void Register_sceUtility();