From 51ddedf512a3795193fb809281beb5d5453bc73a Mon Sep 17 00:00:00 2001 From: "XTra.KrazzY" Date: Sat, 8 Aug 2009 01:39:56 +0000 Subject: [PATCH] Frameskipping! Complete with GUI! Even my most naive approach resulted in great speeds, even with graphic-intensive games such as Pikmin. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3949 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/PluginVideo.cpp | 3 +++ Source/Core/Common/Src/PluginVideo.h | 3 +++ Source/Core/Core/Core.vcproj | 16 ++++++------ Source/Core/Core/Src/Core.cpp | 6 ++--- .../Core/Src/HW/SI_DeviceGCController.cpp | 2 +- .../Core/Core/Src/{Frame.cpp => OnFrame.cpp} | 26 ++++++++++++++++++- Source/Core/Core/Src/{Frame.h => OnFrame.h} | 7 +++++ Source/Core/Core/Src/SConscript | 2 +- Source/Core/DolphinWX/Src/Frame.cpp | 1 + Source/Core/DolphinWX/Src/Frame.h | 3 +++ Source/Core/DolphinWX/Src/FrameTools.cpp | 15 +++++++++++ Source/Core/DolphinWX/Src/Globals.h | 10 +++++++ Source/Core/VideoCommon/Src/Fifo.cpp | 5 ++++ Source/Core/VideoCommon/Src/Fifo.h | 4 +++ .../Core/VideoCommon/Src/OpcodeDecoding.cpp | 2 ++ .../VideoCommon/Src/VertexLoaderManager.cpp | 1 + Source/PluginSpecs/pluginspecs_video.h | 8 ++++++ Source/Plugins/Plugin_VideoDX9/Src/main.cpp | 3 +++ Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 17 ++++++++---- .../Plugin_VideoOGL/Src/VertexManager.cpp | 7 +++++ Source/Plugins/Plugin_VideoOGL/Src/main.cpp | 4 +++ 21 files changed, 126 insertions(+), 19 deletions(-) rename Source/Core/Core/Src/{Frame.cpp => OnFrame.cpp} (77%) rename Source/Core/Core/Src/{Frame.h => OnFrame.h} (84%) diff --git a/Source/Core/Common/Src/PluginVideo.cpp b/Source/Core/Common/Src/PluginVideo.cpp index b35d62a805..159f72f261 100644 --- a/Source/Core/Common/Src/PluginVideo.cpp +++ b/Source/Core/Common/Src/PluginVideo.cpp @@ -50,6 +50,8 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo (LoadSymbol("Video_AddMessage")); Video_AccessEFB = reinterpret_cast (LoadSymbol("Video_AccessEFB")); + Video_SetRendering = reinterpret_cast + (LoadSymbol("Video_SetRendering")); if ((Video_Prepare != 0) && (Video_SendFifoData != 0) && @@ -59,6 +61,7 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo (Video_ExitLoop != 0) && (Video_Screenshot != 0) && (Video_AddMessage != 0) && + (Video_SetRendering != 0) && (Video_AccessEFB != 0)) validVideo = true; } diff --git a/Source/Core/Common/Src/PluginVideo.h b/Source/Core/Common/Src/PluginVideo.h index 25e1582d4e..85af93f907 100644 --- a/Source/Core/Common/Src/PluginVideo.h +++ b/Source/Core/Common/Src/PluginVideo.h @@ -30,6 +30,7 @@ typedef void (__cdecl* TVideo_EndField)(); typedef bool (__cdecl* TVideo_Screenshot)(const char* filename); typedef void (__cdecl* TVideo_EnterLoop)(); typedef void (__cdecl* TVideo_ExitLoop)(); +typedef void (__cdecl* TVideo_SetRendering)(bool bEnabled); typedef void (__cdecl* TVideo_AddMessage)(const char* pstr, unsigned int milliseconds); typedef u32 (__cdecl* TVideo_AccessEFB)(EFBAccessType, u32, u32); @@ -51,6 +52,8 @@ public: TVideo_AddMessage Video_AddMessage; TVideo_Screenshot Video_Screenshot; + TVideo_SetRendering Video_SetRendering; + private: bool validVideo; }; diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index cf4947f50c..1a190287cd 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -2244,14 +2244,6 @@ RelativePath=".\Src\CoreTiming.h" > - - - - @@ -2264,6 +2256,14 @@ RelativePath=".\Src\MemTools.h" > + + + + diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 9124d9e881..d456c300b3 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -56,7 +56,7 @@ #include "LogManager.h" #include "State.h" -#include "Frame.h" +#include "OnFrame.h" #ifndef _WIN32 #define WINAPI @@ -604,9 +604,9 @@ void Callback_VideoCopiedToXFB(bool video_update) static u32 videoupd = 0; if (video_update) - videoupd++; + videoupd += Frame::FrameSkippingFactor() + 1; else - frames++; + frames += Frame::FrameSkippingFactor() + 1; // Custom frame limiter // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ diff --git a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp index 0afc84b7db..f8e3885b84 100644 --- a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp +++ b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp @@ -25,7 +25,7 @@ #include "EXI_Device.h" #include "EXI_DeviceMic.h" -#include "../Frame.h" +#include "../OnFrame.h" ////////////////////////////////////////////////////////////////////////// // --- standard gamecube controller --- diff --git a/Source/Core/Core/Src/Frame.cpp b/Source/Core/Core/Src/OnFrame.cpp similarity index 77% rename from Source/Core/Core/Src/Frame.cpp rename to Source/Core/Core/Src/OnFrame.cpp index 0cb636cf2c..62a1225137 100644 --- a/Source/Core/Core/Src/Frame.cpp +++ b/Source/Core/Core/Src/OnFrame.cpp @@ -15,6 +15,8 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#include "OnFrame.h" + #include "Core.h" #include "PluginManager.h" @@ -25,12 +27,27 @@ bool g_bAutoFire = false; u32 g_autoFirstKey = 0, g_autoSecondKey = 0; bool g_bFirstKey = true; +int g_framesToSkip = 1, g_frameSkipCounter = 0; + void FrameUpdate() { if(g_bFrameStep) Core::SetState(Core::CORE_PAUSE); if(g_bAutoFire) g_bFirstKey = !g_bFirstKey; + + if(g_framesToSkip) + FrameSkipping(); + +} + +void SetFrameSkipping(unsigned int framesToSkip) { + g_framesToSkip = (int)framesToSkip; + g_frameSkipCounter = 0; +} + +int FrameSkippingFactor() { + return g_framesToSkip; } void SetAutoHold(bool bEnabled, u32 keyToHold) { @@ -60,7 +77,6 @@ void SetFrameStepping(bool bEnabled) { g_bFrameStep = bEnabled; } - void ModifyController(SPADStatus *PadStatus) { u32 keyToPress = (g_bFirstKey) ? g_autoFirstKey : g_autoSecondKey; @@ -90,4 +106,12 @@ void ModifyController(SPADStatus *PadStatus) { } +void FrameSkipping() { + g_frameSkipCounter++; + if(g_frameSkipCounter > g_framesToSkip) + g_frameSkipCounter = 0; + + CPluginManager::GetInstance().GetVideo()->Video_SetRendering(!g_frameSkipCounter); +} + }; diff --git a/Source/Core/Core/Src/Frame.h b/Source/Core/Core/Src/OnFrame.h similarity index 84% rename from Source/Core/Core/Src/Frame.h rename to Source/Core/Core/Src/OnFrame.h index e60e806c8d..070ba27a0c 100644 --- a/Source/Core/Core/Src/Frame.h +++ b/Source/Core/Core/Src/OnFrame.h @@ -18,6 +18,9 @@ #ifndef __FRAME_H #define __FRAME_H +#include "Common.h" +#include "pluginspecs_pad.h" + // Per-(video )Frame actions namespace Frame { @@ -33,6 +36,10 @@ void SetFrameStepping(bool bEnabled); void ModifyController(SPADStatus *PadStatus); +void SetFrameSkipping(unsigned int framesToSkip); +int FrameSkippingFactor(); +void FrameSkipping(); + }; #endif // __FRAME_H diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index 26bc7a4887..13dd14dc3e 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -11,7 +11,7 @@ files = ["ActionReplay.cpp", "CoreParameter.cpp", "CoreRerecording.cpp", "CoreTiming.cpp", - "Frame.cpp", + "OnFrame.cpp", "Host.cpp", "MemTools.cpp", "PatchEngine.cpp", diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index 722f2336c8..2304d40e8f 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -278,6 +278,7 @@ EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile) EVT_MENU_RANGE(IDM_LOADSLOT1, IDM_LOADSLOT8, CFrame::OnLoadState) EVT_MENU_RANGE(IDM_SAVESLOT1, IDM_SAVESLOT8, CFrame::OnSaveState) +EVT_MENU_RANGE(IDM_FRAMESKIP0, IDM_FRAMESKIP9, CFrame::OnFrameSkip) EVT_MENU_RANGE(IDM_DRIVE1, IDM_DRIVE24, CFrame::OnBootDrive) EVT_SIZE(CFrame::OnResize) diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 7abf7337e0..ccaa24aef3 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -170,6 +170,8 @@ class CFrame : public wxFrame void OnUndoLoadState(wxCommandEvent& event); void OnUndoSaveState(wxCommandEvent& event); + void OnFrameSkip(wxCommandEvent& event); + void OnConfigMain(wxCommandEvent& event); // Options void OnPluginGFX(wxCommandEvent& event); void OnPluginDSP(wxCommandEvent& event); @@ -210,6 +212,7 @@ class CFrame : public wxFrame // Emulation wxMenuItem* m_pSubMenuLoad; wxMenuItem* m_pSubMenuSave; + wxMenuItem* m_pSubMenuFrameSkipping; void BootGame(); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index f390cfb4c2..f3d8880a9c 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -59,6 +59,7 @@ Core::GetWindowHandle(). #include "ConfigManager.h" // Core #include "Core.h" +#include "OnFrame.h" #include "HW/DVDInterface.h" #include "State.h" #include "VolumeHandler.h" @@ -130,6 +131,12 @@ void CFrame::CreateMenu() emulationMenu->Append(IDM_PLAY, _T("&Play\tF10")); emulationMenu->Append(IDM_CHANGEDISC, _T("Change &Disc")); emulationMenu->Append(IDM_STOP, _T("&Stop")); + + wxMenu *skippingMenu = new wxMenu; + m_pSubMenuFrameSkipping = emulationMenu->AppendSubMenu(skippingMenu, _T("&Frame Skipping")); + for(int i = 0; i < 10; i++) + skippingMenu->Append(IDM_FRAMESKIP0 + i, wxString::Format(_T("%i"), i), wxEmptyString, wxITEM_RADIO); + emulationMenu->AppendSeparator(); emulationMenu->Append(IDM_SCREENSHOT, _T("Take S&creenshot\tF9")); emulationMenu->AppendSeparator(); @@ -713,6 +720,13 @@ void CFrame::OnSaveState(wxCommandEvent& event) State_Save(slot); } +void CFrame::OnFrameSkip(wxCommandEvent& event) +{ + int amount = event.GetId() - IDM_FRAMESKIP0; + + Frame::SetFrameSkipping((unsigned int)amount); +} + void CFrame::OnResize(wxSizeEvent& event) { FitInside(); @@ -817,6 +831,7 @@ void CFrame::UpdateGUI() GetMenuBar()->FindItem(IDM_SCREENSHOT)->Enable(running || paused); m_pSubMenuLoad->Enable(initialized); m_pSubMenuSave->Enable(initialized); + m_pSubMenuFrameSkipping->Enable(initialized); // Misc GetMenuBar()->FindItem(IDM_CHANGEDISC)->Enable(initialized); diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index 5f7a078520..bfebcd4ac5 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -51,6 +51,16 @@ enum IDM_LOADSLOT6, IDM_LOADSLOT7, IDM_LOADSLOT8, + IDM_FRAMESKIP0, + IDM_FRAMESKIP1, + IDM_FRAMESKIP2, + IDM_FRAMESKIP3, + IDM_FRAMESKIP4, + IDM_FRAMESKIP5, + IDM_FRAMESKIP6, + IDM_FRAMESKIP7, + IDM_FRAMESKIP8, + IDM_FRAMESKIP9, IDM_PLAY, IDM_STOP, IDM_SCREENSHOT, diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 649dabc5e2..9be1bd2288 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -24,6 +24,7 @@ #include "Fifo.h" +volatile bool g_bSkipCurrentFrame = false; extern u8* g_pVideoData; @@ -77,6 +78,10 @@ u8* FAKE_GetFifoEndPtr() return &videoBuffer[size]; } +void Fifo_SetRendering(bool bEnabled) { + g_bSkipCurrentFrame = !bEnabled; +} + // Executed from another thread, no the graphics thread! // Basically, all it does is set a flag so that the loop will eventually exit, then // waits for the event to be set, which happens when the loop does exit. diff --git a/Source/Core/VideoCommon/Src/Fifo.h b/Source/Core/VideoCommon/Src/Fifo.h index b682dcbb5f..fa0e0539ed 100644 --- a/Source/Core/VideoCommon/Src/Fifo.h +++ b/Source/Core/VideoCommon/Src/Fifo.h @@ -25,6 +25,8 @@ #define FIFO_SIZE (1024*1024) +extern volatile bool g_bSkipCurrentFrame; + void Fifo_Init(); void Fifo_Shutdown(); @@ -37,6 +39,8 @@ void Fifo_ExitLoopNonBlocking(); void Fifo_DoState(PointerWrap &f); +void Fifo_SetRendering(bool bEnabled); + // Implemented by the Video Plugin void VideoFifo_CheckSwapRequest(); void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight); diff --git a/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp b/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp index 95def571a6..138cc93fd7 100644 --- a/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp +++ b/Source/Core/VideoCommon/Src/OpcodeDecoding.cpp @@ -197,6 +197,7 @@ bool FifoCommandRunnable() static void Decode() { int Cmd = DataReadU8(); + switch(Cmd) { case GX_NOP: @@ -268,6 +269,7 @@ static void Decode() { // load vertices (use computed vertex size from FifoCommandRunnable above) u16 numVertices = DataReadU16(); + VertexLoaderManager::RunVertices( Cmd & GX_VAT_MASK, // Vertex loader index (0 - 7) (Cmd & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, diff --git a/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp b/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp index d7380c42e4..a7db50e420 100644 --- a/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp @@ -115,6 +115,7 @@ void RunVertices(int vtx_attr_group, int primitive, int count) { if (!count) return; + RefreshLoader(vtx_attr_group); g_VertexLoaders[vtx_attr_group]->RunVertices(vtx_attr_group, primitive, count); } diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index ceb38438f2..8a55b3ba54 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -164,6 +164,14 @@ EXPORT void CALL Video_EnterLoop(void); // EXPORT void CALL Video_ExitLoop(void); +// __________________________________________________________________________________________________ +// Function: Video_SetRendering +// Purpose: Sets video rendering on and off. Currently used for frame skipping +// input: Enabled toggle +// output: none +// +EXPORT void CALL Video_SetRendering(bool bEnabled); + // __________________________________________________________________________________________________ // Function: Video_AddMessage // Purpose: Adds a message to the display queue, to be shown forthe specified time diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index cd6aa07708..e39b7c96e9 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -222,6 +222,9 @@ void Video_ExitLoop() Fifo_ExitLoop(); } +void Video_SetRendering(bool bEnabled) { + Fifo_SetRendering(bEnabled); +} void Video_Prepare(void) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index f2c9ba27ff..285ae6621c 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -116,6 +116,8 @@ static int s_targetheight; static FramebufferManager s_framebufferManager; static GLuint s_tempScreenshotFramebuffer = 0; +static bool s_skipSwap = false; + #ifndef _WIN32 int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0; #endif @@ -791,6 +793,8 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { + s_skipSwap = g_bSkipCurrentFrame; + g_VideoInitialize.pCopiedToXFB(false); #ifdef XXX_ENABLE_CPU_CONTROLLED_SWAPPING @@ -814,6 +818,9 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect // This function has the final picture. We adjust the aspect ratio here. void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) { + if(s_skipSwap) + return; + const XFBSource* xfbSource = s_framebufferManager.GetXFBSource(xfbAddr, fbWidth, fbHeight); if (!xfbSource) { @@ -1088,18 +1095,18 @@ void Renderer::SwapBuffers() } } #endif - // Copy the rendered frame to the real window + // Copy the rendered frame to the real window OpenGL_SwapBuffers(); - + GL_REPORT_ERRORD(); - + // Clear framebuffer glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); - GL_REPORT_ERRORD(); + GL_REPORT_ERRORD(); - // Clean out old stuff from caches + // Clean out old stuff from caches VertexShaderCache::ProgressiveCleanup(); PixelShaderCache::ProgressiveCleanup(); TextureMngr::ProgressiveCleanup(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index 596ca0c8d0..821180eb75 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -20,6 +20,8 @@ #include #include +#include "Fifo.h" + #include "Config.h" #include "Statistics.h" #include "MemoryUtil.h" @@ -185,6 +187,11 @@ void Flush() GL_REPORT_ERRORD(); + if(g_bSkipCurrentFrame) { + ResetBuffer(); + return; + } + glBindBuffer(GL_ARRAY_BUFFER, s_vboBuffers[s_nCurVBOIndex]); glBufferData(GL_ARRAY_BUFFER, s_pCurBufferPointer - s_pBaseBufferPointer, s_pBaseBufferPointer, GL_STREAM_DRAW); GL_REPORT_ERRORD(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index 1e39b57333..1b149b5c24 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -448,6 +448,10 @@ void Video_AddMessage(const char* pstr, u32 milliseconds) OSD::AddMessage(pstr, milliseconds); } +void Video_SetRendering(bool bEnabled) { + Fifo_SetRendering(bEnabled); +} + static volatile struct { u32 xfbAddr;