Merge pull request #4136 from unknownbrackets/ui-tweaks

Improve some shutdown problems on Windows
This commit is contained in:
Henrik Rydgård 2013-10-12 02:35:56 -07:00
commit 7a4029fd65
8 changed files with 109 additions and 102 deletions

View File

@ -51,61 +51,54 @@ InputState input_state;
extern InputState input_state;
#endif
void Core_ListenShutdown(Core_ShutdownFunc func)
{
void Core_ListenShutdown(Core_ShutdownFunc func) {
shutdownFuncs.insert(func);
}
void Core_NotifyShutdown()
{
for (auto it = shutdownFuncs.begin(); it != shutdownFuncs.end(); ++it)
void Core_NotifyShutdown() {
for (auto it = shutdownFuncs.begin(); it != shutdownFuncs.end(); ++it) {
(*it)();
}
}
void Core_ErrorPause()
{
void Core_ErrorPause() {
Core_UpdateState(CORE_ERROR);
}
void Core_Halt(const char *msg)
{
void Core_Halt(const char *msg) {
Core_EnableStepping(true);
ERROR_LOG(CPU, "CPU HALTED : %s",msg);
_dbg_update_();
}
void Core_Stop()
{
void Core_Stop() {
Core_UpdateState(CORE_POWERDOWN);
Core_NotifyShutdown();
m_hStepEvent.notify_one();
}
bool Core_IsStepping()
{
bool Core_IsStepping() {
return coreState == CORE_STEPPING || coreState == CORE_POWERDOWN;
}
bool Core_IsActive()
{
bool Core_IsActive() {
return coreState == CORE_RUNNING || coreState == CORE_NEXTFRAME || coreStatePending;
}
bool Core_IsInactive()
{
bool Core_IsInactive() {
return coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME && !coreStatePending;
}
void Core_WaitInactive()
{
while (Core_IsActive())
void Core_WaitInactive() {
while (Core_IsActive()) {
m_hInactiveEvent.wait(m_hInactiveMutex);
}
}
void Core_WaitInactive(int milliseconds)
{
if (Core_IsActive())
void Core_WaitInactive(int milliseconds) {
if (Core_IsActive()) {
m_hInactiveEvent.wait_for(m_hInactiveMutex, milliseconds);
}
}
void UpdateScreenScale() {
@ -127,61 +120,78 @@ void UpdateScreenScale() {
pixel_in_dps = (float)pixel_xres / dp_xres;
}
static inline void UpdateRunLoop() {
UpdateScreenScale();
{
{
#ifdef _WIN32
lock_guard guard(input_state.lock);
input_state.pad_buttons = 0;
input_state.pad_lstick_x = 0;
input_state.pad_lstick_y = 0;
input_state.pad_rstick_x = 0;
input_state.pad_rstick_y = 0;
host->PollControllers(input_state);
UpdateInputState(&input_state);
#endif
}
NativeUpdate(input_state);
EndInputState(&input_state);
}
NativeRender();
}
void Core_RunLoop()
{
while (globalUIState != UISTATE_INGAME && globalUIState != UISTATE_EXIT) {
time_update();
#ifdef _WIN32
double startTime = time_now_d();
UpdateRunLoop();
// Simple throttling to not burn the GPU in the menu.
time_update();
double diffTime = time_now_d() - startTime;
int sleepTime = (int) (1000000.0 / 60.0) - (int) (diffTime * 1000000.0);
if (sleepTime > 0)
Sleep(sleepTime / 1000);
GL_SwapBuffers();
#else
UpdateRunLoop();
#endif
}
while (!coreState) {
time_update();
double startTime = time_now_d();
UpdateScreenScale();
{
{
UpdateRunLoop();
#ifdef _WIN32
lock_guard guard(input_state.lock);
input_state.pad_buttons = 0;
input_state.pad_lstick_x = 0;
input_state.pad_lstick_y = 0;
input_state.pad_rstick_x = 0;
input_state.pad_rstick_y = 0;
host->PollControllers(input_state);
UpdateInputState(&input_state);
#endif
}
NativeUpdate(input_state);
EndInputState(&input_state);
}
NativeRender();
time_update();
// Simple throttling to not burn the GPU in the menu.
#ifdef _WIN32
if (globalUIState != UISTATE_INGAME) {
double diffTime = time_now_d() - startTime;
int sleepTime = (int) (1000000.0 / 60.0) - (int) (diffTime * 1000000.0);
if (sleepTime > 0)
Sleep(sleepTime / 1000);
GL_SwapBuffers();
} else if (!Core_IsStepping()) {
if (!Core_IsStepping()) {
GL_SwapBuffers();
}
#endif
}
}
void Core_DoSingleStep()
{
void Core_DoSingleStep() {
singleStepPending = true;
m_hStepEvent.notify_one();
}
void Core_UpdateSingleStep()
{
void Core_UpdateSingleStep() {
m_hStepEvent.notify_one();
}
void Core_SingleStep()
{
void Core_SingleStep() {
currentMIPS->SingleStep();
}
static inline void CoreStateProcessed() {
if (coreStatePending) {
coreStatePending = false;
m_hInactiveEvent.notify_one();
}
}
// Some platforms, like Android, do not call this function but handle things on their own.
void Core_Run()
@ -194,6 +204,15 @@ void Core_Run()
#endif
{
reswitch:
if (globalUIState != UISTATE_INGAME) {
CoreStateProcessed();
if (globalUIState == UISTATE_EXIT) {
return;
}
Core_RunLoop();
continue;
}
switch (coreState)
{
case CORE_RUNNING:
@ -204,10 +223,7 @@ reswitch:
// We should never get here on Android.
case CORE_STEPPING:
singleStepPending = false;
if (coreStatePending) {
coreStatePending = false;
m_hInactiveEvent.notify_one();
}
CoreStateProcessed();
// Check if there's any pending savestate actions.
SaveState::Process();
@ -251,10 +267,7 @@ reswitch:
case CORE_POWERDOWN:
case CORE_ERROR:
// Exit loop!!
if (coreStatePending) {
coreStatePending = false;
m_hInactiveEvent.notify_one();
}
CoreStateProcessed();
return;
@ -266,19 +279,15 @@ reswitch:
}
void Core_EnableStepping(bool step)
{
if (step)
{
void Core_EnableStepping(bool step) {
if (step) {
sleep_ms(1);
#if defined(_DEBUG)
host->SetDebugMode(true);
#endif
m_hStepEvent.reset();
Core_UpdateState(CORE_STEPPING);
}
else
{
} else {
#if defined(_DEBUG)
host->SetDebugMode(false);
#endif

View File

@ -126,7 +126,7 @@ unsigned int MIPSDebugInterface::readMemory(unsigned int address)
bool MIPSDebugInterface::isAlive()
{
return PSP_IsInited();
return PSP_IsInited() && coreState != CORE_ERROR && coreState != CORE_POWERDOWN;
}
bool MIPSDebugInterface::isBreakpoint(unsigned int address)

View File

@ -67,6 +67,7 @@ static PSPMixer *mixer;
static std::thread *cpuThread = NULL;
static recursive_mutex cpuThreadLock;
static condition_variable cpuThreadCond;
static condition_variable cpuThreadReplyCond;
static u64 cpuThreadUntil;
// This can be read and written from ANYWHERE.
@ -95,9 +96,11 @@ bool IsOnSeparateCPUThread() {
}
bool CPU_NextState(CPUThreadState from, CPUThreadState to) {
lock_guard guard(cpuThreadLock);
if (cpuThreadState == from) {
cpuThreadState = to;
cpuThreadCond.notify_one();
cpuThreadReplyCond.notify_one();
return true;
} else {
return false;
@ -105,8 +108,10 @@ bool CPU_NextState(CPUThreadState from, CPUThreadState to) {
}
void CPU_SetState(CPUThreadState to) {
lock_guard guard(cpuThreadLock);
cpuThreadState = to;
cpuThreadCond.notify_one();
cpuThreadReplyCond.notify_one();
}
bool CPU_IsReady() {
@ -121,11 +126,11 @@ bool CPU_HasPendingAction() {
return cpuThreadState != CPU_THREAD_RUNNING;
}
void CPU_WaitStatus(bool (*pred)()) {
cpuThreadLock.lock();
while (!pred())
cpuThreadCond.wait(cpuThreadLock);
cpuThreadLock.unlock();
void CPU_WaitStatus(condition_variable &cond, bool (*pred)()) {
lock_guard guard(cpuThreadLock);
while (!pred()) {
cond.wait(cpuThreadLock);
}
}
void CPU_Shutdown();
@ -219,7 +224,7 @@ void CPU_RunLoop() {
while (cpuThreadState != CPU_THREAD_SHUTDOWN)
{
CPU_WaitStatus(&CPU_HasPendingAction);
CPU_WaitStatus(cpuThreadCond, &CPU_HasPendingAction);
switch (cpuThreadState) {
case CPU_THREAD_EXECUTE:
mipsr4k.RunLoopUntil(cpuThreadUntil);
@ -271,7 +276,7 @@ bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) {
Core_ListenShutdown(System_Wake);
CPU_SetState(CPU_THREAD_PENDING);
cpuThread = new std::thread(&CPU_RunLoop);
CPU_WaitStatus(&CPU_IsReady);
CPU_WaitStatus(cpuThreadReplyCond, &CPU_IsReady);
} else {
CPU_Init();
}
@ -298,7 +303,7 @@ void PSP_Shutdown() {
Core_NotifyShutdown();
if (cpuThread != NULL) {
CPU_SetState(CPU_THREAD_SHUTDOWN);
CPU_WaitStatus(&CPU_IsShutdown);
CPU_WaitStatus(cpuThreadReplyCond, &CPU_IsShutdown);
delete cpuThread;
cpuThread = 0;
} else {

View File

@ -40,7 +40,8 @@ enum GlobalUIState {
extern GlobalUIState globalUIState;
inline static void UpdateUIState(GlobalUIState newState) {
if (globalUIState != newState) {
// Never leave the EXIT state.
if (globalUIState != newState && globalUIState != UISTATE_EXIT) {
globalUIState = newState;
host->UpdateDisassembly();
}

View File

@ -487,6 +487,7 @@ ShaderManager::~ShaderManager() {
}
void ShaderManager::Clear() {
DirtyLastShader();
for (auto iter = linkedShaderCache_.begin(); iter != linkedShaderCache_.end(); ++iter) {
delete iter->ls;
}

View File

@ -147,7 +147,8 @@ void EmuScreen::sendMessage(const char *message, const char *value) {
if (!strcmp(message, "pause")) {
screenManager()->push(new GamePauseScreen(gamePath_));
} else if (!strcmp(message, "stop")) {
screenManager()->switchScreen(new MainScreen());
// We will push MainScreen in update().
PSP_Shutdown();
} else if (!strcmp(message, "reset")) {
PSP_Shutdown();
std::string resetError;
@ -497,6 +498,7 @@ void EmuScreen::render() {
} else if (coreState == CORE_POWERDOWN) {
ILOG("SELF-POWERDOWN!");
screenManager()->switchScreen(new MainScreen());
invalid_ = true;
}
if (invalid_)

View File

@ -130,11 +130,12 @@ unsigned int WINAPI TheThread(void *)
while (globalUIState != UISTATE_EXIT)
{
Core_Run();
// We're here again, so the game quit. Restart Core_Run() which controls the UI.
// This way they can load a new game.
Core_UpdateState(CORE_RUNNING);
if (!Core_IsActive())
UpdateUIState(UISTATE_MENU);
Core_Run();
}
shutdown:

View File

@ -782,19 +782,6 @@ namespace MainWindow
DialogManager::AddDlg(memoryWindow[0]);
}
void WaitForCore() {
if (Core_IsStepping()) {
// If the current PC is on a breakpoint, disabling stepping doesn't work without
// explicitly skipping it
CBreakPoints::SetSkipFirst(currentMIPS->pc);
Core_EnableStepping(false);
}
Core_EnableStepping(true);
Core_WaitInactive();
Core_EnableStepping(false);
}
void BrowseAndBoot(std::string defaultPath, bool browseDirectory) {
std::string fn;
std::string filter = "PSP ROMs (*.iso *.cso *.pbp *.elf)|*.pbp;*.elf;*.iso;*.cso;*.prx|All files (*.*)|*.*||";
@ -1140,21 +1127,22 @@ namespace MainWindow
break;
case ID_EMULATION_STOP:
WaitForCore();
Core_Stop();
NativeMessageReceived("stop", "");
Core_WaitInactive();
Update();
break;
case ID_EMULATION_RESET:
WaitForCore();
NativeMessageReceived("reset", "");
Core_EnableStepping(false);
break;
case ID_EMULATION_CHEATS:
g_Config.bEnableCheats = !g_Config.bEnableCheats;
osm.ShowOnOff(g->T("Cheats"), g_Config.bEnableCheats);
WaitForCore();
NativeMessageReceived("reset", "");
Core_EnableStepping(false);
break;
case ID_FILE_LOADSTATEFILE: