core, handle background color DMA (aka fantom bitmap)
authorkub <derkub@gmail.com>
Sat, 13 Jan 2024 11:07:13 +0000 (12:07 +0100)
committerkub <derkub@gmail.com>
Sat, 13 Jan 2024 11:09:16 +0000 (12:09 +0100)
pico/draw.c
pico/pico.c
pico/pico_int.h
pico/videoport.c

index 66b4fca..40903e7 100644 (file)
@@ -1599,7 +1599,59 @@ void BackFill(int bgc, int sh, struct PicoEState *est)
 \r
 // --------------------------------------------\r
 \r
-void PicoDoHighPal555_8bit(int sh, int line, struct PicoEState *est)\r
+static u16 *BgcDMAbase;\r
+static u32 BgcDMAsrc, BgcDMAmask;\r
+static int BgcDMAlen, BgcDMAoffs;\r
+\r
+#ifndef _ASM_DRAW_C\r
+static\r
+#endif\r
+// handle DMA to background color\r
+int BgcDMA(u16 *pd, int len, struct PicoEState *est)\r
+{\r
+  int xl = (len == 320 ? 38 : 33); // DMA slots during HSYNC\r
+  int upscale = (est->rendstatus & PDRAW_SOFTSCALE) && len < 320;\r
+\r
+  if (BgcDMAlen > 0) {\r
+    // BG color DMA under way. TODO for now handles the line as all background.\r
+    int i, l = len;\r
+    u16 *q = upscale ? DefOutBuff : pd;\r
+    u16 t;\r
+\r
+    if ((est->rendstatus & PDRAW_BORDER_32) && !upscale)\r
+      q += (320-len) / 2;\r
+\r
+    BgcDMAlen -= (l>>1)+xl;\r
+    if (BgcDMAlen < 0)\r
+      // partial line\r
+      l += 2*BgcDMAlen;\r
+\r
+    for (i = 0; i < l; i += 2) {\r
+      // TODO use ps to overwrite only real bg pixels\r
+      t = BgcDMAbase[BgcDMAsrc++ & BgcDMAmask];\r
+      q[i] = q[i+1] = PXCONV(t);\r
+    }\r
+    BgcDMAsrc += xl; // HSYNC DMA\r
+\r
+    t = est->HighPal[Pico.video.reg[7] & 0x3f];\r
+    while (i < len) q[i++] = t; // fill partial line with BG\r
+\r
+    if (upscale) {\r
+      switch (PicoIn.filter) {\r
+      case 3: h_upscale_bl4_4_5(pd, 320, q, 256, len, f_nop); break;\r
+      case 2: h_upscale_bl2_4_5(pd, 320, q, 256, len, f_nop); break;\r
+      case 1: h_upscale_snn_4_5(pd, 320, q, 256, len, f_nop); break;\r
+      default: h_upscale_nn_4_5(pd, 320, q, 256, len, f_nop); break;\r
+      }\r
+    }\r
+    return 1;\r
+  }\r
+  return 0;\r
+}\r
+\r
+// --------------------------------------------\r
+\r
+static void PicoDoHighPal555_8bit(int sh, int line, struct PicoEState *est)\r
 {\r
   unsigned int *spal, *dpal;\r
   unsigned int cnt = (sh ? 1 : est->SonicPalCount+1);\r
@@ -1695,6 +1747,9 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
   else if ((PicoIn.AHW & PAHW_SMS) && (est->Pico->video.reg[0] & 0x20))\r
     len -= 8, ps += 8;\r
 \r
+  if (BgcDMA(pd, len, est))\r
+    return;\r
+\r
   if ((est->rendstatus & PDRAW_SOFTSCALE) && len < 320) {\r
     if (len >= 240 && len <= 256) {\r
       pd += (256-len)>>1;\r
@@ -2111,6 +2166,35 @@ void PicoDrawRefreshSprites(void)
   }\r
 }\r
 \r
+void PicoDrawBgcDMA(u16 *base, u32 source, u32 mask, int dlen, int sl)\r
+{\r
+  struct PicoEState *est = &Pico.est;\r
+  int len = (est->Pico->video.reg[12]&1) ? 320 : 256;\r
+  int xl = (est->Pico->video.reg[12]&1) ? 38 : 33; // DMA slots during HSYNC\r
+\r
+  BgcDMAbase = base;\r
+  BgcDMAsrc = source;\r
+  BgcDMAmask = mask;\r
+  BgcDMAlen = dlen;\r
+  BgcDMAoffs = 0;\r
+\r
+  // handle slot offset in 1st line\r
+  if (sl-12 > 0) // active display output only starts at slot 12\r
+    BgcDMAoffs = 2*(sl-12);\r
+  else if (sl < 0) { // DMA starts before active display\r
+    BgcDMAsrc += 2*-sl;\r
+    BgcDMAlen -= 2*-sl;\r
+  }\r
+\r
+  // skip 1st line if it had been drawn already\r
+  if (Pico.est.DrawScanline > Pico.m.scanline) {\r
+    len -= BgcDMAoffs;\r
+    BgcDMAsrc += (len>>1)+xl;\r
+    BgcDMAlen -= (len>>1)+xl;\r
+    BgcDMAoffs = 0;\r
+  }\r
+}\r
+\r
 // also works for fast renderer\r
 void PicoDrawUpdateHighPal(void)\r
 {\r
index ced4091..ad57b6e 100644 (file)
@@ -190,6 +190,7 @@ int PicoReset(void)
 \r
   // create an empty "dma" to cause 68k exec start at random frame location\r
   Pico.t.m68c_line_start = Pico.t.m68c_aim;\r
+  PicoDrawBgcDMA(NULL, 0, 0, 0, 0);\r
   PicoVideoFIFOWrite(rand() & 0x1fff, 0, 0, PVS_CPURD);\r
 \r
   SekFinishIdleDet();\r
index e74a4ac..0d33682 100644 (file)
@@ -704,6 +704,7 @@ int CM_compareRun(int cyc, int is_sub);
 void PicoDrawInit(void);\r
 PICO_INTERNAL void PicoFrameStart(void);\r
 void PicoDrawRefreshSprites(void);\r
+void PicoDrawBgcDMA(u16 *base, u32 source, u32 mask, int len, int sl);\r
 void PicoDrawSync(int to, int blank_last_line, int limit_sprites);\r
 void BackFill(int reg7, int sh, struct PicoEState *est);\r
 void FinalizeLine555(int sh, int line, struct PicoEState *est);\r
index bd744a3..fe8e5eb 100644 (file)
@@ -522,6 +522,7 @@ static void DmaSlow(int len, u32 source)
   u32 a = Pico.video.addr | (Pico.video.addr_u << 16), e;\r
   u16 *r, *base = NULL;\r
   u32 mask = 0x1ffff;\r
+  int lc = SekCyclesDone()-Pico.t.m68c_line_start;\r
 \r
   elprintf(EL_VDPDMA, "DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%u] @ %06x",\r
     Pico.video.type, source, a, len, inc, (Pico.video.status&SR_VB)||!(Pico.video.reg[1]&0x40),\r
@@ -603,6 +604,15 @@ static void DmaSlow(int len, u32 source)
     case 3: // cram\r
       Pico.m.dirtyPal = 1;\r
       r = PicoMem.cram;\r
+      if (inc == 0 && (Pico.video.reg[7] & 0x3f) == ((a/2) & 0x3f)) { // bg color DMA\r
+        PicoVideoSync(1);\r
+        int sl = VdpFIFO.fifo_hcounts[lc/clkdiv];\r
+        if (sl > VdpFIFO.fifo_hcounts[0]-5) // hint delay is 5 slots\r
+          sl = (s8)sl;\r
+        // TODO this is needed to cover timing inaccuracies\r
+        if (sl <= 12)  sl = -2;\r
+        PicoDrawBgcDMA(base, source, mask, len, sl);\r
+      }\r
       for (; len; len--)\r
       {\r
         r[(a / 2) & 0x3f] = base[source++ & mask] & 0xeee;\r