GS/Counters: Fix CSR Swap and VBlank Interrupt timing

This commit is contained in:
refractionpcsx2 2020-09-07 20:07:34 +01:00
parent 197eaf3899
commit 1b6b3f692d
2 changed files with 28 additions and 14 deletions

View File

@ -182,6 +182,8 @@ struct vSyncTimingInfo
u32 Render; // time from vblank end to vblank start (cycles) u32 Render; // time from vblank end to vblank start (cycles)
u32 Blank; // time from vblank start to vblank end (cycles) u32 Blank; // time from vblank start to vblank end (cycles)
u32 GSBlank; // GS CSR is swapped roughly 3.5 hblank's after vblank start
u32 hSyncError; // rounding error after the duration of a rendered frame (cycles) u32 hSyncError; // rounding error after the duration of a rendered frame (cycles)
u32 hRender; // time from hblank end to hblank start (cycles) u32 hRender; // time from hblank end to hblank start (cycles)
u32 hBlank; // time from hblank start to hblank end (cycles) u32 hBlank; // time from hblank start to hblank end (cycles)
@ -210,6 +212,7 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, Fixed100 framesPerSecond, u32 s
const u64 HalfFrame = Frame / 2; const u64 HalfFrame = Frame / 2;
const u64 Blank = Scanline * (gsVideoMode == GS_VideoMode::NTSC ? 26 : 22); const u64 Blank = Scanline * (gsVideoMode == GS_VideoMode::NTSC ? 26 : 22);
const u64 Render = HalfFrame - Blank; const u64 Render = HalfFrame - Blank;
const u64 GSBlank = Scanline * 3.5; // GS VBlank/CSR Swap happens roughly 3.5 Scanlines after VBlank Start
// Important! The hRender/hBlank timers should be 50/50 for best results. // Important! The hRender/hBlank timers should be 50/50 for best results.
// (this appears to be what the real EE's timing crystal does anyway) // (this appears to be what the real EE's timing crystal does anyway)
@ -226,6 +229,7 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, Fixed100 framesPerSecond, u32 s
//TODO: Carry fixed-point math all the way through the entire vsync and hsync counting processes, and continually apply rounding //TODO: Carry fixed-point math all the way through the entire vsync and hsync counting processes, and continually apply rounding
//as needed for each scheduled v/hsync related event. Much better to handle than this messed state. //as needed for each scheduled v/hsync related event. Much better to handle than this messed state.
info->Framerate = framesPerSecond; info->Framerate = framesPerSecond;
info->GSBlank = (u32)(GSBlank / 10000);
info->Render = (u32)(Render / 10000); info->Render = (u32)(Render / 10000);
info->Blank = (u32)(Blank / 10000); info->Blank = (u32)(Blank / 10000);
@ -454,13 +458,6 @@ static __fi void VSyncStart(u32 sCycle)
CpuVU0->Vsync(); CpuVU0->Vsync();
CpuVU1->Vsync(); CpuVU1->Vsync();
if (!CSRreg.VSINT)
{
CSRreg.VSINT = true;
if (!GSIMR.VSMSK)
gsIrq();
}
hwIntcIrq(INTC_VBLANK_S); hwIntcIrq(INTC_VBLANK_S);
psxVBlankStart(); psxVBlankStart();
gsPostVsyncStart(); gsPostVsyncStart();
@ -486,6 +483,19 @@ static __fi void VSyncStart(u32 sCycle)
// Should no longer be required (Refraction) // Should no longer be required (Refraction)
} }
static __fi void GSVSync()
{
// CSR is swapped and GS vBlank IRQ is triggered roughly 3.5 hblanks after VSync Start
CSRreg.SwapField();
if (!CSRreg.VSINT)
{
CSRreg.VSINT = true;
if (!GSIMR.VSMSK)
gsIrq();
}
}
static __fi void VSyncEnd(u32 sCycle) static __fi void VSyncEnd(u32 sCycle)
{ {
if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll) if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll)
@ -506,8 +516,6 @@ static __fi void VSyncEnd(u32 sCycle)
frameLimit(); // limit FPS frameLimit(); // limit FPS
//Do this here, breaks Dynasty Warriors otherwise.
CSRreg.SwapField();
// This doesn't seem to be needed here. Games only seem to break with regard to the // This doesn't seem to be needed here. Games only seem to break with regard to the
// vsyncstart irq. // vsyncstart irq.
//cpuRegs.eCycle[30] = 2; //cpuRegs.eCycle[30] = 2;
@ -567,22 +575,27 @@ __fi void rcntUpdate_vSync()
vsyncCounter.CycleT = vSyncInfo.Render; vsyncCounter.CycleT = vSyncInfo.Render;
vsyncCounter.Mode = MODE_VRENDER; vsyncCounter.Mode = MODE_VRENDER;
} }
else if (vsyncCounter.Mode == MODE_GSBLANK) // GS CSR Swap and interrupt
{
GSVSync();
vsyncCounter.Mode = MODE_VSYNC;
// Don't set the start cycle, makes it easier to calculate the correct Vsync End time
vsyncCounter.CycleT = vSyncInfo.Blank;
}
else // VSYNC end / VRENDER begin else // VSYNC end / VRENDER begin
{ {
#ifndef DISABLE_RECORDING #ifndef DISABLE_RECORDING
if (g_Conf->EmuOptions.EnableRecordingTools) if (g_Conf->EmuOptions.EnableRecordingTools)
{ {
g_RecordingControls.HandleFrameAdvanceAndStop(); g_RecordingControls.HandleFrameAdvanceAndStop();
} }
#endif #endif
VSyncStart(vsyncCounter.sCycle); VSyncStart(vsyncCounter.sCycle);
vsyncCounter.sCycle += vSyncInfo.Render; vsyncCounter.sCycle += vSyncInfo.Render;
vsyncCounter.CycleT = vSyncInfo.Blank; vsyncCounter.CycleT = vSyncInfo.GSBlank;
vsyncCounter.Mode = MODE_VSYNC; vsyncCounter.Mode = MODE_GSBLANK;
// Accumulate hsync rounding errors: // Accumulate hsync rounding errors:
hsyncCounter.sCycle += vSyncInfo.hSyncError; hsyncCounter.sCycle += vSyncInfo.hSyncError;

View File

@ -115,6 +115,7 @@ struct SyncCounter
//------------------------------------------------------------------ //------------------------------------------------------------------
#define MODE_VRENDER 0x0 //Set during the Render/Frame Scanlines #define MODE_VRENDER 0x0 //Set during the Render/Frame Scanlines
#define MODE_VBLANK 0x1 //Set during the Blanking Scanlines #define MODE_VBLANK 0x1 //Set during the Blanking Scanlines
#define MODE_GSBLANK 0x2 //Set during the Syncing Scanlines (Delayed GS CSR Swap)
#define MODE_VSYNC 0x3 //Set during the Syncing Scanlines #define MODE_VSYNC 0x3 //Set during the Syncing Scanlines
#define MODE_VBLANK1 0x0 //Set during the Blanking Scanlines (half-frame 1) #define MODE_VBLANK1 0x0 //Set during the Blanking Scanlines (half-frame 1)
#define MODE_VBLANK2 0x1 //Set during the Blanking Scanlines (half-frame 2) #define MODE_VBLANK2 0x1 //Set during the Blanking Scanlines (half-frame 2)