From 72424eeadc3b25159b0c1d12b1328884c42b0fde Mon Sep 17 00:00:00 2001 From: John Peterson Date: Mon, 9 Feb 2009 23:12:15 +0000 Subject: [PATCH] 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 --- Source/Core/Common/Src/ChunkFile.h | 5 +- Source/Core/Core/Src/Core.cpp | 29 ++- Source/Core/Core/Src/State.cpp | 1 + Source/MusicMod.sln | 1 + .../Plugin_PadSimple/Src/GUI/ConfigDlg.cpp | 21 +- .../Plugin_PadSimple/Src/GUI/ConfigDlg.h | 2 + .../Plugin_PadSimple/Src/PadSimple.cpp | 208 ++++++++++-------- .../Plugins/Plugin_PadSimple/Src/PadSimple.h | 4 + 8 files changed, 173 insertions(+), 98 deletions(-) diff --git a/Source/Core/Common/Src/ChunkFile.h b/Source/Core/Common/Src/ChunkFile.h index 8aa18ba618..206bc5dc81 100644 --- a/Source/Core/Common/Src/ChunkFile.h +++ b/Source/Core/Common/Src/ChunkFile.h @@ -45,7 +45,10 @@ struct LinkedListItem : public T class PointerWrap { 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_WRITE, diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 3de9763930..f49d7eb3d7 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -437,15 +437,30 @@ THREAD_RETURN EmuThread(void *pArg) Plugins.GetVideo()->Video_EnterLoop(); } - // Wait for CPU thread to exit - it should have been signaled to do so by now - if (cpuThread) - cpuThread->WaitForDeath(); - if (g_pUpdateFPSDisplay != NULL) - g_pUpdateFPSDisplay("Stopping..."); - + + // We have now exited the Video Loop and will shut down + + + /* 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) { - delete cpuThread; // This joins the cpu thread. + // This joins the cpu thread. + if(!bRenderToMainSingleCore) delete cpuThread; // Returns after game exited cpuThread = NULL; } diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index ffeabd1fa2..eb52f7e065 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -72,6 +72,7 @@ void DoState(PointerWrap &p) CPluginManager &pm = CPluginManager::GetInstance(); pm.GetVideo()->DoState(p.GetPPtr(), p.GetMode()); pm.GetDSP()->DoState(p.GetPPtr(), p.GetMode()); + pm.GetPad(0)->DoState(p.GetPPtr(), p.GetMode()); PowerPC::DoState(p); HW::DoState(p); CoreTiming::DoState(p); diff --git a/Source/MusicMod.sln b/Source/MusicMod.sln index 0aa8b816fe..f1b147eedb 100644 --- a/Source/MusicMod.sln +++ b/Source/MusicMod.sln @@ -184,6 +184,7 @@ Global {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}.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}.Release|Win32.ActiveCfg = Release|Win32 {9A183B48-ECC2-4121-876A-9B3793686073}.Release|Win32.Build.0 = Release|Win32 diff --git a/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp b/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp index fe7bde822e..82d2f66915 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp +++ b/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp @@ -39,6 +39,7 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog) //Recording EVT_CHECKBOX(ID_RECORDING,ConfigDialog::ControllerSettingsChanged) EVT_CHECKBOX(ID_PLAYBACK,ConfigDialog::ControllerSettingsChanged) + EVT_BUTTON(ID_SAVE_RECORDING,ConfigDialog::ControllerSettingsChanged) EVT_BUTTON(CTL_A,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_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_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_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_CheckPlayback[i], 0, wxEXPAND | wxALL, 1); + m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1); // Set values m_Attached[i]->SetValue(pad[i].bAttached); @@ -189,9 +198,12 @@ void ConfigDialog::CreateGUIControls() m_CheckRecording[i]->SetValue(pad[i].bRecording); 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_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 // Check if any XInput pad was found @@ -365,6 +377,11 @@ void ConfigDialog::ControllerSettingsChanged(wxCommandEvent& event) // Turn off the other option pad[page].bRecording = false; m_CheckRecording[page]->SetValue(false); break; + case ID_SAVE_RECORDING: + // Double check again that we are still running a game + if (g_EmulatorRunning) SaveRecord(); + break; + } } diff --git a/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.h b/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.h index 5711d3a142..e5d58d74f6 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.h +++ b/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.h @@ -70,6 +70,7 @@ class ConfigDialog : public wxDialog // Recording wxCheckBox *m_CheckRecording[4]; wxCheckBox *m_CheckPlayback[4]; + wxButton *m_BtnSaveRecording[4]; wxButton *m_ButtonA[4]; wxButton *m_ButtonB[4]; @@ -111,6 +112,7 @@ class ConfigDialog : public wxDialog // Input recording ID_RECORDING, ID_PLAYBACK, + ID_SAVE_RECORDING, // General settings ID_ATTACHED, diff --git a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp index 67ded7ad49..2c36f80942 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp +++ b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp @@ -28,6 +28,7 @@ #include "IniFile.h" #include "ConsoleWindow.h" #include "StringUtil.h" +#include "ChunkFile.h" #if defined(HAVE_WX) && HAVE_WX #include "GUI/ConfigDlg.h" @@ -67,6 +68,7 @@ SPADInitialize g_PADInitialize; //////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////// // Input Recording // ŻŻŻŻŻŻŻŻŻŻŻŻŻ @@ -79,9 +81,14 @@ SPADInitialize g_PADInitialize; #define RECORD_SIZE (1024 * 128) SPADStatus recordBuffer[RECORD_SIZE]; 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 //****************************************************************************** @@ -94,11 +101,17 @@ void RecordInput(const SPADStatus& _rPADStatus) // Logging //u8 TmpData[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() { + // Logging + //Console::Print("PlayRecord(%i)\n", count); + if (count >= RECORD_SIZE) { // Todo: Make the recording size unlimited? @@ -124,10 +137,13 @@ void LoadRecord() { PanicAlert("SimplePad: Could not open pad-record.bin"); } + + //Console::Print("LoadRecord()"); } void SaveRecord() { + // Open the file in a way that clears all old data FILE* pStream = fopen("pad-record.bin", "wb"); if (pStream != NULL) @@ -139,9 +155,8 @@ void SaveRecord() { PanicAlert("SimplePad: Could not save pad-record.bin"); } - - // Reset the counter - count = 0; + //PanicAlert("SaveRecord()"); + //Console::Print("SaveRecord()"); } @@ -239,93 +254,10 @@ void ScaleStickValues(unsigned char* outx, *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 void DInput_Read(int _numPAD, SPADStatus* _pPADStatus) { @@ -657,6 +589,106 @@ void cocoa_Read(int _numPAD, SPADStatus* _pPADStatus) #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 // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ void PAD_Input(u16 _Key, u8 _UpDown) {} diff --git a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h index db3a2f21b7..ee2b055659 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h +++ b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h @@ -86,9 +86,13 @@ struct SPads }; extern SPads pad[]; +extern bool g_EmulatorRunning; void LoadConfig(); void SaveConfig(); bool IsFocus(); +// Input Recording +void SaveRecord(); + #endif