The Mega Change Of Doom - or, fixing Stop. Almost. At least it's better than before. However, the OpenGL plugin seems to lose textures a lot between game restarts :P I think the GL plugin needs to do a lot more cleanup.

This change also includes tons of minor code formatting cleanup. Yeah, should've separated it ... sorry :(

Kills the old CPUCompare support. I'll resurrect it if I need it again, right now it mostly clutters the code.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2321 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-02-20 22:04:52 +00:00
parent f992dae50d
commit 6cd34b318f
47 changed files with 685 additions and 1088 deletions

View File

@ -15,10 +15,8 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
/*
All plugins from Core > Plugins are loaded and unloaded with this class when
Dolpin is started and stopped.
*/
// All plugins from Core > Plugins are loaded and unloaded with this class when
// Dolphin is started and stopped.
#include <string.h> // System
#ifdef _WIN32
@ -34,7 +32,6 @@
#include "DynamicLibrary.h"
#include "ConsoleWindow.h"
DynamicLibrary::DynamicLibrary()
{
library = 0;
@ -42,33 +39,33 @@ DynamicLibrary::DynamicLibrary()
std::string GetLastErrorAsString()
{
#ifdef _WIN32
LPVOID lpMsgBuf = 0;
DWORD error = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0, NULL);
std::string s;
if (lpMsgBuf)
{
s = ((char *)lpMsgBuf);
LocalFree(lpMsgBuf);
} else {
s = StringFromFormat("(unknown error %08x)", error);
}
return s;
#else
static std::string errstr;
char *tmp = dlerror();
if (tmp)
errstr = tmp;
return errstr;
#endif
#ifdef _WIN32
LPVOID lpMsgBuf = 0;
DWORD error = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0, NULL);
std::string s;
if (lpMsgBuf)
{
s = ((char *)lpMsgBuf);
LocalFree(lpMsgBuf);
} else {
s = StringFromFormat("(unknown error %08x)", error);
}
return s;
#else
static std::string errstr;
char *tmp = dlerror();
if (tmp)
errstr = tmp;
return errstr;
#endif
}
/* Function: Loading means loading the dll with LoadLibrary() to get an
@ -81,15 +78,16 @@ std::string GetLastErrorAsString()
Called from: The Dolphin Core */
int DynamicLibrary::Load(const char* filename)
{
if (!filename || strlen(filename) == 0) {
LOG(MASTER_LOG, "Missing filename of dynamic library to load");
PanicAlert("Missing filename of dynamic library to load");
return 0;
if (!filename || strlen(filename) == 0)
{
LOG(MASTER_LOG, "Missing filename of dynamic library to load");
PanicAlert("Missing filename of dynamic library to load");
return 0;
}
LOG(MASTER_LOG, "Trying to load library %s", filename);
if (IsLoaded()) {
LOG(MASTER_LOG, "Trying to load already loaded library %s", filename);
return 2;
if (IsLoaded())
{
LOG(MASTER_LOG, "Trying to load already loaded library %s", filename);
return 2;
}
Console::Print("LoadLibrary: %s", filename);
@ -99,10 +97,11 @@ int DynamicLibrary::Load(const char* filename)
library = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
#endif
Console::Print(" %p\n", library);
if (!library) {
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, GetLastErrorAsString().c_str());
PanicAlert("Error loading DLL %s: %s\n", filename, GetLastErrorAsString().c_str());
return 0;
if (!library)
{
LOG(MASTER_LOG, "Error loading DLL %s: %s", filename, GetLastErrorAsString().c_str());
PanicAlert("Error loading DLL %s: %s\n", filename, GetLastErrorAsString().c_str());
return 0;
}
library_file = filename;
@ -111,28 +110,29 @@ int DynamicLibrary::Load(const char* filename)
int DynamicLibrary::Unload()
{
int retval;
if (!IsLoaded()) {
PanicAlert("Error unloading DLL %s: not loaded", library_file.c_str());
return 0;
}
int retval;
if (!IsLoaded())
{
PanicAlert("Error unloading DLL %s: not loaded", library_file.c_str());
return 0;
}
Console::Print("FreeLibrary: %s %p\n", library_file.c_str(), library);
Console::Print("FreeLibrary: %s %p\n", library_file.c_str(), library);
#ifdef _WIN32
retval = FreeLibrary(library);
retval = FreeLibrary(library);
#else
retval = dlclose(library)?0:1;
retval = dlclose(library)?0:1;
#endif
if (! retval) {
PanicAlert("Error unloading DLL %s: %s", library_file.c_str(),
GetLastErrorAsString().c_str());
}
library = 0;
return retval;
if (!retval)
{
PanicAlert("Error unloading DLL %s: %s", library_file.c_str(),
GetLastErrorAsString().c_str());
}
library = 0;
return retval;
}
void* DynamicLibrary::Get(const char* funcname) const
{
void* retval;
@ -156,5 +156,3 @@ void* DynamicLibrary::Get(const char* funcname) const
return retval;
}

View File

@ -14,17 +14,12 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
//////////////////////////////////////////////////////////////////////////////////////////
// Include
/* ¯¯¯¯¯¯¯¯¯¯¯¯
File description: This is the common Plugin class that links to the functions that are
common to all plugins. This class is inherited by all plugin classes. But it's only created
directly in PluginManager.cpp when we check if a plugin is valid or not.
///////////////////////////////////////////////*/
////////////////////////////////////////////////
// This is the common Plugin class that links to the functions that are
// common to all plugins. This class is inherited by all plugin classes. But it's only created
// directly in PluginManager.cpp when we check if a plugin is valid or not.
///////////////////////////////////////////////
#include "Plugin.h"
@ -33,21 +28,20 @@ namespace Common
CPlugin::~CPlugin()
{
m_hInstLib.Unload();
m_hInstLib.Unload();
}
CPlugin::CPlugin(const char* _szName) : valid(false)
{
m_GetDllInfo = NULL;
m_DllConfig = NULL;
m_DllDebugger = NULL;
m_SetDllGlobals = NULL;
m_Initialize = NULL;
m_Shutdown = NULL;
m_DoState = NULL;
if (m_hInstLib.Load(_szName))
m_GetDllInfo = NULL;
m_DllConfig = NULL;
m_DllDebugger = NULL;
m_SetDllGlobals = NULL;
m_Initialize = NULL;
m_Shutdown = NULL;
m_DoState = NULL;
if (m_hInstLib.Load(_szName))
{
m_GetDllInfo = reinterpret_cast<TGetDllInfo>
(m_hInstLib.Get("GetDllInfo"));
@ -66,7 +60,7 @@ CPlugin::CPlugin(const char* _szName) : valid(false)
}
// Check if the plugin has all the functions it shold have
if (m_GetDllInfo != 0 &&
if (m_GetDllInfo != 0 &&
m_DllConfig != 0 &&
m_DllDebugger != 0 &&
m_SetDllGlobals != 0 &&
@ -81,63 +75,57 @@ CPlugin::CPlugin(const char* _szName) : valid(false)
void *CPlugin::LoadSymbol(const char *sym)
{
return m_hInstLib.Get(sym);
return m_hInstLib.Get(sym);
}
// GetInfo: Get DLL info
bool CPlugin::GetInfo(PLUGIN_INFO& _pluginInfo)
{
if (m_GetDllInfo != NULL) {
m_GetDllInfo(&_pluginInfo);
return(true);
}
return(false);
if (m_GetDllInfo != NULL) {
m_GetDllInfo(&_pluginInfo);
return(true);
}
return(false);
}
// Config: Open the Config window
void CPlugin::Config(HWND _hwnd)
{
if (m_DllConfig != NULL)
m_DllConfig(_hwnd);
if (m_DllConfig != NULL)
m_DllConfig(_hwnd);
}
// Debug: Open the Debugging window
void CPlugin::Debug(HWND _hwnd, bool Show)
{
if (m_DllDebugger != NULL)
m_DllDebugger(_hwnd, Show);
if (m_DllDebugger != NULL)
m_DllDebugger(_hwnd, Show);
}
void CPlugin::SetGlobals(PLUGIN_GLOBALS* _pluginGlobals) {
if (m_SetDllGlobals != NULL)
m_SetDllGlobals(_pluginGlobals);
if (m_SetDllGlobals != NULL)
m_SetDllGlobals(_pluginGlobals);
}
void CPlugin::DoState(unsigned char **ptr, int mode) {
if (m_DoState != NULL)
m_DoState(ptr, mode);
if (m_DoState != NULL)
m_DoState(ptr, mode);
}
// Run Initialize() in the plugin
void CPlugin::Initialize(void *init)
{
/* We first check that we have found the Initialize() function, but there
is no restriction on running this several times */
if (m_Initialize != NULL)
m_Initialize(init);
/* We first check that we have found the Initialize() function, but there
is no restriction on running this several times */
// Uh, the above comment sounds extremely dubious.
if (m_Initialize != NULL)
m_Initialize(init);
}
void CPlugin::Shutdown()
{
if (m_Shutdown != NULL)
m_Shutdown();
if (m_Shutdown != NULL)
m_Shutdown();
}
} // end of namespace Common

View File

@ -1,36 +1,41 @@
#include "PluginDSP.h"
namespace Common {
PluginDSP::PluginDSP(const char *_Filename) : CPlugin(_Filename), validDSP(false) {
PluginDSP::PluginDSP(const char *_Filename) : CPlugin(_Filename), validDSP(false) {
DSP_ReadMailboxHigh = reinterpret_cast<TDSP_ReadMailBox>
(LoadSymbol("DSP_ReadMailboxHigh"));
DSP_ReadMailboxLow = reinterpret_cast<TDSP_ReadMailBox>
(LoadSymbol("DSP_ReadMailboxLow"));
DSP_WriteMailboxHigh = reinterpret_cast<TDSP_WriteMailBox>
(LoadSymbol("DSP_WriteMailboxHigh"));
DSP_WriteMailboxLow = reinterpret_cast<TDSP_WriteMailBox>
(LoadSymbol("DSP_WriteMailboxLow"));
DSP_ReadControlRegister = reinterpret_cast<TDSP_ReadControlRegister>
(LoadSymbol("DSP_ReadControlRegister"));
DSP_WriteControlRegister = reinterpret_cast<TDSP_WriteControlRegister>
(LoadSymbol("DSP_WriteControlRegister"));
DSP_Update = reinterpret_cast<TDSP_Update>
(LoadSymbol("DSP_Update"));
DSP_SendAIBuffer = reinterpret_cast<TDSP_SendAIBuffer>
(LoadSymbol("DSP_SendAIBuffer"));
(LoadSymbol("DSP_ReadMailboxHigh"));
DSP_ReadMailboxLow = reinterpret_cast<TDSP_ReadMailBox>
(LoadSymbol("DSP_ReadMailboxLow"));
DSP_WriteMailboxHigh = reinterpret_cast<TDSP_WriteMailBox>
(LoadSymbol("DSP_WriteMailboxHigh"));
DSP_WriteMailboxLow = reinterpret_cast<TDSP_WriteMailBox>
(LoadSymbol("DSP_WriteMailboxLow"));
DSP_ReadControlRegister = reinterpret_cast<TDSP_ReadControlRegister>
(LoadSymbol("DSP_ReadControlRegister"));
DSP_WriteControlRegister = reinterpret_cast<TDSP_WriteControlRegister>
(LoadSymbol("DSP_WriteControlRegister"));
DSP_Update = reinterpret_cast<TDSP_Update>
(LoadSymbol("DSP_Update"));
DSP_SendAIBuffer = reinterpret_cast<TDSP_SendAIBuffer>
(LoadSymbol("DSP_SendAIBuffer"));
DSP_StopSoundStream = reinterpret_cast<TDSP_StopSoundStream>
(LoadSymbol("DSP_StopSoundStream"));
if ((DSP_ReadMailboxHigh != 0) &&
(DSP_ReadMailboxLow != 0) &&
(DSP_WriteMailboxHigh != 0) &&
(DSP_WriteMailboxLow != 0) &&
(DSP_ReadControlRegister != 0) &&
(DSP_WriteControlRegister != 0) &&
(DSP_SendAIBuffer != 0) &&
(DSP_Update != 0))
validDSP = true;
}
PluginDSP::~PluginDSP() {
}
(DSP_ReadMailboxLow != 0) &&
(DSP_WriteMailboxHigh != 0) &&
(DSP_WriteMailboxLow != 0) &&
(DSP_ReadControlRegister != 0) &&
(DSP_WriteControlRegister != 0) &&
(DSP_SendAIBuffer != 0) &&
(DSP_Update != 0) &&
(DSP_StopSoundStream != 0))
validDSP = true;
}
PluginDSP::~PluginDSP() {
}
} // namespace

View File

@ -5,33 +5,37 @@
#include "Plugin.h"
namespace Common {
typedef void (__cdecl* TDSP_WriteMailBox)(bool _CPUMailbox, unsigned short);
typedef unsigned short (__cdecl* TDSP_ReadMailBox)(bool _CPUMailbox);
typedef unsigned short (__cdecl* TDSP_ReadControlRegister)();
typedef unsigned short (__cdecl* TDSP_WriteControlRegister)(unsigned short);
typedef void (__cdecl* TDSP_SendAIBuffer)(unsigned int address, int sample_rate);
typedef void (__cdecl* TDSP_Update)(int cycles);
class PluginDSP : public CPlugin
{
public:
typedef void (__cdecl* TDSP_WriteMailBox)(bool _CPUMailbox, unsigned short);
typedef unsigned short (__cdecl* TDSP_ReadMailBox)(bool _CPUMailbox);
typedef unsigned short (__cdecl* TDSP_ReadControlRegister)();
typedef unsigned short (__cdecl* TDSP_WriteControlRegister)(unsigned short);
typedef void (__cdecl* TDSP_SendAIBuffer)(unsigned int address, int sample_rate);
typedef void (__cdecl* TDSP_Update)(int cycles);
typedef void (__cdecl* TDSP_StopSoundStream)();
class PluginDSP : public CPlugin
{
public:
PluginDSP(const char *_Filename);
~PluginDSP();
virtual bool IsValid() {return validDSP;};
TDSP_ReadMailBox DSP_ReadMailboxHigh;
TDSP_ReadMailBox DSP_ReadMailboxLow;
TDSP_WriteMailBox DSP_WriteMailboxHigh;
TDSP_ReadMailBox DSP_ReadMailboxHigh;
TDSP_ReadMailBox DSP_ReadMailboxLow;
TDSP_WriteMailBox DSP_WriteMailboxHigh;
TDSP_WriteMailBox DSP_WriteMailboxLow;
TDSP_ReadControlRegister DSP_ReadControlRegister;
TDSP_WriteControlRegister DSP_WriteControlRegister;
TDSP_SendAIBuffer DSP_SendAIBuffer;
TDSP_SendAIBuffer DSP_SendAIBuffer;
TDSP_Update DSP_Update;
TDSP_StopSoundStream DSP_StopSoundStream;
private:
private:
bool validDSP;
};
}
};
} // namespace
#endif

View File

@ -2,41 +2,42 @@
namespace Common
{
PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo(false)
{
PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo(false)
{
Video_Prepare = 0;
Video_SendFifoData = 0;
Video_UpdateXFB = 0;
Video_EnterLoop = 0;
Video_ExitLoop = 0;
Video_Screenshot = 0;
Video_AddMessage = 0;
Video_Stop = 0;
Video_Prepare = reinterpret_cast<TVideo_Prepare>
(LoadSymbol("Video_Prepare"));
Video_Prepare = reinterpret_cast<TVideo_Prepare>
(LoadSymbol("Video_Prepare"));
Video_SendFifoData = reinterpret_cast<TVideo_SendFifoData>
(LoadSymbol("Video_SendFifoData"));
Video_UpdateXFB = reinterpret_cast<TVideo_UpdateXFB>
(LoadSymbol("Video_UpdateXFB"));
Video_Screenshot = reinterpret_cast<TVideo_Screenshot>
(LoadSymbol("Video_Screenshot"));
Video_EnterLoop = reinterpret_cast<TVideo_EnterLoop>
(LoadSymbol("Video_EnterLoop"));
Video_AddMessage = reinterpret_cast<TVideo_AddMessage>
(LoadSymbol("Video_AddMessage"));
Video_Stop = reinterpret_cast<TVideo_Stop>
(LoadSymbol("Video_Stop"));
(LoadSymbol("Video_SendFifoData"));
Video_UpdateXFB = reinterpret_cast<TVideo_UpdateXFB>
(LoadSymbol("Video_UpdateXFB"));
Video_Screenshot = reinterpret_cast<TVideo_Screenshot>
(LoadSymbol("Video_Screenshot"));
Video_EnterLoop = reinterpret_cast<TVideo_EnterLoop>
(LoadSymbol("Video_EnterLoop"));
Video_ExitLoop = reinterpret_cast<TVideo_ExitLoop>
(LoadSymbol("Video_ExitLoop"));
Video_AddMessage = reinterpret_cast<TVideo_AddMessage>
(LoadSymbol("Video_AddMessage"));
if ((Video_Prepare != 0) &&
(Video_SendFifoData != 0) &&
(Video_UpdateXFB != 0) &&
(Video_EnterLoop != 0) &&
(Video_Screenshot != 0) &&
(Video_AddMessage != 0) &&
(Video_Stop != 0))
validVideo = true;
}
PluginVideo::~PluginVideo() {}
if ((Video_Prepare != 0) &&
(Video_SendFifoData != 0) &&
(Video_UpdateXFB != 0) &&
(Video_EnterLoop != 0) &&
(Video_ExitLoop != 0) &&
(Video_Screenshot != 0) &&
(Video_AddMessage != 0))
validVideo = true;
}
PluginVideo::~PluginVideo() {}
} // namespace

View File

@ -10,8 +10,8 @@ namespace Common {
typedef void (__cdecl* TVideo_UpdateXFB)(u8*, u32, u32, s32, bool);
typedef bool (__cdecl* TVideo_Screenshot)(const char* filename);
typedef void (__cdecl* TVideo_EnterLoop)();
typedef void (__cdecl* TVideo_ExitLoop)();
typedef void (__cdecl* TVideo_AddMessage)(const char* pstr, unsigned int milliseconds);
typedef void (__cdecl* TVideo_Stop)();
class PluginVideo : public CPlugin
{
@ -22,15 +22,15 @@ namespace Common {
TVideo_Prepare Video_Prepare;
TVideo_SendFifoData Video_SendFifoData;
TVideo_UpdateXFB Video_UpdateXFB;
TVideo_Screenshot Video_Screenshot;
TVideo_EnterLoop Video_EnterLoop;
TVideo_ExitLoop Video_ExitLoop;
TVideo_UpdateXFB Video_UpdateXFB;
TVideo_AddMessage Video_AddMessage;
TVideo_Stop Video_Stop;
TVideo_Screenshot Video_Screenshot;
private:
bool validVideo;
};
}

View File

@ -15,11 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef __SETUP_h__
#define __SETUP_h__
////////////////////////////////////////////////////////////////////////////////////////
// File description
/* ¯¯¯¯¯¯¯¯¯¯¯¯
@ -31,18 +29,10 @@
////////////////////////*/
////////////////////////////////////////////////////////////////////////////////////////
// Settings
// ¯¯¯¯¯¯¯¯¯¯¯¯
// This may fix a problem with Stop and Start that I described in the comments to revision 2,139
//#define SETUP_FREE_PLUGIN_ON_BOOT
// This may fix a semi-frequent hanging that occured when I used single core and render to main frame
//#define SETUP_AVOID_SINGLE_CORE_HANG_ON_STOP
// This may remove sound artifacts in Wario Land Shake It and perhaps other games
//#define SETUP_AVOID_SOUND_ARTIFACTS
@ -54,5 +44,4 @@
///////////////////////////
#endif // __SETUP_h__

View File

@ -22,6 +22,12 @@
namespace Common
{
#ifdef _WIN32
void InitThreading()
{
// Nothing to do in Win32 build.
}
CriticalSection::CriticalSection(int spincount)
{
if (spincount)
@ -34,25 +40,21 @@ CriticalSection::CriticalSection(int spincount)
}
}
CriticalSection::~CriticalSection()
{
DeleteCriticalSection(&section);
}
void CriticalSection::Enter()
{
EnterCriticalSection(&section);
}
bool CriticalSection::TryEnter()
{
return TryEnterCriticalSection(&section) ? true : false;
}
void CriticalSection::Leave()
{
LeaveCriticalSection(&section);
@ -71,13 +73,11 @@ Thread::Thread(ThreadFunc function, void* arg)
&m_threadId);
}
Thread::~Thread()
{
WaitForDeath();
}
void Thread::WaitForDeath()
{
if (m_hThread)
@ -88,13 +88,11 @@ void Thread::WaitForDeath()
}
}
void Thread::SetAffinity(int mask)
{
SetThreadAffinityMask(m_hThread, mask);
}
void Thread::SetCurrentThreadAffinity(int mask)
{
SetThreadAffinityMask(GetCurrentThread(), mask);
@ -106,32 +104,27 @@ Event::Event()
m_hEvent = 0;
}
void Event::Init()
{
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
void Event::Shutdown()
{
CloseHandle(m_hEvent);
m_hEvent = 0;
}
void Event::Set()
{
SetEvent(m_hEvent);
}
void Event::Wait()
{
WaitForSingleObject(m_hEvent, INFINITE);
}
void SleepCurrentThread(int ms)
{
Sleep(ms);
@ -304,12 +297,13 @@ void Thread::SetCurrentThreadAffinity(int mask)
void InitThreading() {
static int thread_init_done = 0;
if (thread_init_done) return;
thread_init_done++;
if (thread_init_done)
return;
if (pthread_key_create(&threadname_key, NULL/*free*/) != 0)
perror("Unable to create thread name key: ");
thread_init_done++;
}
void SleepCurrentThread(int ms)

View File

@ -63,12 +63,11 @@ public:
Thread(ThreadFunc entry, void* arg);
~Thread();
void WaitForDeath();
void SetAffinity(int mask);
static void SetCurrentThreadAffinity(int mask);
private:
void WaitForDeath();
#ifdef _WIN32
HANDLE m_hThread;
@ -81,29 +80,26 @@ private:
class Event
{
public:
public:
Event();
Event();
void Init();
void Shutdown();
void Init();
void Shutdown();
void Set();
void Wait();
private:
void Set();
void Wait();
private:
#ifdef _WIN32
HANDLE m_hEvent;
HANDLE m_hEvent;
#else
bool is_set_;
pthread_cond_t event_;
pthread_mutex_t mutex_;
bool is_set_;
pthread_cond_t event_;
pthread_mutex_t mutex_;
#endif
};
void InitThreading(void);
void InitThreading();
void SleepCurrentThread(int ms);
void SetCurrentThreadName(const char *name);
@ -114,5 +110,4 @@ LONG SyncInterlockedIncrement(LONG *Dest);
} // end of namespace Common
#endif

View File

@ -120,11 +120,12 @@ u64 Timer::GetTimeElapsed(void)
std::string Timer::GetTimeElapsedFormatted(void)
{
// If we have not started yet, return zero
if(m_StartTime == 0) return "00:00:00:000";
if (m_StartTime == 0)
return "00:00:00:000";
// The number of milliseconds since the start, use a different value if the timer is stopped
u32 Milliseconds;
if(m_Running)
if (m_Running)
Milliseconds = timeGetTime() - m_StartTime;
else
Milliseconds = m_LastTime - m_StartTime;

View File

@ -279,7 +279,7 @@
AssemblerListingLocation="$(IntDir)\"
WarningLevel="3"
WarnAsError="false"
DebugInformationFormat="0"
DebugInformationFormat="3"
ForcedIncludeFiles="stdafx.h"
/>
<Tool
@ -655,14 +655,6 @@
RelativePath=".\Src\Hw\CPU.h"
>
</File>
<File
RelativePath=".\Src\Hw\CPUCompare.cpp"
>
</File>
<File
RelativePath=".\Src\Hw\CPUCompare.h"
>
</File>
<File
RelativePath=".\Src\Hw\HW.cpp"
>

View File

@ -42,7 +42,6 @@
#include "HW/PeripheralInterface.h"
#include "HW/GPFifo.h"
#include "HW/CPU.h"
#include "HW/CPUCompare.h"
#include "HW/HW.h"
#include "HW/DSP.h"
#include "HW/GPFifo.h"
@ -105,9 +104,13 @@ void Stop();
bool g_bHwInit = false;
bool g_bRealWiimote = false;
HWND g_pWindowHandle = NULL;
Common::Thread* g_pThread = NULL;
SCoreStartupParameter g_CoreStartupParameter;
Common::Thread* g_EmuThread = NULL;
SCoreStartupParameter g_CoreStartupParameter;
// This event is set when the emuthread starts.
Common::Event emuThreadGoing;
Common::Event cpuRunloopQuit;
//////////////////////////////////////
@ -137,7 +140,7 @@ void Callback_DebuggerBreak()
CCPU::Break();
}
void* GetWindowHandle()
void *GetWindowHandle()
{
return g_pWindowHandle;
}
@ -146,6 +149,7 @@ bool GetRealWiimote()
{
return g_bRealWiimote;
}
// This can occur when the emulator is not running and the nJoy configuration window is opened
void ReconnectPad()
{
@ -154,26 +158,30 @@ void ReconnectPad()
Plugins.GetPad(0)->Config(g_pWindowHandle);
Console::Print("ReconnectPad()\n");
}
// This doesn't work yet, I don't understand how the connection work yet
void ReconnectWiimote()
{
// This seems to be a hack that just sets some IPC registers to zero. Dubious.
HW::InitWiimote();
Console::Print("ReconnectWiimote()\n");
}
/////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// This is called from the GUI thread. See the booting call schedule in BootManager.cpp
// -----------------
bool Init()
{
if (g_pThread != NULL)
if (g_EmuThread != NULL)
{
PanicAlert("ERROR: Emu Thread already running. Report this bug.");
return false;
}
Common::InitThreading();
// Get a handle to the current instance of the plugin manager
CPluginManager &pManager = CPluginManager::GetInstance();
SCoreStartupParameter &_CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
@ -181,60 +189,63 @@ bool Init()
g_CoreStartupParameter = _CoreParameter;
LogManager::Init();
Host_SetWaitCursor(true);
// Start the thread again
_dbg_assert_(HLE, g_pThread == NULL);
_dbg_assert_(HLE, g_EmuThread == NULL);
// Check that all plugins exist, potentially call LoadLibrary() for unloaded plugins
if (!pManager.InitPlugins()) return false;
if (!pManager.InitPlugins())
return false;
emuThreadGoing.Init();
// This will execute EmuThread() further down in this file
g_pThread = new Common::Thread(EmuThread, NULL);
g_EmuThread = new Common::Thread(EmuThread, NULL);
emuThreadGoing.Wait();
emuThreadGoing.Shutdown();
// all right ... here we go
// All right, the event is set and killed. We are now running.
Host_SetWaitCursor(false);
DisplayMessage("CPU: " + cpu_info.Summarize(), 8000);
DisplayMessage(_CoreParameter.m_strFilename, 3000);
//PluginVideo::DllDebugger(NULL);
return true;
}
// Called from GUI thread or VI thread
// Called from GUI thread or VI thread (why VI??? That must be bad. Window close? TODO: Investigate.)
void Stop() // - Hammertime!
{
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
Host_SetWaitCursor(true);
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
return;
// stop the CPU
PowerPC::Stop();
CCPU::StepOpcode(); //kick it if it's waiting
cpuRunloopQuit.Wait();
cpuRunloopQuit.Shutdown();
// At this point, we must be out of the CPU:s runloop.
// Silence audio - stops audio thread.
CPluginManager::GetInstance().GetDSP()->DSP_StopSoundStream();
// If dual core mode, the CPU thread should immediately exit here.
// The quit is to get it out of its message loop
// Should be moved inside the plugin.
#ifdef _WIN32
PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
#else
CPluginManager::GetInstance().GetVideo()->Video_Stop();
#endif
if (_CoreParameter.bUseDualCore)
CPluginManager::GetInstance().GetVideo()->Video_ExitLoop();
#ifdef _WIN32
/* I have to use this to avoid the hangings, it seems harmless and it works so I'm
okay with it */
if (GetParent((HWND)g_pWindowHandle) == NULL)
delete g_pThread; // Wait for emuthread to close
#else
delete g_pThread;
PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
#endif
g_pThread = 0;
Core::StopTrace();
LogManager::Shutdown();
Host_SetWaitCursor(false);
delete g_EmuThread; // Wait for emuthread to close.
g_EmuThread = 0;
}
@ -243,31 +254,19 @@ void Stop() // - Hammertime!
// ---------------
THREAD_RETURN CpuThread(void *pArg)
{
Common::SetCurrentThreadName("CPU thread");
Common::SetCurrentThreadName("CPU thread");
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
if (!_CoreParameter.bUseDualCore)
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
if (!_CoreParameter.bUseDualCore)
{
//wglMakeCurrent
CPluginManager::GetInstance().GetVideo()->Video_Prepare();
//wglMakeCurrent
CPluginManager::GetInstance().GetVideo()->Video_Prepare();
}
if (_CoreParameter.bRunCompareServer)
{
CPUCompare::StartServer();
PowerPC::Start();
}
else if (_CoreParameter.bRunCompareClient)
{
PanicAlert("Compare Debug : Press OK when ready.");
CPUCompare::ConnectAsClient();
}
if (_CoreParameter.bLockThreads)
if (_CoreParameter.bLockThreads)
Common::Thread::SetCurrentThreadAffinity(1); // Force to first core
if (_CoreParameter.bUseFastMem)
if (_CoreParameter.bUseFastMem)
{
#ifdef _M_X64
// Let's run under memory watch
@ -279,13 +278,10 @@ THREAD_RETURN CpuThread(void *pArg)
#endif
}
CCPU::Run();
if (_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)
{
CPUCompare::Stop();
}
return 0;
// Enter CPU run loop. When we leave it - we are done.
CCPU::Run();
cpuRunloopQuit.Set();
return 0;
}
//////////////////////////////////////////
@ -293,10 +289,11 @@ THREAD_RETURN CpuThread(void *pArg)
//////////////////////////////////////////////////////////////////////////////////////////
// Initalize plugins and create emulation thread
// -------------
/* Call browser: Init():g_pThread(). See the BootManager.cpp file description for a complete
call schedule. */
// Call browser: Init():g_EmuThread(). See the BootManager.cpp file description for a complete call schedule.
THREAD_RETURN EmuThread(void *pArg)
{
cpuRunloopQuit.Init();
Common::SetCurrentThreadName("Emuthread - starting");
const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
@ -331,10 +328,6 @@ THREAD_RETURN EmuThread(void *pArg)
VideoInitialize.pKeyPress = Callback_KeyPress;
VideoInitialize.bWii = _CoreParameter.bWii;
VideoInitialize.bUseDualCore = _CoreParameter.bUseDualCore;
// Needed for Stop and Start
#ifdef SETUP_FREE_PLUGIN_ON_BOOT
Plugins.FreeVideo();
#endif
Plugins.GetVideo()->Initialize(&VideoInitialize); // Call the dll
// Under linux, this is an X11 Display, not an HWND!
@ -355,10 +348,6 @@ THREAD_RETURN EmuThread(void *pArg)
dspInit.pGetAudioStreaming = AudioInterface::Callback_GetStreaming;
dspInit.pEmulatorState = (int *)PowerPC::GetStatePtr();
dspInit.bWii = _CoreParameter.bWii;
// Needed for Stop and Start
#ifdef SETUP_FREE_PLUGIN_ON_BOOT
Plugins.FreeDSP();
#endif
Plugins.GetDSP()->Initialize((void *)&dspInit);
// Load and Init PadPlugin
@ -400,29 +389,31 @@ THREAD_RETURN EmuThread(void *pArg)
// The hardware is initialized.
g_bHwInit = true;
DisplayMessage("CPU: " + cpu_info.Summarize(), 8000);
DisplayMessage(_CoreParameter.m_strFilename, 3000);
// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
PowerPC::SetMode(PowerPC::MODE_INTERPRETER);
CBoot::BootUp();
if( g_pUpdateFPSDisplay != NULL )
g_pUpdateFPSDisplay("Loading...");
if (g_pUpdateFPSDisplay != NULL)
g_pUpdateFPSDisplay(("Loading " + _CoreParameter.m_strFilename).c_str());
// setup our core, but can't use dynarec if we are compare server
// Setup our core, but can't use dynarec if we are compare server
if (_CoreParameter.bUseJIT && (!_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient))
PowerPC::SetMode(PowerPC::MODE_JIT);
else
PowerPC::SetMode(PowerPC::MODE_INTERPRETER);
// update the window again because all stuff is initialized
// Update the window again because all stuff is initialized
Host_UpdateDisasmDialog();
Host_UpdateMainFrame();
//This thread, after creating the EmuWindow, spawns a CPU thread,
//then takes over and becomes the graphics thread
// This thread, after creating the EmuWindow, spawns a CPU thread,
// then takes over and becomes the graphics thread
//In single core mode, the CPU thread does the graphics. In fact, the
//CPU thread should in this case also create the emuwindow...
// In single core mode, this thread is the CPU thread and also does the graphics.
// Spawn the CPU thread
Common::Thread *cpuThread = NULL;
@ -433,34 +424,36 @@ THREAD_RETURN EmuThread(void *pArg)
if (!_CoreParameter.bUseDualCore)
{
#ifdef _WIN32
cpuThread = new Common::Thread(CpuThread, pArg);
//Common::SetCurrentThreadName("Idle thread");
//TODO(ector) : investigate using GetMessage instead .. although
//then we lose the powerdown check. ... unless powerdown sends a message :P
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
{
if (Callback_PeekMessages)
Callback_PeekMessages();
Common::SleepCurrentThread(20);
}
#else
// In single-core mode, the Emulation main thread is also the CPU thread
CpuThread(pArg);
#endif
#ifdef _WIN32
cpuThread = new Common::Thread(CpuThread, pArg);
// Common::SetCurrentThreadName("Idle thread");
// TODO(ector) : investigate using GetMessage instead .. although
// then we lose the powerdown check. ... unless powerdown sends a message :P
while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN)
{
if (Callback_PeekMessages)
Callback_PeekMessages();
Common::SleepCurrentThread(20);
}
#else
// In single-core mode, the Emulation main thread is also the CPU thread
CpuThread(pArg);
#endif
}
else
{
Plugins.GetVideo()->Video_Prepare(); // wglMakeCurrent
cpuThread = new Common::Thread(CpuThread, pArg);
Common::SetCurrentThreadName("Video thread");
Plugins.GetVideo()->Video_EnterLoop();
Plugins.GetVideo()->Video_Prepare(); // wglMakeCurrent
cpuThread = new Common::Thread(CpuThread, pArg);
Common::SetCurrentThreadName("Video thread");
// I bet that many of our stopping problems come from this loop not properly exiting.
Plugins.GetVideo()->Video_EnterLoop();
}
// We have now exited the Video Loop and will shut down
// does this comment still apply?
/* Check if we are using single core and are rendering to the main window. In that case we must avoid the WaitForSingleObject()
loop in the cpu thread thread, because it will hang on occation, perhaps one time in three or so. I had this problem in the Wiimote plugin, what happened was that if I entered the
WaitForSingleObject loop or any loop at all in the main thread, the separate thread would halt at a place where it called a function in
@ -468,21 +461,14 @@ THREAD_RETURN EmuThread(void *pArg)
Perhaps something like that can be done here to? I just don't exactly how since in single core mode there should only be one
thread right? So how can WaitForSingleObject() hang in it? */
bool bRenderToMainSingleCore = false;
#ifdef SETUP_AVOID_SINGLE_CORE_HANG_ON_STOP
if (GetParent((HWND)g_pWindowHandle) == NULL || _CoreParameter.bUseDualCore) bRenderToMainSingleCore = true;
#endif
/* Wait for CPU thread to exit - it should have been signaled to do so by now. On the other hand this will be called by
delete cpuThread to. So now we call it twice right? */
if(!bRenderToMainSingleCore) if (cpuThread) cpuThread->WaitForDeath();
// Write message
if (g_pUpdateFPSDisplay != NULL) g_pUpdateFPSDisplay("Stopping...");
if (g_pUpdateFPSDisplay != NULL)
g_pUpdateFPSDisplay("Stopping...");
if (cpuThread)
{
// This joins the cpu thread.
if(!bRenderToMainSingleCore) delete cpuThread;
// There is a CPU thread - join it.
delete cpuThread;
// Returns after game exited
cpuThread = NULL;
}
@ -500,7 +486,6 @@ THREAD_RETURN EmuThread(void *pArg)
if (_CoreParameter.hMainWindow == g_pWindowHandle)
Host_UpdateMainFrame();
//Console::Close();
return 0;
}
@ -508,27 +493,23 @@ THREAD_RETURN EmuThread(void *pArg)
//////////////////////////////////////////////////////////////////////////////////////////
// Set or get the running state
// --------------
bool SetState(EState _State)
void SetState(EState _State)
{
switch(_State)
switch (_State)
{
case CORE_UNINITIALIZED:
Stop();
break;
case CORE_PAUSE:
CCPU::EnableStepping(true); // Break
break;
case CORE_RUN:
CCPU::EnableStepping(false);
break;
default:
return false;
PanicAlert("Invalid state");
break;
}
return true;
}
EState GetState()
@ -589,7 +570,7 @@ void Callback_VideoLog(const TCHAR *_szMessage, int _bDoBreak)
// __________________________________________________________________________________________________
// Callback_VideoCopiedToXFB
// WARNING - THIS IS EXECUTED FROM VIDEO THREAD
// We do not touch anything outside this function here
// We do not write to anything outside this function here
void Callback_VideoCopiedToXFB()
{
#ifdef RERECORDING
@ -647,6 +628,8 @@ void Callback_VideoCopiedToXFB()
frames = 0;
Timer.Update();
}
// TODO: hm, are these really safe to call from the video thread?
PatchEngine::ApplyFramePatches();
PatchEngine::ApplyARPatches();
}

View File

@ -44,7 +44,7 @@ namespace Core
bool Init();
void Stop();
bool SetState(EState _State);
void SetState(EState _State);
EState GetState();
// Save/Load state

View File

@ -174,16 +174,16 @@ void FrameAdvance()
WriteStatus();
// If a game is not started, return
if(Core::GetState() == Core::CORE_UNINITIALIZED) return;
if (Core::GetState() == Core::CORE_UNINITIALIZED) return;
// Play to the next frame
if(g_FrameStep)
if (g_FrameStep)
{
Run();
Core::SetState(Core::CORE_RUN);
}
}
// Turn on frame stepping
void FrameStepOnOff()
{

View File

@ -22,7 +22,6 @@
#include "../Host.h"
#include "../Core.h"
#include "CPU.h"
#include "CPUCompare.h"
#include "../Debugger/Debugger_BreakPoints.h"
@ -59,6 +58,8 @@ reswitch:
case PowerPC::CPU_RUNNING:
//1: enter a fast runloop
PowerPC::RunLoop();
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
return;
break;
case PowerPC::CPU_STEPPING:
@ -69,13 +70,6 @@ reswitch:
if (PowerPC::GetState() != PowerPC::CPU_STEPPING)
goto reswitch;
//2: check for cpu compare
if (CPUCompare::IsEnabled() && g_Branch)
{
g_Branch = false;
CPUCompare::Sync();
}
//3: do a step
PowerPC::SingleStep();

View File

@ -1,246 +0,0 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifdef _WIN32
#include <windows.h>
#endif
#include "Common.h"
#include "../Core.h"
#include "CPUCompare.h"
#include "../PowerPC/PowerPC.h"
#include "CommandProcessor.h"
#include "../Host.h"
#ifdef _WIN32
namespace CPUCompare
{
HANDLE m_hPipe;
bool m_bIsServer;
bool m_bEnabled;
u32 m_BlockStart;
#define PIPENAME "\\\\.\\pipe\\cpucompare"
int stateSize = 32*4 + 32*16 + 6*4;
void SetBlockStart(u32 addr)
{
m_BlockStart = addr;
}
void StartServer()
{
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
if (m_bEnabled)
return;
//TODO: error checking
m_hPipe = CreateNamedPipe(
PIPENAME,
PIPE_ACCESS_OUTBOUND,
PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
1, //maxinst
0x1000, //outbufsize
0x1000, //inbufsize
INFINITE, //timeout
0);
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to create pipe.");
//_assert_msg_(GEKKO, 0, "Pipe %s created.", PIPENAME);
m_bIsServer = true;
m_bEnabled = true;
}
void ConnectAsClient()
{
_assert_msg_(GEKKO, Core::GetStartupParameter().bUseDualCore != true, "Don't use multithreading together with CPU-compare.");
if (m_bEnabled)
return;
//TODO: error checking
m_hPipe = CreateFile(
PIPENAME,
GENERIC_READ,
0, //share
NULL,
OPEN_EXISTING,
0,
NULL);
_assert_msg_(GEKKO, m_hPipe != INVALID_HANDLE_VALUE, "Failed to connect to pipe. %08x (2 = file not found)", GetLastError());
m_bEnabled = true;
m_bIsServer = false;
}
void Stop()
{
if (m_bEnabled)
{
if (m_bIsServer)
{
DisconnectNamedPipe(m_hPipe);
CloseHandle(m_hPipe);
}
else
{
CloseHandle(m_hPipe); //both for server and client i guess
}
m_bEnabled=false;
}
}
int Sync()
{
_assert_msg_(GEKKO,0,"Sync - PC = %08x", PC);
PowerPC::PowerPCState state;
if (!m_bEnabled)
return 0;
if (m_bIsServer) // This should be interpreter
{
//write cpu state to m_hPipe
HRESULT result;
u32 written;
// LogManager::Redraw();
result = WriteFile(m_hPipe, &PowerPC::ppcState, stateSize, (LPDWORD)&written,FALSE);
//_assert_msg_(GEKKO, 0, "Server Wrote!");
if (FAILED(result))
{
_assert_msg_(GEKKO,0,"Failed to write cpu state to named pipe");
Stop();
}
// LogManager::Redraw();
}
else // This should be JIT
{
u32 read;
memset(&state,0xcc,stateSize);
BOOL res = ReadFile(m_hPipe, &state, stateSize, (LPDWORD)&read, FALSE);
//_assert_msg_(GEKKO, 0, "Client got data!");
//read cpu state to m_hPipe and compare
//if any errors, print report
if (!res || read != stateSize)
{
_assert_msg_(GEKKO,0,"Failed to read cpu state from named pipe");
Stop();
}
else
{
bool difference = false;
for (int i=0; i<32; i++)
{
if (PowerPC::ppcState.gpr[i] != state.gpr[i])
{
LOG(GEKKO, "DIFFERENCE - r%i (local %08x, remote %08x)", i, PowerPC::ppcState.gpr[i], state.gpr[i]);
difference = true;
}
}
for (int i=0; i<32; i++)
{
for (int j=0; j<2; j++)
{
if (PowerPC::ppcState.ps[i][j] != state.ps[i][j])
{
LOG(GEKKO, "DIFFERENCE - ps%i_%i (local %f, remote %f)", i, j, PowerPC::ppcState.ps[i][j], state.ps[i][j]);
difference = true;
}
}
}
if (GetCR() != state.cr)
{
LOG(GEKKO, "DIFFERENCE - CR (local %08x, remote %08x)", PowerPC::ppcState.cr, state.cr);
difference = true;
}
if (PowerPC::ppcState.pc != state.pc)
{
LOG(GEKKO, "DIFFERENCE - PC (local %08x, remote %08x)", PowerPC::ppcState.pc, state.pc);
difference = true;
}
//if (PowerPC::ppcState.npc != state.npc)
///{
// LOG(GEKKO, "DIFFERENCE - NPC (local %08x, remote %08x)", PowerPC::ppcState.npc, state.npc);
// difference = true;
//}
if (PowerPC::ppcState.msr != state.msr)
{
LOG(GEKKO, "DIFFERENCE - MSR (local %08x, remote %08x)", PowerPC::ppcState.msr, state.msr);
difference = true;
}
if (PowerPC::ppcState.fpscr != state.fpscr)
{
LOG(GEKKO, "DIFFERENCE - FPSCR (local %08x, remote %08x)", PowerPC::ppcState.fpscr, state.fpscr);
difference = true;
}
if (difference)
{
Host_UpdateLogDisplay();
//Also show drec compare window here
//CDynaViewDlg::Show(true);
//CDynaViewDlg::ViewAddr(m_BlockStart);
//CDynaViewDlg::Show(true);
//Sleep(INFINITE);
return false;
}
else
{
return true;
//LOG(GEKKO, "No difference!");
}
}
}
return 0;
}
bool IsEnabled()
{
return m_bEnabled;
}
bool IsServer()
{
return m_bIsServer;
}
}
#else
namespace CPUCompare
{
void StartServer() { }
void ConnectAsClient() { }
void Stop() { }
int Sync() { return 0; }
bool IsEnabled() { return false; }
bool IsServer() { return false; }
}
// #error Provide a CPUCompare implementation or dummy it out, please
#endif

View File

@ -1,50 +0,0 @@
// Copyright (C) 2003-2008 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
// Sets up and maintains interprocess communication to make it possible
// to easily compare any two cpu cores by running two instances of DolphinHLE and
// comparing them to each other.
//
#ifndef _CPUCOMPARE_H
#define _CPUCOMPARE_H
#include "Common.h"
namespace CPUCompare
{
// start the server
void StartServer();
// connect as client
void ConnectAsClient();
// stop
void Stop();
// sync
int Sync();
// IsEnabled
bool IsEnabled();
// IsServer
bool IsServer();
void SetBlockStart(u32 addr);
}
#endif

View File

@ -459,10 +459,10 @@ void Write16(const u16 _Value, const u32 _Address)
// This happens at 4 khz, since 32 bytes at 4khz = 4 bytes at 32 khz (16bit stereo pcm)
void UpdateAudioDMA()
{
Common::PluginDSP *dsp = CPluginManager::GetInstance().GetDSP();
if (g_audioDMA.AudioDMAControl.Enabled && g_audioDMA.BlocksLeft) {
// Read audio at g_audioDMA.ReadAddress in RAM and push onto an external audio fifo in the emulator,
// to be mixed with the disc streaming output. If that audio queue fills up, we delay the emulator.
Common::PluginDSP *dsp = CPluginManager::GetInstance().GetDSP();
// TO RESTORE OLD BEHAVIOUR, COMMENT OUT THIS LINE
dsp->DSP_SendAIBuffer(g_audioDMA.ReadAddress, AudioInterface::GetDSPSampleRate());
@ -479,7 +479,7 @@ void UpdateAudioDMA()
} else {
// Send silence. Yeah, it's a bit of a waste to sample rate convert silence.
// or hm. Maybe we shouldn't do this :)
// PluginDSP::DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate());
dsp->DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate());
}
}

