core vdp, implement partial line blanking

This commit is contained in:
kub 2023-04-27 22:24:21 +02:00
parent f9ed944604
commit 97232a47c9
2 changed files with 56 additions and 29 deletions

View file

@ -1987,7 +1987,7 @@ static void DrawBlankedLine(int line, int offs, int sh, int bgc)
est->DrawLineDest = (char *)est->DrawLineDest + DrawLineDestIncrement; 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; struct PicoEState *est = &Pico.est;
int skip = skip_next_line; int skip = skip_next_line;
@ -2006,8 +2006,17 @@ static void PicoLine(int line, int offs, int sh, int bgc)
// Draw screen: // Draw screen:
BackFill(bgc, sh, est); 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); 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) if (FinalizeLine != NULL)
FinalizeLine(sh, line, est); 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; 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; struct PicoEState *est = &Pico.est;
int line, offs = 0; int line, offs = 0;
@ -2035,7 +2044,7 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
} }
if (est->DrawScanline <= to && if (est->DrawScanline <= to &&
(est->rendstatus & (PDRAW_DIRTY_SPRITES|PDRAW_PARSE_SPRITES))) (est->rendstatus & (PDRAW_DIRTY_SPRITES|PDRAW_PARSE_SPRITES)))
ParseSprites(to + 1, limit_sprites); ParseSprites(to + 1, on);
else if (!(est->rendstatus & PDRAW_SYNC_NEEDED)) { else if (!(est->rendstatus & PDRAW_SYNC_NEEDED)) {
// nothing has changed in VDP/VRAM and buffer is the same -> no sync needed // nothing has changed in VDP/VRAM and buffer is the same -> no sync needed
int count = to+1 - est->DrawScanline; 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++) for (line = est->DrawScanline; line < to; line++)
PicoLine(line, offs, sh, bgc); PicoLine(line, offs, sh, bgc, 0, 0);
// last line // last line
if (line <= to) if (line <= to)
{ {
if (blank_last_line) 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); DrawBlankedLine(line, offs, sh, bgc);
else PicoLine(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++; line++;
} }
est->DrawScanline = line; est->DrawScanline = line;

View file

@ -138,8 +138,9 @@ void PicoVideoInit(void)
} }
static int blankline; // display disabled for this line static int linedisabled; // display disabled on this line
static int limitsprites; 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
@ -811,8 +812,9 @@ static inline int InHblank(int offs)
void PicoVideoSync(int skip) void PicoVideoSync(int skip)
{ {
struct VdpFIFO *vf = &VdpFIFO;
int lines = Pico.video.reg[1]&0x08 ? 240 : 224; 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 (!(PicoIn.opt & POPT_ALT_RENDERER) && !PicoIn.skipFrame) {
if (last >= lines) if (last >= lines)
@ -821,13 +823,22 @@ void PicoVideoSync(int skip)
Pico.est.rendstatus |= PDRAW_SYNC_NEXT; Pico.est.rendstatus |= PDRAW_SYNC_NEXT;
//elprintf(EL_ANOMALY, "sync"); //elprintf(EL_ANOMALY, "sync");
if (blankline >= 0 && blankline < last) { if (unlikely(linedisabled >= 0 && linedisabled <= last)) {
PicoDrawSync(blankline, 1, 0); if (Pico.est.DrawScanline <= linedisabled) {
blankline = -1; int sl = vf->fifo_hcounts[lineoffset/clkdiv];
PicoDrawSync(linedisabled, sl ? sl : 1, 0);
} }
PicoDrawSync(last, 0, last == limitsprites); linedisabled = -1;
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) if (skip >= 0)
Pico.est.rendstatus |= PDRAW_SYNC_NEEDED; Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;
@ -911,19 +922,18 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
d &= 0xff; d &= 0xff;
if (num == 0 && !(pvid->reg[0]&2) && (d&2)) if (num == 0 && !(pvid->reg[0]&2) && (d&2))
pvid->hv_latch = PicoVideoRead(0x08); 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)) if (num == 12 && ((pvid->reg[12]^d)&0x01))
PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1); PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1);
if (((1<<num) & 0x738ff) && pvid->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<<num) & 0x738ff) && pvid->reg[num] != d)
// VDP regs 0-7,11-13,16-18 influence rendering, ignore all others // VDP regs 0-7,11-13,16-18 influence rendering, ignore all others
PicoVideoSync(InHblank(93)); // Toy Story PicoVideoSync(InHblank(93)); // Toy Story
pvid->reg[num] = d; pvid->reg[num] = d;