core vdp, fix layer/window borders for vertical window
authorkub <derkub@gmail.com>
Wed, 17 Jul 2024 20:47:02 +0000 (22:47 +0200)
committerkub <derkub@gmail.com>
Wed, 17 Jul 2024 20:47:02 +0000 (22:47 +0200)
pico/draw.c
pico/draw_arm.S

index 5868268..0f9b137 100644 (file)
@@ -304,13 +304,43 @@ TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and)
 // --------------------------------------------\r
 \r
 #ifndef _ASM_DRAW_C\r
+#define DrawTile(mask) { \\r
+  if (code!=oldcode) { \\r
+    oldcode = code; \\r
+ \\r
+    pack = 0; \\r
+    if (code != blank) { \\r
+      /* Get tile address/2: */\\r
+      u32 addr = ((code&0x7ff)<<4) + ty; \\r
+      if (code & 0x1000) addr ^= 0xe; /* Y-flip */ \\r
+ \\r
+      pal = ((code>>9)&0x30) | sh; /* shadow */ \\r
+ \\r
+      pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); \\r
+      if (!pack) \\r
+        blank = code; \\r
+    } \\r
+  } \\r
+ \\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
+      *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
+  } \\r
+}\r
+\r
 static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)\r
 {\r
   unsigned char *pd = Pico.est.HighCol;\r
   u32 *hc = ts->hc;\r
   int tilex, dx, ty, cells;\r
-  u32 pack = 0, oldcode = -1, blank = -1; // The tile we know is blank\r
-  unsigned int pal = 0, sh;\r
+  u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
+  unsigned int pal = 0, pack = 0, sh, mask = ~0;\r
 \r
   // Draw tiles across screen:\r
   sh = (lflags & LF_SH) << 6; // shadow\r
@@ -318,42 +348,39 @@ static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip)
   ty=(ts->line&7)<<1; // Y-Offset into tile\r
   dx=((ts->hscroll-1)&7)+1;\r
   cells = ts->cells - cellskip;\r
-  if(dx != 8) cells++; // have hscroll, need to draw 1 cell more\r
   dx+=cellskip<<3;\r
 \r
+  if (dx & 7) {\r
+    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\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
+    dx += 8, tilex++, cells--;\r
+  }\r
+\r
 //  int force = (lflags&LF_FORCE) << 13;\r
   for (; cells > 0; dx+=8, tilex++, cells--)\r
   {\r
-    u32 code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
+    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
-    if (code!=oldcode) {\r
-      oldcode = code;\r
-\r
-      pack = 0;\r
-      if (code != blank) {\r
-        // Get tile address/2:\r
-        u32 addr = ((code&0x7ff)<<4) + ty;\r
-        if (code & 0x1000) addr ^= 0xe; // Y-flip\r
-\r
-        pal = ((code>>9)&0x30) | sh; // shadow\r
+    DrawTile(~0);\r
+  }\r
 \r
-        pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));\r
-        if (!pack)\r
-          blank = code;\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
+      mask = 0xffffffff<<((dx&7)*4);\r
+      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
+      mask = (mask << 16) | (mask >> 16);\r
 \r
-    if (code & 0x8000) { // (un-forced) high priority tile\r
-      code |= (dx<<16) | (ty<<25);\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
+      DrawTile(mask);\r
     }\r
   }\r
 \r
@@ -451,6 +478,36 @@ static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip)
 }\r
 #endif\r
 \r
+#define DrawTileInterlace(mask) { \\r
+  if (code!=oldcode) { \\r
+    oldcode = code; \\r
+ \\r
+    pack = 0; \\r
+    if (code != blank) { \\r
+      /* Get tile address/2: */ \\r
+      u32 addr = ((code&0x3ff)<<5) + ty; \\r
+      if (code & 0x1000) addr ^= 0x1e; /* Y-flip */ \\r
+ \\r
+      pal = ((code>>9)&0x30) | sh; /* shadow */ \\r
+ \\r
+      pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); \\r
+      if (!pack) \\r
+        blank = code; \\r
+    } \\r
+  } \\r
+ \\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
+      *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
+  } \\r
+}\r
+\r
 #ifndef _ASM_DRAW_C\r
 static\r
 #endif\r
@@ -459,8 +516,8 @@ void DrawStripInterlace(struct TileStrip *ts, int plane_sh)
   unsigned char *pd = Pico.est.HighCol;\r
   u32 *hc = ts->hc;\r
   int tilex = 0, dx = 0, ty = 0, cells;\r
