From 19204882c45e35c30eff0de206dc1503d71e30b4 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Fri, 4 Nov 2022 18:34:43 +0100 Subject: [PATCH] pvr: reschedule spg when SPG_HBLANK_INT is updated Fixes Triggerheart Exelica input lag Issue #691 --- core/hw/pvr/pvr_regs.cpp | 8 +++++ core/hw/pvr/spg.cpp | 65 +++++++++++++++++++++------------------- core/hw/pvr/spg.h | 1 + 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/core/hw/pvr/pvr_regs.cpp b/core/hw/pvr/pvr_regs.cpp index 59bb0696f..235c728fb 100644 --- a/core/hw/pvr/pvr_regs.cpp +++ b/core/hw/pvr/pvr_regs.cpp @@ -205,6 +205,14 @@ void pvr_WriteReg(u32 paddr,u32 data) data &= 0x01fffffc; break; + case SPG_HBLANK_INT_addr: + data &= 0x03FF33FF; + if (data != SPG_HBLANK_INT.full) { + SPG_HBLANK_INT.full = data; + rescheduleSPG(); + } + return; + case PAL_RAM_CTRL_addr: pal_needs_update = pal_needs_update || ((data ^ PAL_RAM_CTRL) & 3) != 0; break; diff --git a/core/hw/pvr/spg.cpp b/core/hw/pvr/spg.cpp index c2583a83d..406818071 100755 --- a/core/hw/pvr/spg.cpp +++ b/core/hw/pvr/spg.cpp @@ -55,6 +55,39 @@ void CalculateSync() sh4_sched_request(vblank_schid, Line_Cycles); } +static int getNextSpgInterrupt() +{ + u32 min_scanline = prv_cur_scanline + 1; + u32 min_active = pvr_numscanlines; + + if (min_scanline < SPG_VBLANK_INT.vblank_in_interrupt_line_number) + min_active = std::min(min_active, SPG_VBLANK_INT.vblank_in_interrupt_line_number); + + if (min_scanline < SPG_VBLANK_INT.vblank_out_interrupt_line_number) + min_active = std::min(min_active, SPG_VBLANK_INT.vblank_out_interrupt_line_number); + + if (min_scanline < SPG_VBLANK.vstart) + min_active = std::min(min_active, SPG_VBLANK.vstart); + + if (min_scanline < SPG_VBLANK.vbend) + min_active = std::min(min_active, SPG_VBLANK.vbend); + + if (lightgun_line != 0xffff && min_scanline < lightgun_line) + min_active = std::min(min_active, lightgun_line); + + if (SPG_HBLANK_INT.hblank_int_mode == 0 && min_scanline < SPG_HBLANK_INT.line_comp_val) + min_active = std::min(min_active, SPG_HBLANK_INT.line_comp_val); + + min_active = std::max(min_active, min_scanline); + + return (min_active - prv_cur_scanline) * Line_Cycles; +} + +void rescheduleSPG() +{ + sh4_sched_request(vblank_schid, getNextSpgInterrupt()); +} + //called from sh4 context , should update pvr/ta state and everything else static int spg_line_sched(int tag, int cycl, int jit) { @@ -190,37 +223,7 @@ static int spg_line_sched(int tag, int cycl, int jit) } } - //interrupts - //0 - //vblank_in_interrupt_line_number - //vblank_out_interrupt_line_number - //vstart - //vbend - //pvr_numscanlines - u32 min_scanline=prv_cur_scanline+1; - u32 min_active=pvr_numscanlines; - - if (min_scanline