gpulib: use more conservative loop detection
[pcsx_rearmed.git] / plugins / gpulib / gpu.c
index 53fe0bc..0e6fe63 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;
@@ -512,11 +521,13 @@ void GPUwriteData(uint32_t data)
 
 long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
 {
-  uint32_t addr, *list;
+  uint32_t addr, *list, ld_addr = 0;
   uint32_t *llist_entry = NULL;
   int len, left, count;
   long cpu_cycles = 0;
 
+  preload(rambase + (start_addr & 0x1fffff) / 4);
+
   if (unlikely(gpu.cmd_len > 0))
     flush_cmd_buffer();
 
@@ -531,39 +542,50 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
 
   log_io("gpu_dma_chain\n");
   addr = start_addr & 0xffffff;
-  for (count = 0; addr != 0xffffff; count++)
+  for (count = 0; (addr & 0x800000) == 0; count++)
   {
     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;
 
     log_io(".chain %08x #%d\n", (list - rambase) * 4, len);
 
-    // loop detection marker
-    // (bit23 set causes DMA error on real machine, so
-    //  unlikely to be ever set by the game)
-    list[0] |= 0x800000;
-
     if (len) {
       left = do_cmd_buffer(list + 1, len);
       if (left)
         log_anomaly("GPUdmaChain: discarded %d/%d words\n", left, len);
     }
 
-    if (addr & 0x800000)
-      break;
+    #define LD_THRESHOLD (8*1024)
+    if (count >= LD_THRESHOLD) {
+      if (count == LD_THRESHOLD) {
+        ld_addr = addr;
+        continue;
+      }
+
+      // loop detection marker
+      // (bit23 set causes DMA error on real machine, so
+      //  unlikely to be ever set by the game)
+      list[0] |= 0x800000;
+    }
   }
 
-  // remove loop detection markers
-  addr = start_addr & 0x1fffff;
-  while (count-- > 0) {
-    list = rambase + addr / 4;
-    addr = list[0] & 0x1fffff;
-    list[0] &= ~0x800000;
+  if (ld_addr != 0) {
+    // remove loop detection markers
+    count -= LD_THRESHOLD + 2;
+    addr = ld_addr & 0x1fffff;
+    while (count-- > 0) {
+      list = rambase + addr / 4;
+      addr = list[0] & 0x1fffff;
+      list[0] &= ~0x800000;
+    }
   }
+
   if (llist_entry)
     *llist_entry &= ~0x800000;