gpulib: handle vram copy in gpulib
authornotaz <notasas@gmail.com>
Fri, 8 Sep 2023 21:39:34 +0000 (00:39 +0300)
committernotaz <notasas@gmail.com>
Fri, 8 Sep 2023 21:48:59 +0000 (00:48 +0300)
use internal buffering according to mednafen
notaz/pcsx_rearmed#289

plugins/dfxvideo/gpulib_if.c
plugins/gpu_neon/psx_gpu/psx_gpu.c
plugins/gpu_neon/psx_gpu/psx_gpu_parse.c
plugins/gpu_senquack/gpulib_if.cpp
plugins/gpu_unai/gpulib_if.cpp
plugins/gpulib/gpu.c

index ba7f16a..978e7d8 100644 (file)
@@ -321,7 +321,7 @@ int do_cmd_list(uint32_t *list, int list_len, int *last_cmd)
     }
 
 #ifndef TEST
-    if (cmd == 0xa0 || cmd == 0xc0)
+    if (0x80 <= cmd && cmd < 0xe0)
       break; // image i/o, forward to upper layer
     else if ((cmd & 0xf8) == 0xe0)
       gpu.ex_regs[cmd & 7] = GETLE32(list);
index a0bff3e..fbacbd5 100644 (file)
@@ -4888,6 +4888,7 @@ void render_block_fill_enh(psx_gpu_struct *psx_gpu, u32 color, u32 x, u32 y,
   }
 }
 
+#ifndef PCSX
 void render_block_copy(psx_gpu_struct *psx_gpu, u16 *source, u32 x, u32 y,
  u32 width, u32 height, u32 pitch)
 {
@@ -4919,7 +4920,7 @@ void render_block_move(psx_gpu_struct *psx_gpu, u32 source_x, u32 source_y,
   render_block_copy(psx_gpu, psx_gpu->vram_ptr + source_x + (source_y * 1024),
    dest_x, dest_y, width, height, 1024);
 }
-
+#endif
 
 void initialize_reciprocal_table(void)
 {
index c756299..5badf6b 100644 (file)
@@ -606,7 +606,13 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
                        break;
       }
   
-      case 0x80:          //  vid -> vid
+#ifdef PCSX
+      case 0x80 ... 0x9F:          //  vid -> vid
+      case 0xA0 ... 0xBF:          //  sys -> vid
+      case 0xC0 ... 0xDF:          //  vid -> sys
+        goto breakloop;
+#else
+      case 0x80 ... 0x9F:          //  vid -> vid
       {
         u32 sx = list_s16[2] & 0x3FF;
         u32 sy = list_s16[3] & 0x1FF;
@@ -622,12 +628,7 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
         break;
       } 
 
-#ifdef PCSX
-               case 0xA0:          //  sys -> vid
-               case 0xC0:          //  vid -> sys
-                       goto breakloop;
-#else
-               case 0xA0:          //  sys -> vid
+      case 0xA0 ... 0xBF:          //  sys -> vid
       {
         u32 load_x = list_s16[2] & 0x3FF;
         u32 load_y = list_s16[3] & 0x1FF;
@@ -645,8 +646,8 @@ u32 gpu_parse(psx_gpu_struct *psx_gpu, u32 *list, u32 size, u32 *last_command)
                        break;
       }
 
-               case 0xC0:          //  vid -> sys
-                       break;
+      case 0xC0 ... 0xDF:          //  vid -> sys
+        break;
 #endif
 
                case 0xE1:
@@ -1575,26 +1576,10 @@ u32 gpu_parse_enhanced(psx_gpu_struct *psx_gpu, u32 *list, u32 size,
           do_sprite_enhanced(psx_gpu, x, y, u, v, 16, 16, list[0]);
         break;
       }
-  
-      case 0x80:          //  vid -> vid
-      {
-        u32 sx = list_s16[2] & 0x3FF;
-        u32 sy = list_s16[3] & 0x1FF;
-        u32 dx = list_s16[4] & 0x3FF;
-        u32 dy = list_s16[5] & 0x1FF;
-        u32 w = ((list_s16[6] - 1) & 0x3FF) + 1;
-        u32 h = ((list_s16[7] - 1) & 0x1FF) + 1;
 
-        if (sx == dx && sy == dy && psx_gpu->mask_msb == 0)
-          break;
-
-        render_block_move(psx_gpu, sx, sy, dx, dy, w, h);
-        sync_enhancement_buffers(dx, dy, w, h);
-        break;
-      }
-      case 0xA0:          //  sys -> vid
-      case 0xC0:          //  vid -> sys
+      case 0x80 ... 0x9F:          //  vid -> vid
+      case 0xA0 ... 0xBF:          //  sys -> vid
+      case 0xC0 ... 0xDF:          //  vid -> sys
         goto breakloop;
 
       case 0xE1:
index 0bc63c6..72dcc6d 100644 (file)
@@ -575,11 +575,11 @@ int do_cmd_list(u32 *list, int list_len, int *last_cmd)
         gpuDrawS(packet, driver);
       } break;
 
