core vdp, avoid rendering if no changes to RAMs/registers
authorkub <derkub@gmail.com>
Thu, 27 Apr 2023 20:18:55 +0000 (22:18 +0200)
committerkub <derkub@gmail.com>
Thu, 27 Apr 2023 20:18:55 +0000 (22:18 +0200)
mainly benefits 32X in faster/fastest rendering mode, 0-5% saved

pico/32x/32x.c
pico/draw.c
pico/pico.h
pico/pico_cmn.c
pico/pico_int.h
pico/videoport.c

index 19b3f50..815d1a6 100644 (file)
@@ -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",
index 31a6d03..5d507d5 100644 (file)
@@ -1910,6 +1910,7 @@ PICO_INTERNAL void PicoFrameStart(void)
   int loffs = 8, lines = 224, coffs = 0, columns = 320;\r
   int sprep = est->rendstatus & PDRAW_DIRTY_SPRITES;\r
   int skipped = est->rendstatus & PDRAW_SKIP_FRAME;\r
+  int sync = est->rendstatus & (PDRAW_SYNC_NEEDED | PDRAW_SYNC_NEXT);\r
 \r
   // prepare to do this frame\r
   est->rendstatus = 0;\r
@@ -1935,7 +1936,12 @@ PICO_INTERNAL void PicoFrameStart(void)
     // mode_change() might reset rendstatus_old by calling SetColorFormat\r
     emu_video_mode_change(loffs, lines, coffs, columns);\r
     rendstatus_old = est->rendstatus & (PDRAW_INTERLACE|PDRAW_32_COLS|PDRAW_30_ROWS);\r
+    // mode_change() might clear buffers, redraw needed\r
+    est->rendstatus |= PDRAW_SYNC_NEEDED;\r
   }\r
+\r
+  if (sync | skipped)\r
+    est->rendstatus |= PDRAW_SYNC_NEEDED;\r
   if (PicoIn.skipFrame) // preserve this until something is rendered at last\r
     est->rendstatus |= PDRAW_SKIP_FRAME;\r
   if (sprep | skipped)\r
@@ -2030,6 +2036,14 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
   if (est->DrawScanline <= to &&\r
                 (est->rendstatus & (PDRAW_DIRTY_SPRITES|PDRAW_PARSE_SPRITES)))\r
     ParseSprites(to + 1, limit_sprites);\r
+  else if (!(est->rendstatus & PDRAW_SYNC_NEEDED)) {\r
+    // nothing has changed in VDP/VRAM and buffer is the same -> no sync needed\r
+    int count = to+1 - est->DrawScanline;\r
+    est->HighCol += count*HighColIncrement;\r
+    est->DrawLineDest = (char *)est->DrawLineDest + count*DrawLineDestIncrement;\r
+    est->DrawScanline = to+1;\r
+    return;\r
+  }\r
 \r
   for (line = est->DrawScanline; line < to; line++)\r
     PicoLine(line, offs, sh, bgc);\r
