From 97232a47c9bcf6005ee34af0eaff017c5d363eee Mon Sep 17 00:00:00 2001 From: kub Date: Thu, 27 Apr 2023 22:24:21 +0200 Subject: [PATCH] core vdp, implement partial line blanking --- pico/draw.c | 33 ++++++++++++++++++++++-------- pico/videoport.c | 52 +++++++++++++++++++++++++++++------------------- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/pico/draw.c b/pico/draw.c index 5d507d57..99664121 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -1987,7 +1987,7 @@ static void DrawBlankedLine(int line, int offs, int sh, int bgc) est->DrawLineDest = (char *)est->DrawLineDest + DrawLineDestIncrement; } -static void PicoLine(int line, int offs, int sh, int bgc) +static void PicoLine(int line, int offs, int sh, int bgc, int off, int on) { struct PicoEState *est = &Pico.est; int skip = skip_next_line; @@ -2006,8 +2006,17 @@ static void PicoLine(int line, int offs, int sh, int bgc) // Draw screen: BackFill(bgc, sh, est); - if (Pico.video.reg[1]&0x40) + if (Pico.video.reg[1]&0x40) { + int width = (Pico.video.reg[12]&1) ? 320 : 256; DrawDisplay(sh); + // partial line blanking (display on or off inside the line) + if (unlikely(off|on)) { + if (off > 0) + memset(est->HighCol+8 + off, bgc, width-off); + if (on > 0) + memset(est->HighCol+8, bgc, on); + } + } if (FinalizeLine != NULL) FinalizeLine(sh, line, est); @@ -2019,7 +2028,7 @@ static void PicoLine(int line, int offs, int sh, int bgc) est->DrawLineDest = (char *)est->DrawLineDest + DrawLineDestIncrement; } -void PicoDrawSync(int to, int blank_last_line, int limit_sprites) +void PicoDrawSync(int to, int off, int on) { struct PicoEState *est = &Pico.est; int line, offs = 0; @@ -2035,7 +2044,7 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites) } if (est->DrawScanline <= to && (est->rendstatus & (PDRAW_DIRTY_SPRITES|PDRAW_PARSE_SPRITES))) - ParseSprites(to + 1, limit_sprites); + ParseSprites(to + 1, on); else if (!(est->rendstatus & PDRAW_SYNC_NEEDED)) { // nothing has changed in VDP/VRAM and buffer is the same -> no sync needed int count = to+1 - est->DrawScanline; @@ -2046,14 +2055,22 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites) } for (line = est->DrawScanline; line < to; line++) - PicoLine(line, offs, sh, bgc); + PicoLine(line, offs, sh, bgc, 0, 0); // last line if (line <= to) { - if (blank_last_line) - DrawBlankedLine(line, offs, sh, bgc); - else PicoLine(line, offs, sh, bgc); + int width2 = (Pico.video.reg[12]&1) ? 160 : 128; + + // technically, VDP starts active display output at slot 12 + if (unlikely(on|off) && (off >= width2 || + // hack for timing inaccuracy, if on/off near borders + (off && off <= 24) || (on < width2 && on >= width2-24))) + DrawBlankedLine(line, offs, sh, bgc); + else { + if (on > width2) on = 0; // on, before start of line? + PicoLine(line, offs, sh, bgc, 2*off, 2*on); + } line++; } est->DrawScanline = line; diff --git a/pico/videoport.c b/pico/videoport.c index 4778ba99..fa8a3329 100644 --- a/pico/videoport.c +++ b/pico/videoport.c @@ -138,10 +138,11 @@ void PicoVideoInit(void) } -static int blankline; // display disabled for this line -static int limitsprites; +static int linedisabled; // display disabled on this line +static int lineenabled; // display enabled on this line +static int lineoffset; // offset at which dis/enable took place -u32 SATaddr, SATmask; // VRAM addr of sprite attribute table +u32 SATaddr, SATmask; // VRAM addr of sprite attribute table int (*PicoDmaHook)(u32 source, int len, unsigned short **base, u32 *mask) = NULL; @@ -811,8 +812,9 @@ static inline int InHblank(int offs) void PicoVideoSync(int skip) { + struct VdpFIFO *vf = &VdpFIFO; int lines = Pico.video.reg[1]&0x08 ? 240 : 224; - int last = Pico.m.scanline - ((skip > 0) || blankline == Pico.m.scanline); + int last = Pico.m.scanline - (skip > 0); if (!(PicoIn.opt & POPT_ALT_RENDERER) && !PicoIn.skipFrame) { if (last >= lines) @@ -821,13 +823,22 @@ void PicoVideoSync(int skip) Pico.est.rendstatus |= PDRAW_SYNC_NEXT; //elprintf(EL_ANOMALY, "sync"); - if (blankline >= 0 && blankline < last) { - PicoDrawSync(blankline, 1, 0); - blankline = -1; + if (unlikely(linedisabled >= 0 && linedisabled <= last)) { + if (Pico.est.DrawScanline <= linedisabled) { + int sl = vf->fifo_hcounts[lineoffset/clkdiv]; + PicoDrawSync(linedisabled, sl ? sl : 1, 0); + } + linedisabled = -1; } - PicoDrawSync(last, 0, last == limitsprites); - if (last >= limitsprites) - limitsprites = -1; + if (unlikely(lineenabled >= 0 && lineenabled <= last)) { + if (Pico.est.DrawScanline <= lineenabled) { + int sl = vf->fifo_hcounts[lineoffset/clkdiv]; + PicoDrawSync(lineenabled, 0, sl ? sl : 1); + } + lineenabled = -1; + } + if (Pico.est.DrawScanline <= last) + PicoDrawSync(last, 0, 0); } if (skip >= 0) Pico.est.rendstatus |= PDRAW_SYNC_NEEDED; @@ -911,19 +922,18 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d) d &= 0xff; if (num == 0 && !(pvid->reg[0]&2) && (d&2)) pvid->hv_latch = PicoVideoRead(0x08); - if (num == 1 && ((pvid->reg[1]^d)&0x40)) { - PicoVideoFIFOMode(d & 0x40, pvid->reg[12]&1); - // handle line blanking before line rendering - if (InHblank(93)) { - // sprite rendering is limited if display is disabled and reenabled - // in HBLANK of the same scanline (Overdrive) - limitsprites = (d&0x40) && blankline == Pico.m.scanline ? Pico.m.scanline : -1; - blankline = (d&0x40) ? -1 : Pico.m.scanline; - } - } if (num == 12 && ((pvid->reg[12]^d)&0x01)) PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1); - if (((1<reg[num] != d) + + if (num == 1 && ((pvid->reg[1]^d)&0x40)) { + PicoVideoFIFOMode(d & 0x40, pvid->reg[12]&1); + // handle line blanking before line rendering. Only the last switch + // before the 1st sync for other reasons is honoured. + PicoVideoSync(1); + lineenabled = (d&0x40) ? Pico.m.scanline : -1; + linedisabled = (d&0x40) ? -1 : Pico.m.scanline; + lineoffset = SekCyclesDone() - Pico.t.m68c_line_start; + } else if (((1<reg[num] != d) // VDP regs 0-7,11-13,16-18 influence rendering, ignore all others PicoVideoSync(InHblank(93)); // Toy Story pvid->reg[num] = d; -- 2.39.2