+#ifdef TEST
       case 0x80:          //  vid -> vid
         gpuMoveImage(packet);
         break;
 
-#ifdef TEST
       case 0xA0:          //  sys -> vid
       {
         u32 load_width = list[2] & 0xffff;
@@ -592,8 +592,9 @@ int do_cmd_list(u32 *list, int list_len, int *last_cmd)
       case 0xC0:
         break;
 #else
-      case 0xA0:          //  sys ->vid
-      case 0xC0:          //  vid -> sys
+      case 0x80 ... 0x9F:          //  vid -> vid
+      case 0xA0 ... 0xBF:          //  sys -> vid
+      case 0xC0 ... 0xDF:          //  vid -> sys
         // Handled by gpulib
         goto breakloop;
 #endif
index 0064aaa..1c46142 100644 (file)
@@ -438,10 +438,10 @@ int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
           gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | (enableAbbeyHack<<7)  | PixelMSB]);
         break;
 
+#ifdef TEST
       case 0x80:          //  vid -> vid
         gpuMoveImage();   //  prim handles updateLace && skip
         break;
-#ifdef TEST
       case 0xA0:          //  sys -> vid
       {
         u32 load_width = list[2] & 0xffff;
@@ -454,8 +454,10 @@ int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
       case 0xC0:
         break;
 #else
-      case 0xA0:          //  sys ->vid
-      case 0xC0:          //  vid -> sys
+      case 0x80 ... 0x9F:          //  vid -> vid
+      case 0xA0 ... 0xBF:          //  sys -> vid
+      case 0xC0 ... 0xDF:          //  vid -> sys
+        // Handled by gpulib
         goto breakloop;
 #endif
       case 0xE1: {
index 1bf25af..dfaff58 100644 (file)
@@ -336,23 +336,33 @@ const unsigned char cmd_lengths[256] =
        3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
        2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, // 60
        1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
-       3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a0
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-       2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c0
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 80
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // a0
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e0
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
 #define VRAM_MEM_XY(x, y) &gpu.vram[(y) * 1024 + (x)]
 
-static inline void do_vram_line(int x, int y, uint16_t *mem, int l, int is_read)
+static void cpy_msb(uint16_t *dst, const uint16_t *src, int l, uint16_t msb)
+{
+  int i;
+  for (i = 0; i < l; i++)
+    dst[i] = src[i] | msb;
+}
+
+static inline void do_vram_line(int x, int y, uint16_t *mem, int l,
+    int is_read, uint16_t msb)
 {
   uint16_t *vram = VRAM_MEM_XY(x, y);
-  if (is_read)
+  if (unlikely(is_read))
     memcpy(mem, vram, l * 2);
+  else if (unlikely(msb))
+    cpy_msb(vram, mem, l, msb);
   else
     memcpy(vram, mem, l * 2);
 }
@@ -360,6 +370,7 @@ static inline void do_vram_line(int x, int y, uint16_t *mem, int l, int is_read)
 static int do_vram_io(uint32_t *data, int count, int is_read)
 {
   int count_initial = count;
+  uint16_t msb = gpu.ex_regs[6] << 15;
   uint16_t *sdata = (uint16_t *)data;
   int x = gpu.dma.x, y = gpu.dma.y;
   int w = gpu.dma.w, h = gpu.dma.h;
@@ -372,7 +383,7 @@ static int do_vram_io(uint32_t *data, int count, int is_read)
     if (count < l)
       l = count;
 
-    do_vram_line(x + o, y, sdata, l, is_read);
+    do_vram_line(x + o, y, sdata, l, is_read, msb);
 
     if (o + l < w)
       o += l;
@@ -387,13 +398,13 @@ static int do_vram_io(uint32_t *data, int count, int is_read)
 
   for (; h > 0 && count >= w; sdata += w, count -= w, y++, h--) {
     y &= 511;
-    do_vram_line(x, y, sdata, w, is_read);
+    do_vram_line(x, y, sdata, w, is_read, msb);
   }
 
   if (h > 0) {
     if (count > 0) {
       y &= 511;
-      do_vram_line(x, y, sdata, count, is_read);
+      do_vram_line(x, y, sdata, count, is_read, msb);
       o = count;
       count = 0;
     }
@@ -441,6 +452,51 @@ static void finish_vram_transfer(int is_read)
                            gpu.dma_start.w, gpu.dma_start.h, 0);
 }
 
+static void do_vram_copy(const uint32_t *params)
+{
+  const uint32_t sx =  LE32TOH(params[0]) & 0x3FF;
+  const uint32_t sy = (LE32TOH(params[0]) >> 16) & 0x1FF;
+  const uint32_t dx =  LE32TOH(params[1]) & 0x3FF;
+  const uint32_t dy = (LE32TOH(params[1]) >> 16) & 0x1FF;
+  uint32_t w =  ((LE32TOH(params[2]) - 1) & 0x3FF) + 1;
+  uint32_t h = (((LE32TOH(params[2]) >> 16) - 1) & 0x1FF) + 1;
+  uint16_t msb = gpu.ex_regs[6] << 15;
+  uint16_t lbuf[128];
+  uint32_t x, y;
+
+  if (sx == dx && sy == dy && msb == 0)
+    return;
+
+  renderer_flush_queues();
+
+  if (unlikely((sx < dx && dx < sx + w) || sx + w > 1024 || dx + w > 1024 || msb))
+  {
+    for (y = 0; y < h; y++)
+    {
+      const uint16_t *src = VRAM_MEM_XY(0, (sy + y) & 0x1ff);
+      uint16_t *dst = VRAM_MEM_XY(0, (dy + y) & 0x1ff);
+      for (x = 0; x < w; x += ARRAY_SIZE(lbuf))
+      {
+        uint32_t x1, w1 = w - x;
+        if (w1 > ARRAY_SIZE(lbuf))
+          w1 = ARRAY_SIZE(lbuf);
+        for (x1 = 0; x1 < w1; x1++)
+          lbuf[x1] = src[(sx + x + x1) & 0x3ff];
+        for (x1 = 0; x1 < w1; x1++)
+          dst[(dx + x + x1) & 0x3ff] = lbuf[x1] | msb;
+      }
+    }
+  }
+  else
+  {
+    uint32_t sy1 = sy, dy1 = dy;
+    for (y = 0; y < h; y++, sy1++, dy1++)
+      memcpy(VRAM_MEM_XY(dx, dy1 & 0x1ff), VRAM_MEM_XY(sx, sy1 & 0x1ff), w * 2);
+  }
+
+  renderer_update_caches(dx, dy, w, h, 0);
+}
+
 static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd)
 {
   int cmd = 0, pos = 0, len, dummy, v;
@@ -496,7 +552,7 @@ static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd)
       cmd = -1;
       break; // incomplete cmd
     }
-    if (0xa0 <= cmd && cmd <= 0xdf)
+    if (0x80 <= cmd && cmd <= 0xdf)
       break; // image i/o
 
     pos += len;
@@ -536,6 +592,15 @@ static noinline int do_cmd_buffer(uint32_t *data, int count)
       pos += 3;
       continue;
     }
+    else if ((cmd & 0xe0) == 0x80) {
+      if (unlikely((pos+3) >= count)) {
+        cmd = -1; // incomplete cmd, can't consume yet
+        break;
+      }
+      do_vram_copy(data + pos + 1);
+      pos += 4;
+      continue;
+    }
 
     // 0xex cmds might affect frameskip.allow, so pass to do_cmd_list_skip
     if (gpu.frameskip.active && (gpu.frameskip.allow || ((LE32TOH(data[pos]) >> 24) & 0xf0) == 0xe0))