From d9d909849db660ee3be8f44ffafa6a59e4998826 Mon Sep 17 00:00:00 2001 From: refraction Date: Thu, 5 May 2011 22:22:45 +0000 Subject: [PATCH] Adjusted VSync to work more like the PS2 does it, also involves a small change which "might" sold some half screen issues. Fixed a couple of counter log bugs too (caused it to crash when EE Counter logs were enabled) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4624 96395faa-99c1-11dd-bbfe-3dabce05a288 --- pcsx2/Counters.cpp | 48 +++++++++++++++++++++++----------------------- pcsx2/GS.cpp | 7 +++++-- pcsx2/GS.h | 4 ++-- pcsx2/MTGS.cpp | 2 +- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index ae50301a56..623f99d36d 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -193,7 +193,14 @@ static void vSyncInfoCalc( vSyncTimingInfo* info, Fixed100 framesPerSecond, u32 u64 Frame = ((u64)PS2CLK * 1000000ULL) / (framesPerSecond*100).ToIntRounded(); u64 HalfFrame = Frame / 2; - u64 Blank = HalfFrame / 2; // two blanks and renders per frame + u64 Blank = (Frame / scansPerFrame) * 22; // PAL VBlank Period is roughly 22 HSyncs + + if(scansPerFrame == SCANLINES_TOTAL_NTSC) + Blank = (Frame / scansPerFrame) * 26; // NTSC VBlank Period is roughly 26 HSyncs, so we update + + //I would have suspected this to be Frame - Blank, but that seems to completely freak it out + //and the test results are completely wrong. It seems 100% the same as the PS2 test on this, + //So let's roll with it :P u64 Render = HalfFrame - Blank; // so use the half-frame value for these... // Important! The hRender/hBlank timers should be 50/50 for best results. @@ -237,9 +244,7 @@ u32 UpdateVSyncRate() // The PS2's vsync timer is an *independent* crystal that is fixed to either 59.94 (NTSC) // or 50.0 (PAL) Hz. It has *nothing* to do with real TV timings or the real vsync of // the GS's output circuit. It is the same regardless if the GS is outputting interlace - // or progressive scan content. Indications are that it is also a simple 50/50 timer and - // that it does not actually measure Vblank/Vdraw zones accurately (which would be like - // 1/5 and 4/5 ratios). + // or progressive scan content. Fixed100 framerate; u32 scanlines; @@ -264,11 +269,6 @@ u32 UpdateVSyncRate() Console.WriteLn( Color_Green, "(UpdateVSyncRate) Mode Changed to %s.", ( gsRegionMode == Region_PAL ) ? "PAL" : "NTSC" ); if( isCustom ) Console.Indent().WriteLn( Color_StrongGreen, "... with user configured refresh rate: %.02f Hz", framerate.ToFloat() ); - - hsyncCounter.CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated - vsyncCounter.CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated - - cpuRcntSet(); } Fixed100 fpslimit = framerate * @@ -369,7 +369,7 @@ static __fi void VSyncStart(u32 sCycle) hwIntcIrq(INTC_VBLANK_S); psxVBlankStart(); - + gsPostVsyncStart(); if (gates) rcntStartGate(true, sCycle); // Counters Start Gate code // INTC - VB Blank Start Hack -- @@ -399,7 +399,7 @@ static __fi void VSyncEnd(u32 sCycle) g_FrameCount++; - gsPostVsyncEnd(); + hwIntcIrq(INTC_VBLANK_E); // HW Irq psxVBlankEnd(); // psxCounters vBlank End @@ -462,17 +462,17 @@ __fi void rcntUpdate_vSync() if (vsyncCounter.Mode == MODE_VSYNC) { VSyncEnd(vsyncCounter.sCycle); - - vsyncCounter.sCycle += vSyncInfo.Blank; - vsyncCounter.CycleT = vSyncInfo.Render; + + vsyncCounter.sCycle += vSyncInfo.Render; + vsyncCounter.CycleT = 0; vsyncCounter.Mode = MODE_VRENDER; } else // VSYNC end / VRENDER begin { VSyncStart(vsyncCounter.sCycle); - vsyncCounter.sCycle += vSyncInfo.Render; - vsyncCounter.CycleT = vSyncInfo.Blank; + vsyncCounter.sCycle += vSyncInfo.Blank; + vsyncCounter.CycleT = 0; vsyncCounter.Mode = MODE_VSYNC; // Accumulate hsync rounding errors: @@ -620,8 +620,8 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle) counters[i].mode.IsCounting = 1; counters[i].sCycleT = sCycle; - EECNT_LOG("EE Counter[%d] %s StartGate Type0, count = %x", - isVblank ? "vblank" : "hblank", i, counters[i].count ); + EECNT_LOG("EE Counter[%d] %s StartGate Type0, count = %x", i, + isVblank ? "vblank" : "hblank", counters[i].count ); break; case 0x2: // reset and start counting on vsync end @@ -634,8 +634,8 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle) counters[i].count = 0; counters[i].target &= 0xffff; counters[i].sCycleT = sCycle; - EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x", - isVblank ? "vblank" : "hblank", i, counters[i].mode.GateMode, counters[i].count ); + EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x", i, + isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count ); break; } } @@ -667,8 +667,8 @@ static __fi void rcntEndGate(bool isVblank , u32 sCycle) counters[i].count = rcntRcount(i); counters[i].mode.IsCounting = 0; counters[i].sCycleT = sCycle; - EECNT_LOG("EE Counter[%d] %s EndGate Type0, count = %x", - isVblank ? "vblank" : "hblank", i, counters[i].count ); + EECNT_LOG("EE Counter[%d] %s EndGate Type0, count = %x", i, + isVblank ? "vblank" : "hblank", counters[i].count ); break; case 0x1: // Reset and start counting on Vsync start @@ -681,8 +681,8 @@ static __fi void rcntEndGate(bool isVblank , u32 sCycle) counters[i].count = 0; counters[i].target &= 0xffff; counters[i].sCycleT = sCycle; - EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x", - isVblank ? "vblank" : "hblank", i, counters[i].mode.GateMode, counters[i].count ); + EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x", i, + isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count ); break; } } diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index cd38050cbc..1e7c742c64 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -438,10 +438,13 @@ __fi void gsFrameSkip() } } -void gsPostVsyncEnd() +//These are done at VSync Start. Drawing is done when VSync is off, then output the screen when Vsync is on +//The GS needs to be told at the start of a vsync else it loses half of its picture (could be responsible for some halfscreen issues) +//We got away with it before i think due to our awful GS timing, but now we have it right (ish) +void gsPostVsyncStart() { CSRreg.SwapField(); - GetMTGS().PostVsyncEnd(); + GetMTGS().PostVsyncStart(); } void _gs_ResetFrameskip() diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 8162149218..d79cbd9def 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -331,7 +331,7 @@ public: u8* GetDataPacketPtr() const; void SetEvent(); - void PostVsyncEnd(); + void PostVsyncStart(); bool IsPluginOpened() const { return m_PluginOpened; } @@ -371,7 +371,7 @@ extern void gsReset(); extern void gsOnModeChanged( Fixed100 framerate, u32 newTickrate ); extern void gsSetRegionMode( GS_RegionMode isPal ); extern void gsResetFrameSkip(); -extern void gsPostVsyncEnd(); +extern void gsPostVsyncStart(); extern void gsFrameSkip(); // Some functions shared by both the GS and MTGS diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index c951392ebe..89b5ab8193 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -125,7 +125,7 @@ struct RingCmdPacket_Vsync GSRegSIGBLID siglblid; }; -void SysMtgsThread::PostVsyncEnd() +void SysMtgsThread::PostVsyncStart() { // Optimization note: Typically regset1 isn't needed. The regs in that area are typically // changed infrequently, usually during video mode changes. However, on modern systems the