From 9cbd50818100df4b6dabeeb294206d8cb9ab3fc7 Mon Sep 17 00:00:00 2001 From: ayuanx Date: Thu, 7 Jan 2010 20:01:41 +0000 Subject: [PATCH] 1. This should fix Issue 1625 (Bizarre Auto Frame Limit) Now the frame limiter yields on CPU thread, not as before on GPU thread mistakenly 2. Fixed clear of VI interrupts I guess VI interrupts are not used at all, because they were never cleared before 3. Made GPU thread 0% processor usage when paused whatever your active config is. I tried the event approach but somehow the thread resume latency is excessively long (Who can tell me why?) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4790 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/Timer.cpp | 2 +- Source/Core/Common/Src/Timer.h | 2 +- Source/Core/Core/Src/Core.cpp | 162 ++++++------------ Source/Core/Core/Src/Core.h | 1 + Source/Core/Core/Src/HW/VideoInterface.cpp | 115 ++++--------- Source/Core/Core/Src/HW/VideoInterface.h | 30 +++- Source/Core/Core/Src/OnFrame.cpp | 5 +- Source/Core/Core/Src/OnFrame.h | 4 +- .../Core/VideoCommon/Src/CommandProcessor.cpp | 9 +- Source/Core/VideoCommon/Src/Fifo.cpp | 11 +- Source/Core/VideoCommon/Src/Fifo.h | 2 +- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 5 +- Source/Plugins/Plugin_VideoDX9/Src/main.cpp | 13 +- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 3 + Source/Plugins/Plugin_VideoOGL/Src/main.cpp | 4 +- 15 files changed, 141 insertions(+), 227 deletions(-) diff --git a/Source/Core/Common/Src/Timer.cpp b/Source/Core/Common/Src/Timer.cpp index 47eec6a755..3f851ce8cc 100644 --- a/Source/Core/Common/Src/Timer.cpp +++ b/Source/Core/Common/Src/Timer.cpp @@ -78,7 +78,7 @@ void Timer::Update() // ------------------------------------- // Get the number of milliseconds since the last Update() -s64 Timer::GetTimeDifference() +u64 Timer::GetTimeDifference() { return(timeGetTime() - m_LastTime); } diff --git a/Source/Core/Common/Src/Timer.h b/Source/Core/Common/Src/Timer.h index c457bf0fab..4b9b9496c4 100644 --- a/Source/Core/Common/Src/Timer.h +++ b/Source/Core/Common/Src/Timer.h @@ -36,7 +36,7 @@ public: void Update(); // The time difference is always returned in milliseconds, regardless of alternative internal representation - s64 GetTimeDifference(); + u64 GetTimeDifference(); void AddTimeDifference(); void WindBackStartingTime(u64 WindBack); diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index ad9f91390b..31fd948941 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -21,6 +21,7 @@ #endif #include "Setup.h" // Common +#include "Atomic.h" #include "Thread.h" #include "Timer.h" #include "Common.h" @@ -64,11 +65,9 @@ namespace Core { - // Declarations and definitions Common::Timer Timer; -u32 frames = 0; - +volatile u32 DrawnFrame = 0; // Function forwarding //void Callback_VideoRequestWindowSize(int _iWidth, int _iHeight, BOOL _bFullscreen); @@ -587,102 +586,29 @@ void ScreenShot() { ScreenShot(GenerateScreenshotName()); } - -// --- Callbacks for plugins / engine --- - -// Callback_VideoLog -// WARNING - THIS IS EXECUTED FROM VIDEO THREAD -void Callback_VideoLog(const TCHAR *_szMessage, int _bDoBreak) +// Apply Frame Limit and Display FPS info +// This should only be called from VI +void FrameThrottle() { - INFO_LOG(VIDEO, _szMessage); -} - -// reports if a frame should be skipped or not -// depending on the framelimit set -bool report_slow(int skipped) -{ - u32 targetfps = SConfig::GetInstance().m_Framelimit * 5; - double wait_frametime; + u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1) ? SConfig::GetInstance().m_Framelimit * 5 + : VideoInterface::TargetRefreshRate; + u32 frames = Common::AtomicLoad(DrawnFrame); - if (targetfps < 5) - wait_frametime = (1000.0 / VideoInterface::TargetRefreshRate); - else - wait_frametime = (1000.0 / targetfps); - - bool fps_slow; - - if (Timer.GetTimeDifference() < wait_frametime * (frames + skipped)) - fps_slow=false; - else - fps_slow=true; - - if (targetfps == 5) - fps_slow=true; - - return fps_slow; -} - -// Callback_VideoCopiedToXFB -// WARNING - THIS IS EXECUTED FROM VIDEO THREAD -// We do not write to anything outside this function here -void Callback_VideoCopiedToXFB(bool video_update) -{ - if(!video_update) - Frame::FrameUpdate(); - - SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; - - //count FPS and VPS - static u32 videoupd = 0; - static u32 no_framelimit = 0; - - - if (video_update) - videoupd++; - else - frames++; - - if (no_framelimit>0) - no_framelimit--; - - // Custom frame limiter - // -------------------- - u32 targetfps = SConfig::GetInstance().m_Framelimit * 5; - - if (targetfps > 5) + // When frame limit is NOT off + if (frames && SConfig::GetInstance().m_Framelimit != 1) { - double wait_frametime = (1000.0 / targetfps); - - if (Timer.GetTimeDifference() >= wait_frametime * frames) - no_framelimit = (u32)Timer.GetTimeDifference(); - - while (Timer.GetTimeDifference() < wait_frametime * frames) - { - if (no_framelimit == 0) - Common::SleepCurrentThread(1); - } - } - else if (targetfps < 5) - { - double wait_frametime = (1000.0 / VideoInterface::TargetRefreshRate); - - if (Timer.GetTimeDifference() >= wait_frametime * frames) - no_framelimit = (u32)Timer.GetTimeDifference(); - - while (Timer.GetTimeDifference() < wait_frametime * videoupd) - { - // TODO : This is wrong, the sleep shouldn't be there but rather in cputhread - // as it's not based on the fps but on the refresh rate... - if (no_framelimit == 0) - Common::SleepCurrentThread(1); - } + u32 frametime = frames * 1000 / TargetFPS; + while (Timer.GetTimeDifference() < frametime) + //Common::YieldCPU(); + Common::SleepCurrentThread(1); } - if (Timer.GetTimeDifference() >= 1000) + // Update info per second + u32 ElapseTime = (u32)Timer.GetTimeDifference(); + if (ElapseTime >= 1000) { - // Time passed - float t = (float)(Timer.GetTimeDifference()) / 1000.f; + SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; // Use extended or summary information. The summary information does not print the ticks data, // that's more of a debugging interest, it can always be optional of course if someone is interested. @@ -691,8 +617,8 @@ void Callback_VideoCopiedToXFB(bool video_update) u64 newTicks = CoreTiming::GetTicks(); u64 newIdleTicks = CoreTiming::GetIdleTicks(); - s64 diff = (newTicks - ticks) / 1000000; - s64 idleDiff = (newIdleTicks - idleTicks) / 1000000; + u64 diff = (newTicks - ticks) / 1000000; + u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; ticks = newTicks; idleTicks = newIdleTicks; @@ -700,13 +626,9 @@ void Callback_VideoCopiedToXFB(bool video_update) float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; #endif - float FPS = (float)frames / t; - // for some reasons "VideoInterface::ActualRefreshRate" gives some odd results :( - float VPS = (float)videoupd / t; + u32 FPS = frames * 1000 / ElapseTime; - int TargetVPS = (int)(VideoInterface::TargetRefreshRate + 0.5); - - float Speed = ((VPS > 0.0f ? VPS : VideoInterface::ActualRefreshRate) / TargetVPS) * 100.0f; + float Speed = (float)FPS / (float)TargetFPS * 100.0f; // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat(" | Core: %s %s", @@ -726,8 +648,7 @@ void Callback_VideoCopiedToXFB(bool video_update) _CoreParameter.bCPUThread ? "DC" : "SC"); #ifdef EXTENDED_INFO - std::string SFPS = StringFromFormat("FPS: %4.1f - VPS: %i/%i (%3.0f%%)", - FPS, VPS > 0 ? (int)VPS : (int)VideoInterface::ActualRefreshRate, TargetVPS, Speed); + std::string SFPS = StringFromFormat("FPS: %i/%i (%3.0f%%)", FPS, TargetFPS, Speed); SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), @@ -738,8 +659,7 @@ void Callback_VideoCopiedToXFB(bool video_update) TicksPercentage); #else // Summary information - std::string SFPS = StringFromFormat("FPS: %4.1f - VPS: %i/%i (%3.0f%%)", - FPS, VPS > 0 ? (int)VPS : (int)VideoInterface::ActualRefreshRate, TargetVPS, Speed); + std::string SFPS = StringFromFormat("FPS: %i/%i (%3.0f%%)", FPS, TargetFPS, Speed); #endif // This is our final "frame counter" string @@ -752,12 +672,39 @@ void Callback_VideoCopiedToXFB(bool video_update) Host_UpdateStatusBar(SMessage.c_str()); // Reset frame counter - frames = 0; - videoupd = 0; Timer.Update(); + Common::AtomicStore(DrawnFrame, 0); } } +// Executed from GPU thread +// reports if a frame should be skipped or not +// depending on the framelimit set +bool report_slow(int skipped) +{ + u32 TargetFPS = (SConfig::GetInstance().m_Framelimit > 1) ? SConfig::GetInstance().m_Framelimit * 5 + : VideoInterface::TargetRefreshRate; + u32 frames = Common::AtomicLoad(DrawnFrame); + bool fps_slow = (Timer.GetTimeDifference() < (frames + skipped) * 1000 / TargetFPS) ? false : true; + + return fps_slow; +} + +// --- Callbacks for plugins / engine --- + +// Callback_VideoLog +// WARNING - THIS IS EXECUTED FROM VIDEO THREAD +void Callback_VideoLog(const TCHAR *_szMessage, int _bDoBreak) +{ + INFO_LOG(VIDEO, _szMessage); +} + +// Should be called from GPU thread when a frame is drawn +void Callback_VideoCopiedToXFB(bool video_update) +{ + Common::AtomicIncrement(DrawnFrame); + Frame::FrameUpdate(); +} // Callback_DSPLog // WARNING - THIS MAY BE EXECUTED FROM DSP THREAD @@ -835,7 +782,8 @@ void Callback_WiimoteLog(const TCHAR* _szMessage, int _v) } // TODO: Get rid of at some point -const SCoreStartupParameter& GetStartupParameter() { +const SCoreStartupParameter& GetStartupParameter() +{ return SConfig::GetInstance().m_LocalCoreStartupParameter; } diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h index b284565a59..8740f6d899 100644 --- a/Source/Core/Core/Src/Core.h +++ b/Source/Core/Core/Src/Core.h @@ -74,6 +74,7 @@ namespace Core void StopTrace(); bool report_slow(int skipped); + void FrameThrottle(); // ----------------------------------------- #ifdef RERECORDING diff --git a/Source/Core/Core/Src/HW/VideoInterface.cpp b/Source/Core/Core/Src/HW/VideoInterface.cpp index 9aa34a6b71..a40a7437bf 100644 --- a/Source/Core/Core/Src/HW/VideoInterface.cpp +++ b/Source/Core/Core/Src/HW/VideoInterface.cpp @@ -19,8 +19,7 @@ #include "ChunkFile.h" #include "../PowerPC/PowerPC.h" - -#include "../Core.h" // <- for Core::GetStartupParameter().bUseDualCore +#include "../Core.h" #include "ProcessorInterface.h" #include "VideoInterface.h" #include "Memmap.h" @@ -28,7 +27,6 @@ #include "../CoreTiming.h" #include "../HW/SystemTimers.h" #include "StringUtil.h" -#include "Timer.h" namespace VideoInterface { @@ -53,7 +51,7 @@ enum VI_FB_LEFT_TOP_LO = 0x1e, VI_FB_RIGHT_TOP_HI = 0x20, // FB_RIGHT_TOP is only used in 3D mode VI_FB_RIGHT_TOP_LO = 0x22, - VI_FB_LEFT_BOTTOM_HI = 0x24, // FB_LEFT_TOP is second half of XFB info + VI_FB_LEFT_BOTTOM_HI = 0x24, // FB_LEFT_BOTTOM is second half of XFB info VI_FB_LEFT_BOTTOM_LO = 0x26, VI_FB_RIGHT_BOTTOM_HI = 0x28, // FB_RIGHT_BOTTOM is only used in 3D mode VI_FB_RIGHT_BOTTOM_LO = 0x2a, @@ -268,6 +266,7 @@ union UVIFilterCoefTable3 unsigned : 2; }; }; + // Used for tables 3-6 union UVIFilterCoefTable4 { @@ -281,6 +280,7 @@ union UVIFilterCoefTable4 unsigned Tap3 : 8; }; }; + struct SVIFilterCoefTables { UVIFilterCoefTable3 Tables02[3]; @@ -331,16 +331,13 @@ static UVIBorderBlankRegister m_BorderHBlank; // 0xcc002076 - 0xcc00207f is full of 0x00FF: unknown // 0xcc002080 - 0xcc002100 even more unknown +u32 TargetRefreshRate = 0; static u32 TicksPerFrame = 0; static u32 s_lineCount = 0; static u32 s_upperFieldBegin = 0; static u32 s_lowerFieldBegin = 0; -float TargetRefreshRate = 0.0; -float ActualRefreshRate = 0.0; -s64 SyncTicksProgress = 0; - void DoState(PointerWrap &p) { p.Do(m_VerticalTimingRegister); @@ -367,7 +364,7 @@ void DoState(PointerWrap &p) p.Do(m_DTVStatus); p.Do(m_FBWidth); p.Do(m_BorderHBlank); - + p.Do(TargetRefreshRate); p.Do(TicksPerFrame); p.Do(s_lineCount); p.Do(s_upperFieldBegin); @@ -376,11 +373,6 @@ void DoState(PointerWrap &p) void PreInit(bool _bNTSC) { - TicksPerFrame = 0; - s_lineCount = 0; - s_upperFieldBegin = 0; - s_lowerFieldBegin = 0; - m_VerticalTimingRegister.EQU = 6; m_DisplayControlRegister.ENB = 1; @@ -439,9 +431,7 @@ void Init() m_DisplayControlRegister.Hex = 0; - s_lineCount = 0; - s_upperFieldBegin = 0; - s_lowerFieldBegin = 0; + UpdateTiming(); } void Read8(u8& _uReturnValue, const u32 _iAddress) @@ -711,9 +701,12 @@ void Write16(const u16 _iValue, const u32 _iAddress) { // shuffle2 clear all data, reset to default vals, and enter idle mode m_DisplayControlRegister.RST = 0; + for (int i = 0; i < 4; i++) + m_InterruptRegister[i].Hex = 0; + UpdateInterrupts(); } - UpdateTiming(); + UpdateTiming(); } break; @@ -802,38 +795,38 @@ void Write16(const u16 _iValue, const u32 _iAddress) // RETRACE STUFF ... case VI_PRERETRACE_HI: m_InterruptRegister[0].Hi = _iValue; + m_InterruptRegister[0].IR_INT = 0; UpdateInterrupts(); break; case VI_PRERETRACE_LO: m_InterruptRegister[0].Lo = _iValue; - UpdateInterrupts(); break; case VI_POSTRETRACE_HI: m_InterruptRegister[1].Hi = _iValue; + m_InterruptRegister[1].IR_INT = 0; UpdateInterrupts(); break; case VI_POSTRETRACE_LO: m_InterruptRegister[1].Lo = _iValue; - UpdateInterrupts(); break; case VI_DISPLAY_INTERRUPT_2_HI: m_InterruptRegister[2].Hi = _iValue; + m_InterruptRegister[2].IR_INT = 0; UpdateInterrupts(); break; case VI_DISPLAY_INTERRUPT_2_LO: m_InterruptRegister[2].Lo = _iValue; - UpdateInterrupts(); break; case VI_DISPLAY_INTERRUPT_3_HI: m_InterruptRegister[3].Hi = _iValue; + m_InterruptRegister[3].IR_INT = 0; UpdateInterrupts(); break; case VI_DISPLAY_INTERRUPT_3_LO: m_InterruptRegister[3].Lo = _iValue; - UpdateInterrupts(); break; case VI_DISPLAY_LATCH_0_HI: @@ -988,46 +981,22 @@ u32 GetXFBAddressBottom() return m_XFBInfoBottom.FBB; } - -// NTSC is 60 FPS, right? -// Wrong, it's about 59.94 FPS. The NTSC engineers had to slightly lower -// the field rate from 60 FPS when they added color to the standard. -// This was done to prevent analog interference between the video and -// audio signals. PAL has no similar reduction; it is exactly 50 FPS. -const double NTSC_FIELD_RATE = 60.0 / 1.001; -const u32 NTSC_LINE_COUNT = 525; -// These line numbers indicate the beginning of the "active video" in a frame. -// An NTSC frame has the lower field first followed by the upper field. -// TODO: Is this true for PAL-M? Is this true for EURGB60? -const u32 NTSC_LOWER_BEGIN = 21; -const u32 NTSC_UPPER_BEGIN = 283; - -const double PAL_FIELD_RATE = 50.0; -const u32 PAL_LINE_COUNT = 625; -// These line numbers indicate the beginning of the "active video" in a frame. -// A PAL frame has the upper field first followed by the lower field. -const u32 PAL_UPPER_BEGIN = 23; // TODO: Actually 23.5! -const u32 PAL_LOWER_BEGIN = 336; - -// Screenshot and screen message void UpdateTiming() { switch (m_DisplayControlRegister.FMT) { - case 0: // NTSC case 2: // PAL-M - - TicksPerFrame = (u32)(SystemTimers::GetTicksPerSecond() / (NTSC_FIELD_RATE / 2.0)); + TargetRefreshRate = NTSC_FIELD_RATE; + TicksPerFrame = SystemTimers::GetTicksPerSecond() / (NTSC_FIELD_RATE / 2); s_lineCount = m_DisplayControlRegister.NIN ? (NTSC_LINE_COUNT+1)/2 : NTSC_LINE_COUNT; - // TODO: The game may have some control over these parameters (not that it's useful). s_upperFieldBegin = NTSC_UPPER_BEGIN; s_lowerFieldBegin = NTSC_LOWER_BEGIN; break; case 1: // PAL - - TicksPerFrame = (u32)(SystemTimers::GetTicksPerSecond() / (PAL_FIELD_RATE / 2.0)); + TargetRefreshRate = PAL_FIELD_RATE; + TicksPerFrame = SystemTimers::GetTicksPerSecond() / (PAL_FIELD_RATE / 2); s_lineCount = m_DisplayControlRegister.NIN ? (PAL_LINE_COUNT+1)/2 : PAL_LINE_COUNT; s_upperFieldBegin = PAL_UPPER_BEGIN; s_lowerFieldBegin = PAL_LOWER_BEGIN; @@ -1040,7 +1009,6 @@ void UpdateTiming() default: PanicAlert("Unknown Video Format - CVideoInterface"); break; - } } @@ -1056,7 +1024,6 @@ int GetTicksPerFrame() return TicksPerFrame; } - static void BeginField(FieldType field) { u32 fbWidth = m_HorizontalStepping.FieldSteps * 16; @@ -1088,45 +1055,24 @@ static void EndField() } -// Purpose 1: Send VI interrupt for every screen refresh -// Purpose 2: Execute XFB copy in homebrew games -// Run when: This is run 15700 times per second on full speed +// Purpose: Send VI interrupt when triggered +// Run when: When every line is scaned void Update() { - // Update the target refresh rate - TargetRefreshRate = (float)((m_DisplayControlRegister.FMT == 0 || m_DisplayControlRegister.FMT == 2) - ? NTSC_FIELD_RATE : PAL_FIELD_RATE); - - // Calculate actual refresh rate - static u64 LastTick = 0; - static s64 UpdateCheck = timeGetTime() + 1000, TickProgress = 0; - s64 curTime = timeGetTime(); - if (UpdateCheck < (int)curTime) - { - UpdateCheck = curTime + 1000; - TickProgress = CoreTiming::GetTicks() - LastTick; - // Calculated CPU-GPU synced ticks for the dual core mode too - // NOTICE_LOG(VIDEO, "Removed: %s Mhz", ThS(SyncTicksProgress / 1000000, false).c_str()); - SyncTicksProgress += TickProgress; - // Multipled by two because of the way TicksPerFrame is calculated (divided by 25 and 30 - // rather than 50 and 60) - - ActualRefreshRate = (float)(((double)SyncTicksProgress / (double)TicksPerFrame) * 2.0); - LastTick = CoreTiming::GetTicks(); - SyncTicksProgress = 0; - } // TODO: What's the correct behavior for progressive mode? - if (m_VBeamPos == s_upperFieldBegin + m_VerticalTimingRegister.ACV) EndField(); - - if (m_VBeamPos == s_lowerFieldBegin + m_VerticalTimingRegister.ACV) + else if (m_VBeamPos == s_lowerFieldBegin + m_VerticalTimingRegister.ACV) EndField(); - m_VBeamPos++; - if (m_VBeamPos > s_lineCount) + + if (++m_VBeamPos > s_lineCount) + { m_VBeamPos = 1; + // Apply frame throttle wheneven a full screen scan finishes + Core::FrameThrottle(); + } for (int i = 0; i < 4; ++i) { @@ -1135,11 +1081,12 @@ void Update() } UpdateInterrupts(); + if (m_VBeamPos == s_upperFieldBegin) BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_UPPER); - - if (m_VBeamPos == s_lowerFieldBegin) + else if (m_VBeamPos == s_lowerFieldBegin) BeginField(m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_LOWER); + } } // namespace diff --git a/Source/Core/Core/Src/HW/VideoInterface.h b/Source/Core/Core/Src/HW/VideoInterface.h index 0260adf24e..9964ee499b 100644 --- a/Source/Core/Core/Src/HW/VideoInterface.h +++ b/Source/Core/Core/Src/HW/VideoInterface.h @@ -22,6 +22,31 @@ class PointerWrap; namespace VideoInterface { +// NTSC is 60 FPS, right? +// Wrong, it's about 59.94 FPS. The NTSC engineers had to slightly lower +// the field rate from 60 FPS when they added color to the standard. +// This was done to prevent analog interference between the video and +// audio signals. PAL has no similar reduction; it is exactly 50 FPS. +//#define NTSC_FIELD_RATE (60.0f / 1.001f) +#define NTSC_FIELD_RATE 60 +#define NTSC_LINE_COUNT 525 +// These line numbers indicate the beginning of the "active video" in a frame. +// An NTSC frame has the lower field first followed by the upper field. +// TODO: Is this true for PAL-M? Is this true for EURGB60? +#define NTSC_LOWER_BEGIN 21 +#define NTSC_UPPER_BEGIN 283 + +//#define PAL_FIELD_RATE 50.0f +#define PAL_FIELD_RATE 50 +#define PAL_LINE_COUNT 625 +// These line numbers indicate the beginning of the "active video" in a frame. +// A PAL frame has the upper field first followed by the lower field. +#define PAL_UPPER_BEGIN 23 // TODO: Actually 23.5! +#define PAL_LOWER_BEGIN 336 + + // urgh, ugly externs. + extern u32 TargetRefreshRate; + // For BS2 HLE void PreInit(bool _bNTSC); void SetRegionReg(char _region); @@ -43,11 +68,6 @@ namespace VideoInterface // Update and draw framebuffer(s) void Update(); - // urgh, ugly externs. - extern float ActualRefreshRate; - extern float TargetRefreshRate; - extern s64 SyncTicksProgress; - // UpdateInterrupts: check if we have to generate a new VI Interrupt void UpdateInterrupts(); diff --git a/Source/Core/Core/Src/OnFrame.cpp b/Source/Core/Core/Src/OnFrame.cpp index 09d34491a5..566bf4658e 100644 --- a/Source/Core/Core/Src/OnFrame.cpp +++ b/Source/Core/Core/Src/OnFrame.cpp @@ -32,7 +32,7 @@ u32 g_autoFirstKey = 0, g_autoSecondKey = 0; bool g_bFirstKey = true; PlayMode g_playMode = MODE_NONE; -int g_framesToSkip = 0, g_frameSkipCounter = 0; +unsigned int g_framesToSkip = 0, g_frameSkipCounter = 0; int g_numPads = 0; ControllerState *g_padStates; @@ -70,14 +70,13 @@ void FrameUpdate() { EndPlayInput(); } - g_bPolled = false; } void SetFrameSkipping(unsigned int framesToSkip) { cs_frameSkip.Enter(); - g_framesToSkip = (int)framesToSkip; + g_framesToSkip = framesToSkip; g_frameSkipCounter = 0; // Don't forget to re-enable rendering in case it wasn't... diff --git a/Source/Core/Core/Src/OnFrame.h b/Source/Core/Core/Src/OnFrame.h index e6eae03a4e..21103826c2 100644 --- a/Source/Core/Core/Src/OnFrame.h +++ b/Source/Core/Core/Src/OnFrame.h @@ -51,7 +51,9 @@ extern bool g_bFrameStep, g_bAutoFire, g_bFirstKey, g_bPolled; extern u32 g_autoFirstKey, g_autoSecondKey; extern PlayMode g_playMode; -extern int g_framesToSkip, g_frameSkipCounter, g_numPads; +extern unsigned int g_framesToSkip, g_frameSkipCounter; + +extern int g_numPads; extern ControllerState *g_padStates; extern FILE *g_recordfd; extern std::string g_recordFile; diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index bf88c57e57..27a5b0ea27 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -383,7 +383,6 @@ void Write16(const u16 _Value, const u32 _Address) // Touching that game is a no-go so I don't want to take the risk :p while (fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint))) { - Fifo_RunLoop(); s_fifoIdleEvent.MsgWait(); } } @@ -414,8 +413,6 @@ void Write16(const u16 _Value, const u32 _Address) Common::AtomicStore(fifo.bFF_Breakpoint, 0); } - Fifo_RunLoop(); - DEBUG_LOG(COMMANDPROCESSOR,"\t write to CTRL_REGISTER : %04x", _Value); DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | LINK %s | BP %s || Init %s | OvF %s | UndF %s" , fifo.bFF_GPReadEnable ? "ON" : "OFF" @@ -572,10 +569,9 @@ void WaitForFrameFinish() { while ((fake_GPWatchdogLastToken == fifo.Fake_GPWDToken) && fifo.bFF_GPReadEnable && ((!fifo.bFF_BPEnable && fifo.CPReadWriteDistance) || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint))); { - Fifo_RunLoop(); s_fifoIdleEvent.MsgWait(); } - + fake_GPWatchdogLastToken = fifo.Fake_GPWDToken; } @@ -594,7 +590,6 @@ void STACKALIGN GatherPipeBursted() fifo.CPWritePointer += GATHER_PIPE_SIZE; Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE); - Fifo_RunLoop(); // High watermark overflow handling (hacked way) if (fifo.CPReadWriteDistance > fifo.CPHiWatermark) @@ -619,7 +614,6 @@ void STACKALIGN GatherPipeBursted() // Wait for GPU to catch up while (fifo.CPReadWriteDistance > fifo.CPLoWatermark && fifo.bFF_GPReadEnable && (!fifo.bFF_BPEnable || (fifo.bFF_BPEnable && !fifo.bFF_Breakpoint))) { - Fifo_RunLoop(); s_fifoIdleEvent.MsgWait(); } } @@ -725,7 +719,6 @@ void UpdateFifoRegister() dist = (wp - fifo.CPBase) + ((fifo.CPEnd + GATHER_PIPE_SIZE) - rp); Common::AtomicStore(fifo.CPReadWriteDistance, dist); - Fifo_RunLoop(); if (!g_VideoInitialize.bOnThread) CatchUpGPU(); diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index e87a437edc..172d6095fa 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -34,6 +34,7 @@ extern u8* g_pVideoData; namespace { static volatile bool fifoStateRun = false; +static volatile bool EmuRunning = false; static u8 *videoBuffer; static Common::Event fifo_run_event; // STATE_TO_SAVE @@ -100,9 +101,11 @@ void Fifo_ExitLoopNonBlocking() fifo_run_event.Set(); } -void Fifo_RunLoop() +void Fifo_RunLoop(bool run) { - fifo_run_event.Set(); + EmuRunning = run; + if (run) + fifo_run_event.Set(); } // Description: Fifo_EnterLoop() sends data through this function. @@ -210,9 +213,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize) } CommandProcessor::SetFifoIdleFromVideoPlugin(); - // "VideoFifo_CheckEFBAccess()" & "VideoFifo_CheckSwapRequest()" should be - // moved to a more suitable place than inside function "Fifo_EnterLoop()" - if (g_ActiveConfig.bEFBAccessEnable || g_ActiveConfig.bUseXFB) + if (EmuRunning) Common::YieldCPU(); else fifo_run_event.MsgWait(); diff --git a/Source/Core/VideoCommon/Src/Fifo.h b/Source/Core/VideoCommon/Src/Fifo.h index 48b94f3bdd..124a019f7d 100644 --- a/Source/Core/VideoCommon/Src/Fifo.h +++ b/Source/Core/VideoCommon/Src/Fifo.h @@ -36,7 +36,7 @@ void Fifo_SendFifoData(u8* _uData, u32 len); void Fifo_EnterLoop(const SVideoInitialize &video_initialize); void Fifo_ExitLoop(); void Fifo_ExitLoopNonBlocking(); -void Fifo_RunLoop(); +void Fifo_RunLoop(bool run); void Fifo_DoState(PointerWrap &f); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index c94535c314..3e11bea9e2 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -535,6 +535,7 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect DEBUGGER_PAUSE_LOG_AT(NEXT_XFB_CMD,false,{printf("RenderToXFB - disabled");}); return; } + Renderer::ResetAPIState(); // Set the backbuffer as the rendering target D3D::dev->SetDepthStencilSurface(NULL); @@ -543,7 +544,6 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect D3DDumpFrame(); EFBTextureToD3DBackBuffer(sourceRc); D3D::EndFrame(); - DEBUGGER_LOG_AT((NEXT_XFB_CMD|NEXT_EFB_CMD|NEXT_FRAME), {printf("StretchRect, EFB->XFB\n");}); @@ -553,6 +553,7 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect xfbAddr, fbWidth, fbHeight, sourceRc.left, sourceRc.top, sourceRc.right, sourceRc.bottom);} ); + Swap(0,FIELD_PROGRESSIVE,0,0); // we used to swap the buffer here, now we will wait // until the XFB pointer is updated by VI D3D::BeginFrame(); @@ -959,9 +960,9 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) // Make any new configuration settings active. UpdateActiveConfig(); - //TODO: Resize backbuffer if window size has changed. This code crashes, debug it. g_VideoInitialize.pCopiedToXFB(false); + //TODO: Resize backbuffer if window size has changed. This code crashes, debug it. CheckForResize(); // --------------------------------------------------------------------- diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index 654ed86b94..a76267e735 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -312,6 +312,7 @@ void DoState(unsigned char **ptr, int mode) { void EmuStateChange(PLUGIN_EMUSTATE newState) { + Fifo_RunLoop((newState == PLUGIN_EMUSTATE_PLAY) ? true : false); } void Video_EnterLoop() @@ -333,7 +334,7 @@ void Video_SetRendering(bool bEnabled) { // Run from the graphics thread void VideoFifo_CheckSwapRequest() { - // CPU swap, not finished, seems to be working fine for dual-core for now + // swap unimplemented return; if (s_swapRequested) @@ -351,12 +352,15 @@ void VideoFifo_CheckSwapRequest() // Run from the graphics thread void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight) { - // CPU swap unimplemented + // swap unimplemented } // Run from the CPU thread (from VideoInterface.cpp) void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) { + // swap unimplemented + return; + s_beginFieldArgs.xfbAddr = xfbAddr; s_beginFieldArgs.field = field; s_beginFieldArgs.fbWidth = fbWidth; @@ -365,14 +369,11 @@ void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) if (s_initialized) { - // Make sure previous swap request has made it to the screen if (g_VideoInitialize.bOnThread) { - // It seems to be working fine in this way for now without using AtomicLoadAcquire - // ector, please check here //while (Common::AtomicLoadAcquire(s_swapRequested)) - // Common::YieldCPU(); + //Common::YieldCPU(); } else VideoFifo_CheckSwapRequest(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 46bc91d313..fb9e2f0cc2 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -597,6 +597,9 @@ void Renderer::SetBlendMode(bool forceUpdate) u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) { + if(!g_ActiveConfig.bEFBAccessEnable) + return 0; + // Get the rectangular target region covered by the EFB pixel. EFBRectangle efbPixelRc; efbPixelRc.left = x; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index df386efdbc..43c19489d1 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -379,6 +379,7 @@ void DoState(unsigned char **ptr, int mode) { void EmuStateChange(PLUGIN_EMUSTATE newState) { + Fifo_RunLoop((newState == PLUGIN_EMUSTATE_PLAY) ? true : false); } // This is called after Video_Initialize() from the Core @@ -494,9 +495,6 @@ void VideoFifo_CheckSwapRequest() g_VideoInitialize.pCopiedToXFB(false); } - // TODO : This just updates the frame counter, so we may change this func's name as well - g_VideoInitialize.pCopiedToXFB(true); - Common::AtomicStoreRelease(s_swapRequested, FALSE); } }