PadSimple: Added rerecording option in that the input saving counter it saved with the save state and rewinded when a saved state is loaded

Core: Tried to a address a semi-frequent hanging that would occur in single core mode and render to main frame

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2191 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2009-02-09 23:12:15 +00:00
parent ec71298b06
commit 72424eeadc
8 changed files with 173 additions and 98 deletions

View File

@ -45,7 +45,10 @@ struct LinkedListItem : public T
class PointerWrap class PointerWrap
{ {
public: public:
enum Mode // also defined in pluginspecs.h. Didn't want to couple them. /* READ is when we read from the save state file, WRITE is when we write to the
save state file. This enumareted list is also defined in pluginspecs.h. Didn't
want to couple them. */
enum Mode
{ {
MODE_READ = 1, MODE_READ = 1,
MODE_WRITE, MODE_WRITE,

View File

@ -437,15 +437,30 @@ THREAD_RETURN EmuThread(void *pArg)
Plugins.GetVideo()->Video_EnterLoop(); Plugins.GetVideo()->Video_EnterLoop();
} }
// Wait for CPU thread to exit - it should have been signaled to do so by now
if (cpuThread) // We have now exited the Video Loop and will shut down
cpuThread->WaitForDeath();
if (g_pUpdateFPSDisplay != NULL)
g_pUpdateFPSDisplay("Stopping..."); /* 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
the wxDialog class. The solution was to wait for the thread to stop with a timer from the wxDialog, and the proceed to shutdown.
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;
if (GetParent((HWND)g_pWindowHandle) == NULL || _CoreParameter.bUseDualCore) bRenderToMainSingleCore = true;
/* 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 (cpuThread) if (cpuThread)
{ {
delete cpuThread; // This joins the cpu thread. // This joins the cpu thread.
if(!bRenderToMainSingleCore) delete cpuThread;
// Returns after game exited // Returns after game exited
cpuThread = NULL; cpuThread = NULL;
} }

View File

@ -72,6 +72,7 @@ void DoState(PointerWrap &p)
CPluginManager &pm = CPluginManager::GetInstance(); CPluginManager &pm = CPluginManager::GetInstance();
pm.GetVideo()->DoState(p.GetPPtr(), p.GetMode()); pm.GetVideo()->DoState(p.GetPPtr(), p.GetMode());
pm.GetDSP()->DoState(p.GetPPtr(), p.GetMode()); pm.GetDSP()->DoState(p.GetPPtr(), p.GetMode());
pm.GetPad(0)->DoState(p.GetPPtr(), p.GetMode());
PowerPC::DoState(p); PowerPC::DoState(p);
HW::DoState(p); HW::DoState(p);
CoreTiming::DoState(p); CoreTiming::DoState(p);

View File

@ -184,6 +184,7 @@ Global
{9A183B48-ECC2-4121-876A-9B3793686073}.Debug|Win32.ActiveCfg = Debug|Win32 {9A183B48-ECC2-4121-876A-9B3793686073}.Debug|Win32.ActiveCfg = Debug|Win32
{9A183B48-ECC2-4121-876A-9B3793686073}.Debug|x64.ActiveCfg = Debug|x64 {9A183B48-ECC2-4121-876A-9B3793686073}.Debug|x64.ActiveCfg = Debug|x64
{9A183B48-ECC2-4121-876A-9B3793686073}.DebugFast|Win32.ActiveCfg = DebugFast|Win32 {9A183B48-ECC2-4121-876A-9B3793686073}.DebugFast|Win32.ActiveCfg = DebugFast|Win32
{9A183B48-ECC2-4121-876A-9B3793686073}.DebugFast|Win32.Build.0 = DebugFast|Win32
{9A183B48-ECC2-4121-876A-9B3793686073}.DebugFast|x64.ActiveCfg = DebugFast|x64 {9A183B48-ECC2-4121-876A-9B3793686073}.DebugFast|x64.ActiveCfg = DebugFast|x64
{9A183B48-ECC2-4121-876A-9B3793686073}.Release|Win32.ActiveCfg = Release|Win32 {9A183B48-ECC2-4121-876A-9B3793686073}.Release|Win32.ActiveCfg = Release|Win32
{9A183B48-ECC2-4121-876A-9B3793686073}.Release|Win32.Build.0 = Release|Win32 {9A183B48-ECC2-4121-876A-9B3793686073}.Release|Win32.Build.0 = Release|Win32

View File

@ -39,6 +39,7 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
//Recording //Recording
EVT_CHECKBOX(ID_RECORDING,ConfigDialog::ControllerSettingsChanged) EVT_CHECKBOX(ID_RECORDING,ConfigDialog::ControllerSettingsChanged)
EVT_CHECKBOX(ID_PLAYBACK,ConfigDialog::ControllerSettingsChanged) EVT_CHECKBOX(ID_PLAYBACK,ConfigDialog::ControllerSettingsChanged)
EVT_BUTTON(ID_SAVE_RECORDING,ConfigDialog::ControllerSettingsChanged)
EVT_BUTTON(CTL_A,ConfigDialog::OnButtonClick) EVT_BUTTON(CTL_A,ConfigDialog::OnButtonClick)
EVT_BUTTON(CTL_B,ConfigDialog::OnButtonClick) EVT_BUTTON(CTL_B,ConfigDialog::OnButtonClick)
@ -177,11 +178,19 @@ void ConfigDialog::CreateGUIControls()
m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording")); m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording"));
m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input")); m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input"));
m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input")); m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input"));
m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize);
// Tool tips
m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game")); m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game"));
m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir")); m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir"));
m_BtnSaveRecording[i]->SetToolTip(wxT(
"This will save the current recording to pad-record.bin. Your recording will\n"
"also be automatically saved every 60 * 10 frames. And when you shut down the\n"
"game."));
m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1); m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1); m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1);
m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1);
// Set values // Set values
m_Attached[i]->SetValue(pad[i].bAttached); m_Attached[i]->SetValue(pad[i].bAttached);
@ -189,9 +198,12 @@ void ConfigDialog::CreateGUIControls()
m_CheckRecording[i]->SetValue(pad[i].bRecording); m_CheckRecording[i]->SetValue(pad[i].bRecording);
m_CheckPlayback[i]->SetValue(pad[i].bPlayback); m_CheckPlayback[i]->SetValue(pad[i].bPlayback);
// Disable // Only enable these options for pad 3
m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true); m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true);
m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true); m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true);
m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true);
// Don't allow saving when we are not recording
m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && pad[0].bRecording);
#ifdef _WIN32 #ifdef _WIN32
// Check if any XInput pad was found // Check if any XInput pad was found
@ -365,6 +377,11 @@ void ConfigDialog::ControllerSettingsChanged(wxCommandEvent& event)
// Turn off the other option // Turn off the other option
pad[page].bRecording = false; m_CheckRecording[page]->SetValue(false); pad[page].bRecording = false; m_CheckRecording[page]->SetValue(false);
break; break;
case ID_SAVE_RECORDING:
// Double check again that we are still running a game
if (g_EmulatorRunning) SaveRecord();
break;
} }
} }

View File

@ -70,6 +70,7 @@ class ConfigDialog : public wxDialog
// Recording // Recording
wxCheckBox *m_CheckRecording[4]; wxCheckBox *m_CheckRecording[4];
wxCheckBox *m_CheckPlayback[4]; wxCheckBox *m_CheckPlayback[4];
wxButton *m_BtnSaveRecording[4];
wxButton *m_ButtonA[4]; wxButton *m_ButtonA[4];
wxButton *m_ButtonB[4]; wxButton *m_ButtonB[4];
@ -111,6 +112,7 @@ class ConfigDialog : public wxDialog
// Input recording // Input recording
ID_RECORDING, ID_RECORDING,
ID_PLAYBACK, ID_PLAYBACK,
ID_SAVE_RECORDING,
// General settings // General settings
ID_ATTACHED, ID_ATTACHED,

View File

@ -28,6 +28,7 @@
#include "IniFile.h" #include "IniFile.h"
#include "ConsoleWindow.h" #include "ConsoleWindow.h"
#include "StringUtil.h" #include "StringUtil.h"
#include "ChunkFile.h"
#if defined(HAVE_WX) && HAVE_WX #if defined(HAVE_WX) && HAVE_WX
#include "GUI/ConfigDlg.h" #include "GUI/ConfigDlg.h"
@ -67,6 +68,7 @@ SPADInitialize g_PADInitialize;
//////////////////////////////// ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// Input Recording // Input Recording
// ¯¯¯¯¯¯¯¯¯¯¯¯¯ // ¯¯¯¯¯¯¯¯¯¯¯¯¯
@ -79,9 +81,14 @@ SPADInitialize g_PADInitialize;
#define RECORD_SIZE (1024 * 128) #define RECORD_SIZE (1024 * 128)
SPADStatus recordBuffer[RECORD_SIZE]; SPADStatus recordBuffer[RECORD_SIZE];
int count = 0; int count = 0;
bool g_EmulatorRunning = false;
//////////////////////////////// ////////////////////////////////
void __Log(int log, const char *format, ...) {}
void __Logv(int log, int v, const char *format, ...) {}
//****************************************************************************** //******************************************************************************
// Supporting functions // Supporting functions
//****************************************************************************** //******************************************************************************
@ -94,11 +101,17 @@ void RecordInput(const SPADStatus& _rPADStatus)
// Logging // Logging
//u8 TmpData[sizeof(SPADStatus)]; //u8 TmpData[sizeof(SPADStatus)];
//memcpy(TmpData, &recordBuffer[count - 1], sizeof(SPADStatus)); //memcpy(TmpData, &recordBuffer[count - 1], sizeof(SPADStatus));
//Console::Print("RecordInput(): %s\n", ArrayToString(TmpData, sizeof(SPADStatus), 0, 30).c_str()); //Console::Print("RecordInput(%i): %s\n", count, ArrayToString(TmpData, sizeof(SPADStatus), 0, 30).c_str());
// Auto save every ten seconds
if (count % (60 * 10) == 0) SaveRecord();
} }
const SPADStatus& PlayRecord() const SPADStatus& PlayRecord()
{ {
// Logging
//Console::Print("PlayRecord(%i)\n", count);
if (count >= RECORD_SIZE) if (count >= RECORD_SIZE)
{ {
// Todo: Make the recording size unlimited? // Todo: Make the recording size unlimited?
@ -124,10 +137,13 @@ void LoadRecord()
{ {
PanicAlert("SimplePad: Could not open pad-record.bin"); PanicAlert("SimplePad: Could not open pad-record.bin");
} }
//Console::Print("LoadRecord()");
} }
void SaveRecord() void SaveRecord()
{ {
// Open the file in a way that clears all old data
FILE* pStream = fopen("pad-record.bin", "wb"); FILE* pStream = fopen("pad-record.bin", "wb");
if (pStream != NULL) if (pStream != NULL)
@ -139,9 +155,8 @@ void SaveRecord()
{ {
PanicAlert("SimplePad: Could not save pad-record.bin"); PanicAlert("SimplePad: Could not save pad-record.bin");
} }
//PanicAlert("SaveRecord()");
// Reset the counter //Console::Print("SaveRecord()");
count = 0;
} }
@ -239,93 +254,10 @@ void ScaleStickValues(unsigned char* outx,
*outy = 0x80 + iy; *outy = 0x80 + iy;
} }
//****************************************************************************** //******************************************************************************
// Plugin specification functions // Input
//****************************************************************************** //******************************************************************************
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
{
_PluginInfo->Version = 0x0100;
_PluginInfo->Type = PLUGIN_TYPE_PAD;
#ifdef DEBUGFAST
sprintf(_PluginInfo->Name, "Dolphin KB/X360pad (DebugFast)");
#else
#ifndef _DEBUG
sprintf(_PluginInfo->Name, "Dolphin KB/X360pad");
#else
sprintf(_PluginInfo->Name, "Dolphin KB/X360pad (Debug)");
#endif
#endif
}
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals) {}
void DllConfig(HWND _hParent)
{
LoadConfig();
#ifdef _WIN32
wxWindow win;
win.SetHWND(_hParent);
ConfigDialog frame(&win);
frame.ShowModal();
win.SetHWND(0);
#elif defined(HAVE_WX) && HAVE_WX
ConfigDialog frame(NULL);
frame.ShowModal();
#endif
SaveConfig();
}
void DllDebugger(HWND _hParent, bool Show) {}
void Initialize(void *init)
{
//Console::Open(70, 5000);
// Load configuration
LoadConfig();
// Load recorded input
if (pad[0].bPlayback) LoadRecord();
g_PADInitialize = *(SPADInitialize*)init;
#ifdef _WIN32
dinput.Init((HWND)g_PADInitialize.hWnd);
#elif defined(HAVE_X11) && HAVE_X11
GXdsp = (Display*)g_PADInitialize.hWnd;
#elif defined(HAVE_COCOA) && HAVE_COCOA
#endif
}
void DoState(unsigned char **ptr, int mode) {
}
void Shutdown()
{
// Save recording
if (pad[0].bRecording) SaveRecord();
#ifdef _WIN32
dinput.Free();
// Kill xpad rumble
XINPUT_VIBRATION vib;
vib.wLeftMotorSpeed = 0;
vib.wRightMotorSpeed = 0;
for (int i = 0; i < 4; i++)
if (pad[i].bRumble)
XInputSetState(pad[i].XPadPlayer, &vib);
#endif
SaveConfig();
}
#ifdef _WIN32 #ifdef _WIN32
void DInput_Read(int _numPAD, SPADStatus* _pPADStatus) void DInput_Read(int _numPAD, SPADStatus* _pPADStatus)
{ {
@ -657,6 +589,106 @@ void cocoa_Read(int _numPAD, SPADStatus* _pPADStatus)
#endif #endif
//******************************************************************************
// Plugin specification functions
//******************************************************************************
void GetDllInfo(PLUGIN_INFO* _PluginInfo)
{
_PluginInfo->Version = 0x0100;
_PluginInfo->Type = PLUGIN_TYPE_PAD;
#ifdef DEBUGFAST
sprintf(_PluginInfo->Name, "Dolphin KB/X360pad (DebugFast)");
#else
#ifndef _DEBUG
sprintf(_PluginInfo->Name, "Dolphin KB/X360pad");
#else
sprintf(_PluginInfo->Name, "Dolphin KB/X360pad (Debug)");
#endif
#endif
}
void SetDllGlobals(PLUGIN_GLOBALS* _pPluginGlobals) {}
void DllConfig(HWND _hParent)
{
LoadConfig();
#ifdef _WIN32
wxWindow win;
win.SetHWND(_hParent);
ConfigDialog frame(&win);
frame.ShowModal();
win.SetHWND(0);
#elif defined(HAVE_WX) && HAVE_WX
ConfigDialog frame(NULL);
frame.ShowModal();
#endif
SaveConfig();
}
void DllDebugger(HWND _hParent, bool Show) {}
void Initialize(void *init)
{
//Console::Open(70, 5000);
// We are now running a game
g_EmulatorRunning = true;
// Load configuration
LoadConfig();
// Load recorded input if we are to play it back, otherwise begin with a blank recording
if (pad[0].bPlayback) LoadRecord();
g_PADInitialize = *(SPADInitialize*)init;
#ifdef _WIN32
dinput.Init((HWND)g_PADInitialize.hWnd);
#elif defined(HAVE_X11) && HAVE_X11
GXdsp = (Display*)g_PADInitialize.hWnd;
#elif defined(HAVE_COCOA) && HAVE_COCOA
#endif
}
void DoState(unsigned char **ptr, int mode)
{
// Load or save the counter
PointerWrap p(ptr, mode);
p.Do(count);
}
void Shutdown()
{
//Console::Print("ShutDown()\n");
// Save recording
if (pad[0].bRecording) SaveRecord();
// Reset the counter
count = 0;
// We have stopped the game
g_EmulatorRunning = false;
#ifdef _WIN32
dinput.Free();
// Kill xpad rumble
XINPUT_VIBRATION vib;
vib.wLeftMotorSpeed = 0;
vib.wRightMotorSpeed = 0;
for (int i = 0; i < 4; i++)
if (pad[i].bRumble)
XInputSetState(pad[i].XPadPlayer, &vib);
#endif
SaveConfig();
}
// Set buttons status from wxWidgets in the main application // Set buttons status from wxWidgets in the main application
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
void PAD_Input(u16 _Key, u8 _UpDown) {} void PAD_Input(u16 _Key, u8 _UpDown) {}

View File

@ -86,9 +86,13 @@ struct SPads
}; };
extern SPads pad[]; extern SPads pad[];
extern bool g_EmulatorRunning;
void LoadConfig(); void LoadConfig();
void SaveConfig(); void SaveConfig();
bool IsFocus(); bool IsFocus();
// Input Recording
void SaveRecord();
#endif #endif