From 40f4dd30c2c38497f7b9988a5399262c6ac2cbfb Mon Sep 17 00:00:00 2001 From: ayuanx Date: Thu, 31 Dec 2009 16:25:12 +0000 Subject: [PATCH] Fixed Issue 1711 (a bug that prevents some games from booting) Thanks to chuvit's help Added safety check for CFrame::Update git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4759 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/DolphinWX/Src/Frame.cpp | 5 + Source/Core/DolphinWX/Src/Frame.h | 1 + Source/Core/DolphinWX/Src/FrameTools.cpp | 3 + .../Core/VideoCommon/Src/CommandProcessor.cpp | 168 +++++++++++------- .../Core/VideoCommon/Src/CommandProcessor.h | 42 ++--- Source/Core/VideoCommon/Src/Fifo.cpp | 121 ++++++------- 6 files changed, 190 insertions(+), 150 deletions(-) diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index 9678636aa3..b4fbd28a9d 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -309,6 +309,8 @@ CFrame::CFrame(wxFrame* parent, #endif { + m_bControlsCreated = false; + if (ShowLogWindow) SConfig::GetInstance().m_InterfaceLogWindow = true; // Give it a console early to show potential messages from this onward @@ -461,6 +463,7 @@ CFrame::CFrame(wxFrame* parent, // ---------- // Update controls + m_bControlsCreated = true; UpdateGUI(); //if we are ever going back to optional iso caching: @@ -477,6 +480,8 @@ CFrame::CFrame(wxFrame* parent, // Destructor CFrame::~CFrame() { + m_bControlsCreated = false; + cdio_free_device_list(drives); /* The statbar sample has this so I add this to, but I guess timer will be deleted after this anyway */ diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 2d55c1d4eb..8470023ec3 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -195,6 +195,7 @@ class CFrame : public wxFrame bool m_bTabSplit; bool m_bNoDocking; bool m_bModalDialogOpen; + bool m_bControlsCreated; char **drives; diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 81ca9de7ce..08173cbb70 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -915,6 +915,9 @@ void CFrame::OnFrameSkip(wxCommandEvent& event) // Update the enabled/disabled status void CFrame::UpdateGUI() { + if (!m_bControlsCreated) + return; + // Save status bool Initialized = Core::isRunning(); bool Running = Core::GetState() == Core::CORE_RUN; diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index a9151af1b0..4fe8dae6d6 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -83,6 +83,11 @@ namespace CommandProcessor int et_UpdateInterrupts; +void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate) +{ + UpdateInterrupts((userdata) ? true : false); +} + // look for 1002 verts, breakpoint there, see why next draw is flushed // TODO(ector): Warn on bbox read/write @@ -151,12 +156,12 @@ void Init() fake_GPWatchdogLastToken = 0; memset(&fifo,0,sizeof(fifo)); - //fifo.CPCmdIdle = 1 ; + fifo.CPCmdIdle = 1 ; fifo.CPReadIdle = 1; s_fifoIdleEvent.Init(); -// et_UpdateInterrupts = g_VideoInitialize.pRegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); + et_UpdateInterrupts = g_VideoInitialize.pRegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); } void Shutdown() @@ -179,14 +184,14 @@ void Read16(u16& _rReturnValue, const u32 _Address) //m_CPStatusReg.ReadIdle = 1; //m_CPStatusReg.CommandIdle = 1; - m_CPStatusReg.ReadIdle = fifo.CPReadIdle; // This seems not necessary though + //m_CPStatusReg.ReadIdle = fifo.CPReadIdle; // This seems not necessary though m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; - // Clear on Read - UpdateInterrupts(false); - _rReturnValue = m_CPStatusReg.Hex; - DEBUG_LOG(COMMANDPROCESSOR, "\t iBP %s | fREADIDLE %s | fCMDIDLE %s | iOvF %s | iUndF %s" + // Clear on read + UpdateInterrupts(false); + + DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s" , m_CPStatusReg.Breakpoint ? "ON" : "OFF" , m_CPStatusReg.ReadIdle ? "ON" : "OFF" , m_CPStatusReg.CommandIdle ? "ON" : "OFF" @@ -196,7 +201,10 @@ void Read16(u16& _rReturnValue, const u32 _Address) return; case CTRL_REGISTER: _rReturnValue = m_CPCtrlReg.Hex; return; - case CLEAR_REGISTER: _rReturnValue = m_CPClearReg.Hex; return; + case CLEAR_REGISTER: + _rReturnValue = m_CPClearReg.Hex; + DEBUG_LOG(COMMANDPROCESSOR, "(r) clear: 0x%04x", _rReturnValue); + return; case FIFO_TOKEN_REGISTER: _rReturnValue = m_tokenReg; return; case FIFO_BOUNDING_BOX_LEFT: _rReturnValue = m_bboxleft; return; @@ -256,32 +264,86 @@ void Read16(u16& _rReturnValue, const u32 _Address) case FIFO_BP_LO: _rReturnValue = ReadLow (fifo.CPBreakpoint); return; case FIFO_BP_HI: _rReturnValue = ReadHigh(fifo.CPBreakpoint); return; - case CP_PERF0_L: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF0_L: %04x", _rReturnValue); break; // XF counters - case CP_PERF0_H: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF0_H: %04x", _rReturnValue); break; + // AyuanX: Lots of games read the followings (e.g. Mario Power Tennis) + case XF_RASBUSY_L: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_RASBUSY_L: %04x", _rReturnValue); + return; + case XF_RASBUSY_H: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_RASBUSY_H: %04x", _rReturnValue); + return; - case CP_PERF1_L: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF1_L: %04x", _rReturnValue); break; - case CP_PERF1_H: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF1_H: %04x", _rReturnValue); break; + case XF_CLKS_L: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_CLKS_L: %04x", _rReturnValue); + return; + case XF_CLKS_H: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_CLKS_H: %04x", _rReturnValue); + return; - case CP_PERF2_L: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF2_L: %04x", _rReturnValue); break; - case CP_PERF2_H: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF2_H: %04x", _rReturnValue); break; + case XF_WAIT_IN_L: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_WAIT_IN_L: %04x", _rReturnValue); + return; + case XF_WAIT_IN_H: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_WAIT_IN_H: %04x", _rReturnValue); + return; - case CP_PERF3_L: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF3_L: %04x", _rReturnValue); break; - case CP_PERF3_H: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "Read from PERF3_H: %04x", _rReturnValue); break; + case XF_WAIT_OUT_L: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_WAIT_OUT_L: %04x", _rReturnValue); + return; + case XF_WAIT_OUT_H: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from XF_WAIT_OUT_H: %04x", _rReturnValue); + return; + + case VCACHE_METRIC_CHECK_L: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from VCACHE_METRIC_CHECK_L: %04x", _rReturnValue); + return; + case VCACHE_METRIC_CHECK_H: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from VCACHE_METRIC_CHECK_H: %04x", _rReturnValue); + return; + + case VCACHE_METRIC_MISS_L: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from VCACHE_METRIC_MISS_L: %04x", _rReturnValue); + return; + case VCACHE_METRIC_MISS_H: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from VCACHE_METRIC_MISS_H: %04x", _rReturnValue); + return; + + case VCACHE_METRIC_STALL_L: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from VCACHE_METRIC_STALL_L: %04x", _rReturnValue); + return; + case VCACHE_METRIC_STALL_H: + _rReturnValue = 0; // TODO: Figure out the true value + DEBUG_LOG(COMMANDPROCESSOR, "Read from VCACHE_METRIC_STALL_H: %04x", _rReturnValue); + return; case CLKS_PER_VTX_OUT: _rReturnValue = 4; //Number of clocks per vertex.. TODO: Calculate properly WARN_LOG(COMMANDPROCESSOR, "Read from CLKS_PER_VTX_OUT: %04x", _rReturnValue); - break; + return; //add all the other regs here? are they ever read? default: _rReturnValue = 0; WARN_LOG(COMMANDPROCESSOR, "(r16) unknown CP reg @ %08x", _Address); + return; } return; } void Write16(const u16 _Value, const u32 _Address) { + bool bUpdate = false; INFO_LOG(COMMANDPROCESSOR, "(write16): 0x%04x @ 0x%08x",_Value,_Address); //Spin until queue is empty - it WILL become empty because this is the only thread @@ -335,41 +397,17 @@ void Write16(const u16 _Value, const u32 _Address) case CTRL_REGISTER: { - // TOCHECK (mb2): could BP irq be cleared with w16 to STATUS_REGISTER? - // funny hack: eg in MP1 if we disable the clear breakpoint ability by commenting this block - // the game is of course faster but looks stable too. - // Well, the hack is more stable than the "proper" way actualy :p ... it breaks MP2 when ship lands - // So I let the hack for now. - // Checkmate re-enabled it, so please test - // TODO (mb2): fix this! - UCPCtrlReg tmpCtrl(_Value); m_CPCtrlReg.Hex = tmpCtrl.Hex; Common::AtomicStore(fifo.bFF_GPLinkEnable, tmpCtrl.GPLinkEnable); Common::AtomicStore(fifo.bFF_GPReadEnable, tmpCtrl.GPReadEnable); + Common::AtomicStore(fifo.bFF_BPEnable, tmpCtrl.BPEnable); - if (g_VideoInitialize.bOnThread) + if (tmpCtrl.BPInit && tmpCtrl.BPEnable && tmpCtrl.GPReadEnable) { - // Instant Breakpoint and Interrupt, since we haven't implemented accurate BP on dual core - // Most likely the Read thread has already exceeded BP here, but it seems we are still cool - if (tmpCtrl.BPEnable && tmpCtrl.CPIntEnable && tmpCtrl.GPReadEnable && tmpCtrl.GPLinkEnable) - { - Common::AtomicStore(fifo.bFF_Breakpoint, 1); - UpdateInterrupts(true); - } - else - { - Common::AtomicStore(fifo.bFF_Breakpoint, 0); - } - - } - else - { - // fifo.bFF_BPEnable is only used in single core - Common::AtomicStore(fifo.bFF_BPEnable, tmpCtrl.BPEnable && tmpCtrl.CPIntEnable && tmpCtrl.GPReadEnable && tmpCtrl.GPLinkEnable); - if (!tmpCtrl.BPEnable || !tmpCtrl.CPIntEnable || !tmpCtrl.GPReadEnable || !tmpCtrl.GPLinkEnable) - Common::AtomicStore(fifo.bFF_Breakpoint, 0); + // Clear old BP and initiate new BP + Common::AtomicStore(fifo.bFF_Breakpoint, 0); } DEBUG_LOG(COMMANDPROCESSOR,"\t write to CTRL_REGISTER : %04x", _Value); @@ -385,8 +423,8 @@ void Write16(const u16 _Value, const u32 _Address) break; case PERF_SELECT: - // Seems to select which set of perf counters should be exposed. - WARN_LOG(COMMANDPROCESSOR, "write to PERF_SELECT: %04x", _Value); + // Seems to select which set of perf registers should be exposed. + DEBUG_LOG(COMMANDPROCESSOR, "write to PERF_SELECT: %04x", _Value); break; case CLEAR_REGISTER: @@ -404,38 +442,46 @@ void Write16(const u16 _Value, const u32 _Address) break; case FIFO_BASE_LO: - // Oh hell, somtimes this value is not aligned with 32B, like New Super Mario Bros. Wii + bUpdate = true; WriteLow ((u32 &)fifo.CPBase, _Value & 0xFFE0); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_LO : %04x", _Value); break; case FIFO_BASE_HI: + bUpdate = true; WriteHigh((u32 &)fifo.CPBase, _Value); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_BASE_HI : %04x", _Value); break; case FIFO_END_LO: + bUpdate = true; + // Somtimes this value is not aligned with 32B, e.g. New Super Mario Bros. Wii WriteLow ((u32 &)fifo.CPEnd, _Value & 0xFFE0); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_LO : %04x", _Value); break; case FIFO_END_HI: + bUpdate = true; WriteHigh((u32 &)fifo.CPEnd, _Value); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_END_HI : %04x", _Value); break; case FIFO_WRITE_POINTER_LO: + bUpdate = true; WriteLow ((u32 &)fifo.CPWritePointer, _Value & 0xFFE0); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_LO : %04x", _Value); break; case FIFO_WRITE_POINTER_HI: + bUpdate = true; WriteHigh((u32 &)fifo.CPWritePointer, _Value); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_WRITE_POINTER_HI : %04x", _Value); break; case FIFO_READ_POINTER_LO: + bUpdate = true; WriteLow ((u32 &)fifo.CPReadPointer, _Value & 0xFFE0); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_LO : %04x", _Value); break; case FIFO_READ_POINTER_HI: + bUpdate = true; WriteHigh((u32 &)fifo.CPReadPointer, _Value); DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI : %04x", _Value); break; @@ -484,14 +530,11 @@ void Write16(const u16 _Value, const u32 _Address) WARN_LOG(COMMANDPROCESSOR, "(w16) unknown CP reg write %04x @ %08x", _Value, _Address); } - // TODO(mb2): better. Check if it help: avoid CPReadPointer overwrites when stupidly done like in Super Monkey Ball - if ((!fifo.bFF_GPReadEnable && fifo.CPReadIdle) || !g_VideoInitialize.bOnThread) // TOCHECK(mb2): check again if thread safe? + if (bUpdate || !g_VideoInitialize.bOnThread) // TOCHECK(mb2): check again if thread safe? { -// Disabling this thread synchronization check does boost the speed -// Hope it is safe to skip this check -// if (g_VideoInitialize.bOnThread) FifoCriticalEnter(); // This may not be necessary, just for safety + if (g_VideoInitialize.bOnThread) FifoCriticalEnter(); // This may not be necessary, just for safety UpdateFifoRegister(); -// if (g_VideoInitialize.bOnThread) FifoCriticalLeave(); + if (g_VideoInitialize.bOnThread) FifoCriticalLeave(); } } @@ -514,7 +557,7 @@ void IncrementGPWDToken() bool AllowIdleSkipping() { - return !g_VideoInitialize.bOnThread || (!m_CPCtrlReg.CPIntEnable && !m_CPCtrlReg.BPEnable); + return !g_VideoInitialize.bOnThread || !m_CPCtrlReg.BPEnable; } // Check every FAKE_GP_WATCHDOG_PERIOD if a PE-frame-finish occured @@ -562,7 +605,7 @@ void STACKALIGN GatherPipeBursted() // - CPU can write to fifo // - disable Underflow interrupt - INFO_LOG(COMMANDPROCESSOR, "(GatherPipeBursted): CPHiWatermark reached"); + INFO_LOG(COMMANDPROCESSOR, "(GatherPipeBursted): CPHiWatermark reached, 0x%04X, 0x%04X", fifo.CPReadWriteDistance, fifo.CPLoWatermark); // Wait for GPU to catch up while (fifo.CPReadWriteDistance > fifo.CPLoWatermark && !fifo.bFF_Breakpoint) s_fifoIdleEvent.MsgWait(); @@ -591,7 +634,7 @@ void STACKALIGN GatherPipeBursted() void CatchUpGPU() { // check if we are able to run this buffer - if (fifo.bFF_GPReadEnable && !fifo.bFF_Breakpoint) + if (fifo.bFF_GPReadEnable && !(fifo.bFF_BPEnable && fifo.bFF_Breakpoint)) { // HyperIris: Memory_GetPtr is an expensive call, call it less, run faster u8 *ptr = Memory_GetPtr(fifo.CPReadPointer); @@ -678,18 +721,11 @@ void UpdateInterrupts(bool active) g_VideoInitialize.pSetInterrupt(INT_CAUSE_CP, active); } -/* -void UpdateInterruptsFromVideoPlugin() +void UpdateInterruptsFromVideoPlugin(bool active) { - g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, 0); + g_VideoInitialize.pScheduleEvent_Threadsafe(0, et_UpdateInterrupts, active); } -void UpdateInterrupts_Wrapper(u64 userdata, int cyclesLate) -{ - UpdateInterrupts(); -} -*/ - void SetFifoIdleFromVideoPlugin() { s_fifoIdleEvent.Set(); diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index 668b2c2f34..e91148d6e2 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -36,7 +36,7 @@ enum STATUS_REGISTER = 0x00, CTRL_REGISTER = 0x02, CLEAR_REGISTER = 0x04, - PERF_SELECT = 0x06, + PERF_SELECT = 0x06, FIFO_TOKEN_REGISTER = 0x0E, FIFO_BOUNDING_BOX_LEFT = 0x10, FIFO_BOUNDING_BOX_RIGHT = 0x12, @@ -58,23 +58,23 @@ enum FIFO_READ_POINTER_HI = 0x3A, FIFO_BP_LO = 0x3C, FIFO_BP_HI = 0x3E, - CP_PERF0_L = 0x40, - CP_PERF0_H = 0x42, - CP_PERF1_L = 0x44, - CP_PERF1_H = 0x46, - CP_PERF2_L = 0x48, - CP_PERF2_H = 0x4a, - CP_PERF3_L = 0x4c, - CP_PERF3_H = 0x4e, - VCACHE_METRIC_CHECK_LO = 0x50, - VCACHE_METRIC_CHECK_HI = 0x52, - VCACHE_METRIC_MISS_LO = 0x54, - VCACHE_METRIC_MISS_HI = 0x56, - VCACHE_METRIC_STALL_LO = 0x58, - VCACHE_METRIC_STALL_HI = 0x5A, - CLKS_PER_VTX_IN0 = 0x60, - CLKS_PER_VTX_IN1 = 0x62, - CLKS_PER_VTX_OUT = 0x64, + XF_RASBUSY_L = 0x40, + XF_RASBUSY_H = 0x42, + XF_CLKS_L = 0x44, + XF_CLKS_H = 0x46, + XF_WAIT_IN_L = 0x48, + XF_WAIT_IN_H = 0x4a, + XF_WAIT_OUT_L = 0x4c, + XF_WAIT_OUT_H = 0x4e, + VCACHE_METRIC_CHECK_L = 0x50, + VCACHE_METRIC_CHECK_H = 0x52, + VCACHE_METRIC_MISS_L = 0x54, + VCACHE_METRIC_MISS_H = 0x56, + VCACHE_METRIC_STALL_L = 0x58, + VCACHE_METRIC_STALL_H = 0x5A, + CLKS_PER_VTX_IN_L = 0x60, + CLKS_PER_VTX_IN_H = 0x62, + CLKS_PER_VTX_OUT = 0x64, }; enum @@ -106,11 +106,11 @@ union UCPCtrlReg struct { unsigned GPReadEnable : 1; - unsigned CPIntEnable : 1; + unsigned BPEnable : 1; unsigned FifoOverflowIntEnable : 1; unsigned FifoUnderflowIntEnable : 1; unsigned GPLinkEnable : 1; - unsigned BPEnable : 1; + unsigned BPInit : 1; unsigned : 10; }; u16 Hex; @@ -149,7 +149,7 @@ void CatchUpGPU(); void GatherPipeBursted(); void UpdateFifoRegister(); void UpdateInterrupts(bool active); -//void UpdateInterruptsFromVideoPlugin(); +void UpdateInterruptsFromVideoPlugin(bool active); void SetFifoIdleFromVideoPlugin(); bool AllowIdleSkipping(); diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 072bbaad28..9d218adf97 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -138,78 +138,73 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) VideoFifo_CheckSwapRequest(); // check if we are able to run this buffer - if (_fifo.bFF_GPReadEnable && _fifo.CPReadWriteDistance && !_fifo.bFF_Breakpoint) + while (_fifo.bFF_GPReadEnable && _fifo.CPReadWriteDistance && !(_fifo.bFF_BPEnable && _fifo.bFF_Breakpoint)) { - Common::AtomicStore(_fifo.CPReadIdle, 0); + if (!fifoStateRun) + break; - while (_fifo.bFF_GPReadEnable && _fifo.CPReadWriteDistance) + 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) { - if (!fifoStateRun) - break; - - // Create pointer to video data and send it to the VideoPlugin - u32 readPtr = _fifo.CPReadPointer; - u8 *uData = video_initialize.pGetMemoryPointer(readPtr); - - CommandProcessor::FifoCriticalEnter(); - -// It looks like even in BP mode, we still can send all the chunks we have -/* - // if we are on BP mode we must send 32B chunks to Video plugin for BP checking - // TODO (mb2): test & check if MP1/MP2 realy need this now. - 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.CPWritePointer) || + (_fifo.CPWritePointer < _fifo.CPBreakpoint) + ) { - if (readPtr == _fifo.CPBreakpoint) - { - Common::AtomicStore(_fifo.bFF_Breakpoint, 1); - CommandProcessor::UpdateInterruptsFromVideoPlugin(); - break; - } + Common::AtomicStore(_fifo.bFF_Breakpoint, 1); + CommandProcessor::UpdateInterruptsFromVideoPlugin(true); + break; + } - distToSend = 32; - - if ( readPtr >= _fifo.CPEnd) - readPtr = _fifo.CPBase; - else - readPtr += 32; + distToSend = 32; + + if ( readPtr >= _fifo.CPEnd) + readPtr = _fifo.CPBase; + else + readPtr += 32; + } + 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 -*/ - { - 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(); + readPtr += distToSend; } - Common::AtomicStore(_fifo.CPReadIdle, 1); - CommandProcessor::SetFifoIdleFromVideoPlugin(); + + // 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(); } - else - { - Common::YieldCPU(); - } + + Common::YieldCPU(); } fifo_exit_event.Set(); }