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() 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) { void rcntReset(int index) {
@ -231,7 +233,7 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
// Jak II - random speedups // Jak II - random speedups
// Shadow of Rome - FMV audio issues // Shadow of Rome - FMV audio issues
const u64 HalfFrame = Frame / 2; 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 Render = HalfFrame - Blank;
const u64 GSBlank = Scanline * 3.5; // GS VBlank/CSR Swap happens roughly 3.5 Scanlines after VBlank Start 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) switch (gsVideoMode)
{ {
case GS_VideoMode::Uninitialized: // SYSCALL instruction hasn't executed yet, give some temporary values. 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; break;
case GS_VideoMode::PAL: case GS_VideoMode::PAL:
case GS_VideoMode::DVD_PAL: case GS_VideoMode::DVD_PAL:
custom = (EmuConfig.GS.FrameratePAL != 50.0); 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; break;
case GS_VideoMode::NTSC: case GS_VideoMode::NTSC:
case GS_VideoMode::DVD_NTSC: case GS_VideoMode::DVD_NTSC:
custom = (EmuConfig.GS.FramerateNTSC != 59.94); 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; break;
case GS_VideoMode::SDTV_480P: case GS_VideoMode::SDTV_480P:
case GS_VideoMode::SDTV_576P: case GS_VideoMode::SDTV_576P:
case GS_VideoMode::HDTV_720P: case GS_VideoMode::HDTV_720P:
case GS_VideoMode::VESA: case GS_VideoMode::VESA:
total_scanlines = SCANLINES_TOTAL_NTSC; total_scanlines = SCANLINES_TOTAL_NTSC_I;
break; break;
case GS_VideoMode::HDTV_1080P: case GS_VideoMode::HDTV_1080P:
case GS_VideoMode::HDTV_1080I: case GS_VideoMode::HDTV_1080I:
@ -428,7 +439,10 @@ u32 UpdateVSyncRate()
break; break;
case GS_VideoMode::Unknown: case GS_VideoMode::Unknown:
default: 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"); Console.Error("PCSX2-Counters: Unknown video mode detected");
pxAssertDev(false , "Unknown video mode detected via SetGsCrt"); pxAssertDev(false , "Unknown video mode detected via SetGsCrt");
} }
@ -728,8 +742,7 @@ __fi void rcntUpdate_hScanline()
__fi void rcntUpdate_vSync() __fi void rcntUpdate_vSync()
{ {
s32 diff = (cpuRegs.cycle - vsyncCounter.sCycle); if (!cpuTestCycle(vsyncCounter.sCycle, vsyncCounter.CycleT)) return;
if( diff < vsyncCounter.CycleT ) return;
if (vsyncCounter.Mode == MODE_VSYNC) if (vsyncCounter.Mode == MODE_VSYNC)
{ {

View File

@ -96,7 +96,8 @@ struct SyncCounter
//------------------------------------------------------------------ //------------------------------------------------------------------
#define FRAMERATE_NTSC 29.97 // frames per second #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_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_VRENDER_NTSC 240 // scanlines in a half-frame (because of interlacing)
#define SCANLINES_VBLANK1_NTSC 19 // scanlines used for vblank1 (even interlace) #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 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_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_VRENDER_PAL 288 // scanlines in a half-frame (because of interlacing)
#define SCANLINES_VBLANK1_PAL 19 // scanlines used for vblank1 (even interlace) #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; 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() GSVideoMode GSState::GetVideoMode()
{ {
// TODO: Get confirmation of videomode from SYSCALL ? not necessary but would be nice. // 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 IsEnabled(int i);
bool isinterlaced(); bool isinterlaced();
bool isReallyInterlaced();
bool IsAnalogue(); bool IsAnalogue();
float GetTvRefreshRate(); 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 // 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); 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; const bool scanmask = m_scanmask_used && scanmask_frame && GSConfig.InterlaceMode == GSInterlaceMode::Automatic;