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:
John Peterson 2009-02-22 21:16:12 +00:00
parent 769160dfbd
commit 927815bc9b
16 changed files with 367 additions and 31 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
} }

View File

@ -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

View File

@ -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);

View File

@ -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);
} }

View File

@ -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

View File

@ -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;

View File

@ -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
} }

View File

@ -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
}; };
/////////////////////////////// ///////////////////////////////

View File

@ -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"
@ -768,9 +769,11 @@ void OpenGL_Shutdown()
hRC = NULL; // Set RC To NULL hRC = NULL; // Set RC To NULL
} }
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

View File

@ -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;

View File

@ -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();

View File

@ -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
} }