From f9ed944604effd3122052e3ae3d7712e5aabdd89 Mon Sep 17 00:00:00 2001 From: kub Date: Thu, 27 Apr 2023 22:18:55 +0200 Subject: [PATCH] core vdp, avoid rendering if no changes to RAMs/registers mainly benefits 32X in faster/fastest rendering mode, 0-5% saved --- pico/32x/32x.c | 2 ++ pico/draw.c | 18 ++++++++++++++++++ pico/pico.h | 2 ++ pico/pico_cmn.c | 7 +++++-- pico/pico_int.h | 1 + pico/videoport.c | 29 ++++++++++++++++++++--------- 6 files changed, 48 insertions(+), 11 deletions(-) diff --git a/pico/32x/32x.c b/pico/32x/32x.c index 19b3f505..815d1a6d 100644 --- a/pico/32x/32x.c +++ b/pico/32x/32x.c @@ -587,6 +587,8 @@ void PicoFrame32x(void) pcd_prepare_frame(); PicoFrameStart(); + if (Pico32xDrawMode != PDM32X_BOTH) + Pico.est.rendstatus |= PDRAW_SYNC_NEEDED; PicoFrameHints(); elprintf(EL_32X, "poll: %02x %02x %02x", diff --git a/pico/draw.c b/pico/draw.c index 31a6d039..5d507d57 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -1910,6 +1910,7 @@ PICO_INTERNAL void PicoFrameStart(void) int loffs = 8, lines = 224, coffs = 0, columns = 320; int sprep = est->rendstatus & PDRAW_DIRTY_SPRITES; int skipped = est->rendstatus & PDRAW_SKIP_FRAME; + int sync = est->rendstatus & (PDRAW_SYNC_NEEDED | PDRAW_SYNC_NEXT); // prepare to do this frame est->rendstatus = 0; @@ -1935,7 +1936,12 @@ PICO_INTERNAL void PicoFrameStart(void) // mode_change() might reset rendstatus_old by calling SetColorFormat emu_video_mode_change(loffs, lines, coffs, columns); rendstatus_old = est->rendstatus & (PDRAW_INTERLACE|PDRAW_32_COLS|PDRAW_30_ROWS); + // mode_change() might clear buffers, redraw needed + est->rendstatus |= PDRAW_SYNC_NEEDED; } + + if (sync | skipped) + est->rendstatus |= PDRAW_SYNC_NEEDED; if (PicoIn.skipFrame) // preserve this until something is rendered at last est->rendstatus |= PDRAW_SKIP_FRAME; if (sprep | skipped) @@ -2030,6 +2036,14 @@ 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); + 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; + est->HighCol += count*HighColIncrement; + est->DrawLineDest = (char *)est->DrawLineDest + count*DrawLineDestIncrement; + est->DrawScanline = to+1; + return; + } for (line = est->DrawScanline; line < to; line++) PicoLine(line, offs, sh, bgc); @@ -2135,6 +2149,8 @@ void PicoDrawSetOutBufMD(void *dest, int increment) PicoDrawSetInternalBuf(dest, increment); // needed for SMS PicoDraw2SetOutBuf(dest, increment); } else if (dest != NULL) { + if (dest != DrawLineDestBase) + Pico.est.rendstatus |= PDRAW_SYNC_NEEDED; DrawLineDestBase = dest; DrawLineDestIncrement = increment; Pico.est.DrawLineDest = (char *)DrawLineDestBase + Pico.est.DrawScanline * increment; @@ -2157,6 +2173,8 @@ void PicoDrawSetOutBuf(void *dest, int increment) void PicoDrawSetInternalBuf(void *dest, int increment) { if (dest != NULL) { + if (dest != HighColBase) + Pico.est.rendstatus |= PDRAW_SYNC_NEEDED; HighColBase = dest; HighColIncrement = increment; Pico.est.HighCol = HighColBase + Pico.est.DrawScanline * increment; diff --git a/pico/pico.h b/pico/pico.h index cd525b12..e73c3456 100644 --- a/pico/pico.h +++ b/pico/pico.h @@ -223,6 +223,7 @@ void vidConvCpyRGB565(void *to, void *from, int pixels); #endif void PicoDoHighPal555(int sh, int line, struct PicoEState *est); // internals, NB must keep in sync with ASM draw functions +#define PDRAW_SYNC_NEEDED (1<<0) // redraw needed #define PDRAW_WND_DIFF_PRIO (1<<1) // not all window tiles use same priority #define PDRAW_PARSE_SPRITES (1<<2) // SAT needs parsing #define PDRAW_INTERLACE (1<<3) @@ -236,6 +237,7 @@ void PicoDoHighPal555(int sh, int line, struct PicoEState *est); #define PDRAW_30_ROWS (1<<11) // 30 rows mode (240 lines) #define PDRAW_32X_SCALE (1<<12) // scale CLUT layer for 32X #define PDRAW_SMS_BLANK_1 (1<<13) // 1st column blanked +#define PDRAW_SYNC_NEXT (1<<14) // sync next frame extern int rendstatus_old; extern int rendlines; diff --git a/pico/pico_cmn.c b/pico/pico_cmn.c index f2a3c225..ed369e39 100644 --- a/pico/pico_cmn.c +++ b/pico/pico_cmn.c @@ -168,10 +168,12 @@ static int PicoFrameHints(void) { // find the right moment for frame renderer, when display is no longer blanked if ((pv->reg[1]&0x40) || y > 100) { - PicoFrameFull(); + if (Pico.est.rendstatus & PDRAW_SYNC_NEEDED) + PicoFrameFull(); #ifdef DRAW_FINISH_FUNC DRAW_FINISH_FUNC(); #endif + Pico.est.rendstatus &= ~PDRAW_SYNC_NEEDED; skip = 1; } } @@ -191,10 +193,11 @@ static int PicoFrameHints(void) if (!skip) { if (Pico.est.DrawScanline < y) - PicoDrawSync(y - 1, 0, 0); + PicoVideoSync(-1); #ifdef DRAW_FINISH_FUNC DRAW_FINISH_FUNC(); #endif + Pico.est.rendstatus &= ~PDRAW_SYNC_NEEDED; } #ifdef PICO_32X p32x_render_frame(); diff --git a/pico/pico_int.h b/pico/pico_int.h index fa6d12d4..b08db6a5 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -917,6 +917,7 @@ int PicoVideoFIFOHint(void); void PicoVideoFIFOMode(int active, int h40); int PicoVideoFIFOWrite(int count, int byte_p, unsigned sr_mask, unsigned sr_flags); void PicoVideoInit(void); +void PicoVideoSync(int skip); void PicoVideoSave(void); void PicoVideoLoad(void); void PicoVideoCacheSAT(int load); diff --git a/pico/videoport.c b/pico/videoport.c index 971a85dc..4778ba99 100644 --- a/pico/videoport.c +++ b/pico/videoport.c @@ -809,13 +809,17 @@ static inline int InHblank(int offs) return SekCyclesDone() - Pico.t.m68c_line_start <= offs; } -static void DrawSync(int skip) +void PicoVideoSync(int skip) { int lines = Pico.video.reg[1]&0x08 ? 240 : 224; - int last = Pico.m.scanline - (skip || blankline == Pico.m.scanline); + int last = Pico.m.scanline - ((skip > 0) || blankline == Pico.m.scanline); + + if (!(PicoIn.opt & POPT_ALT_RENDERER) && !PicoIn.skipFrame) { + if (last >= lines) + last = lines-1; + else // in active display, need to sync next frame as well + Pico.est.rendstatus |= PDRAW_SYNC_NEXT; - if (last < lines && !(PicoIn.opt & POPT_ALT_RENDERER) && - !PicoIn.skipFrame && Pico.est.DrawScanline <= last) { //elprintf(EL_ANOMALY, "sync"); if (blankline >= 0 && blankline < last) { PicoDrawSync(blankline, 1, 0); @@ -825,6 +829,8 @@ static void DrawSync(int skip) if (last >= limitsprites) limitsprites = -1; } + if (skip >= 0) + Pico.est.rendstatus |= PDRAW_SYNC_NEEDED; } PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d) @@ -849,7 +855,11 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d) !(pvid->type == 1 && !(pvid->addr&1) && ((pvid->addr^SATaddr)&SATmask) && PicoMem.vram[pvid->addr>>1] == d) && !(pvid->type == 3 && PicoMem.cram[(pvid->addr>>1) & 0x3f] == (d & 0xeee)) && !(pvid->type == 5 && PicoMem.vsram[(pvid->addr>>1) & 0x3f] == (d & 0x7ff))) - DrawSync(InHblank(48)); // experimentally, Overdrive 2 + // the vertical scroll value for this line must be read from VSRAM early, + // since the A/B tile row to be read depends on it. E.g. Skitchin, OD2 + // in contrast, CRAM writes would have an immediate effect on the current + // pixel. XXX think about different offset values for different RAM types + PicoVideoSync(InHblank(30)); if (!(PicoIn.opt&POPT_DIS_VDP_FIFO)) { @@ -881,7 +891,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d) CommandChange(pvid); // Check for dma: if (d & 0x80) { - DrawSync(InHblank(93)); + PicoVideoSync(InHblank(93)); CommandDma(); } } @@ -913,9 +923,10 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d) } if (num == 12 && ((pvid->reg[12]^d)&0x01)) PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1); - if (num <= 18 && pvid->reg[num] != d) // no sync for DMA setup - DrawSync(InHblank(93)); // Toy Story - pvid->reg[num]=d; + 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; switch (num) { -- 2.39.5