mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
66ba9a07ce
commit
d9d909849d
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue