From 688fda1a0e844743053e3c6108d8236af2fc4838 Mon Sep 17 00:00:00 2001 From: Marcos Vitali Date: Wed, 28 Jul 2010 02:57:17 +0000 Subject: [PATCH] When the new FIFO is being attached We make sure there wont be SetFinish event pending if so reset this. This protection fix Eternal Darkness booting, because the second SetFinish event when it is booting seems invalid or has a bug and hang the game. This is EXPERIMENTAL, in theory don't break any game but if so Revert this commit immediately please. Note: Beside Eternal Darkness needs DirectX 11 or DirectX 9 with Zelda Hack to works fine. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5986 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/Core.cpp | 1 + Source/Core/Core/Src/CoreTiming.cpp | 52 +++++++++++++++++++ Source/Core/Core/Src/CoreTiming.h | 2 + .../Core/VideoCommon/Src/CommandProcessor.cpp | 10 +++- Source/Core/VideoCommon/Src/PixelEngine.cpp | 16 ++++++ Source/Core/VideoCommon/Src/PixelEngine.h | 1 + Source/PluginSpecs/pluginspecs_video.h | 2 + 7 files changed, 83 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index eaafc2a74e..d46d2bf443 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -330,6 +330,7 @@ THREAD_RETURN EmuThread(void *pArg) VideoInitialize.pSetInterrupt = ProcessorInterface::SetInterrupt; VideoInitialize.pRegisterEvent = CoreTiming::RegisterEvent; VideoInitialize.pScheduleEvent_Threadsafe = CoreTiming::ScheduleEvent_Threadsafe; + VideoInitialize.pRemoveEvent = CoreTiming::RemoveAllEvents; // This is first the m_Panel handle, then it is updated to have the new window handle VideoInitialize.pWindowHandle = _CoreParameter.hMainWindow; VideoInitialize.pLog = Callback_VideoLog; diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp index 8dd4dcbbd7..50c3f33b34 100644 --- a/Source/Core/Core/Src/CoreTiming.cpp +++ b/Source/Core/Core/Src/CoreTiming.cpp @@ -96,6 +96,13 @@ void FreeEvent(Event* ev) eventPool = ev; } +void FreeTsEvent(Event* ev) +{ + ev->next = eventTsPool; + eventTsPool = ev; + allocatedTsEvents--; +} + int RegisterEvent(const char *name, TimedCallback callback) { EventType type; @@ -302,10 +309,13 @@ bool IsScheduled(int event_type) void RemoveEvent(int event_type) { + if (!first) return; if (first->type == event_type) { + if (event_type == 24) + NOTICE_LOG(FILEMON, "REMOVE 24"); Event *next = first->next; FreeEvent(first); first = next; @@ -318,6 +328,8 @@ void RemoveEvent(int event_type) { if (ptr->type == event_type) { + if (event_type == 24) + NOTICE_LOG(FILEMON, "REMOVE 24"); prev->next = ptr->next; FreeEvent(ptr); ptr = prev->next; @@ -330,6 +342,46 @@ void RemoveEvent(int event_type) } } +void RemoveThreadsafeEvent(int event_type) +{ + if (!tsFirst) + return; + if (tsFirst->type == event_type) + { + if (event_type == 24) + NOTICE_LOG(FILEMON, "REMOVE 24"); + Event *next = tsFirst->next; + FreeTsEvent(tsFirst); + tsFirst = next; + } + if (!tsFirst) + return; + Event *prev = tsFirst; + Event *ptr = prev->next; + while (ptr) + { + if (ptr->type == event_type) + { + if (event_type == 24) + NOTICE_LOG(FILEMON, "REMOVE 24"); + prev->next = ptr->next; + FreeTsEvent(ptr); + ptr = prev->next; + } + else + { + prev = ptr; + ptr = ptr->next; + } + } +} + +void RemoveAllEvents(int event_type) +{ + RemoveThreadsafeEvent(event_type); + RemoveEvent(event_type); +} + void SetMaximumSlice(int maximumSliceLength) { maxSliceLength = maximumSliceLength; diff --git a/Source/Core/Core/Src/CoreTiming.h b/Source/Core/Core/Src/CoreTiming.h index 1b40749882..7d5a89c846 100644 --- a/Source/Core/Core/Src/CoreTiming.h +++ b/Source/Core/Core/Src/CoreTiming.h @@ -62,6 +62,8 @@ void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata=0); // We only permit one event of each type in the queue at a time. void RemoveEvent(int event_type); +void RemoveThreadsafeEvent(int event_type); +void RemoveAllEvents(int event_type); bool IsScheduled(int event_type); void Advance(); void MoveEvents(); diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index 39da6aeb6f..0bc11714b5 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -77,7 +77,7 @@ #include "Fifo.h" #include "ChunkFile.h" #include "CommandProcessor.h" - +#include "PixelEngine.h" namespace CommandProcessor { @@ -411,6 +411,14 @@ void Write16(const u16 _Value, const u32 _Address) m_CPStatusReg.OverflowHiWatermark = false; UpdateInterrupts(); + + // If the new fifo is being attached We make sure there wont be SetFinish event pending. + // This protection fix eternal darkness booting, because the second SetFinish event when it is booting + // seems invalid or has a bug and hang the game. + if (!fifo.bFF_GPReadEnable && tmpCtrl.GPReadEnable && !tmpCtrl.BPEnable) + { + PixelEngine::ResetSetFinish(); + } fifo.bFF_BPInt = tmpCtrl.BPInt; fifo.bFF_BPEnable = tmpCtrl.BPEnable; diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 8bfe6a314e..12f353f7e7 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -377,4 +377,20 @@ void SetFinish() INFO_LOG(PIXELENGINE, "VIDEO Set Finish"); } +//This function is used in CommandProcessor when write CTRL_REGISTER and the new fifo is attached. +void ResetSetFinish() +{ + //if SetFinish happened but PE_CTRL_REGISTER not, I reset the interrupt else + //remove event from the queque + if (g_bSignalFinishInterrupt) + { + g_VideoInitialize.pSetInterrupt(INT_CAUSE_PE_FINISH, false); + g_bSignalFinishInterrupt = false; + + }else + { + g_VideoInitialize.pRemoveEvent(et_SetFinishOnMainThread); + } +} + } // end of namespace PixelEngine diff --git a/Source/Core/VideoCommon/Src/PixelEngine.h b/Source/Core/VideoCommon/Src/PixelEngine.h index 0043f16b8e..6124c7b6e3 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.h +++ b/Source/Core/VideoCommon/Src/PixelEngine.h @@ -67,6 +67,7 @@ void Write32(const u32 _iValue, const u32 _iAddress); // gfx plugin support void SetToken(const u16 _token, const int _bSetTokenAcknowledge); void SetFinish(void); +void ResetSetFinish(void); bool AllowIdleSkipping(); // Bounding box functionality. Paper Mario (both) are a couple of the few games that use it. diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index 57b7828953..6388db13a0 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -14,6 +14,7 @@ typedef void (*TimedCallback)(u64 userdata, int cyclesLate); typedef void (*TSetInterrupt)(u32 _causemask, bool _bSet); typedef int (*TRegisterEvent)(const char *name, TimedCallback callback); typedef void (*TScheduleEvent_Threadsafe)(int cyclesIntoFuture, int event_type, u64 userdata, bool fifoWait); +typedef void (*TRemoveEvent)(int event_type); typedef unsigned char* (*TGetMemoryPointer)(const unsigned int _iAddress); typedef void (*TVideoLog)(const char* _pMessage, int _bBreak); typedef void (*TSysMessage)(const char *fmt, ...); @@ -74,6 +75,7 @@ typedef struct TSetInterrupt pSetInterrupt; TRegisterEvent pRegisterEvent; TScheduleEvent_Threadsafe pScheduleEvent_Threadsafe; + TRemoveEvent pRemoveEvent; TGetMemoryPointer pGetMemoryPointer; TVideoLog pLog; TSysMessage pSysMessage;