View File

@ -196,4 +196,5 @@ void ApplyARPatches()
{
ActionReplay::RunAllActive();
}
} // namespace

View File

@ -27,7 +27,7 @@
When plugins are freed and loaded:
In an attempt to avoid the crash that occurs when the use LoadLibrary() and FreeLibrary() often
(every tiem a game is stopped and started) these functions will only be used when
(every time a game is stopped and started) these functions will only be used when
1. Dolphin is started
2. A plugin is changed
3. Dolphin is closed
@ -90,8 +90,10 @@ CPluginManager::CPluginManager() :
// Set initial values to NULL, this is only done when Dolphin is started
m_video = NULL;
m_dsp = NULL;
for (int i = 0; i < MAXPADS; i++) m_pad[i] = NULL;
for (int i = 0; i < MAXWIIMOTES; i++) m_wiimote[i] = NULL;
for (int i = 0; i < MAXPADS; i++)
m_pad[i] = NULL;
for (int i = 0; i < MAXWIIMOTES; i++)
m_wiimote[i] = NULL;
}
// This will call FreeLibrary() for all plugins
@ -100,7 +102,6 @@ CPluginManager::~CPluginManager()
Console::Print("Delete CPluginManager\n");
delete m_PluginGlobals;
delete m_dsp;
for (int i = 0; i < MAXPADS; i++) {
@ -112,10 +113,10 @@ CPluginManager::~CPluginManager()
}
for (int i = 0; i < MAXWIIMOTES; i++)
if (m_wiimote[i]) delete m_wiimote[i];
delete m_video;
if (m_wiimote[i])
delete m_wiimote[i];
delete m_video;
}
//////////////////////////////////////////////
@ -126,13 +127,13 @@ CPluginManager::~CPluginManager()
// Function: Point the m_pad[] and other variables to a certain plugin
bool CPluginManager::InitPlugins()
{
if (! GetDSP()) {
if (!GetDSP()) {
PanicAlert("Can't init DSP Plugin");
return false;
}
Console::Print("Before GetVideo\n");
if (! GetVideo()) {
if (!GetVideo()) {
PanicAlert("Can't init Video Plugin");
return false;
}
@ -146,11 +147,13 @@ bool CPluginManager::InitPlugins()
for (int i = 0; i < MAXPADS; i++)
{
// Check that the plugin has a name
if (! m_params.m_strPadPlugin[i].empty()) GetPad(i);
if (!m_params.m_strPadPlugin[i].empty())
GetPad(i);
// Check that GetPad succeeded
if (m_pad[i] != NULL) pad = true;
if (m_pad[i] != NULL)
pad = true;
}
if (! pad)
if (!pad)
{
PanicAlert("Can't init any PAD Plugins");
return false;
@ -159,13 +162,13 @@ bool CPluginManager::InitPlugins()
// Init wiimote
if (m_params.bWii) {
for (int i = 0; i < MAXWIIMOTES; i++) {
if (! m_params.m_strWiimotePlugin[i].empty())
if (!m_params.m_strWiimotePlugin[i].empty())
GetWiimote(i);
if (m_wiimote[i] != NULL)
wiimote = true;
}
if (! wiimote) {
if (!wiimote) {
PanicAlert("Can't init any Wiimote Plugins");
return false;
}
@ -189,7 +192,8 @@ void CPluginManager::ShutdownPlugins()
for (int i = 0; i < MAXWIIMOTES; i++)
{
if (m_wiimote[i]) m_wiimote[i]->Shutdown();
if (m_wiimote[i])
m_wiimote[i]->Shutdown();
//delete m_wiimote[i];
//m_wiimote[i] = NULL;
}
@ -284,7 +288,8 @@ void *CPluginManager::LoadPlugin(const char *_rFilename, int Number)
Common::CPlugin *plugin = NULL;
// Check again that the file exists, the first check is when CPluginInfo info is created
if (! File::Exists(_rFilename)) return NULL;
if (!File::Exists(_rFilename))
return NULL;
switch (type)
{
@ -452,11 +457,13 @@ void CPluginManager::FreeVideo()
delete m_video;
m_video = NULL;
}
void CPluginManager::FreeDSP()
{
delete m_dsp;
m_dsp = NULL;
}
void CPluginManager::FreePad(u32 Pad)
{
if (Pad < MAXPADS) {
@ -464,6 +471,7 @@ void CPluginManager::FreePad(u32 Pad)
m_pad[Pad] = NULL;
}
}
void CPluginManager::FreeWiimote(u32 Wiimote)
{
if (Wiimote < MAXWIIMOTES)
@ -509,7 +517,7 @@ void CPluginManager::OpenConfig(void* _Parent, const char *_rFilename, PLUGIN_TY
// Open debugging window. Type = Video or DSP. Show = Show or hide window.
void CPluginManager::OpenDebug(void* _Parent, const char *_rFilename, PLUGIN_TYPE Type, bool Show)
{
if (! File::Exists(_rFilename))
if (!File::Exists(_rFilename))
{
PanicAlert("Can't find plugin %s", _rFilename);
return;

View File

@ -28,7 +28,6 @@
#include "Jit.h"
#include "JitCache.h"
#include "../../HW/CPUCompare.h"
#include "../../HW/GPFifo.h"
#include "../../Core.h"
#include "JitAsm.h"

View File

@ -231,7 +231,7 @@ void CheckExceptions()
SRR1 = MSR & 0x0780FF77;
NPC = 0x80000C00;
LOGV(GEKKO, 1, "EXCEPTION_SYSCALL (PC=%08x)",PC);
LOGV(GEKKO, 1, "EXCEPTION_SYSCALL (PC=%08x)", PC);
ppcState.Exceptions &= ~EXCEPTION_SYSCALL;
SRR1 |= 0x02; //recoverable
}

View File

@ -30,7 +30,6 @@ files = ["Console.cpp",
"HW/AudioInterface.cpp",
"HW/CommandProcessor.cpp",
"HW/CPU.cpp",
"HW/CPUCompare.cpp",
"HW/DSP.cpp",
"HW/DVDInterface.cpp",
"HW/EXI.cpp",

View File

@ -26,6 +26,7 @@
#include "PowerPC/PowerPC.h"
namespace Core {
FILE *tracefile;
bool bReadTrace = false;
@ -56,8 +57,8 @@ void StopTrace()
}
}
int stateSize = 32*4;// + 32*16 + 6*4;
u64 tb;
static int stateSize = 32*4;// + 32*16 + 6*4;
static u64 tb;
int SyncTrace()
{

View File

@ -245,7 +245,7 @@ bool DolphinApp::OnInit()
ini.Get("MainWindow", "w", &w, 800);
ini.Get("MainWindow", "h", &h, 600);
// -------------------
if(UseDebugger)
if (UseDebugger)
{
main_frame = new CFrame((wxFrame*) NULL, wxID_ANY, wxString::FromAscii(title),
wxPoint(x, y), wxSize(w, h));

View File

@ -23,24 +23,26 @@
#include "Fifo.h"
extern u8* g_pVideoData;
// TODO (mb2): move/rm this global
volatile u32 g_XFBUpdateRequested = FALSE;
extern u8* g_pVideoData;
#ifndef _WIN32
static bool fifoStateRun = true;
#endif
namespace {
// STATE_TO_SAVE
static bool fifoStateRun = false;
static u8 *videoBuffer;
static Common::Event fifo_exit_event;
// STATE_TO_SAVE
static int size = 0;
} // namespace
void Fifo_DoState(PointerWrap &p)
{
p.DoArray(videoBuffer, FIFO_SIZE);
p.Do(size);
int pos = (int)(g_pVideoData-videoBuffer); // get offset
int pos = (int)(g_pVideoData - videoBuffer); // get offset
p.Do(pos); // read or write offset (depends on the mode afaik)
g_pVideoData = &videoBuffer[pos]; // overwrite g_pVideoData -> expected no change when load ss and change when save ss
}
@ -48,25 +50,16 @@ void Fifo_DoState(PointerWrap &p)
void Fifo_Init()
{
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
#ifndef _WIN32
fifo_exit_event.Init();
fifoStateRun = true;
#endif
g_XFBUpdateRequested = FALSE;
}
void Fifo_Shutdown()
{
if (fifoStateRun)
PanicAlert("Fifo shutting down while active");
FreeMemoryPages(videoBuffer, FIFO_SIZE);
#ifndef _WIN32
fifoStateRun = false;
#endif
}
void Fifo_Stop()
{
#ifndef _WIN32
fifoStateRun = false;
#endif
}
u8* FAKE_GetFifoStartPtr()
@ -79,16 +72,18 @@ u8* FAKE_GetFifoEndPtr()
return &videoBuffer[size];
}
// The loop in EnterLoop sends data through this function.
// TODO: Possibly inline it? This one is exported so it will likely not be inlined at all.
void Video_SendFifoData(u8* _uData, u32 len)
{
if (size + len >= FIFO_SIZE)
{
int pos = (int)(g_pVideoData-videoBuffer);
if (size-pos > pos)
int pos = (int)(g_pVideoData - videoBuffer);
if (size - pos > pos)
{
PanicAlert("FIFO out of bounds (sz = %i, at %08x)", size, pos);
}
memmove(&videoBuffer[0], &videoBuffer[pos], size - pos );
memmove(&videoBuffer[0], &videoBuffer[pos], size - pos);
size -= pos;
g_pVideoData = FAKE_GetFifoStartPtr();
}
@ -97,18 +92,23 @@ void Video_SendFifoData(u8* _uData, u32 len)
OpcodeDecoder_Run();
}
void Fifo_ExitLoop()
{
fifoStateRun = false;
fifo_exit_event.Wait();
fifo_exit_event.Shutdown();
}
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
{
SCPFifoStruct &_fifo = *video_initialize.pCPFifo;
s32 distToSend;
#ifdef _WIN32
// TODO(ector): Don't peek so often!
while (video_initialize.pPeekMessages())
#else
while (fifoStateRun)
#endif
{
#ifdef _WIN32
video_initialize.pPeekMessages();
#endif
if (_fifo.CPReadWriteDistance == 0)
Common::SleepCurrentThread(1);
@ -156,16 +156,18 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
else
{
#if 0 // ugly random GP slowdown for testing DC robustness... TODO: remove when completly sure DC is ok
int r=rand();if ((r&0xF)==r) Common::SleepCurrentThread(r);
distToSend = 32;
readPtr += 32;
if ( readPtr >= _fifo.CPEnd)
readPtr = _fifo.CPBase;
int r = rand();
if ((r & 0xF) == r)
Common::SleepCurrentThread(r);
distToSend = 32;
readPtr += 32;
if (readPtr >= _fifo.CPEnd)
readPtr = _fifo.CPBase;
#else
distToSend = _fifo.CPReadWriteDistance;
// send 1024B chunk max lenght to have better control over PeekMessages' period
// send 1024B chunk max length to have better control over PeekMessages' period
distToSend = distToSend > 1024 ? 1024 : distToSend;
if ( (distToSend+readPtr) >= _fifo.CPEnd) // TODO: better?
if ((distToSend + readPtr) >= _fifo.CPEnd) // TODO: better?
{
distToSend =_fifo.CPEnd - readPtr;
readPtr = _fifo.CPBase;
@ -182,5 +184,5 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
Common::SyncInterlockedExchange((LONG*)&_fifo.CPReadIdle, 1);
}
}
fifo_exit_event.Set();
}

View File

@ -27,9 +27,13 @@
void Fifo_Init();
void Fifo_Shutdown();
/* void Video_SendFifoData(); */ // defined in plugin spec - implemented in Fifo.cpp
// These two are for dual core mode only.
void Fifo_EnterLoop(const SVideoInitialize &video_initialize);
void Fifo_ExitLoop();
void Fifo_DoState(PointerWrap &f);
void Fifo_Stop();
#endif

View File

@ -96,6 +96,10 @@ EXPORT void CALL DSP_Update(int cycles);
//
EXPORT void CALL DSP_SendAIBuffer(unsigned int address, int sample_rate);
// __________________________________________________________________________________________________
// Function: DSP_StopSoundStream
// Purpose: Stops audio playback. Must be called before Shutdown().
EXPORT void CALL DSP_StopSoundStream();
#include "ExportEpilog.h"
#endif

View File

@ -90,16 +90,17 @@ typedef struct
EXPORT void CALL Video_Prepare(void);
// __________________________________________________________________________________________________
// Function: Video_ExecuteFifoBuffer
// Purpose: This function is called if data is inside the fifo-buffer
// input: a data-byte (i know we have to optimize this ;-))
// Function: Video_SendFifoData
// Purpose: This function is called to submit fifo data directly - only single core mode calls this.
// input: u8 *_uData, u32 len - a block of fifo data.
// output: none
//
EXPORT void CALL Video_SendFifoData(u8* _uData, u32 len);
// __________________________________________________________________________________________________
// Function: Video_UpdateXFB
// Purpose: This fucntion is called when you have to flip the yuv2
// TODO: This DOC IS BROKEN!
// Purpose: This function is called when you have to flip the yuv2
// video-buffer. You should ignore this function after you
// got the first EFB to XFB copy.
// input: pointer to the XFB, width and height of the XFB
@ -109,7 +110,6 @@ EXPORT void CALL Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dw
// __________________________________________________________________________________________________
// Function: Video_Screenshot
// Purpose: This fucntion is called when you want to do a screenshot
// input: Filename
// output: TRUE if all was okay
//
@ -117,12 +117,20 @@ EXPORT unsigned int CALL Video_Screenshot(TCHAR* _szFilename);
// __________________________________________________________________________________________________
// Function: Video_EnterLoop
// Purpose: FIXME!
// Purpose: Enters the video fifo dispatch loop. This is only used in Dual Core mode.
// input: none
// output: none
//
EXPORT void CALL Video_EnterLoop(void);
// __________________________________________________________________________________________________
// Function: Video_ExitLoop
// Purpose: Exits the video dispatch loop. This is only used in Dual Core mode.
// input: none
// output: none
//
EXPORT void CALL Video_ExitLoop(void);
// __________________________________________________________________________________________________
// Function: Video_AddMessage
// Purpose: Adds a message to the display queue, to be shown forthe specified time
@ -131,13 +139,5 @@ EXPORT void CALL Video_EnterLoop(void);
//
EXPORT void CALL Video_AddMessage(const char* pstr, unsigned int milliseconds);
// __________________________________________________________________________________________________
// Function: Video_Stop
// Purpose: Stop the video plugin before shutdown
// input/output:
// input:
//
EXPORT void CALL Video_Stop();
#include "ExportEpilog.h"
#endif

View File

@ -24,7 +24,6 @@ typedef struct
TWiimoteInput pWiimoteInput;
} SWiimoteInitialize;
/////////////////////////////////////////////////////////////////////////////////////////////////////
// I N T E R F A C E ////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -31,7 +31,8 @@ void AOSound::SoundLoop()
format.byte_format = AO_FMT_LITTLE;
device = ao_open_live(default_driver, &format, NULL /* no options */);
if (device == NULL) {
if (!device)
{
PanicAlert("DSP_HLE: Error opening AO device.\n");
ao_shutdown();
Stop();
@ -40,23 +41,26 @@ void AOSound::SoundLoop()
buf_size = format.bits/8 * format.channels * format.rate;
while (!threadData) {
soundCriticalSection->Enter();
uint_32 numBytesToRender = 256;
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16, sampleRate, 2);
ao_play(device, (char*)realtimeBuffer, numBytesToRender);
soundCriticalSection->Leave();
soundSyncEvent->Wait();
}
while (!threadData)
{
soundCriticalSection->Enter();
uint_32 numBytesToRender = 256;
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16, sampleRate, 2);
ao_play(device, (char*)realtimeBuffer, numBytesToRender);
soundCriticalSection->Leave();
soundSyncEvent->Wait();
}
}
void *soundThread(void *args) {
void *soundThread(void *args)
{
((AOSound *)args)->SoundLoop();
return NULL;
}
bool AOSound::Start() {
bool AOSound::Start()
{
memset(realtimeBuffer, 0, sizeof(realtimeBuffer));
soundSyncEvent = new Common::Event();
@ -68,7 +72,8 @@ bool AOSound::Start() {
return true;
}
void AOSound::Update() {
void AOSound::Update()
{
soundSyncEvent->Set();
}

View File

@ -26,61 +26,52 @@
#include "Thread.h"
class AOSound : public SoundStream
{
#if defined(HAVE_AO) && HAVE_AO
Common::Thread *thread;
Common::Thread *thread;
Common::CriticalSection *soundCriticalSection;
Common::Event *soundSyncEvent;
Common::CriticalSection *soundCriticalSection;
Common::Event *soundSyncEvent;
int buf_size;
ao_device *device;
ao_sample_format format;
int default_driver;
short realtimeBuffer[1024 * 1024];
int buf_size;
ao_device *device;
ao_sample_format format;
int default_driver;
short realtimeBuffer[1024 * 1024];
public:
AOSound(int _sampleRate, StreamCallback _callback) :
AOSound(int _sampleRate, StreamCallback _callback) :
SoundStream(_sampleRate, _callback) {}
virtual ~AOSound() {}
virtual bool Start();
virtual void SoundLoop();
virtual void Stop();
static bool isValid() {
return true;
}
virtual bool usesMixer() {
return true;
}
virtual void Update();
virtual ~AOSound() {}
virtual bool Start();
virtual void SoundLoop();
virtual void Stop();
static bool isValid() {
return true;
}
virtual bool usesMixer() const {
return true;
}
virtual void Update();
virtual int GetSampleRate() {
return sampleRate;
}
virtual int GetSampleRate() {
return sampleRate;
}
#else
public:
AOSound(int _sampleRate, StreamCallback _callback) :
AOSound(int _sampleRate, StreamCallback _callback) :
SoundStream(_sampleRate, _callback) {}
#endif
};
#endif //__AOSOUNDSTREAM_H__

View File

@ -16,13 +16,9 @@
// http://code.google.com/p/dolphin-emu/
#include <dxerr.h>
#include "DSoundStream.h"
#include "../main.h"
#include "WaveFile.h"
extern bool log_ai;
extern WaveFileWriter g_wave_writer;
bool DSound::CreateBuffer()
{
@ -39,9 +35,9 @@ bool DSound::CreateBuffer()
pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
pcmwf.wBitsPerSample = 16;
//buffer description
// Fill out DSound buffer description.
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS; //VIKTIGT //DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
dsbdesc.dwBufferBytes = bufferSize = BUFSIZE;
dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&pcmwf;
@ -51,7 +47,8 @@ bool DSound::CreateBuffer()
dsBuffer->SetCurrentPosition(0);
return true;
}
else {
else
{
// Failed.
PanicAlert("Sound buffer creation failed: %s", DXGetErrorString(res));
dsBuffer = NULL;
@ -64,11 +61,12 @@ bool DSound::WriteDataToBuffer(DWORD dwOffset, // Our own write
DWORD dwSoundBytes) // Size of block to copy.
{
// I want to record the regular audio to, how do I do that?
// Well, it's gonna be a bit tricky. For future work :)
//std::string Data = ArrayToString((const u8*)soundData, dwSoundBytes);
//Console::Print("Data: %s\n\n", Data.c_str());
//if (log_ai) g_wave_writer.AddStereoSamples((const short*)soundData, dwSoundBytes);
void* ptr1, * ptr2;
void *ptr1, *ptr2;
DWORD numBytes1, numBytes2;
// Obtain memory address of write block. This will be in two parts if the block wraps around.
HRESULT hr = dsBuffer->Lock(dwOffset, dwSoundBytes, &ptr1, &numBytes1, &ptr2, &numBytes2, 0);
@ -79,15 +77,11 @@ bool DSound::WriteDataToBuffer(DWORD dwOffset, // Our own write
dsBuffer->Restore();
hr = dsBuffer->Lock(dwOffset, dwSoundBytes, &ptr1, &numBytes1, &ptr2, &numBytes2, 0);
}
if (SUCCEEDED(hr))
{
memcpy(ptr1, soundData, numBytes1);
if (ptr2 != 0)
{
memcpy(ptr2, soundData + numBytes1, numBytes2);
}
// Release the data back to DirectSound.
dsBuffer->Unlock(ptr1, numBytes1, ptr2, numBytes2);
@ -100,43 +94,33 @@ bool DSound::WriteDataToBuffer(DWORD dwOffset, // Our own write
// The audio thread.
DWORD WINAPI soundThread(void* args)
{
((DSound *)args)->SoundLoop();
return 0; //huzzah! :D
(reinterpret_cast<DSound *>(args))->SoundLoop();
return 0;
}
void DSound::SoundLoop() {
void DSound::SoundLoop()
{
currentPos = 0;
lastPos = 0;
// Prefill buffer?
//writeDataToBuffer(0,realtimeBuffer,bufferSize);
// dsBuffer->Lock(0, bufferSize, (void **)&p1, &num1, (void **)&p2, &num2, 0);
dsBuffer->Play(0, 0, DSBPLAY_LOOPING);
while (!threadData) {
while (!threadData)
{
// No blocking inside the csection
soundCriticalSection->Enter();
dsBuffer->GetCurrentPosition((DWORD*)&currentPos, 0);
int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
if (numBytesToRender >= 256)
{
if (numBytesToRender > sizeof(realtimeBuffer))
PanicAlert("soundThread: too big render call");
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16,
sampleRate, 2);
(*callback)(realtimeBuffer, numBytesToRender >> 2, 16, sampleRate, 2);
WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);
currentPos = ModBufferSize(lastPos + numBytesToRender);
totalRenderedBytes += numBytesToRender;
lastPos = currentPos;
}
soundCriticalSection->Leave();
soundSyncEvent->Wait();
}
@ -145,20 +129,14 @@ void DSound::SoundLoop() {
bool DSound::Start()
{
//no security attributes, automatic resetting, init state nonset, untitled
soundSyncEvent = new Common::Event();
soundSyncEvent->Init();
//vi initierar den...........
soundCriticalSection = new Common::CriticalSection();
//vi vill ha access till DSOUND så...
if (FAILED(DirectSoundCreate8(0, &ds, 0)))
return false;
return false;
if(hWnd)
ds->SetCooperativeLevel((HWND)hWnd, DSSCL_NORMAL);
if (!CreateBuffer())
return false;
@ -168,7 +146,6 @@ bool DSound::Start()
memset(p1, 0, num1);
dsBuffer->Unlock(p1, num1, 0, 0);
totalRenderedBytes = -bufferSize;
thread = new Common::Thread(soundThread, (void *)this);
return true;
}
@ -196,15 +173,3 @@ void DSound::Stop()
soundSyncEvent = NULL;
thread = NULL;
}
/* Unused, is it needed?
int DSound::GetCurSample()
{
soundCriticalSection->Enter();
int playCursor;
dsBuffer->GetCurrentPosition((DWORD*)&playCursor, 0);
playCursor = ModBufferSize(playCursor - lastPos) + totalRenderedBytes;
soundCriticalSection->Leave();
return playCursor;
}
*/

View File

@ -34,11 +34,8 @@
class DSound : public SoundStream
{
#ifdef _WIN32
Common::Thread *thread;
Common::CriticalSection *soundCriticalSection;
Common::Event *soundSyncEvent;
void *hWnd;
@ -55,20 +52,18 @@ class DSound : public SoundStream
short realtimeBuffer[1024 * 1024];
inline int FIX128(int x) {
return x & (~127);
return x & (~127);
}
inline int ModBufferSize(int x) {
return (x + bufferSize) % bufferSize;
return (x + bufferSize) % bufferSize;
}
bool CreateBuffer();
bool WriteDataToBuffer(DWORD dwOffset, char* soundData,
DWORD dwSoundBytes);
public:
public:
DSound(int _sampleRate, StreamCallback _callback) :
SoundStream(_sampleRate, _callback) {}
@ -76,29 +71,19 @@ public:
SoundStream(_sampleRate, _callback), hWnd(_hWnd) {}
virtual ~DSound() {}
virtual bool Start();
virtual bool Start();
virtual void SoundLoop();
virtual void Stop();
static bool isValid() { return true; }
virtual bool usesMixer() { return true; }
virtual bool usesMixer() const { return true; }
virtual void Update();
#else
public:
DSound(int _sampleRate, StreamCallback _callback, void *hWnd = NULL) :
SoundStream(_sampleRate, _callback) {}
#endif
};
#endif //__DSOUNDSTREAM_H__

View File

@ -31,9 +31,8 @@
#include "Mixer.h"
#include "FixedSizeQueue.h"
namespace {
Common::CriticalSection push_sync;
// On real hardware, this fifo is much, much smaller. But timing is also tighter than under Windows, so...
@ -46,13 +45,6 @@ FixedSizeQueue<s16, queue_maxlength> sample_queue;
volatile bool mixer_HLEready = false;
volatile int queue_size = 0;
bool bThrottling = false;
/* What is this for?
void UpdateThrottle(bool update)
{
bThrottling = update;
}*/
void Mixer(short *buffer, int numSamples, int bits, int rate, int channels)
{
@ -105,11 +97,8 @@ void Mixer_MixUCode(short *buffer, int numSamples, int bits, int rate,
void Mixer_PushSamples(short *buffer, int num_stereo_samples, int sample_rate)
{
// We alredady do this with the WaveFileWriter right? So no need for this to?
// static FILE *f;
// if (!f)
// f = fopen("d:\\hello.raw", "wb");
// fwrite(buffer, num_stereo_samples * 4, 1, f);
if (!soundStream)
return;
if (queue_size == 0)
{
@ -128,14 +117,18 @@ void Mixer_PushSamples(short *buffer, int num_stereo_samples, int sample_rate)
#endif
// Write Other Audio
//bThrottling = g_Config.m_EnableThrottle;
if (g_Config.m_EnableThrottle)
{
/* This is only needed for non-AX sound, currently directly
streamed and DTK sound. For AX we call SoundStream::Update in
AXTask() for example. */
while (queue_size > queue_maxlength / 2) {
soundStream->Update();
// Urgh.
if (g_dspInitialize.pEmulatorState) {
if (*g_dspInitialize.pEmulatorState != 0)
return;
}
soundStream->Update();
Common::SleepCurrentThread(0);
}
@ -144,64 +137,64 @@ void Mixer_PushSamples(short *buffer, int num_stereo_samples, int sample_rate)
push_sync.Enter();
while (num_stereo_samples)
{
acc += sample_rate;
while (num_stereo_samples && (acc >= 48000))
{
acc += sample_rate;
while (num_stereo_samples && (acc >= 48000))
{
PV4l=PV3l;
PV3l=PV2l;
PV2l=PV1l;
PV1l=*(buffer++); //32bit processing
PV4r=PV3r;
PV3r=PV2r;
PV2r=PV1r;
PV1r=*(buffer++); //32bit processing
num_stereo_samples--;
acc-=48000;
}
// defaults to nearest
s32 DataL = PV1l;
s32 DataR = PV1r;
if (mode == 1) //linear
{
DataL = PV1l + ((PV2l - PV1l)*acc)/48000;
DataR = PV1r + ((PV2r - PV1r)*acc)/48000;
}
else if (mode == 2) //cubic
{
s32 a0l = PV1l - PV2l - PV4l + PV3l;
s32 a0r = PV1r - PV2r - PV4r + PV3r;
s32 a1l = PV4l - PV3l - a0l;
s32 a1r = PV4r - PV3r - a0r;
s32 a2l = PV1l - PV4l;
s32 a2r = PV1r - PV4r;
s32 a3l = PV2l;
s32 a3r = PV2r;
s32 t0l = ((a0l )*acc)/48000;
s32 t0r = ((a0r )*acc)/48000;
s32 t1l = ((t0l+a1l)*acc)/48000;
s32 t1r = ((t0r+a1r)*acc)/48000;
s32 t2l = ((t1l+a2l)*acc)/48000;
s32 t2r = ((t1r+a2r)*acc)/48000;
s32 t3l = ((t2l+a3l));
s32 t3r = ((t2r+a3r));
DataL = t3l;
DataR = t3r;
}
int l = DataL, r = DataR;
if (l < -32767) l = -32767;
if (r < -32767) r = -32767;
if (l > 32767) l = 32767;
if (r > 32767) r = 32767;
sample_queue.push(l);
sample_queue.push(r);
queue_size += 2;
PV4l=PV3l;
PV3l=PV2l;
PV2l=PV1l;
PV1l=*(buffer++); //32bit processing
PV4r=PV3r;
PV3r=PV2r;
PV2r=PV1r;
PV1r=*(buffer++); //32bit processing
num_stereo_samples--;
acc-=48000;
}
// defaults to nearest
s32 DataL = PV1l;
s32 DataR = PV1r;
if (mode == 1) //linear
{
DataL = PV1l + ((PV2l - PV1l)*acc)/48000;
DataR = PV1r + ((PV2r - PV1r)*acc)/48000;
}
else if (mode == 2) //cubic
{
s32 a0l = PV1l - PV2l - PV4l + PV3l;
s32 a0r = PV1r - PV2r - PV4r + PV3r;
s32 a1l = PV4l - PV3l - a0l;
s32 a1r = PV4r - PV3r - a0r;
s32 a2l = PV1l - PV4l;
s32 a2r = PV1r - PV4r;
s32 a3l = PV2l;
s32 a3r = PV2r;
s32 t0l = ((a0l )*acc)/48000;
s32 t0r = ((a0r )*acc)/48000;
s32 t1l = ((t0l+a1l)*acc)/48000;
s32 t1r = ((t0r+a1r)*acc)/48000;
s32 t2l = ((t1l+a2l)*acc)/48000;
s32 t2r = ((t1r+a2r)*acc)/48000;
s32 t3l = ((t2l+a3l));
s32 t3r = ((t2r+a3r));
DataL = t3l;
DataR = t3r;
}
int l = DataL, r = DataR;
if (l < -32767) l = -32767;
if (r < -32767) r = -32767;
if (l > 32767) l = 32767;
if (r > 32767) r = 32767;
sample_queue.push(l);
sample_queue.push(r);
queue_size += 2;
}
push_sync.Leave();
}
}

View File

@ -22,37 +22,29 @@
typedef void (*StreamCallback)(short* buffer, int numSamples, int bits, int rate, int channels);
class SoundStream {
protected:
class SoundStream
{
protected:
int sampleRate;
StreamCallback callback;
// We set this to shut down the sound thread.
// 0=keep playing, 1=stop playing NOW.
volatile int threadData;
public:
public:
SoundStream(int _sampleRate, StreamCallback _callback) :
sampleRate(_sampleRate), callback(_callback), threadData(0) {}
sampleRate(_sampleRate), callback(_callback), threadData(0) {}
virtual ~SoundStream() {}
static bool isValid() { return false; }
virtual bool usesMixer() { return false; }
virtual bool usesMixer() const { return false; }
virtual bool Start() { return false; }
virtual void SoundLoop() { }
virtual void SoundLoop() {}
virtual void Stop() {}
virtual void Update() {}
virtual int GetSampleRate() { return sampleRate; }
virtual int GetSampleRate() const { return sampleRate; }
};
#endif

View File

@ -47,7 +47,6 @@ std::string gpName;
SoundStream *soundStream = NULL;
// Set this if you want to log audio. search for log_ai in this file to see the filename.
bool log_ai = false;
WaveFileWriter g_wave_writer;
@ -155,17 +154,16 @@ void CloseConsole()
void DllDebugger(HWND _hParent, bool Show)
{
#if defined(HAVE_WX) && HAVE_WX
if(m_frame && Show) // if we have created it, let us show it again
if (m_frame && Show) // if we have created it, let us show it again
{
m_frame->DoShow();
}
else if(!m_frame && Show)
else if (!m_frame && Show)
{
m_frame = new CDebugger(NULL);
m_frame->Show();
}
else if(m_frame && !Show)
else if (m_frame && !Show)
{
m_frame->DoHide();
}
@ -213,10 +211,9 @@ void Initialize(void *init)
{
//Console::Open(80, 5000);
g_Config.Load();
g_dspInitialize = *(DSPInitialize*)init;
g_Config.Load();
g_pMemory = g_dspInitialize.pGetMemoryPointer(0);
#if defined(_DEBUG) || defined(DEBUGFAST)
@ -237,12 +234,12 @@ void Initialize(void *init)
if (DSound::isValid())
soundStream = new DSound(48000, Mixer, g_dspInitialize.hWnd);
}
else if(g_Config.sBackend == "AOSound")
else if (g_Config.sBackend == "AOSound")
{
if (AOSound::isValid())
soundStream = new AOSound(48000, Mixer);
}
else if(g_Config.sBackend == "NullSound")
else if (g_Config.sBackend == "NullSound")
{
soundStream = new NullSound(48000, Mixer_MixUCode);
}
@ -258,15 +255,19 @@ void Initialize(void *init)
_CrtSetDbgFlag(tmpflag);
#endif
if (soundStream) {
if(!soundStream->Start()) {
if (soundStream)
{
if (!soundStream->Start())
{
PanicAlert("Could not initialize backend %s, falling back to NULL",
g_Config.sBackend);
delete soundStream;
soundStream = new NullSound(48000, Mixer);
soundStream->Start();
}
} else {
}
else
{
PanicAlert("Sound backend %s is not valid, falling back to NULL",
g_Config.sBackend);
delete soundStream;
@ -282,28 +283,38 @@ void Initialize(void *init)
}
}
void Shutdown()
void DSP_StopSoundStream()
{
// Stop the sound recording
if (log_ai) g_wave_writer.Stop();
// Delete the UCodes
if (!soundStream)
PanicAlert("Can't stop non running SoundStream!");
soundStream->Stop();
delete soundStream;
soundStream = NULL;
}
void Shutdown()
{
// Check that soundstream already is stopped.
if (soundStream)
PanicAlert("SoundStream alive in DSP::Shutdown!");
// Stop the sound recording
if (log_ai)
g_wave_writer.Stop();
// Delete the UCodes
CDSPHandler::Destroy();
#if defined(HAVE_WX) && HAVE_WX
// Reset mails
if(m_frame)
{
sMailLog.clear();
sMailTime.clear();
m_frame->sMail.clear();
m_frame->sMailEnd.clear();
}
#endif
#if defined(HAVE_WX) && HAVE_WX
// Reset mails
if (m_frame)
{
sMailLog.clear();
sMailTime.clear();
m_frame->sMail.clear();
m_frame->sMailEnd.clear();
}
#endif
}
void DoState(unsigned char **ptr, int mode)
@ -406,7 +417,12 @@ void DSP_Update(int cycles)
game has started. */
void DSP_SendAIBuffer(unsigned int address, int sample_rate)
{
if(soundStream->usesMixer())
// TODO: This is not yet fully threadsafe.
if (!soundStream) {
return;
}
if (soundStream->usesMixer())
{
short samples[16] = {0}; // interleaved stereo
if (address)
@ -417,21 +433,19 @@ void DSP_SendAIBuffer(unsigned int address, int sample_rate)
}
// Write the audio to a file
if (log_ai) g_wave_writer.AddStereoSamples(samples, 8);
if (log_ai)
g_wave_writer.AddStereoSamples(samples, 8);
}
Mixer_PushSamples(samples, 32 / 4, sample_rate);
}
/* If I don't use this in Wario Land Shake It I get bad sound, it's a lot of static and noise
in the sound. It's the same both with an without Enable Other Audio. I can't really say why
this occurs because I don't know what SoundSyncEvent->Set() does. */
#ifdef SETUP_AVOID_SOUND_ARTIFACTS
static int counter = 0;
counter++;
if ((counter & 255) == 0)
#endif
// SoundStream is updated only when necessary (there is no 70 ms limit
// so each sample now triggers the sound stream)
soundStream->Update();
// TODO: think about this.
static int counter = 0;
counter++;
if ((counter & 31) == 0 && soundStream)
soundStream->Update();
}
/////////////////////////////////////

View File

@ -291,20 +291,23 @@ void Initialize(void *init)
#endif
}
void DSP_StopSoundStream()
{
#ifdef _WIN32
if (g_hDSPThread != NULL)
{
TerminateThread(g_hDSPThread, 0);
}
#else
// Isn't pthread_cancel kind of evil?
pthread_cancel(g_hDSPThread);
#endif
}
void Shutdown(void)
{
if (log_ai)
g_wave_writer.Stop();
#ifdef _WIN32
if (g_hDSPThread != NULL)
{
TerminateThread(g_hDSPThread, 0);
}
#else
pthread_cancel(g_hDSPThread);
#endif
}
u16 DSP_WriteControlRegister(u16 _uFlag)

View File

@ -200,12 +200,17 @@ void DoState(unsigned char **ptr, int mode) {
//PanicAlert("Saving/Loading state from DirectX9");
}
void Video_EnterLoop()
{
Fifo_EnterLoop(g_VideoInitialize);
}
void Video_ExitLoop()
{
Fifo_ExitLoop();
}
void Video_Prepare(void)
{
Renderer::Init(g_VideoInitialize);
@ -230,10 +235,6 @@ void Shutdown(void)
DeInit();
}
void Video_Stop(void)
{
}
void Video_UpdateXFB(u8* /*_pXFB*/, u32 /*_dwWidth*/, u32 /*_dwHeight*/, s32 /*_dwYOffset*/, bool /*scheduling*/)
{
/*
@ -251,6 +252,10 @@ void Video_UpdateXFB(u8* /*_pXFB*/, u32 /*_dwWidth*/, u32 /*_dwHeight*/, s32 /*_
D3D::BeginFrame();*/
}
void Video_AddMessage(const char* pstr, u32 milliseconds)
{
Renderer::AddMessage(pstr,milliseconds);
}
void DebugLog(const char* _fmt, ...)
{
@ -306,19 +311,10 @@ HRESULT ScreenShot(TCHAR *File)
}
surf->Release();
return S_OK;
}
unsigned int Video_Screenshot(TCHAR* _szFilename)
{
if (ScreenShot(_szFilename) == S_OK)
return TRUE;
return FALSE;
}
void Video_AddMessage(const char* pstr, u32 milliseconds)
{
Renderer::AddMessage(pstr,milliseconds);
return ScreenShot(_szFilename) == S_OK ? TRUE : FALSE;
}

View File

@ -206,7 +206,7 @@
SuppressStartupBanner="true"
AdditionalLibraryDirectories="..\..\..\Externals\Cg64;..\..\..\Externals\GLew;..\..\..\Externals\libjpeg"
GenerateManifest="false"
GenerateDebugInformation="false"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
RandomizedBaseAddress="1"
FixedBaseAddress="1"

View File

@ -121,11 +121,11 @@ void CDebugger::LoadSettings()
m_Check[1]->SetValue(Console);
file.Get("VideoWindow", "ConfBits", &g_Config.iLog, 0);
bInfoLog = g_Config.iLog & CONF_LOG;
bPrimLog = g_Config.iLog & CONF_PRIMLOG;
bSaveTextures = g_Config.iLog & CONF_SAVETEXTURES;
bSaveTargets = g_Config.iLog & CONF_SAVETARGETS;
bSaveShaders = g_Config.iLog & CONF_SAVESHADERS;
bInfoLog = (g_Config.iLog & CONF_LOG) ? true : false;
bPrimLog = (g_Config.iLog & CONF_PRIMLOG) ? true : false;
bSaveTextures = (g_Config.iLog & CONF_SAVETEXTURES) ? true : false;
bSaveTargets = (g_Config.iLog & CONF_SAVETARGETS) ? true : false;
bSaveShaders = (g_Config.iLog & CONF_SAVESHADERS) ? true : false;
m_Check[2]->SetValue(bInfoLog);
m_Check[3]->SetValue(bPrimLog);
m_Check[4]->SetValue(bSaveTextures);

View File

@ -91,20 +91,19 @@ extern bool gShowDebugger;
//////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// The rendering window
// ¯¯¯¯¯¯¯¯¯¯
namespace EmuWindow
{
HWND m_hWnd = NULL; // The new window that is created here
HWND m_hParent = NULL, m_hMain = NULL; // The main CPanel
HWND m_hParent = NULL;
HWND m_hMain = NULL; // The main CPanel
HINSTANCE m_hInstance = NULL;
WNDCLASSEX wndClass;
const TCHAR m_szClassName[] = "DolphinEmuWnd";
int g_winstyle;
// ------------------------------------------
/* Invisible cursor option. In the lack of a predefined IDC_BLANK we make
@ -117,7 +116,7 @@ namespace EmuWindow
BYTE XORmaskCursor[] = { 0x00 };
hCursorBlank = CreateCursor(hInstance, 0,0, 1,1, ANDmaskCursor,XORmaskCursor);
hCursor = LoadCursor( NULL, IDC_ARROW );
hCursor = LoadCursor(NULL, IDC_ARROW);
}
@ -156,25 +155,27 @@ namespace EmuWindow
/* The fullscreen option for Windows users is not very user friendly. With this the user
can only get out of the fullscreen mode by pressing Esc or Alt + F4. Esc also stops
the emulation. Todo: But currently it hangs, so I have disabled the shutdown. */
//if(m_hParent == NULL) ExitProcess(0);
if(m_hParent == NULL)
//if (m_hParent == NULL) ExitProcess(0);
if (m_hParent == NULL)
{
if (g_Config.bFullscreen)
{
//PostMessage(m_hMain, WM_USER, OPENGL_WM_USER_STOP, 0); // Stop
}
else
{
// Toggle maximize and restore
if (IsZoomed(hWnd)) ShowWindow(hWnd, SW_RESTORE); else ShowWindow(hWnd, SW_MAXIMIZE);
if (IsZoomed(hWnd))
ShowWindow(hWnd, SW_RESTORE);
else
ShowWindow(hWnd, SW_MAXIMIZE);
}
return 0;
}
break;
/*
case MY_KEYS:
hypotheticalScene->sendMessage(KEYDOWN...);
*/
case 'E': // EFB hotkey
if(g_Config.bEFBCopyDisableHotKey)
if (g_Config.bEFBCopyDisableHotKey)
{
g_Config.bEFBCopyDisable = !g_Config.bEFBCopyDisable;
Renderer::AddMessage(StringFromFormat("Copy EFB was turned %s",
@ -206,9 +207,9 @@ namespace EmuWindow
case WM_USER:
/* I set wParam to 10 just in case there are other WM_USER events. If we want more
WM_USER cases we would start making wParam or lParam cases */
if(wParam == 10)
if (wParam == 10)
{
if(lParam)
if (lParam)
SetCursor(hCursor);
else
SetCursor(hCursorBlank);
@ -225,24 +226,13 @@ namespace EmuWindow
// This is called when we close the window when we render to a separate window
case WM_CLOSE:
if(m_hParent == NULL)
if (m_hParent == NULL)
{
// Simple hack to easily exit without stopping. Hope to fix the stopping errors soon.
ExitProcess(0);
/* Attempt to only Stop when we close the separate window. But it didn't work, it hanged.
It may need some more coordination with the Stop code in the Core */
//PostMessage(m_hMain, WM_USER, 5, 0);
return 0;
}
/* This is called from the Core when we Stop, but currently we only use DefWindowProc(),
whatever that does with it, if any */
//case WM_QUIT:
//Video_Shutdown();
// ExitProcess(0);
// return 0;
case WM_DESTROY:
//Shutdown();
//PostQuitMessage( 0 ); // Call WM_QUIT

View File

@ -318,13 +318,13 @@ void Video_Prepare(void)
void Shutdown(void)
{
Fifo_Shutdown();
TextureConverter::Shutdown();
VertexLoaderManager::Shutdown();
VertexShaderCache::Shutdown();
VertexShaderManager::Shutdown();
PixelShaderManager::Shutdown();
PixelShaderCache::Shutdown();
Fifo_Shutdown();
VertexManager::Shutdown();
TextureMngr::Shutdown();
OpcodeDecoder_Shutdown();
@ -332,17 +332,16 @@ void Shutdown(void)
OpenGL_Shutdown();
}
void Video_Stop(void)
{
Fifo_Stop();
}
void Video_EnterLoop()
{
Fifo_EnterLoop(g_VideoInitialize);
}
void Video_ExitLoop()
{
Fifo_ExitLoop();
}
void DebugLog(const char* _fmt, ...)
{
#if defined(_DEBUG) || defined(DEBUGFAST)

View File

@ -42,10 +42,9 @@ void ConfigDialog::LoadFile()
IniFile file;
file.Load("WiimoteMovement.ini");
for(int i = 1; i < (RECORDING_ROWS + 1); i++)
for (int i = 1; i < (RECORDING_ROWS + 1); i++)
{
// Temporary storage
bool bTmp;
int iTmp;
std::string STmp;

View File

@ -132,11 +132,11 @@ void PitchDegreeToAccelerometer(float _Roll, float _Pitch, u8 &_x, u8 &_y, u8 &_
if (abs(cos(_Roll)) < abs(cos(_Pitch))) z = cos(_Roll); else z = cos(_Pitch);
/* I got these from reversing the calculation in PitchAccelerometerToDegree() in a math program
I don't know if we can derive these from some kind of matrix or something */
float x_num = 2 * tan(0.5 * _Roll) * z;
float x_den = pow(tan(0.5 * _Roll),2) - 1;
float x_num = 2 * tanf(0.5f * _Roll) * z;
float x_den = powf(tanf(0.5f * _Roll), 2) - 1;
x = - (x_num / x_den);
float y_num = 2 * tan(0.5 * _Pitch) * z;
float y_den = pow(tan(0.5 * _Pitch), 2) - 1;
float y_num = 2 * tanf(0.5f * _Pitch) * z;
float y_den = powf(tanf(0.5f * _Pitch), 2) - 1;
y = - (y_num / y_den);
// =========================
}

View File

@ -100,8 +100,8 @@ void PadStateAdjustments(int &Lx, int &Ly, int &Rx, int &Ry, int &Tl, int &Tr)
}
// Dead zone adjustment
float DeadZoneLeft = (float)PadMapping[Page].DeadZoneL / 100.0;
float DeadZoneRight = (float)PadMapping[Page].DeadZoneR / 100.0;
float DeadZoneLeft = (float)PadMapping[Page].DeadZoneL / 100.0f;
float DeadZoneRight = (float)PadMapping[Page].DeadZoneR / 100.0f;
if (InputCommon::IsDeadZone(DeadZoneLeft, Lx, Ly))
{
Lx = 0;

View File

@ -393,7 +393,7 @@ int Initialize()
// Initialized, even if we didn't find a Wiimote
g_RealWiiMoteInitialized = true;
return g_NumberOfWiiMotes;
return g_NumberOfWiiMotes;
}
void DoState(void* ptr, int mode) {}
@ -401,25 +401,25 @@ void DoState(void* ptr, int mode) {}
void Shutdown(void)
{
// Stop the loop in the thread
g_Shutdown = true;
g_Shutdown = true;
// Stop the thread
if (g_pReadThread != NULL)
{
g_pReadThread->WaitForDeath();
delete g_pReadThread;
g_pReadThread = NULL;
}
// Stop the thread
if (g_pReadThread != NULL)
{
delete g_pReadThread;
g_pReadThread = NULL;
}
// Delete the wiimotes
for (int i = 0; i < g_NumberOfWiiMotes; i++)
{
delete g_WiiMotes[i];
g_WiiMotes[i] = NULL;
}
// Delete the wiimotes
for (int i = 0; i < g_NumberOfWiiMotes; i++)
{
delete g_WiiMotes[i];
g_WiiMotes[i] = NULL;
}
// Flash flights
if (!g_EmulatorRunning && g_RealWiiMotePresent) FlashLights(false);
if (!g_EmulatorRunning && g_RealWiiMotePresent)
FlashLights(false);
// Clean up wiiuse
wiiuse_cleanup(g_WiiMotesFromWiiUse, g_NumberOfWiiMotes);