core vdp, fix rendering (layer/window high prio)
authorkub <derkub@gmail.com>
Thu, 8 Aug 2024 20:32:28 +0000 (22:32 +0200)
committerkub <derkub@gmail.com>
Thu, 8 Aug 2024 21:59:02 +0000 (23:59 +0200)
pico/draw.c

index 387f3a4..6d27f1b 100644 (file)
@@ -85,6 +85,8 @@ u32 VdpSATCache[2*128];  // VDP sprite cache (1st 32 sprite attr bits)
 #define LF_PLANE   (1 << 0) // must be = 1\r
 #define LF_SH      (1 << 1) // must be = 2\r
 //#define LF_FORCE   (1 << 2)\r
+#define LF_LINE    (1 << 3) // covers the line\r
+#define LF_LPRIO   (1 << 8) // seen low prio tile\r
 \r
 #define LF_PLANE_A 0\r
 #define LF_PLANE_B 1\r
@@ -304,7 +306,7 @@ TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and)
 // --------------------------------------------\r
 \r
 #ifndef _ASM_DRAW_C\r
-#define DrawTile(mask) {                                               \\r
+#define DrawTile(mask,masked) {                                                \\r
   if (code!=oldcode) {                                                 \\r
     oldcode = code;                                                    \\r
                                                                        \\r
@@ -324,13 +326,16 @@ TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and)
                                                                        \\r
   if (code & 0x8000) { /* (un-forced) high priority tile */            \\r
     if (sh | (pack&mask)) {                                            \\r
-      code |= (dx<<16) | (ty<<25);                                     \\r
-      if (code & 0x1000) code ^= 0xe<<25;                              \\r
+      code |= (dx<<16) | (ty<<26) | (masked<<25);                      \\r
+      if (code & 0x1000) code ^= 0xe<<26;                              \\r
       *hc++ = code, *hc++ = pack&mask; /* cache it */                  \\r
     }                                                                  \\r
-  } else if (pack&mask) {                                              \\r
-    if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);              \\r
-    else               TileNorm(pd + dx, pack&mask, pal);              \\r
+  } else {                                                             \\r
+    lflags |= LF_LPRIO;                                                        \\r
+    if (pack&mask) {                                                   \\r
+      if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);            \\r
+      else               TileNorm(pd + dx, pack&mask, pal);            \\r
+    }                                                                  \\r
   }                                                                    \\r
 }\r
 \r
@@ -340,7 +345,7 @@ static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
   u32 *hc = ts->hc;\r
   int tilex, dx, ty, cells;\r
   u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
-  unsigned int pal = 0, pack = 0, sh, mask = ~0;\r
+  u32 pal = 0, pack = 0, sh, mask;\r
 \r
   // Draw tiles across screen:\r
   sh = (lflags & LF_SH) << 6; // shadow\r
@@ -352,11 +357,13 @@ static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
 \r
   if (dx & 7) {\r
     code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
+//    code &= ~force; // forced always draw everything\r
+\r
     mask = 0xffffffff<<((dx&7)*4);\r
     if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
     mask = (~mask << 16) | (~mask >> 16);\r
 \r
-    DrawTile(mask);\r
+    DrawTile(mask,1);\r
     dx += 8, tilex++, cells--;\r
   }\r
 \r
@@ -366,29 +373,57 @@ static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
     code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
 //    code &= ~force; // forced always draw everything\r
 \r
-    if (code == blank && !((code & 0x8000) && sh))\r
-      continue;\r
-\r
-    DrawTile(~0);\r
+    if (code != blank || ((code & 0x8000) && sh))\r
+      DrawTile(~0,0);\r
   }\r
 \r
   if (dx & 7) {\r
     code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
 //    code &= ~force; // forced always draw everything\r
-    if (!(code == blank && !((code & 0x8000) && sh))) {\r
+\r
+    if (code != blank || ((code & 0x8000) && sh)) {\r
       mask = 0xffffffff<<((dx&7)*4);\r
       if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
       mask = (mask << 16) | (mask >> 16);\r
 \r
-      DrawTile(mask);\r
+      DrawTile(mask,1);\r
     }\r
   }\r
 \r
   // terminate the cache list\r
   *hc = 0;\r
 \r
-  // if oldcode wasn't changed, it means all layer is hi priority\r
-  if (oldcode == -1) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
+  // flags bit is clear if all layer is hi priority\r
+  if (!(lflags & LF_LPRIO) && (lflags & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
+}\r
+\r
+#define DrawTileVSRam(mask,masked) {                                   \\r
+  if (code!=oldcode) {                                                 \\r
+    oldcode = code;                                                    \\r
+    /* Get tile address/2: */                                          \\r
+    addr = (code&0x7ff)<<4;                                            \\r
+                                                                       \\r
+    pal = ((code>>9)&0x30) | sh; /* shadow */                          \\r
+                                                                       \\r
+    pack = (code & 0x1000 ? ty^0xe : ty); /* Y-flip */                 \\r
+    pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr+pack));                        \\r
+    if (!pack)                                                         \\r
+      blank = code;                                                    \\r
+  }                                                                    \\r
+                                                                       \\r
+  if (code & 0x8000) { /* (un-forced) high priority tile */            \\r
+    if (sh | (pack&mask)) {                                            \\r
+      code |= (dx<<16) | (masked<<25);                                 \\r
+      if (code & 0x1000) code ^= 0xe<<26;                              \\r
+      *hc++ = code, *hc++ = pack&mask; /* cache it */                  \\r
+    }                                                                  \\r
+  } else {                                                             \\r
+    plane_sh |= LF_LPRIO;                                              \\r
+    if (pack&mask) {                                                   \\r
+      if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);            \\r
+      else               TileNorm(pd + dx, pack&mask, pal);            \\r
+    }                                                                  \\r
+  }                                                                    \\r
 }\r
 \r
 // this is messy\r
