From 35b6e71f03b5327288ca6206739104337511bf31 Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 23 Jan 2010 12:50:56 +0000 Subject: [PATCH] Experimental FIFO thread. Speeds up the emulator by moving FIFO to its own thread. This will work best with quad cores, though there is a noticeable improvement on my dual core. Enable the thread by adding this line to the video plugin ini files, "User\Config\gfx_dx9.ini" and "User\Config\gfx_opengl.ini": UseFIFOThread = True The line should be added under the UseXFB line. To disable the FIFO thread, use this line: UseFIFOThread = False If the line is not in the ini file, the default is disabled (i.e. False). The FIFO thread causes an error when the OpenGL plugin is used. The D3D plugin works. Only top left quarter of the screen can be seen when rendering to main window. The entire screen can be viewed when running in a window. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4930 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/VideoCommon/Src/Fifo.cpp | 197 ++++++++++++-------- Source/Core/VideoCommon/Src/VideoConfig.cpp | 6 +- Source/Core/VideoCommon/Src/VideoConfig.h | 1 + 3 files changed, 126 insertions(+), 78 deletions(-) diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index b097af4644..dbdfa582b0 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -39,8 +39,12 @@ static u8 *videoBuffer; static Common::EventEx fifo_run_event; // STATE_TO_SAVE static int size = 0; + } // namespace +Common::Thread *g_hFifoThread = NULL; +SVideoInitialize video_initialize; + void Fifo_DoState(PointerWrap &p) { CommandProcessor::FifoCriticalEnter(); @@ -132,93 +136,134 @@ void Fifo_SendFifoData(u8* _uData, u32 len) OpcodeDecoder_Run(g_bSkipCurrentFrame); } -// Description: Main FIFO update loop -// Purpose: Keep the Core HW updated about the CPU-GPU distance -void Fifo_EnterLoop(const SVideoInitialize &video_initialize) +inline void Fifo_Run() { - fifoStateRun = true; SCPFifoStruct &_fifo = CommandProcessor::fifo; s32 distToSend; + // check if we are able to run this buffer + while (_fifo.bFF_GPReadEnable && ((!_fifo.bFF_BPEnable && _fifo.CPReadWriteDistance) || (_fifo.bFF_BPEnable && !_fifo.bFF_Breakpoint))) + { + if (!fifoStateRun) + break; + + CommandProcessor::FifoCriticalEnter(); + + // Create pointer to video data and send it to the VideoPlugin + u32 readPtr = _fifo.CPReadPointer; + u8 *uData = video_initialize.pGetMemoryPointer(readPtr); + + // If we are in BP mode we only send 32B chunks to Video plugin for BP checking + if (_fifo.bFF_BPEnable) + { + // Sometimes we have already exceeded the BP even before it is set + // so careful check is required + if ( + (readPtr == _fifo.CPBreakpoint) || + //(readPtr <= _fifo.CPBreakpoint && readPtr + 32 > _fifo.CPBreakpoint) || + (readPtr <= _fifo.CPWritePointer && _fifo.CPWritePointer < _fifo.CPBreakpoint) || + (readPtr <= _fifo.CPWritePointer && readPtr > _fifo.CPBreakpoint) || + (readPtr > _fifo.CPBreakpoint && _fifo.CPBreakpoint > _fifo.CPWritePointer) + ) + { + Common::AtomicStore(_fifo.bFF_Breakpoint, 1); + CommandProcessor::UpdateInterruptsFromVideoPlugin(true); + CommandProcessor::FifoCriticalLeave(); + break; + } + distToSend = 32; + + if ( readPtr >= _fifo.CPEnd) + readPtr = _fifo.CPBase; + else + readPtr += 32; + } + // If we are not in BP mode we send all the chunk we have to speed up + else + { + distToSend = _fifo.CPReadWriteDistance; + // send 1024B chunk max length to have better control over PeekMessages' period + distToSend = distToSend > 1024 ? 1024 : distToSend; + // add 32 bytes because the cp end points to the start of the last 32 byte chunk + if ((distToSend + readPtr) >= (_fifo.CPEnd + 32)) // TODO: better? + { + distToSend =(_fifo.CPEnd + 32) - readPtr; + readPtr = _fifo.CPBase; + } + else + readPtr += distToSend; + } + + // Execute new instructions found in uData + Fifo_SendFifoData(uData, distToSend); + + Common::AtomicStore(_fifo.CPReadPointer, readPtr); + Common::AtomicAdd(_fifo.CPReadWriteDistance, -distToSend); + + CommandProcessor::FifoCriticalLeave(); + } + + CommandProcessor::SetFifoIdleFromVideoPlugin(); +} + +// Regular thread +THREAD_RETURN fifo_thread(void* lpParameter) +{ while (fifoStateRun) { - video_initialize.pPeekMessages(); + Fifo_Run(); - VideoFifo_CheckEFBAccess(); - VideoFifo_CheckSwapRequest(); - - // check if we are able to run this buffer - while (_fifo.bFF_GPReadEnable && ((!_fifo.bFF_BPEnable && _fifo.CPReadWriteDistance) || (_fifo.bFF_BPEnable && !_fifo.bFF_Breakpoint))) - { - if (!fifoStateRun) - break; - - CommandProcessor::FifoCriticalEnter(); - - // Create pointer to video data and send it to the VideoPlugin - u32 readPtr = _fifo.CPReadPointer; - u8 *uData = video_initialize.pGetMemoryPointer(readPtr); - - // If we are in BP mode we only send 32B chunks to Video plugin for BP checking - if (_fifo.bFF_BPEnable) - { - // Sometimes we have already exceeded the BP even before it is set - // so careful check is required - if ( - (readPtr == _fifo.CPBreakpoint) || - //(readPtr <= _fifo.CPBreakpoint && readPtr + 32 > _fifo.CPBreakpoint) || - (readPtr <= _fifo.CPWritePointer && _fifo.CPWritePointer < _fifo.CPBreakpoint) || - (readPtr <= _fifo.CPWritePointer && readPtr > _fifo.CPBreakpoint) || - (readPtr > _fifo.CPBreakpoint && _fifo.CPBreakpoint > _fifo.CPWritePointer) - ) - { - Common::AtomicStore(_fifo.bFF_Breakpoint, 1); - CommandProcessor::UpdateInterruptsFromVideoPlugin(true); - CommandProcessor::FifoCriticalLeave(); - break; - } - distToSend = 32; - - if ( readPtr >= _fifo.CPEnd) - readPtr = _fifo.CPBase; - else - readPtr += 32; - } - // If we are not in BP mode we send all the chunk we have to speed up - else - { - distToSend = _fifo.CPReadWriteDistance; - // send 1024B chunk max length to have better control over PeekMessages' period - distToSend = distToSend > 1024 ? 1024 : distToSend; - // add 32 bytes because the cp end points to the start of the last 32 byte chunk - if ((distToSend + readPtr) >= (_fifo.CPEnd + 32)) // TODO: better? - { - distToSend =(_fifo.CPEnd + 32) - readPtr; - readPtr = _fifo.CPBase; - } - else - readPtr += distToSend; - } - - // Execute new instructions found in uData - Fifo_SendFifoData(uData, distToSend); - - Common::AtomicStore(_fifo.CPReadPointer, readPtr); - Common::AtomicAdd(_fifo.CPReadWriteDistance, -distToSend); - - CommandProcessor::FifoCriticalLeave(); - - // Those two are pretty important and must be called in the FIFO Loop. - // If we don't, s_swapRequested (OGL only) or s_efbAccessRequested won't be set to false - // leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down. - VideoFifo_CheckEFBAccess(); - VideoFifo_CheckSwapRequest(); - } - CommandProcessor::SetFifoIdleFromVideoPlugin(); + // Must use YieldCPU() in this loop. SLEEP(1) will make MP2 + // hang on boot. if (EmuRunning) Common::YieldCPU(); else fifo_run_event.MsgWait(); } + + return 0; } +// Description: Main FIFO update loop +// Purpose: Keep the Core HW updated about the CPU-GPU distance +void Fifo_EnterLoop(const SVideoInitialize &video_init) +{ + fifoStateRun = true; + video_initialize = video_init; + + if (g_ActiveConfig.bUseFIFOThread) // threaded mode + { + g_hFifoThread = new Common::Thread(fifo_thread, NULL); + while (fifoStateRun) + { + video_initialize.pPeekMessages(); + + // The two VideoFifo checks below are pretty important and must be + // called in the FIFO Loop. If we don't, s_swapRequested (OGL only) + // or s_efbAccessRequested won't be set to false leading the CPU + // thread to wait in Video_BeginField or Video_AccessEFB thus slowing + // things down. + + VideoFifo_CheckEFBAccess(); + VideoFifo_CheckSwapRequest(); + + SLEEP(1); + } + } + else + { + while (fifoStateRun) + { + video_initialize.pPeekMessages(); + VideoFifo_CheckEFBAccess(); + VideoFifo_CheckSwapRequest(); + + Fifo_Run(); + + if (EmuRunning) + Common::YieldCPU(); + else + fifo_run_event.MsgWait(); + } + } +} \ No newline at end of file diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index 614811c813..282e04b0aa 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -57,7 +57,8 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Settings", "AspectRatio", &iAspectRatio, (int)ASPECT_AUTO); iniFile.Get("Settings", "Crop", &bCrop, false); iniFile.Get("Settings", "HideCursor", &bHideCursor, false); - iniFile.Get("Settings", "UseXFB", &bUseXFB, 0); + iniFile.Get("Settings", "UseXFB", &bUseXFB, false); + iniFile.Get("Settings", "UseFIFOThread", &bUseFIFOThread, false); iniFile.Get("Settings", "AutoScale", &bAutoScale, true); iniFile.Get("Settings", "SafeTextureCache", &bSafeTextureCache, false); // Settings @@ -130,7 +131,7 @@ void VideoConfig::GameIniLoad(const char *ini_file) if (iniFile.Exists("Video", "DstAlphaPass")) iniFile.Get("Video", "DstAlphaPass", &bDstAlphaPass, false); if (iniFile.Exists("Video", "UseXFB")) - iniFile.Get("Video", "UseXFB", &bUseXFB, 0); + iniFile.Get("Video", "UseXFB", &bUseXFB, false); if (iniFile.Exists("Video", "FIFOBPHack")) iniFile.Get("Video", "FIFOBPHack", &bFIFOBPhack, false); if (iniFile.Exists("Video", "ProjectionHack")) @@ -153,6 +154,7 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Settings", "wideScreenHack", bWidescreenHack); iniFile.Set("Settings", "HideCursor", bHideCursor); iniFile.Set("Settings", "UseXFB", bUseXFB); + iniFile.Set("Settings", "UseFIFOThread", bUseFIFOThread); iniFile.Set("Settings", "AutoScale", bAutoScale); iniFile.Set("Settings", "SafeTextureCache", bSafeTextureCache); diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 359dc549d3..8254ad4ffe 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -81,6 +81,7 @@ struct VideoConfig int iAspectRatio; bool bCrop; // Aspect ratio controls. bool bUseXFB; + bool bUseFIFOThread; bool bAutoScale; // Removes annoying borders without using XFB. Doesn't always work perfectly. // Enhancements