some random improvements
[pcsx_rearmed.git] / plugins / gpulib / gpu.c
index b61bff6..c9b05d4 100644 (file)
 #include "gpu.h"
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#ifdef __GNUC__
 #define unlikely(x) __builtin_expect((x), 0)
+#define preload __builtin_prefetch
 #define noinline __attribute__((noinline))
+#else
+#define unlikely(x)
+#define preload(...)
+#define noinline
+#error huh
+#endif
 
 #define gpu_log(fmt, ...) \
   printf("%d:%03d: " fmt, *gpu.state.frame_count, *gpu.state.hcnt, ##__VA_ARGS__)
@@ -68,10 +76,11 @@ static noinline void update_width(void)
 
 static noinline void update_height(void)
 {
+  // TODO: emulate this properly..
   int sh = gpu.screen.y2 - gpu.screen.y1;
   if (gpu.status.dheight)
     sh *= 2;
-  if (sh <= 0)
+  if (sh <= 0 || sh > gpu.screen.vres)
     sh = gpu.screen.vres;
 
   gpu.screen.h = sh;
@@ -212,7 +221,7 @@ void GPUwriteStatus(uint32_t data)
       break;
     case 0x05:
       gpu.screen.x = data & 0x3ff;
-      gpu.screen.y = (data >> 10) & 0x3ff;
+      gpu.screen.y = (data >> 10) & 0x1ff;
       if (gpu.frameskip.set) {
         decide_frameskip_allow(gpu.ex_regs[3]);
         if (gpu.frameskip.last_flip_frame != *gpu.state.frame_count) {
@@ -367,46 +376,62 @@ static void finish_vram_transfer(int is_read)
 
 static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd)
 {
-  int cmd = 0, pos = 0, len, dummy;
+  int cmd = 0, pos = 0, len, dummy, v;
   int skip = 1;
 
   gpu.frameskip.pending_fill[0] = 0;
 
-  // XXX: polylines are not properly handled
   while (pos < count && skip) {
     uint32_t *list = data + pos;
     cmd = list[0] >> 24;
     len = 1 + cmd_lengths[cmd];
 
-    if (cmd == 0x02) {
-      if ((list[2] & 0x3ff) > gpu.screen.w || ((list[2] >> 16) & 0x1ff) > gpu.screen.h)
-        // clearing something large, don't skip
-        do_cmd_list(list, 3, &dummy);
-      else
-        memcpy(gpu.frameskip.pending_fill, list, 3 * 4);
-    }
-    else if ((cmd & 0xf4) == 0x24) {
-      // flat textured prim
-      gpu.ex_regs[1] &= ~0x1ff;
-      gpu.ex_regs[1] |= list[4] & 0x1ff;
-    }
-    else if ((cmd & 0xf4) == 0x34) {
-      // shaded textured prim
-      gpu.ex_regs[1] &= ~0x1ff;
-      gpu.ex_regs[1] |= list[5] & 0x1ff;
+    switch (cmd) {
+      case 0x02:
+        if ((list[2] & 0x3ff) > gpu.screen.w || ((list[2] >> 16) & 0x1ff) > gpu.screen.h)
+          // clearing something large, don't skip
+          do_cmd_list(list, 3, &dummy);
+        else
+          memcpy(gpu.frameskip.pending_fill, list, 3 * 4);
+        break;
+      case 0x24 ... 0x27:
+      case 0x2c ... 0x2f:
+      case 0x34 ... 0x37:
+      case 0x3c ... 0x3f:
+        gpu.ex_regs[1] &= ~0x1ff;
+        gpu.ex_regs[1] |= list[4 + ((cmd >> 4) & 1)] & 0x1ff;
+        break;
+      case 0x48 ... 0x4F:
+        for (v = 3; pos + v < count; v++)
+        {
+          if ((list[v] & 0xf000f000) == 0x50005000)
+            break;
+        }
+        len += v - 3;
+        break;
+      case 0x58 ... 0x5F:
+        for (v = 4; pos + v < count; v += 2)
+        {
+          if ((list[v] & 0xf000f000) == 0x50005000)
+            break;
+        }
+        len += v - 4;
+        break;
+      default:
+        if (cmd == 0xe3)
+          skip = decide_frameskip_allow(list[0]);
+        if ((cmd & 0xf8) == 0xe0)
+          gpu.ex_regs[cmd & 7] = list[0];
+        break;
     }
-    else if (cmd == 0xe3)
-      skip = decide_frameskip_allow(list[0]);
-
-    if ((cmd & 0xf8) == 0xe0)
-      gpu.ex_regs[cmd & 7] = list[0];
 
     if (pos + len > count) {
       cmd = -1;
       break; // incomplete cmd
     }
-    if (cmd == 0xa0 || cmd == 0xc0)
+    if (0xa0 <= cmd && cmd <= 0xdf)
       break; // image i/o
+
     pos += len;
   }
 
@@ -432,9 +457,9 @@ static noinline int do_cmd_buffer(uint32_t *data, int count)
     }
 
     cmd = data[pos] >> 24;
-    if (cmd == 0xa0 || cmd == 0xc0) {
+    if (0xa0 <= cmd && cmd <= 0xdf) {
       // consume vram write/read cmd
-      start_vram_transfer(data[pos + 1], data[pos + 2], cmd == 0xc0);
+      start_vram_transfer(data[pos + 1], data[pos + 2], (cmd & 0xe0) == 0xc0);
       pos += 3;
       continue;
     }
@@ -501,6 +526,8 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
   int len, left, count;
   long cpu_cycles = 0;
 
+  preload(rambase + (start_addr & 0x1fffff) / 4);
+
   if (unlikely(gpu.cmd_len > 0))
     flush_cmd_buffer();
 
@@ -520,6 +547,8 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
     list = rambase + (addr & 0x1fffff) / 4;
     len = list[0] >> 24;
     addr = list[0] & 0xffffff;
+    preload(rambase + (addr & 0x1fffff) / 4);
+
     cpu_cycles += 10;
     if (len > 0)
       cpu_cycles += 5 + len;