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
This commit is contained in:
refraction 2011-05-05 22:22:45 +00:00
parent 66ba9a07ce
commit d9d909849d
4 changed files with 32 additions and 29 deletions

View File

@ -193,7 +193,14 @@ static void vSyncInfoCalc( vSyncTimingInfo* info, Fixed100 framesPerSecond, u32
u64 Frame = ((u64)PS2CLK * 1000000ULL) / (framesPerSecond*100).ToIntRounded(); u64 Frame = ((u64)PS2CLK * 1000000ULL) / (framesPerSecond*100).ToIntRounded();
u64 HalfFrame = Frame / 2; 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... u64 Render = HalfFrame - Blank; // so use the half-frame value for these...
// Important! The hRender/hBlank timers should be 50/50 for best results. // 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) // 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 // 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 // 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 // or progressive scan content.
// that it does not actually measure Vblank/Vdraw zones accurately (which would be like
// 1/5 and 4/5 ratios).
Fixed100 framerate; Fixed100 framerate;
u32 scanlines; u32 scanlines;
@ -264,11 +269,6 @@ u32 UpdateVSyncRate()
Console.WriteLn( Color_Green, "(UpdateVSyncRate) Mode Changed to %s.", ( gsRegionMode == Region_PAL ) ? "PAL" : "NTSC" ); Console.WriteLn( Color_Green, "(UpdateVSyncRate) Mode Changed to %s.", ( gsRegionMode == Region_PAL ) ? "PAL" : "NTSC" );
if( isCustom ) if( isCustom )
Console.Indent().WriteLn( Color_StrongGreen, "... with user configured refresh rate: %.02f Hz", framerate.ToFloat() ); 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 * Fixed100 fpslimit = framerate *
@ -369,7 +369,7 @@ static __fi void VSyncStart(u32 sCycle)
hwIntcIrq(INTC_VBLANK_S); hwIntcIrq(INTC_VBLANK_S);
psxVBlankStart(); psxVBlankStart();
gsPostVsyncStart();
if (gates) rcntStartGate(true, sCycle); // Counters Start Gate code if (gates) rcntStartGate(true, sCycle); // Counters Start Gate code
// INTC - VB Blank Start Hack -- // INTC - VB Blank Start Hack --
@ -399,7 +399,7 @@ static __fi void VSyncEnd(u32 sCycle)
g_FrameCount++; g_FrameCount++;
gsPostVsyncEnd();
hwIntcIrq(INTC_VBLANK_E); // HW Irq hwIntcIrq(INTC_VBLANK_E); // HW Irq
psxVBlankEnd(); // psxCounters vBlank End psxVBlankEnd(); // psxCounters vBlank End
@ -462,17 +462,17 @@ __fi void rcntUpdate_vSync()
if (vsyncCounter.Mode == MODE_VSYNC) if (vsyncCounter.Mode == MODE_VSYNC)
{ {
VSyncEnd(vsyncCounter.sCycle); VSyncEnd(vsyncCounter.sCycle);
vsyncCounter.sCycle += vSyncInfo.Blank; vsyncCounter.sCycle += vSyncInfo.Render;
vsyncCounter.CycleT = vSyncInfo.Render; vsyncCounter.CycleT = 0;
vsyncCounter.Mode = MODE_VRENDER; vsyncCounter.Mode = MODE_VRENDER;
} }
else // VSYNC end / VRENDER begin else // VSYNC end / VRENDER begin
{ {
VSyncStart(vsyncCounter.sCycle); VSyncStart(vsyncCounter.sCycle);
vsyncCounter.sCycle += vSyncInfo.Render; vsyncCounter.sCycle += vSyncInfo.Blank;
vsyncCounter.CycleT = vSyncInfo.Blank; vsyncCounter.CycleT = 0;
vsyncCounter.Mode = MODE_VSYNC; vsyncCounter.Mode = MODE_VSYNC;
// Accumulate hsync rounding errors: // Accumulate hsync rounding errors:
@ -620,8 +620,8 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle)
counters[i].mode.IsCounting = 1; counters[i].mode.IsCounting = 1;
counters[i].sCycleT = sCycle; counters[i].sCycleT = sCycle;
EECNT_LOG("EE Counter[%d] %s StartGate Type0, count = %x", EECNT_LOG("EE Counter[%d] %s StartGate Type0, count = %x", i,
isVblank ? "vblank" : "hblank", i, counters[i].count ); isVblank ? "vblank" : "hblank", counters[i].count );
break; break;
case 0x2: // reset and start counting on vsync end 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].count = 0;
counters[i].target &= 0xffff; counters[i].target &= 0xffff;
counters[i].sCycleT = sCycle; counters[i].sCycleT = sCycle;
EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x", EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x", i,
isVblank ? "vblank" : "hblank", i, counters[i].mode.GateMode, counters[i].count ); isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count );
break; break;
} }
} }
@ -667,8 +667,8 @@ static __fi void rcntEndGate(bool isVblank , u32 sCycle)
counters[i].count = rcntRcount(i); counters[i].count = rcntRcount(i);
counters[i].mode.IsCounting = 0; counters[i].mode.IsCounting = 0;
counters[i].sCycleT = sCycle; counters[i].sCycleT = sCycle;
EECNT_LOG("EE Counter[%d] %s EndGate Type0, count = %x", EECNT_LOG("EE Counter[%d] %s EndGate Type0, count = %x", i,
isVblank ? "vblank" : "hblank", i, counters[i].count ); isVblank ? "vblank" : "hblank", counters[i].count );
break; break;
case 0x1: // Reset and start counting on Vsync start 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].count = 0;
counters[i].target &= 0xffff; counters[i].target &= 0xffff;
counters[i].sCycleT = sCycle; counters[i].sCycleT = sCycle;
EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x", EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x", i,
isVblank ? "vblank" : "hblank", i, counters[i].mode.GateMode, counters[i].count ); isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count );
break; break;
} }
} }

View File

@ -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(); CSRreg.SwapField();
GetMTGS().PostVsyncEnd(); GetMTGS().PostVsyncStart();
} }
void _gs_ResetFrameskip() void _gs_ResetFrameskip()

View File

@ -331,7 +331,7 @@ public:
u8* GetDataPacketPtr() const; u8* GetDataPacketPtr() const;
void SetEvent(); void SetEvent();
void PostVsyncEnd(); void PostVsyncStart();
bool IsPluginOpened() const { return m_PluginOpened; } bool IsPluginOpened() const { return m_PluginOpened; }
@ -371,7 +371,7 @@ extern void gsReset();
extern void gsOnModeChanged( Fixed100 framerate, u32 newTickrate ); extern void gsOnModeChanged( Fixed100 framerate, u32 newTickrate );
extern void gsSetRegionMode( GS_RegionMode isPal ); extern void gsSetRegionMode( GS_RegionMode isPal );
extern void gsResetFrameSkip(); extern void gsResetFrameSkip();
extern void gsPostVsyncEnd(); extern void gsPostVsyncStart();
extern void gsFrameSkip(); extern void gsFrameSkip();
// Some functions shared by both the GS and MTGS // Some functions shared by both the GS and MTGS

View File

@ -125,7 +125,7 @@ struct RingCmdPacket_Vsync
GSRegSIGBLID siglblid; GSRegSIGBLID siglblid;
}; };
void SysMtgsThread::PostVsyncEnd() void SysMtgsThread::PostVsyncStart()
{ {
// Optimization note: Typically regset1 isn't needed. The regs in that area are typically // 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 // changed infrequently, usually during video mode changes. However, on modern systems the