GS: Correctly handle field/deinterlace for progressive/interlaced mode.

Also correct the number of scanlines for progressive (double strike) and how long vblank is.
This commit is contained in:
refractionpcsx2 2022-06-05 05:17:16 +01:00
parent 394f1f2049
commit cf3cfdb2bc
5 changed files with 34 additions and 12 deletions

View File

@ -78,7 +78,9 @@ static bool IsInterlacedVideoMode()
static bool IsProgressiveVideoMode()
{
return (gsVideoMode == GS_VideoMode::VESA || gsVideoMode == GS_VideoMode::SDTV_480P || gsVideoMode == GS_VideoMode::SDTV_576P || gsVideoMode == GS_VideoMode::HDTV_720P || gsVideoMode == GS_VideoMode::HDTV_1080P);
// The FIELD register only flips if the CMOD field in SMODE1 is set to anything but 0 and Front Porch bottom bit in SYNCV is set.
// Also see "isReallyInterlaced()" in GSState.cpp
return !(*(u32*)PS2GS_BASE(GS_SYNCV) & 0x1) || !(*(u32*)PS2GS_BASE(GS_SMODE1) & 0x6000);
}
void rcntReset(int index) {
@ -231,7 +233,7 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
// Jak II - random speedups
// Shadow of Rome - FMV audio issues
const u64 HalfFrame = Frame / 2;
const u64 Blank = Scanline * (gsVideoMode == GS_VideoMode::NTSC ? 22 : 26);
const u64 Blank = Scanline *((gsVideoMode == GS_VideoMode::NTSC ? 22 : 25) + static_cast<int>(gsIsInterlaced));
const u64 Render = HalfFrame - Blank;
const u64 GSBlank = Scanline * 3.5; // GS VBlank/CSR Swap happens roughly 3.5 Scanlines after VBlank Start
@ -404,23 +406,32 @@ u32 UpdateVSyncRate()
switch (gsVideoMode)
{
case GS_VideoMode::Uninitialized: // SYSCALL instruction hasn't executed yet, give some temporary values.
total_scanlines = SCANLINES_TOTAL_NTSC;
if(gsIsInterlaced)
total_scanlines = SCANLINES_TOTAL_NTSC_I;
else
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
break;
case GS_VideoMode::PAL:
case GS_VideoMode::DVD_PAL:
custom = (EmuConfig.GS.FrameratePAL != 50.0);
total_scanlines = SCANLINES_TOTAL_PAL;
if (gsIsInterlaced)
total_scanlines = SCANLINES_TOTAL_PAL_I;
else
total_scanlines = SCANLINES_TOTAL_PAL_NI;
break;
case GS_VideoMode::NTSC:
case GS_VideoMode::DVD_NTSC:
custom = (EmuConfig.GS.FramerateNTSC != 59.94);
total_scanlines = SCANLINES_TOTAL_NTSC;
if (gsIsInterlaced)
total_scanlines = SCANLINES_TOTAL_NTSC_I;
else
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
break;
case GS_VideoMode::SDTV_480P:
case GS_VideoMode::SDTV_576P:
case GS_VideoMode::HDTV_720P:
case GS_VideoMode::VESA:
total_scanlines = SCANLINES_TOTAL_NTSC;
total_scanlines = SCANLINES_TOTAL_NTSC_I;
break;
case GS_VideoMode::HDTV_1080P:
case GS_VideoMode::HDTV_1080I:
@ -428,7 +439,10 @@ u32 UpdateVSyncRate()
break;
case GS_VideoMode::Unknown:
default:
total_scanlines = SCANLINES_TOTAL_NTSC;
if (gsIsInterlaced)
total_scanlines = SCANLINES_TOTAL_NTSC_I;
else
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
Console.Error("PCSX2-Counters: Unknown video mode detected");
pxAssertDev(false , "Unknown video mode detected via SetGsCrt");
}
@ -728,8 +742,7 @@ __fi void rcntUpdate_hScanline()
__fi void rcntUpdate_vSync()
{
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle);
if( diff < vsyncCounter.CycleT ) return;
if (!cpuTestCycle(vsyncCounter.sCycle, vsyncCounter.CycleT)) return;
if (vsyncCounter.Mode == MODE_VSYNC)
{

View File

@ -96,7 +96,8 @@ struct SyncCounter
//------------------------------------------------------------------
#define FRAMERATE_NTSC 29.97 // frames per second
#define SCANLINES_TOTAL_NTSC 525 // total number of scanlines
#define SCANLINES_TOTAL_NTSC_I 525 // total number of scanlines (Interlaced)
#define SCANLINES_TOTAL_NTSC_NI 526 // total number of scanlines (Interlaced)
#define SCANLINES_VSYNC_NTSC 3 // scanlines that are used for syncing every half-frame
#define SCANLINES_VRENDER_NTSC 240 // scanlines in a half-frame (because of interlacing)
#define SCANLINES_VBLANK1_NTSC 19 // scanlines used for vblank1 (even interlace)
@ -107,7 +108,8 @@ struct SyncCounter
//------------------------------------------------------------------
#define FRAMERATE_PAL 25.0// frames per second * 100 (25)
#define SCANLINES_TOTAL_PAL 625 // total number of scanlines per frame
#define SCANLINES_TOTAL_PAL_I 625 // total number of scanlines per frame (Interlaced)
#define SCANLINES_TOTAL_PAL_NI 628 // total number of scanlines per frame (Not Interlaced)
#define SCANLINES_VSYNC_PAL 5 // scanlines that are used for syncing every half-frame
#define SCANLINES_VRENDER_PAL 288 // scanlines in a half-frame (because of interlacing)
#define SCANLINES_VBLANK1_PAL 19 // scanlines used for vblank1 (even interlace)

View File

@ -340,6 +340,12 @@ bool GSState::isinterlaced()
return !!m_regs->SMODE2.INT;
}
bool GSState::isReallyInterlaced()
{
// The FIELD register only flips if the CMOD field in SMODE1 is set to anything but 0 and Front Porch bottom bit in SYNCV is set.
return (m_regs->SYNCV.VFP & 0x1) && m_regs->SMODE1.CMOD;
}
GSVideoMode GSState::GetVideoMode()
{
// TODO: Get confirmation of videomode from SYSCALL ? not necessary but would be nice.

View File

@ -298,6 +298,7 @@ public:
bool IsEnabled(int i);
bool isinterlaced();
bool isReallyInterlaced();
bool IsAnalogue();
float GetTvRefreshRate();

View File

@ -337,7 +337,7 @@ bool GSRenderer::Merge(int field)
// Offset is not compatible with scanmsk, as scanmsk renders every other line, but at x7 the interlace offset will be 7 lines
const int offset = (m_scanmask_used || !m_regs->SMODE2.FFMD) ? 0 : (int)(tex[1] ? tex[1]->GetScale().y : tex[0]->GetScale().y);
if (m_regs->SMODE2.INT && GSConfig.InterlaceMode != GSInterlaceMode::Off)
if (isReallyInterlaced() && GSConfig.InterlaceMode != GSInterlaceMode::Off)
{
const bool scanmask = m_scanmask_used && scanmask_frame && GSConfig.InterlaceMode == GSInterlaceMode::Automatic;