@@ -2135,6 +2149,8 @@ void PicoDrawSetOutBufMD(void *dest, int increment)
     PicoDrawSetInternalBuf(dest, increment); // needed for SMS\r
     PicoDraw2SetOutBuf(dest, increment);\r
   } else if (dest != NULL) {\r
+    if (dest != DrawLineDestBase)\r
+      Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;\r
     DrawLineDestBase = dest;\r
     DrawLineDestIncrement = increment;\r
     Pico.est.DrawLineDest = (char *)DrawLineDestBase + Pico.est.DrawScanline * increment;\r
@@ -2157,6 +2173,8 @@ void PicoDrawSetOutBuf(void *dest, int increment)
 void PicoDrawSetInternalBuf(void *dest, int increment)\r
 {\r
   if (dest != NULL) {\r
+    if (dest != HighColBase)\r
+      Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;\r
     HighColBase = dest;\r
     HighColIncrement = increment;\r
     Pico.est.HighCol = HighColBase + Pico.est.DrawScanline * increment;\r
index cd525b1..e73c345 100644 (file)
@@ -223,6 +223,7 @@ void vidConvCpyRGB565(void *to, void *from, int pixels);
 #endif\r
 void PicoDoHighPal555(int sh, int line, struct PicoEState *est);\r
 // internals, NB must keep in sync with ASM draw functions\r
+#define PDRAW_SYNC_NEEDED   (1<<0) // redraw needed\r
 #define PDRAW_WND_DIFF_PRIO (1<<1) // not all window tiles use same priority\r
 #define PDRAW_PARSE_SPRITES (1<<2) // SAT needs parsing\r
 #define PDRAW_INTERLACE     (1<<3)\r
@@ -236,6 +237,7 @@ void PicoDoHighPal555(int sh, int line, struct PicoEState *est);
 #define PDRAW_30_ROWS      (1<<11) // 30 rows mode (240 lines)\r
 #define PDRAW_32X_SCALE    (1<<12) // scale CLUT layer for 32X\r
 #define PDRAW_SMS_BLANK_1  (1<<13) // 1st column blanked\r
+#define PDRAW_SYNC_NEXT    (1<<14) // sync next frame\r
 extern int rendstatus_old;\r
 extern int rendlines;\r
 \r
index f2a3c22..ed369e3 100644 (file)
@@ -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();
index fa6d12d..b08db6a 100644 (file)
@@ -917,6 +917,7 @@ int PicoVideoFIFOHint(void);
 void PicoVideoFIFOMode(int active, int h40);\r
 int PicoVideoFIFOWrite(int count, int byte_p, unsigned sr_mask, unsigned sr_flags);\r
 void PicoVideoInit(void);\r
+void PicoVideoSync(int skip);\r
 void PicoVideoSave(void);\r
 void PicoVideoLoad(void);\r
 void PicoVideoCacheSAT(int load);\r
index 971a85d..4778ba9 100644 (file)
@@ -809,13 +809,17 @@ static inline int InHblank(int offs)
   return SekCyclesDone() - Pico.t.m68c_line_start <= offs;\r
 }\r
 \r
-static void DrawSync(int skip)\r
+void PicoVideoSync(int skip)\r
 {\r
   int lines = Pico.video.reg[1]&0x08 ? 240 : 224;\r
-  int last = Pico.m.scanline - (skip || blankline == Pico.m.scanline);\r
+  int last = Pico.m.scanline - ((skip > 0) || blankline == Pico.m.scanline);\r
+\r
+  if (!(PicoIn.opt & POPT_ALT_RENDERER) && !PicoIn.skipFrame) {\r
+    if (last >= lines)\r
+      last = lines-1;\r
+    else // in active display, need to sync next frame as well\r
+      Pico.est.rendstatus |= PDRAW_SYNC_NEXT;\r
 \r
-  if (last < lines && !(PicoIn.opt & POPT_ALT_RENDERER) &&\r
-      !PicoIn.skipFrame && Pico.est.DrawScanline <= last) {\r
     //elprintf(EL_ANOMALY, "sync");\r
     if (blankline >= 0 && blankline < last) {\r
       PicoDrawSync(blankline, 1, 0);\r
@@ -825,6 +829,8 @@ static void DrawSync(int skip)
     if (last >= limitsprites)\r
       limitsprites = -1;\r
   }\r
+  if (skip >= 0)\r
+    Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;\r
 }\r
 \r
 PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)\r
@@ -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) &&\r
         !(pvid->type == 3 && PicoMem.cram[(pvid->addr>>1) & 0x3f] == (d & 0xeee)) &&\r
         !(pvid->type == 5 && PicoMem.vsram[(pvid->addr>>1) & 0x3f] == (d & 0x7ff)))\r
-      DrawSync(InHblank(48)); // experimentally, Overdrive 2\r
+      // the vertical scroll value for this line must be read from VSRAM early,\r
+      // since the A/B tile row to be read depends on it. E.g. Skitchin, OD2\r
+      // in contrast, CRAM writes would have an immediate effect on the current\r
+      // pixel. XXX think about different offset values for different RAM types\r
+      PicoVideoSync(InHblank(30));\r
 \r
     if (!(PicoIn.opt&POPT_DIS_VDP_FIFO))\r
     {\r
@@ -881,7 +891,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
       CommandChange(pvid);\r
       // Check for dma:\r
       if (d & 0x80) {\r
-        DrawSync(InHblank(93));\r
+        PicoVideoSync(InHblank(93));\r
         CommandDma();\r
       }\r
     }\r
@@ -913,9 +923,10 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
         }\r
         if (num == 12 && ((pvid->reg[12]^d)&0x01))\r
           PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1);\r
-        if (num <= 18 && pvid->reg[num] != d) // no sync for DMA setup\r
-          DrawSync(InHblank(93)); // Toy Story\r
-        pvid->reg[num]=d;\r
+        if (((1<<num) & 0x738ff) && pvid->reg[num] != d)\r
+          // VDP regs 0-7,11-13,16-18 influence rendering, ignore all others\r
+          PicoVideoSync(InHblank(93)); // Toy Story\r
+        pvid->reg[num] = d;\r
 \r
         switch (num)\r
         {\r