core vdp, implement partial line blanking
authorkub <derkub@gmail.com>
Thu, 27 Apr 2023 20:24:21 +0000 (22:24 +0200)
committerkub <derkub@gmail.com>
Thu, 27 Apr 2023 20:24:21 +0000 (22:24 +0200)
pico/draw.c
pico/videoport.c

index 5d507d5..9966412 100644 (file)
@@ -1987,7 +1987,7 @@ static void DrawBlankedLine(int line, int offs, int sh, int bgc)
   est->DrawLineDest = (char *)est->DrawLineDest + DrawLineDestIncrement;\r
 }\r
 \r
-static void PicoLine(int line, int offs, int sh, int bgc)\r
+static void PicoLine(int line, int offs, int sh, int bgc, int off, int on)\r
 {\r
   struct PicoEState *est = &Pico.est;\r
   int skip = skip_next_line;\r
@@ -2006,8 +2006,17 @@ static void PicoLine(int line, int offs, int sh, int bgc)
 \r
   // Draw screen:\r
   BackFill(bgc, sh, est);\r
-  if (Pico.video.reg[1]&0x40)\r
+  if (Pico.video.reg[1]&0x40) {\r
+    int width = (Pico.video.reg[12]&1) ? 320 : 256;\r
     DrawDisplay(sh);\r
+    // partial line blanking (display on or off inside the line)\r
+    if (unlikely(off|on)) {\r
+      if (off > 0)\r
+        memset(est->HighCol+8 + off, bgc, width-off);\r
+      if (on > 0)\r
+        memset(est->HighCol+8, bgc, on);\r
+    }\r
+  }\r
 \r
   if (FinalizeLine != NULL)\r
     FinalizeLine(sh, line, est);\r
@@ -2019,7 +2028,7 @@ static void PicoLine(int line, int offs, int sh, int bgc)
   est->DrawLineDest = (char *)est->DrawLineDest + DrawLineDestIncrement;\r
 }\r
 \r
-void PicoDrawSync(int to, int blank_last_line, int limit_sprites)\r
+void PicoDrawSync(int to, int off, int on)\r
 {\r
   struct PicoEState *est = &Pico.est;\r
   int line, offs = 0;\r
@@ -2035,7 +2044,7 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
   }\r
   if (est->DrawScanline <= to &&\r
                 (est->rendstatus & (PDRAW_DIRTY_SPRITES|PDRAW_PARSE_SPRITES)))\r
-    ParseSprites(to + 1, limit_sprites);\r
+    ParseSprites(to + 1, on);\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
@@ -2046,14 +2055,22 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
   }\r
 \r
   for (line = est->DrawScanline; line < to; line++)\r
-    PicoLine(line, offs, sh, bgc);\r
+    PicoLine(line, offs, sh, bgc, 0, 0);\r
 \r
   // last line\r
   if (line <= to)\r
   {\r
-    if (blank_last_line)\r
-         DrawBlankedLine(line, offs, sh, bgc);\r
-    else PicoLine(line, offs, sh, bgc);\r
+    int width2 = (Pico.video.reg[12]&1) ? 160 : 128;\r
+\r
+    // technically, VDP starts active display output at slot 12\r
+    if (unlikely(on|off) && (off >= width2 ||\r
+          // hack for timing inaccuracy, if on/off near borders\r
+          (off && off <= 24) || (on < width2 && on >= width2-24)))\r
+      DrawBlankedLine(line, offs, sh, bgc);\r
+    else {\r
+      if (on > width2) on = 0; // on, before start of line?\r
+      PicoLine(line, offs, sh, bgc, 2*off, 2*on);\r
+    }\r
     line++;\r
   }\r
   est->DrawScanline = line;\r
index 4778ba9..fa8a332 100644 (file)
@@ -138,10 +138,11 @@ void PicoVideoInit(void)
 }\r
 \r
 \r
-static int blankline;           // display disabled for this line\r
-static int limitsprites;\r
+static int linedisabled;    // display disabled on this line\r
+static int lineenabled;     // display enabled on this line\r
+static int lineoffset;      // offset at which dis/enable took place\r
 \r