-  u32 oldcode = -1, blank = -1; // The tile we know is blank\r
-  unsigned int pal = 0, pack = 0, sh;\r
+  u32 code, oldcode = -1, blank = -1; // The tile we know is blank\r
+  unsigned int pal = 0, pack = 0, sh, mask = ~0;\r
 \r
   // Draw tiles across screen:\r
   sh = (plane_sh & LF_SH) << 6; // shadow\r
@@ -468,7 +525,16 @@ void DrawStripInterlace(struct TileStrip *ts, int plane_sh)
   ty=(ts->line&15)<<1; // Y-Offset into tile\r
   dx=((ts->hscroll-1)&7)+1;\r
   cells = ts->cells;\r
-  if(dx != 8) cells++; // have hscroll, need to draw 1 cell more\r
+\r
+  if (dx & 7) {\r
+    code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)];\r
+    mask = 0xffffffff<<(dx*4);\r
+    if (code & 0x0800) mask = 0xffffffff>>(dx*4);\r
+    mask = (~mask << 16) | (~mask >> 16);\r
+\r
+    DrawTileInterlace(mask);\r
+    dx += 8, tilex++, cells--;\r
+  }\r
 \r
 //  int force = (plane_sh&LF_FORCE) << 13;\r
   for (; cells; dx+=8,tilex++,cells--)\r
@@ -479,33 +545,18 @@ void DrawStripInterlace(struct TileStrip *ts, int plane_sh)
     if (code == blank && !(code & 0x8000))\r
       continue;\r
 \r
-    if (code!=oldcode) {\r
-      oldcode = code;\r
-\r
-      pack = 0;\r
-      if (code != blank) {\r
-        // Get tile address/2:\r
-        u32 addr = ((code&0x3ff)<<5) + ty;\r
-        if (code & 0x1000) addr ^= 0x1e; // Y-flip\r
-\r
-        pal = ((code>>9)&0x30) | sh; // shadow\r
+    DrawTileInterlace(~0);\r
+  }\r
 \r
-        pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr));\r
-        if (!pack)\r
-          blank = code;\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
+      mask = 0xffffffff<<((dx&7)*4);\r
+      if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4);\r
+      mask = (mask << 16) | (mask >> 16);\r
 \r
-    if (code & 0x8000) { // high priority tile\r
-      if ((plane_sh&LF_SH) | (code!=blank)) {\r
-        code = (code&0xfc00) | ((code&0x3ff)<<1) | (dx<<16) | (ty<<25);\r
-        if (code & 0x1000) code ^= 0x1e<<25;\r
-        *hc++ = code, *hc++ = pack; // cache it\r
-      }\r
-      continue;\r
-    } else if (code != blank) {\r
-      if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
-      else               TileNorm(pd + dx, pack, pal);\r
+      DrawTileInterlace(mask);\r
     }\r
   }\r
 \r
@@ -698,19 +749,6 @@ static void DrawWindow(int tstart, int tend, int prio, int sh,
 \r
 // --------------------------------------------\r
 \r
-static void DrawTilesFromCacheShPrep(void)\r
-{\r
-  // as some layer has covered whole line with hi priority tiles,\r
-  // 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 c = 320/4, *zb = (int *)(Pico.est.HighCol+8);\r
-  Pico.est.rendstatus |= PDRAW_SHHI_DONE;\r
-  while (c--)\r
-  {\r
-    *zb++ &= 0x7f7f7f7f;\r
-  }\r
-}\r
-\r
 static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est)\r
 {\r
   unsigned char *pd = est->HighCol;\r
@@ -722,8 +760,18 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
 \r
   if (sh && (est->rendstatus & (PDRAW_SHHI_DONE|PDRAW_PLANE_HI_PRIO)))\r
   {\r
-    if (!(est->rendstatus & PDRAW_SHHI_DONE))\r
-      DrawTilesFromCacheShPrep();\r
+    if (!(est->rendstatus & PDRAW_SHHI_DONE)) {\r
+      // as some layer has covered whole line with hi priority tiles,\r
+      // 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
+      while (c--)\r
+      {\r
+        *zb++ &= 0x7f7f7f7f;\r
+      }\r
+      Pico.est.rendstatus |= PDRAW_SHHI_DONE;\r
+    }\r
     sh = 0;\r
   }\r
 \r
@@ -731,13 +779,13 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
   {\r
     while ((code=*hc++)) {\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
-      if (rlim-dx < 0)\r
-        goto last_cut_tile;\r
 \r
       if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
       else               TileNorm(pd + dx, pack, pal);\r
@@ -754,12 +802,12 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
       *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f;\r
 \r
       pack = *hc++;\r
+      if (rlim - dx < 0)\r
+        goto last_cut_tile;\r
       if (!pack)\r
         continue;\r
 \r
       pal = ((code >> 9) & 0x30);\r
-      if (rlim - dx < 0)\r
-        goto last_cut_tile;\r
 \r
       if (code & 0x0800) TileFlip(pd + dx, pack, pal);\r
       else               TileNorm(pd + dx, pack, pal);\r
@@ -770,35 +818,18 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est
 last_cut_tile:\r
   // for vertical window cutoff\r
   {\r
-    unsigned int t;\r
-\r
-    pd += dx;\r
-    if (code&0x0800)\r
-    {\r
-      switch (rlim-dx+8)\r
-      {\r
-        case 7: t=pack&0x00000f00; if (t) pd[6]=(unsigned char)(pal|(t>> 8)); // "break" is left out intentionally\r
-        case 6: t=pack&0x000000f0; if (t) pd[5]=(unsigned char)(pal|(t>> 4));\r
-        case 5: t=pack&0x0000000f; if (t) pd[4]=(unsigned char)(pal|(t    ));\r
-        case 4: t=pack&0xf0000000; if (t) pd[3]=(unsigned char)(pal|(t>>28));\r
-        case 3: t=pack&0x0f000000; if (t) pd[2]=(unsigned char)(pal|(t>>24));\r
-        case 2: t=pack&0x00f00000; if (t) pd[1]=(unsigned char)(pal|(t>>20));\r
-        case 1: t=pack&0x000f0000; if (t) pd[0]=(unsigned char)(pal|(t>>16));\r
-        default: break;\r
-      }\r
-    }\r
-    else\r
-    {\r
-      switch (rlim-dx+8)\r
-      {\r
-        case 7: t=pack&0x00f00000; if (t) pd[6]=(unsigned char)(pal|(t>>20));\r
-        case 6: t=pack&0x0f000000; if (t) pd[5]=(unsigned char)(pal|(t>>24));\r
-        case 5: t=pack&0xf0000000; if (t) pd[4]=(unsigned char)(pal|(t>>28));\r
-        case 4: t=pack&0x0000000f; if (t) pd[3]=(unsigned char)(pal|(t    ));\r
-        case 3: t=pack&0x000000f0; if (t) pd[2]=(unsigned char)(pal|(t>> 4));\r
-        case 2: t=pack&0x00000f00; if (t) pd[1]=(unsigned char)(pal|(t>> 8));\r
-        case 1: t=pack&0x0000f000; if (t) pd[0]=(unsigned char)(pal|(t>>12));\r
-        default: break;\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
index e3f6ce8..7a2e6f1 100644 (file)
@@ -433,11 +433,11 @@ DrawLayer:
     movs    r3, r9, lsl #1  @ (force[31]|sh[30]) << 1\r
     mov     r3, #0\r
     orrmi   r10,r10, #1<<23 @ r10=cells[31:24]|sh[23]|hi_not_empty[22]\r
-@    orrcc   r10,r10, #1<<20 @    |had_output[21]|!force[20]|ty[15:0]\r
+@    orrcc   r10,r10, #1<<20 @   |had_output[21]|!force[20]|hscroll[19:17]|ty[15:0]\r
     movmi   r3, #0x80       @ default to shadowed pal on sh mode\r
 \r
-    cmp     r7, #8\r
-    addne   r10,r10, #0x01000000 @ we will loop cells+1 times if there is scroll\r
+    and     r4, r7, #7\r
+    orr     r10,r10, r4, lsl #16 @ we will process cells+1 if there is scroll\r
 \r
     and     r9, r9, #0xff00\r
     add     r8, r8, r9, lsr #8   @ tilex+=cellskip\r
@@ -452,9 +452,40 @@ DrawLayer:
     mvn     r9, #0               @ r9=prevcode=-1\r
     add     r1, r11, r7          @ r1=pdest\r
 \r
-    @ r10=cells[31:24]|sh[23]|hi_not_empty[22]|had_output[21]|!force[20]|ty[15:0]\r
+    @ r10=cells[31:24]|sh[23]|hi_not_empty[22]|had_output[21]|!force[20]|hscroll[19:17]|ty[15:0]\r
     @ r1=pd+dx r2=pack r3=pal r5=xmask r6=hc r8=tilex r9=prevcode r11=HighCol r12=nametab lr=vram\r
     @ r4 & r7 are scratch in this loop\r
+\r
+    ands    r4, r10, #7<<16  @ hscroll?\r
+    beq     .dsloop_subr1\r
+    subs    r10,r10, #0x01000000\r
+    bmi     .dsloop_exit\r
+\r
+    and     r7, r5, r8         @ do first cut tile\r
+    add     r7, lr, r7, lsl #1 @ Pico.vram+((tilex&ts->xmask) as halfwords)\r
+    ldrh    r9, [r7, r12]      @ r7=code (int, but from unsigned, no sign extend)\r
+\r
+    add     r8, r8, #1\r
+\r
+    movs    r2, r9, lsl #20 @ if (code&0x1000)\r
+    mov     r2, r2, lsl #1\r
+    add     r2, r2, r10, lsl #17\r
+    mov     r2, r2, lsr #17\r
+    eorcs   r2, r2, #0x0e   @ if (code&0x1000) addr^=0xe;\r
+\r
+    ldr     r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
+\r
+    mvn     r7, #0\r
+    mov     r4, r4, lsr #16-2  @ (dx&7)*4\r
+    tst     r9, #0x0800\r
+    moveq   r7, r7, lsl r4     @ mask = ~0 [shift] (dx&7)*4\r
+    movne   r7, r7, lsr r4\r
+    mvn     r7, r7, ror #16\r
+    and     r2, r2, r7         @ pack&mask\r
+\r
+    orr     r9, r9, #0x80000000 @ invalidate oldcode since pack is masked\r
+    b       .DrawStrip_samecode\r
+\r
 .dsloop_subr1:\r
     sub     r1, r1, #8\r
 .dsloop: @ 40-41 times\r
@@ -480,7 +511,6 @@ DrawLayer:
     eorcs   r2, r2, #0x0e   @ if (code&0x1000) addr^=0xe;\r
 \r
     ldr     r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
-\r
 .DrawStrip_samecode:\r
     tst     r9, #0x8000\r
 @    tstne   r10, #1<<20     @ !force[20]\r
@@ -538,6 +568,35 @@ DrawLayer:
     b       .dsloop\r
 \r
 .dsloop_exit:\r
+    ands    r4,r10, #7<<16        @ hscroll?\r
+    beq     .DrawStrip_noscroll\r
+\r
+    and     r7, r5, r8         @ do one more cut tile\r
+    add     r7, lr, r7, lsl #1 @ Pico.vram+((tilex&ts->xmask) as halfwords)\r
+    ldrh    r9, [r7, r12]      @ r7=code (int, but from unsigned, no sign extend)\r
+\r
+    add     r1, r1, #8\r
+\r
+    movs    r2, r9, lsl #20 @ if (code&0x1000)\r
+    mov     r2, r2, lsl #1\r
+    add     r2, r2, r10, lsl #17\r
+    mov     r2, r2, lsr #17\r
+    eorcs   r2, r2, #0x0e   @ if (code&0x1000) addr^=0xe;\r
+\r
+    ldr     r2, [lr, r2, lsl #1] @ pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels\r
+\r
+    mvn     r7, #0\r
+    mov     r4, r4, lsr #16-2  @ (dx&7)*4\r
+    tst     r9, #0x0800\r
+    moveq   r7, r7, lsl r4     @ mask = ~0 [shift] (dx&7)*4\r
+    movne   r7, r7, lsr r4\r
+    mov     r7, r7, ror #16\r
+    and     r2, r2, r7         @ pack&mask\r
+\r
+    bic     r10,r10, #7<<16\r
+    b       .DrawStrip_samecode @ one last time, with last tile now masked\r
+\r
+.DrawStrip_noscroll:\r
     tst     r10, #1<<21 @ seen non hi-prio tile\r
     ldr     r1, [sp, #9*4]  @ est\r
     mov     r0, #0\r
@@ -939,15 +998,17 @@ DrawTilesFromCache:
     b       .dtfc_loop\r
 \r
 .dtfc_cut_tile:\r
-    add     r4, r4, #7      @ 0-6\r
+    cmn     r4, #8\r
+    ble     .dtfc_loop      @ off limits\r
+\r
+    rsb     r4, r4, #0      @ 1-7\r
     mov     r4, r4, lsl #2\r
-    mov     r12,#0xf<<28\r
-    mov     r12,r12,asr r4\r
-    mov     r2, r2, ror #16\r
+    mvn     r12,#0\r
     tst     r6, #0x0800     @ flipped?\r
-    mvnne   r12,r12\r
+    moveq   r12,r12, lsl r4\r
+    movne   r12,r12, lsr r4\r
+    mov     r12,r12, ror #16\r
     and     r2, r2, r12\r
-    mov     r2, r2, ror #16\r
     mov     r12,#0xf\r
     tst     r8, #1\r
     bne     .dtfc_shadow\r