@@ -397,8 +432,8 @@ static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
   unsigned char *pd = Pico.est.HighCol;\r
   u32 *hc = ts->hc;\r
   int tilex, dx, ty = 0, addr = 0, cell = 0, nametabadd = 0;\r
-  u32 oldcode = -1, blank = -1; // The tile we know is blank\r
-  unsigned int pal = 0, scan = Pico.est.DrawScanline, sh, plane;\r
+  u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
+  u32 pal = 0, pack, scan = Pico.est.DrawScanline, sh, plane, mask;\r
 \r
   // Draw tiles across screen:\r
   sh = (plane_sh & LF_SH) << 6; // shadow\r
@@ -416,8 +451,7 @@ static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
   dx+=cellskip<<3;\r
 \r
 //  int force = (plane_sh&LF_FORCE) << 13;\r
-  if ((cell&1)==1)\r
-  {\r
+  if ((cell&1)==1 || (dx&7)) {\r
     int line,vscroll;\r
     vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
 \r
@@ -426,12 +460,22 @@ static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
     nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]\r
     ty=(line&7)<<1; // Y-Offset into tile\r
   }\r
+  if (dx & 7) {\r
+    code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)];\r
+    code |= ty<<26; // add ty since that can change pixel row for every 2nd tile\r
+//    code &= ~force; // forced always draw everything\r
+\r
+    mask = 0xffffffff<<((dx&7)*4);\r
+    if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
+    mask = (~mask << 16) | (~mask >> 16);\r
+\r
+    DrawTileVSRam(mask,1);\r
+\r
+    dx += 8, tilex++, cell++;\r
+  }\r
   for (; cell < ts->cells; dx+=8,tilex++,cell++)\r
   {\r
-    u32 code, pack;\r
-\r
-    if ((cell&1)==0)\r
-    {\r
+    if ((cell&1)==0) {\r
       int line,vscroll;\r
       vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
 \r
@@ -442,43 +486,44 @@ static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
     }\r
 \r
     code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)];\r
+    code |= ty<<26; // add ty since that can change pixel row for every 2nd tile\r
 //    code &= ~force; // forced always draw everything\r
-    code |= ty<<25; // add ty since that can change pixel row for every 2nd tile\r
 \r
-    if (code == blank && !((code & 0x8000) && sh))\r
-      continue;\r
-\r
-    if (code!=oldcode) {\r
-      oldcode = code;\r
-      // Get tile address/2:\r
-      addr = (code&0x7ff)<<4;\r
+    if (code != blank || ((code & 0x8000) && sh))\r
+      DrawTileVSRam(~0,0);\r
+  }\r
+  if (dx & 7) {\r
+    if ((cell&1)==0) {\r
+      int line,vscroll;\r
+      vscroll = PicoMem.vsram[plane + (cell&0x3e)];\r
 \r
-      pal = ((code>>9)&0x30) | sh; // shadow\r
+      // Find the line in the name table\r
+      line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask ..\r
+      nametabadd=(line>>3)<<(ts->line>>24);    // .. and shift[width]\r
+      ty=(line&7)<<1; // Y-Offset into tile\r
     }\r
 \r
-    pack = (code & 0x1000 ? ty^0xe : ty); // Y-flip\r
-    pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr+pack));\r
-    if (!pack)\r
-      blank = code;\r
-\r
-    if (code & 0x8000) { // (un-forced) high priority tile\r
-      code |= (dx<<16);\r
-      if (code & 0x1000) code ^= 0xe<<25;\r
-      *hc++ = code, *hc++ = pack; // cache it\r
-    } else if (code != blank) {\r
-      if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
-      else               TileNorm(pd + dx, pack, pal);\r
+    code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)];\r
+    code |= ty<<26; // add ty since that can change pixel row for every 2nd tile\r
+//    code &= ~force; // forced always draw everything\r
+\r
+    if (code != blank || ((code & 0x8000) && sh)) {\r
+      mask = 0xffffffff<<((dx&7)*4);\r
+      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
+      mask = (mask << 16) | (mask >> 16);\r
+\r
+      DrawTileVSRam(mask,1);\r
     }\r
   }\r
 \r
   // terminate the cache list\r
   *hc = 0;\r
 \r
