Core Stop and Start: Added alternative separate thread timer/loop based waiting, instead of same thread loop waiting. You can try it with the SETUP_TIMER_WAITING option in Setup.h.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2375 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
769160dfbd
commit
927815bc9b
|
@ -49,6 +49,15 @@
|
||||||
// Build with playback rerecording options
|
// Build with playback rerecording options
|
||||||
//#define SETUP_AVOID_OPENGL_SCREEN_MESSAGE_HANG
|
//#define SETUP_AVOID_OPENGL_SCREEN_MESSAGE_HANG
|
||||||
|
|
||||||
|
// Use a timer to wait for threads for stop instead of WaitForEternity()
|
||||||
|
/* I tried that this worked with these options
|
||||||
|
SETUP_FREE_VIDEO_PLUGIN_ON_BOOT
|
||||||
|
SETUP_DONT_FREE_PLUGIN_ON_STOP
|
||||||
|
then the Confirm on Close message box doesn't hang, and we have a controlled Shutdown process
|
||||||
|
without any hanged threads. The downside is a few error messages in the ShutDown() of the
|
||||||
|
OpenGL plugin, so I still need FreeLibrary() to clean it, even with this option. */
|
||||||
|
//#define SETUP_TIMER_WAITING
|
||||||
|
|
||||||
// Build with playback rerecording options
|
// Build with playback rerecording options
|
||||||
//#define RERECORDING
|
//#define RERECORDING
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,16 @@
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
|
#include "Setup.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
|
// -----------------------------------------
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// -----------------
|
||||||
|
#include <windows.h>
|
||||||
|
#include "ConsoleWindow.h"
|
||||||
|
EventCallBack FunctionPointer[10];
|
||||||
|
#endif
|
||||||
|
// ------------------------
|
||||||
|
|
||||||
#define THREAD_DEBUG 1
|
#define THREAD_DEBUG 1
|
||||||
|
|
||||||
|
@ -99,9 +108,18 @@ void Thread::SetCurrentThreadAffinity(int mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Regular same thread loop based waiting
|
||||||
|
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
|
||||||
Event::Event()
|
Event::Event()
|
||||||
{
|
{
|
||||||
m_hEvent = 0;
|
m_hEvent = 0;
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
DoneWaiting = false;
|
||||||
|
StartWait = false;
|
||||||
|
hTimer = NULL;
|
||||||
|
hTimerQueue = NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Event::Init()
|
void Event::Init()
|
||||||
|
@ -115,22 +133,125 @@ void Event::Shutdown()
|
||||||
m_hEvent = 0;
|
m_hEvent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Event::Set()
|
void Event::Set()
|
||||||
{
|
{
|
||||||
SetEvent(m_hEvent);
|
SetEvent(m_hEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Wait()
|
void Event::Wait()
|
||||||
{
|
{
|
||||||
WaitForSingleObject(m_hEvent, INFINITE);
|
WaitForSingleObject(m_hEvent, INFINITE);
|
||||||
}
|
}
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/* Separate thread timer based waiting, instead of same thread loop waiting. The downside with this
|
||||||
|
is that it's less convenient to use because we can't stall any threads with a loop. The positive
|
||||||
|
is that we don't cause these incredibly annoying WaitForEternity() hangings. */
|
||||||
|
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
/* I could not figure out how to place this in the class to, CreateTimerQueueTimer() would complain
|
||||||
|
about some kind of type casting, anyone have any ideas about how to do it? */
|
||||||
|
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
|
||||||
|
{
|
||||||
|
if (lpParam == NULL)
|
||||||
|
{
|
||||||
|
Console::Print("TimerRoutine lpParam is NULL\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// lpParam points to the argument; in this case it is an int
|
||||||
|
|
||||||
|
//Console::Print("Timer[%i] will call back\n", *(int*)lpParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call back
|
||||||
|
int Id = *(int*)lpParam;
|
||||||
|
if (FunctionPointer[Id]) FunctionPointer[Id]();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a timer that will call back to the calling function
|
||||||
|
bool Event::TimerWait(EventCallBack WaitCB, int _Id, bool OptCondition)
|
||||||
|
{
|
||||||
|
Id = _Id;
|
||||||
|
|
||||||
|
//Console::Print("TimerWait[%i]: %i %i %i\n", Id, StartWait, DoneWaiting, OptCondition);
|
||||||
|
|
||||||
|
FunctionPointer[Id] = WaitCB;
|
||||||
|
|
||||||
|
// This means we are done waiting, so we wont call back again, and we also reset the variables for this Event
|
||||||
|
if (DoneWaiting && OptCondition)
|
||||||
|
{
|
||||||
|
StartWait = false;
|
||||||
|
DoneWaiting = false;
|
||||||
|
FunctionPointer[Id] = NULL;
|
||||||
|
|
||||||
|
// Delete all timers in the timer queue.
|
||||||
|
if (!DeleteTimerQueue(hTimerQueue))
|
||||||
|
Console::Print("DeleteTimerQueue failed (%d)\n", GetLastError());
|
||||||
|
|
||||||
|
hTimer = NULL;
|
||||||
|
hTimerQueue = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else start a new callback timer
|
||||||
|
StartWait = true;
|
||||||
|
|
||||||
|
// Create the timer queue if needed
|
||||||
|
if (!hTimerQueue)
|
||||||
|
{
|
||||||
|
hTimerQueue = CreateTimerQueue();
|
||||||
|
if (NULL == hTimerQueue)
|
||||||
|
{
|
||||||
|
Console::Print("CreateTimerQueue failed (%d)\n", GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a timer to call the timer routine in 10 seconds.
|
||||||
|
if (!CreateTimerQueueTimer( &hTimer, hTimerQueue,
|
||||||
|
(WAITORTIMERCALLBACK)TimerRoutine, &Id , 10, 0, 0))
|
||||||
|
{
|
||||||
|
Console::Print("CreateTimerQueueTimer failed (%d)\n", GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Check if we are done or not
|
||||||
|
bool Event::DoneWait()
|
||||||
|
{
|
||||||
|
if (StartWait && DoneWaiting)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Tells the timer that we are done waiting
|
||||||
|
void Event::SetTimer()
|
||||||
|
{
|
||||||
|
// We can not be done before we have started waiting
|
||||||
|
if (StartWait) DoneWaiting = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Supporting functions
|
||||||
|
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
|
||||||
|
|
||||||
void SleepCurrentThread(int ms)
|
void SleepCurrentThread(int ms)
|
||||||
{
|
{
|
||||||
Sleep(ms);
|
Sleep(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct tagTHREADNAME_INFO
|
typedef struct tagTHREADNAME_INFO
|
||||||
{
|
{
|
||||||
DWORD dwType; // must be 0x1000
|
DWORD dwType; // must be 0x1000
|
||||||
|
@ -188,6 +309,8 @@ LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
|
||||||
{
|
{
|
||||||
return InterlockedExchange(Dest, Val);
|
return InterlockedExchange(Dest, Val);
|
||||||
}
|
}
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
#else // !WIN32, so must be POSIX threads
|
#else // !WIN32, so must be POSIX threads
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,15 @@
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// -----------------
|
||||||
|
typedef void (*EventCallBack)(void);
|
||||||
|
#endif
|
||||||
|
// ----------------------
|
||||||
|
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
class CriticalSection
|
class CriticalSection
|
||||||
|
@ -78,6 +87,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Event
|
class Event
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -89,6 +99,20 @@ public:
|
||||||
void Set();
|
void Set();
|
||||||
void Wait();
|
void Wait();
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// -----------------
|
||||||
|
bool TimerWait(EventCallBack WaitCB, int Id = 0, bool OptCondition = true);
|
||||||
|
bool DoneWait();
|
||||||
|
void SetTimer();
|
||||||
|
bool DoneWaiting;
|
||||||
|
bool StartWait;
|
||||||
|
int Id;
|
||||||
|
HANDLE hTimer;
|
||||||
|
HANDLE hTimerQueue;
|
||||||
|
#endif
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE m_hEvent;
|
HANDLE m_hEvent;
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Thread.h" // Common
|
#include "Setup.h" // Common
|
||||||
#include "Setup.h"
|
#include "Thread.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "ConsoleWindow.h"
|
#include "ConsoleWindow.h"
|
||||||
|
@ -110,6 +110,19 @@ SCoreStartupParameter g_CoreStartupParameter;
|
||||||
// This event is set when the emuthread starts.
|
// This event is set when the emuthread starts.
|
||||||
Common::Event emuThreadGoing;
|
Common::Event emuThreadGoing;
|
||||||
Common::Event cpuRunloopQuit;
|
Common::Event cpuRunloopQuit;
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// -----------------
|
||||||
|
bool VideoThreadRunning = false;
|
||||||
|
bool StopUpToVideoDone = false;
|
||||||
|
bool EmuThreadReachedEnd = false;
|
||||||
|
bool StopReachedEnd = false;
|
||||||
|
static Common::Event VideoThreadEvent;
|
||||||
|
static Common::Event VideoThreadEvent2;
|
||||||
|
void EmuThreadEnd();
|
||||||
|
#endif
|
||||||
|
// ---------------------------
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,9 +175,24 @@ void ReconnectPad()
|
||||||
void ReconnectWiimote()
|
void ReconnectWiimote()
|
||||||
{
|
{
|
||||||
// This seems to be a hack that just sets some IPC registers to zero. Dubious.
|
// This seems to be a hack that just sets some IPC registers to zero. Dubious.
|
||||||
|
/* JP: Yes, it's basically nothing right now, I could not figure out how to reset the Wiimote
|
||||||
|
for reconnection */
|
||||||
HW::InitWiimote();
|
HW::InitWiimote();
|
||||||
Console::Print("ReconnectWiimote()\n");
|
Console::Print("ReconnectWiimote()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// -----------------
|
||||||
|
void VideoThreadEnd()
|
||||||
|
{
|
||||||
|
VideoThreadRunning = false;
|
||||||
|
VideoThreadEvent.SetTimer();
|
||||||
|
VideoThreadEvent2.SetTimer();
|
||||||
|
//Console::Print("VideoThreadEnd\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// ---------------------------
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
@ -201,6 +229,9 @@ bool Init()
|
||||||
g_EmuThread = new Common::Thread(EmuThread, NULL);
|
g_EmuThread = new Common::Thread(EmuThread, NULL);
|
||||||
emuThreadGoing.Wait();
|
emuThreadGoing.Wait();
|
||||||
emuThreadGoing.Shutdown();
|
emuThreadGoing.Shutdown();
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
VideoThreadRunning = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
// All right, the event is set and killed. We are now running.
|
// All right, the event is set and killed. We are now running.
|
||||||
Host_SetWaitCursor(false);
|
Host_SetWaitCursor(false);
|
||||||
|
@ -208,17 +239,29 @@ bool Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from GUI thread or VI thread (why VI??? That must be bad. Window close? TODO: Investigate.)
|
// Called from GUI thread or VI thread (why VI??? That must be bad. Window close? TODO: Investigate.)
|
||||||
void Stop() // - Hammertime!
|
// JP: No, when you press Stop this is run from the Main Thread it seems
|
||||||
|
// - Hammertime!
|
||||||
|
void Stop()
|
||||||
{
|
{
|
||||||
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||||
|
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
if (!StopUpToVideoDone)
|
||||||
|
{
|
||||||
|
Console::Print("--------------------------------------------------------------\n");
|
||||||
|
Console::Print("Stop [Main Thread]: Shutting down...\n");
|
||||||
|
// Reset variables
|
||||||
|
StopReachedEnd = false;
|
||||||
|
EmuThreadReachedEnd = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
Host_SetWaitCursor(true);
|
Host_SetWaitCursor(true);
|
||||||
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
|
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// stop the CPU
|
// Stop the CPU
|
||||||
PowerPC::Stop();
|
PowerPC::Stop();
|
||||||
CCPU::StepOpcode(); //kick it if it's waiting
|
CCPU::StepOpcode(); // Kick it if it's waiting
|
||||||
|
|
||||||
cpuRunloopQuit.Wait();
|
cpuRunloopQuit.Wait();
|
||||||
cpuRunloopQuit.Shutdown();
|
cpuRunloopQuit.Shutdown();
|
||||||
|
@ -229,10 +272,22 @@ void Stop() // - Hammertime!
|
||||||
|
|
||||||
// If dual core mode, the CPU thread should immediately exit here.
|
// If dual core mode, the CPU thread should immediately exit here.
|
||||||
|
|
||||||
|
Console::Print("Stop [Main Thread]: Wait for Video Loop...\n");
|
||||||
|
|
||||||
// Should be moved inside the plugin.
|
// Should be moved inside the plugin.
|
||||||
if (_CoreParameter.bUseDualCore)
|
if (_CoreParameter.bUseDualCore)
|
||||||
CPluginManager::GetInstance().GetVideo()->Video_ExitLoop();
|
CPluginManager::GetInstance().GetVideo()->Video_ExitLoop();
|
||||||
|
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
StopUpToVideoDone = true;
|
||||||
|
}
|
||||||
|
// Call this back
|
||||||
|
//if (!VideoThreadEvent.TimerWait(Stop, 1, EmuThreadReachedEnd) || !EmuThreadReachedEnd) return;
|
||||||
|
if (!VideoThreadEvent.TimerWait(Stop, 1)) return;
|
||||||
|
|
||||||
|
//Console::Print("Stop() will continue\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest
|
/* Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest
|
||||||
of the commands in this function */
|
of the commands in this function */
|
||||||
|
|
||||||
|
@ -240,24 +295,37 @@ void Stop() // - Hammertime!
|
||||||
And since we have no while(GetMessage()) loop we can't wait for this to happen, or say exactly when
|
And since we have no while(GetMessage()) loop we can't wait for this to happen, or say exactly when
|
||||||
the loop has ended */
|
the loop has ended */
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
|
//PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Close the trace file
|
||||||
Core::StopTrace();
|
Core::StopTrace();
|
||||||
|
#ifndef SETUP_TIMER_WAITING // This hangs
|
||||||
LogManager::Shutdown();
|
LogManager::Shutdown();
|
||||||
|
#endif
|
||||||
|
// Update mouse pointer
|
||||||
Host_SetWaitCursor(false);
|
Host_SetWaitCursor(false);
|
||||||
#ifdef SETUP_AVOID_CHILD_WINDOW_RENDERING_HANG
|
#ifdef SETUP_AVOID_CHILD_WINDOW_RENDERING_HANG
|
||||||
/* This may hang when we are rendering to a child window, but currently it doesn't, at least
|
/* This may hang when we are rendering to a child window, but currently it doesn't, at least
|
||||||
not on my system, but I'll leave this option for a while anyway */
|
not on my system, but I'll leave this option for a while anyway */
|
||||||
if (GetParent((HWND)g_pWindowHandle) == NULL)
|
if (GetParent((HWND)g_pWindowHandle) == NULL)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef SETUP_TIMER_WAITING // This is moved
|
||||||
delete g_EmuThread; // Wait for emuthread to close.
|
delete g_EmuThread; // Wait for emuthread to close.
|
||||||
g_EmuThread = 0;
|
g_EmuThread = 0;
|
||||||
|
#endif
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
Host_UpdateGUI();
|
||||||
|
StopUpToVideoDone = false;
|
||||||
|
StopReachedEnd = true;
|
||||||
|
//Console::Print("Stop() reached the end\n");
|
||||||
|
if (EmuThreadReachedEnd) Console::Print("--------------------------------------------------------------\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Create the CPU thread
|
// Create the CPU thread. For use with Single Core mode only.
|
||||||
// ---------------
|
// ---------------
|
||||||
THREAD_RETURN CpuThread(void *pArg)
|
THREAD_RETURN CpuThread(void *pArg)
|
||||||
{
|
{
|
||||||
|
@ -465,6 +533,34 @@ THREAD_RETURN EmuThread(void *pArg)
|
||||||
// I bet that many of our stopping problems come from this loop not properly exiting.
|
// I bet that many of our stopping problems come from this loop not properly exiting.
|
||||||
Plugins.GetVideo()->Video_EnterLoop();
|
Plugins.GetVideo()->Video_EnterLoop();
|
||||||
}
|
}
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
|
||||||
|
VideoThreadEvent2.TimerWait(EmuThreadEnd, 2);
|
||||||
|
//Console::Print("Video loop [Video Thread]: Stopped\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void EmuThreadEnd()
|
||||||
|
{
|
||||||
|
CPluginManager &Plugins = CPluginManager::GetInstance();
|
||||||
|
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
|
||||||
|
|
||||||
|
//Console::Print("Video loop [Video Thread]: EmuThreadEnd [StopEnd:%i]\n", StopReachedEnd);
|
||||||
|
|
||||||
|
//if (!VideoThreadEvent2.TimerWait(EmuThreadEnd, 2)) return;
|
||||||
|
if (!VideoThreadEvent2.TimerWait(EmuThreadEnd, 2, StopReachedEnd) || !StopReachedEnd)
|
||||||
|
{
|
||||||
|
Console::Print("Stop [Video Thread]: Waiting for Stop() and Video Loop to end...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Console::Print("EmuThreadEnd() will continue\n");
|
||||||
|
|
||||||
|
/* There will be a few problems with the OpenGL ShutDown() after this, for example the "Release
|
||||||
|
Device Context Failed" error message */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Console::Print("Stop [Video Thread]: Stop() and Video Loop Ended\n");
|
||||||
|
Console::Print("Stop [Video Thread]: Shutting down HW and Plugins\n");
|
||||||
|
|
||||||
// We have now exited the Video Loop and will shut down
|
// We have now exited the Video Loop and will shut down
|
||||||
|
|
||||||
|
@ -484,6 +580,7 @@ THREAD_RETURN EmuThread(void *pArg)
|
||||||
if (g_pUpdateFPSDisplay != NULL)
|
if (g_pUpdateFPSDisplay != NULL)
|
||||||
g_pUpdateFPSDisplay("Stopping...");
|
g_pUpdateFPSDisplay("Stopping...");
|
||||||
|
|
||||||
|
#ifndef SETUP_TIMER_WAITING
|
||||||
if (cpuThread)
|
if (cpuThread)
|
||||||
{
|
{
|
||||||
// There is a CPU thread - join it.
|
// There is a CPU thread - join it.
|
||||||
|
@ -491,6 +588,7 @@ THREAD_RETURN EmuThread(void *pArg)
|
||||||
// Returns after game exited
|
// Returns after game exited
|
||||||
cpuThread = NULL;
|
cpuThread = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// The hardware is uninitialized
|
// The hardware is uninitialized
|
||||||
g_bHwInit = false;
|
g_bHwInit = false;
|
||||||
|
@ -503,8 +601,18 @@ THREAD_RETURN EmuThread(void *pArg)
|
||||||
// so we can restart the plugins (or load new ones) for the next game.
|
// so we can restart the plugins (or load new ones) for the next game.
|
||||||
if (_CoreParameter.hMainWindow == g_pWindowHandle)
|
if (_CoreParameter.hMainWindow == g_pWindowHandle)
|
||||||
Host_UpdateMainFrame();
|
Host_UpdateMainFrame();
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
EmuThreadReachedEnd = true;
|
||||||
|
//Console::Print("EmuThread() reached the end\n");
|
||||||
|
Host_UpdateGUI();
|
||||||
|
Console::Print("Stop [Video Thread]: Done\n");
|
||||||
|
if (StopReachedEnd) Console::Print("--------------------------------------------------------------\n");
|
||||||
|
delete g_EmuThread; // Wait for emuthread to close.
|
||||||
|
g_EmuThread = 0;
|
||||||
|
#endif
|
||||||
|
#ifndef SETUP_TIMER_WAITING
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,17 @@ namespace Core
|
||||||
void SetBlockStart(u32 addr);
|
void SetBlockStart(u32 addr);
|
||||||
void StopTrace();
|
void StopTrace();
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// -----------------
|
||||||
|
// Thread shutdown
|
||||||
|
void VideoThreadEnd();
|
||||||
|
#endif
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
#ifdef RERECORDING
|
#ifdef RERECORDING
|
||||||
|
// -----------------
|
||||||
void FrameUpdate();
|
void FrameUpdate();
|
||||||
void FrameAdvance();
|
void FrameAdvance();
|
||||||
void FrameStepOnOff();
|
void FrameStepOnOff();
|
||||||
|
@ -84,6 +94,7 @@ namespace Core
|
||||||
extern int g_FrameCounter;
|
extern int g_FrameCounter;
|
||||||
extern bool g_FrameStep;
|
extern bool g_FrameStep;
|
||||||
#endif
|
#endif
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,9 @@ void Host_SetDebugMode(bool enable);
|
||||||
void Host_SetWaitCursor(bool enable);
|
void Host_SetWaitCursor(bool enable);
|
||||||
|
|
||||||
void Host_UpdateStatusBar(const char* _pText, int Filed = 0);
|
void Host_UpdateStatusBar(const char* _pText, int Filed = 0);
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
void Host_UpdateGUI();
|
||||||
|
#endif
|
||||||
|
|
||||||
void Host_SysMessage(const char *fmt, ...);
|
void Host_SysMessage(const char *fmt, ...);
|
||||||
void Host_SetWiiMoteConnectionState(int _State);
|
void Host_SetWiiMoteConnectionState(int _State);
|
||||||
|
|
|
@ -194,15 +194,29 @@ int abc = 0;
|
||||||
Core::ReconnectWiimote();
|
Core::ReconnectWiimote();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
#ifdef RERECORDING
|
#ifdef RERECORDING
|
||||||
|
// -----------------
|
||||||
case INPUT_FRAME_COUNTER:
|
case INPUT_FRAME_COUNTER:
|
||||||
// Wind back the frame counter after a save state has been loaded
|
// Wind back the frame counter after a save state has been loaded
|
||||||
Core::WindBack((int)lParam);
|
Core::WindBack((int)lParam);
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
// -----------------------------
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// -----------------
|
||||||
|
case OPENGL_VIDEO_STOP:
|
||||||
|
// The Video thread has been shut down
|
||||||
|
Core::VideoThreadEnd();
|
||||||
|
//Console::Print("OPENGL_VIDEO_STOP\n");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
// -----------------------------
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//default:
|
//default:
|
||||||
// return wxPanel::MSWWindowProc(nMsg, wParam, lParam);
|
// return wxPanel::MSWWindowProc(nMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ class CFrame : public wxFrame
|
||||||
void InitBitmaps();
|
void InitBitmaps();
|
||||||
void DoStop();
|
void DoStop();
|
||||||
bool bRenderToMain;
|
bool bRenderToMain;
|
||||||
|
void UpdateGUI();
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
// Wiimote leds
|
// Wiimote leds
|
||||||
|
@ -220,7 +221,6 @@ class CFrame : public wxFrame
|
||||||
wxMenuItem* m_pMenuItemSave;
|
wxMenuItem* m_pMenuItemSave;
|
||||||
wxToolBarToolBase* m_pToolPlay;
|
wxToolBarToolBase* m_pToolPlay;
|
||||||
|
|
||||||
void UpdateGUI();
|
|
||||||
void BootGame();
|
void BootGame();
|
||||||
|
|
||||||
// Double click and mouse move options
|
// Double click and mouse move options
|
||||||
|
|
|
@ -31,16 +31,17 @@
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Globals.h" // Core
|
|
||||||
#include "Host.h"
|
|
||||||
|
|
||||||
#include "Common.h" // Common
|
#include "Common.h" // Common
|
||||||
#include "CPUDetect.h"
|
#include "CPUDetect.h"
|
||||||
#include "IniFile.h"
|
#include "IniFile.h"
|
||||||
#include "FileUtil.h"
|
#include "FileUtil.h"
|
||||||
#include "ConsoleWindow.h"
|
#include "ConsoleWindow.h"
|
||||||
|
#include "Setup.h"
|
||||||
|
|
||||||
#include "Main.h" // Local
|
#include "Host.h" // Core
|
||||||
|
|
||||||
|
#include "Globals.h" // Local
|
||||||
|
#include "Main.h"
|
||||||
#include "Frame.h"
|
#include "Frame.h"
|
||||||
#include "ConfigManager.h"
|
#include "ConfigManager.h"
|
||||||
#include "CodeWindow.h"
|
#include "CodeWindow.h"
|
||||||
|
@ -458,6 +459,13 @@ void Host_UpdateStatusBar(const char* _pText, int Field)
|
||||||
wxPostEvent(main_frame, event);
|
wxPostEvent(main_frame, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
void Host_UpdateGUI()
|
||||||
|
{
|
||||||
|
main_frame->UpdateGUI();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Host_SysMessage(const char *fmt, ...)
|
void Host_SysMessage(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list list;
|
va_list list;
|
||||||
|
|
|
@ -17,10 +17,14 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Setup.h"
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
#include "../../../Plugins/Plugin_VideoOGL/Src/OS/Win32.h"
|
||||||
|
#endif
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "OpcodeDecoding.h"
|
#include "OpcodeDecoding.h"
|
||||||
#include "Setup.h"
|
#include "ConsoleWindow.h"
|
||||||
|
|
||||||
#include "Fifo.h"
|
#include "Fifo.h"
|
||||||
|
|
||||||
|
@ -96,8 +100,18 @@ void Video_SendFifoData(u8* _uData, u32 len)
|
||||||
void Fifo_ExitLoop()
|
void Fifo_ExitLoop()
|
||||||
{
|
{
|
||||||
fifoStateRun = false;
|
fifoStateRun = false;
|
||||||
|
#ifndef SETUP_TIMER_WAITING
|
||||||
fifo_exit_event.Wait();
|
fifo_exit_event.Wait();
|
||||||
fifo_exit_event.Shutdown();
|
fifo_exit_event.Shutdown();
|
||||||
|
#else
|
||||||
|
//Console::Print("Video: Fifo_ExitLoop: Done:%i\n", fifo_exit_event.DoneWait());
|
||||||
|
if (fifo_exit_event.TimerWait(Fifo_ExitLoop))
|
||||||
|
{
|
||||||
|
//Console::Print("Video: Fifo_Shutdown: Done:%i\n\n", fifo_exit_event.DoneWait());
|
||||||
|
fifo_exit_event.Shutdown();
|
||||||
|
PostMessage(EmuWindow::GetParentWnd(), WM_USER, OPENGL_VIDEO_STOP, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
||||||
|
@ -111,6 +125,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
||||||
#if defined(_WIN32) && !defined(SETUP_AVOID_OPENGL_SCREEN_MESSAGE_HANG)
|
#if defined(_WIN32) && !defined(SETUP_AVOID_OPENGL_SCREEN_MESSAGE_HANG)
|
||||||
video_initialize.pPeekMessages();
|
video_initialize.pPeekMessages();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_fifo.CPReadWriteDistance == 0)
|
if (_fifo.CPReadWriteDistance == 0)
|
||||||
Common::SleepCurrentThread(1);
|
Common::SleepCurrentThread(1);
|
||||||
|
|
||||||
|
@ -187,4 +202,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fifo_exit_event.Set();
|
fifo_exit_event.Set();
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
fifo_exit_event.SetTimer();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,8 @@ enum PLUGIN_COMM
|
||||||
OPENGL_WM_USER_CREATE,
|
OPENGL_WM_USER_CREATE,
|
||||||
NJOY_RELOAD, // Reload nJoy if DirectInput has failed
|
NJOY_RELOAD, // Reload nJoy if DirectInput has failed
|
||||||
WIIMOTE_RECONNECT, // Reconnect the Wiimote if it has disconnected
|
WIIMOTE_RECONNECT, // Reconnect the Wiimote if it has disconnected
|
||||||
INPUT_FRAME_COUNTER // Wind back the frame counter for rerecording
|
INPUT_FRAME_COUNTER, // Wind back the frame counter for rerecording
|
||||||
|
OPENGL_VIDEO_STOP
|
||||||
};
|
};
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "IniFile.h"
|
#include "IniFile.h"
|
||||||
#include "svnrev.h"
|
#include "svnrev.h"
|
||||||
|
#include "Setup.h"
|
||||||
|
|
||||||
#include "Render.h"
|
#include "Render.h"
|
||||||
|
|
||||||
|
@ -770,7 +771,9 @@ void OpenGL_Shutdown()
|
||||||
|
|
||||||
if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) // Are We Able To Release The DC
|
if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) // Are We Able To Release The DC
|
||||||
{
|
{
|
||||||
|
#ifndef SETUP_TIMER_WAITING // This fails
|
||||||
MessageBox(NULL,"Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
|
MessageBox(NULL,"Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
|
||||||
|
#endif
|
||||||
hDC = NULL; // Set DC To NULL
|
hDC = NULL; // Set DC To NULL
|
||||||
}
|
}
|
||||||
#elif defined(HAVE_X11) && HAVE_X11
|
#elif defined(HAVE_X11) && HAVE_X11
|
||||||
|
|
|
@ -148,6 +148,11 @@ HWND GetParentWnd()
|
||||||
return m_hParent;
|
return m_hParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HWND GetChildParentWnd()
|
||||||
|
{
|
||||||
|
return m_hMain;
|
||||||
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
|
LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
|
||||||
{
|
{
|
||||||
HDC hdc;
|
HDC hdc;
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace EmuWindow
|
||||||
|
|
||||||
HWND GetWnd();
|
HWND GetWnd();
|
||||||
HWND GetParentWnd();
|
HWND GetParentWnd();
|
||||||
|
HWND GetChildParentWnd();
|
||||||
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title);
|
HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title);
|
||||||
void Show();
|
void Show();
|
||||||
void Close();
|
void Close();
|
||||||
|
|
|
@ -299,7 +299,9 @@ void Video_Prepare(void)
|
||||||
void Shutdown(void)
|
void Shutdown(void)
|
||||||
{
|
{
|
||||||
Fifo_Shutdown();
|
Fifo_Shutdown();
|
||||||
|
#ifndef SETUP_TIMER_WAITING // This is not compatible, it crashes after the second Stop
|
||||||
TextureConverter::Shutdown();
|
TextureConverter::Shutdown();
|
||||||
|
#endif
|
||||||
VertexLoaderManager::Shutdown();
|
VertexLoaderManager::Shutdown();
|
||||||
VertexShaderCache::Shutdown();
|
VertexShaderCache::Shutdown();
|
||||||
VertexShaderManager::Shutdown();
|
VertexShaderManager::Shutdown();
|
||||||
|
@ -308,8 +310,14 @@ void Shutdown(void)
|
||||||
VertexManager::Shutdown();
|
VertexManager::Shutdown();
|
||||||
TextureMngr::Shutdown();
|
TextureMngr::Shutdown();
|
||||||
OpcodeDecoder_Shutdown();
|
OpcodeDecoder_Shutdown();
|
||||||
|
#ifndef SETUP_TIMER_WAITING // This is not compatible, it may crashes after a Stop
|
||||||
Renderer::Shutdown();
|
Renderer::Shutdown();
|
||||||
|
#endif
|
||||||
OpenGL_Shutdown();
|
OpenGL_Shutdown();
|
||||||
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
// Do we ever destroy the window?
|
||||||
|
EmuWindow::Close();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue