diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index c003741fd3..e8d0426931 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -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(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) { diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index f34d2d03a5..a49057d978 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -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) diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 4f94618a0e..697f25f397 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -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. diff --git a/pcsx2/GS/GSState.h b/pcsx2/GS/GSState.h index fcf7884835..02308f2ad0 100644 --- a/pcsx2/GS/GSState.h +++ b/pcsx2/GS/GSState.h @@ -298,6 +298,7 @@ public: bool IsEnabled(int i); bool isinterlaced(); + bool isReallyInterlaced(); bool IsAnalogue(); float GetTvRefreshRate(); diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index 4ce9cc5c7f..7aa7a13d27 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -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;