-u32 SATaddr, SATmask;      // VRAM addr of sprite attribute table\r
+u32 SATaddr, SATmask;       // VRAM addr of sprite attribute table\r
 \r
 int (*PicoDmaHook)(u32 source, int len, unsigned short **base, u32 *mask) = NULL;\r
 \r
@@ -811,8 +812,9 @@ static inline int InHblank(int offs)
 \r
 void PicoVideoSync(int skip)\r
 {\r
+  struct VdpFIFO *vf = &VdpFIFO;\r
   int lines = Pico.video.reg[1]&0x08 ? 240 : 224;\r
-  int last = Pico.m.scanline - ((skip > 0) || blankline == Pico.m.scanline);\r
+  int last = Pico.m.scanline - (skip > 0);\r
 \r
   if (!(PicoIn.opt & POPT_ALT_RENDERER) && !PicoIn.skipFrame) {\r
     if (last >= lines)\r
@@ -821,13 +823,22 @@ void PicoVideoSync(int skip)
       Pico.est.rendstatus |= PDRAW_SYNC_NEXT;\r
 \r
     //elprintf(EL_ANOMALY, "sync");\r
-    if (blankline >= 0 && blankline < last) {\r
-      PicoDrawSync(blankline, 1, 0);\r
-      blankline = -1;\r
+    if (unlikely(linedisabled >= 0 && linedisabled <= last)) {\r
+      if (Pico.est.DrawScanline <= linedisabled) {\r
+        int sl = vf->fifo_hcounts[lineoffset/clkdiv];\r
+        PicoDrawSync(linedisabled, sl ? sl : 1, 0);\r
+      }\r
+      linedisabled = -1;\r
     }\r
-    PicoDrawSync(last, 0, last == limitsprites);\r
-    if (last >= limitsprites)\r
-      limitsprites = -1;\r
+    if (unlikely(lineenabled >= 0 && lineenabled <= last)) {\r
+      if (Pico.est.DrawScanline <= lineenabled) {\r
+        int sl = vf->fifo_hcounts[lineoffset/clkdiv];\r
+        PicoDrawSync(lineenabled, 0, sl ? sl : 1);\r
+      }\r
+      lineenabled = -1;\r
+    }\r
+    if (Pico.est.DrawScanline <= last)\r
+      PicoDrawSync(last, 0, 0);\r
   }\r
   if (skip >= 0)\r
     Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;\r
@@ -911,19 +922,18 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
         d &= 0xff;\r
         if (num == 0 && !(pvid->reg[0]&2) && (d&2))\r
           pvid->hv_latch = PicoVideoRead(0x08);\r
-        if (num == 1 && ((pvid->reg[1]^d)&0x40)) {\r
-          PicoVideoFIFOMode(d & 0x40, pvid->reg[12]&1);\r
-          // handle line blanking before line rendering\r
-          if (InHblank(93)) {\r
-            // sprite rendering is limited if display is disabled and reenabled\r
-            // in HBLANK of the same scanline (Overdrive)\r
-            limitsprites = (d&0x40) && blankline == Pico.m.scanline ? Pico.m.scanline : -1;\r
-            blankline = (d&0x40) ? -1 : Pico.m.scanline;\r
-          }\r
-        }\r
         if (num == 12 && ((pvid->reg[12]^d)&0x01))\r
           PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1);\r
-        if (((1<<num) & 0x738ff) && pvid->reg[num] != d)\r
+\r
+        if (num == 1 && ((pvid->reg[1]^d)&0x40)) {\r
+          PicoVideoFIFOMode(d & 0x40, pvid->reg[12]&1);\r
+          // handle line blanking before line rendering. Only the last switch\r
+          // before the 1st sync for other reasons is honoured.\r
+          PicoVideoSync(1);\r
+          lineenabled = (d&0x40) ? Pico.m.scanline : -1;\r
+          linedisabled = (d&0x40) ? -1 : Pico.m.scanline;\r
+          lineoffset = SekCyclesDone() - Pico.t.m68c_line_start;\r
+       } else 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