-  if (oldcode == -1) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
+  if (!(plane_sh & LF_LPRIO) && (plane_sh & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
 }\r
 #endif\r
 \r
-#define DrawTileInterlace(mask) {                                      \\r
+#define DrawTileInterlace(mask,masked) {                               \\r
   if (code!=oldcode) {                                                 \\r
     oldcode = code;                                                    \\r
                                                                        \\r
@@ -498,13 +543,16 @@ static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
                                                                        \\r
   if (code & 0x8000) { /* high priority tile */                                \\r
     if (sh | (pack&mask)) {                                            \\r
-      code = (code&0xfc00) | ((code&0x3ff)<<1) | (dx<<16) | (ty<<25);  \\r
-      if (code & 0x1000) code ^= 0x1e<<25;                             \\r
+      code = (code&0xfc00) | ((code&0x3ff)<<1) | (dx<<16) | (ty<<26) | (masked<<25);   \\r
+      if (code & 0x1000) code ^= 0x1e<<26;                             \\r
       *hc++ = code, *hc++ = pack&mask; /* cache it */                  \\r
     }                                                                  \\r
-  } else if (pack&mask) {                                              \\r
-    if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);              \\r
-    else               TileNorm(pd + dx, pack&mask, pal);              \\r
+  } else {                                                             \\r
+    plane_sh |= LF_LPRIO;                                              \\r
+    if (pack&mask) {                                                   \\r
+      if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);            \\r
+      else               TileNorm(pd + dx, pack&mask, pal);            \\r
+    }                                                                  \\r
   }                                                                    \\r
 }\r
 \r
@@ -517,7 +565,7 @@ void DrawStripInterlace(struct TileStrip *ts, int plane_sh)
   u32 *hc = ts->hc;\r
   int tilex = 0, dx = 0, ty = 0, cells;\r
   u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
-  unsigned int pal = 0, pack = 0, sh, mask = ~0;\r
+  u32 pal = 0, pack = 0, sh, mask;\r
 \r
   // Draw tiles across screen:\r
   sh = (plane_sh & LF_SH) << 6; // shadow\r
@@ -528,11 +576,13 @@ void DrawStripInterlace(struct TileStrip *ts, int plane_sh)
 \r
   if (dx & 7) {\r
     code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
+//    code &= ~force; // forced always draw everything\r
+\r
     mask = 0xffffffff<<(dx*4);\r
     if (code & 0x0800) mask = 0xffffffff>>(dx*4);\r
     mask = (~mask << 16) | (~mask >> 16);\r
 \r
-    DrawTileInterlace(mask);\r
+    DrawTileInterlace(mask,1);\r
     dx += 8, tilex++, cells--;\r
   }\r
 \r
@@ -542,26 +592,27 @@ void DrawStripInterlace(struct TileStrip *ts, int plane_sh)
     u32 code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
 //    code &= ~force; // forced always draw everything\r
 \r
-    if (code == blank && !(code & 0x8000))\r
-      continue;\r
-\r
-    DrawTileInterlace(~0);\r
+    if (code != blank || ((code & 0x8000) && sh))\r
+      DrawTileInterlace(~0,0);\r
   }\r
 \r
   if (dx & 7) {\r
     code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
 //    code &= ~force; // forced always draw everything\r
-    if (!(code == blank && !((code & 0x8000) && sh))) {\r
+\r
+    if (code != blank || ((code & 0x8000) && sh)) {\r
       mask = 0xffffffff<<((dx&7)*4);\r
       if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
       mask = (mask << 16) | (mask >> 16);\r
 \r
-      DrawTileInterlace(mask);\r
+      DrawTileInterlace(mask,1);\r
     }\r
   }\r
 \r
   // terminate the cache list\r
   *hc = 0;\r
+\r
+  if (!(plane_sh & LF_LPRIO) && (plane_sh & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO;\r
 }\r
 \r
 // --------------------------------------------\r
@@ -755,8 +806,9 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
   u32 code, dx;\r
   u32 pack;\r
   int pal;\r
+  int hs;\r
 \r
-  // *ts->hc++ = code | (dx<<16) | (ty<<25); // cache it\r
+  // *ts->hc++ = code | (dx<<16) | (ty<<26); // cache it\r
 \r
   if (sh && (est->rendstatus & (PDRAW_SHHI_DONE|PDRAW_PLANE_HI_PRIO)))\r
   {\r
@@ -765,7 +817,7 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
       // we can process whole line and then act as if sh/hi mode was off,\r
       // but leave lo pri op sprite markers alone\r
       int *zb = (int *)(Pico.est.HighCol+8);\r
-      int c = rlim / 4;\r
+      int c = 320/4;\r
       while (c--)\r
       {\r
         *zb++ &= 0x7f7f7f7f;\r
@@ -778,13 +830,11 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
   if (!sh)\r
   {\r
     while ((code=*hc++)) {\r
+      dx = (code >> 16) & 0x1ff;\r
       pack = *hc++;\r
-      if (rlim-dx < 0)\r
-        goto last_cut_tile;\r
       if (!pack)\r
         continue;\r
 \r
-      dx = (code >> 16) & 0x1ff;\r
       pal = ((code >> 9) & 0x30);\r
 \r
       if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
@@ -797,13 +847,20 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
       unsigned char *zb;\r
 \r
       dx = (code >> 16) & 0x1ff;\r
+      pack = *hc++;\r
+\r
       zb = est->HighCol+dx;\r
-      *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f;\r
-      *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f;\r
+      if (likely(~code&(1<<25))) {\r
+        *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f;\r
+        *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f;\r
+      } else {\r
+        hs = dx & 7;\r
+        if (*hc == 0) // last tile?\r
+          for (            pal = hs; pal < 8;  pal++) *zb++ &= 0x7f;\r
+        else // first tile\r
+          for (zb += 8-hs, pal = 0;  pal < hs; pal++) *zb++ &= 0x7f;\r
+      }\r
 \r
-      pack = *hc++;\r
-      if (rlim - dx < 0)\r
-        goto last_cut_tile;\r
       if (!pack)\r
         continue;\r
 \r
@@ -813,26 +870,6 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
       else               TileNorm(pd + dx, pack, pal);\r
     }\r
   }\r
-  return;\r
-\r
-last_cut_tile:\r
-  // for vertical window cutoff\r
-  {\r
-    unsigned int t, mask;\r
-\r
-    // rlim-dx + 8 px to draw -> mask shift 8-(rlim-dx + 8)\r
-    t = -(rlim - dx);\r
-    if (t < 8) {\r
-      mask = 0xffffffff<<(t*4);\r
-      if (code & 0x0800) mask = 0xffffffff>>(t*4);\r
-      mask = (mask << 16) | (mask >> 16);\r
-\r
-      if (pack&mask) {\r
-        if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal);\r
-        else               TileNorm(pd + dx, pack&mask, pal);\r
-      }\r
-    }\r
-  }\r
 }\r
 \r
 // --------------------------------------------\r
@@ -1886,9 +1923,9 @@ static int DrawDisplay(int sh)
   est->HighPreSpr = HighPreSpr + (sprited[0]&0x80)*2;\r
 \r
   if (pvid->reg[12]&1) {\r
-    maxw = 328; maxcells = 40;\r
+    maxw = 320; maxcells = 40;\r
   } else {\r
-    maxw = 264; maxcells = 32;\r
+    maxw = 256; maxcells = 32;\r
   }\r
 \r
   // Find out if the window is on this line:\r
@@ -1915,7 +1952,7 @@ static int DrawDisplay(int sh)
   /* - layer B low - */\r
   if (!(pvid->debug_p & PVD_KILL_B)) {\r
     lflags = LF_PLANE_B | (sh<<1);\r
-    DrawLayer(lflags, HighCacheB, 0, maxcells, est);\r
+    DrawLayer(lflags | LF_LINE, HighCacheB, 0, maxcells, est);\r
   }\r
   /* - layer A low - */\r
   lflags = LF_PLANE_A | (sh<<1);\r
@@ -1928,7 +1965,7 @@ static int DrawDisplay(int sh)
     DrawWindow(                   (win&0x80) ? edge :       0, (win&0x80) ? maxcells>>1 : edge, 0, sh, est);\r
   }\r
   else\r
-    DrawLayer(lflags, HighCacheA, 0, maxcells, est);\r
+    DrawLayer(lflags | LF_LINE, HighCacheA, 0, maxcells, est);\r
   /* - sprites low - */\r
   if (pvid->debug_p & PVD_KILL_S_LO)\r
     ;\r
@@ -1947,7 +1984,7 @@ static int DrawDisplay(int sh)
     DrawWindow(0, maxcells>>1, 1, sh, est);\r
   else if (hvwind == 2) {\r
     if (HighCacheA[0])\r
-      DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : maxw, est);\r
+      DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : -edge<<4, est);\r
     DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh, est);\r
   } else\r
     if (HighCacheA[0])\r