dma: add optional slow linked list walking
authornotaz <notasas@gmail.com>
Sun, 13 Nov 2022 21:33:49 +0000 (23:33 +0200)
committernotaz <notasas@gmail.com>
Sun, 13 Nov 2022 22:02:03 +0000 (00:02 +0200)
libretro/pcsx_rearmed#478
libretro/pcsx_rearmed#264
libretro/pcsx_rearmed#132
notaz/pcsx_rearmed#95

12 files changed:
frontend/libretro.c
frontend/libretro_core_options.h
frontend/main.c
frontend/menu.c
libpcsxcore/database.c
libpcsxcore/mdec.c
libpcsxcore/plugins.h
libpcsxcore/psxcommon.h
libpcsxcore/psxdma.c
libpcsxcore/psxhw.c
plugins/gpulib/gpu.c
plugins/gpulib/gpu.h

index 42f6151..3e74b23 100644 (file)
@@ -2117,6 +2117,18 @@ static void update_variables(bool in_flight)
          Config.Cdda = 0;
    }
 
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_slow_llists";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+        Config.GpuListWalking = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+        Config.GpuListWalking = 1;
+      else // auto
+        Config.GpuListWalking = -1;
+   }
+
 #ifdef THREAD_RENDERING
    var.key = "pcsx_rearmed_gpu_thread_rendering";
    var.value = NULL;
index 39bc32b..935c6f9 100644 (file)
@@ -423,6 +423,21 @@ struct retro_core_option_v2_definition option_defs_us[] = {
       },
       "disabled",
    },
+   {
+      "pcsx_rearmed_gpu_slow_llists",
+      "(GPU) Slow linked list processing",
+      NULL,
+      "Slower but more accurate GPU linked list processing. Needed by only a few games like Vampire Hunter D. Should be autodetected in most cases.",
+      NULL,
+      "video",
+      {
+         { "auto", NULL },
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "auto",
+   },
 #ifdef GPU_NEON
    {
       "pcsx_rearmed_neon_interlace_enable",
index dcac1d9..2773f7a 100644 (file)
@@ -133,6 +133,7 @@ void emu_set_default_config(void)
        Config.icache_emulation = 0;
        Config.PsxAuto = 1;
        Config.cycle_multiplier = CYCLE_MULT_DEFAULT;
+       Config.GpuListWalking = -1;
 
        pl_rearmed_cbs.gpu_neon.allow_interlace = 2; // auto
        pl_rearmed_cbs.gpu_neon.enhancement_enable =
index d1e0413..3a772d0 100644 (file)
@@ -397,6 +397,7 @@ static const struct {
        CE_CONFIG_VAL(icache_emulation),
        CE_CONFIG_VAL(DisableStalls),
        CE_CONFIG_VAL(Cpu),
+       CE_CONFIG_VAL(GpuListWalking),
        CE_INTVAL(region),
        CE_INTVAL_V(g_scaler, 3),
        CE_INTVAL(g_gamma),
@@ -1578,6 +1579,8 @@ static int menu_loop_speed_hacks(int id, int keys)
        return 0;
 }
 
+static const char *men_gpul[]    = { "Auto", "Off", "On", NULL };
+
 static const char h_cfg_cpul[]   = "Shows CPU usage in %";
 static const char h_cfg_spu[]    = "Shows active SPU channels\n"
                                   "(green: normal, red: fmod, blue: noise)";
@@ -1591,10 +1594,12 @@ static const char h_cfg_nodrc[]  = "Disable dynamic recompiler and use interpret
 #endif
 static const char h_cfg_shacks[] = "Breaks games but may give better performance";
 static const char h_cfg_icache[] = "Support F1 games (only when dynarec is off)";
+static const char h_cfg_gpul[]   = "Try enabling this if the game is missing some graphics\n"
+                                  "causes a performance hit";
 static const char h_cfg_psxclk[]  = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
                                    "(adjust this if the game is too slow/too fast/hangs)";
 
-enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_CPU };
+enum { AMO_XA, AMO_CDDA, AMO_IC, AMO_CPU, AMO_GPUL };
 
 static menu_entry e_menu_adv_options[] =
 {
@@ -1604,6 +1609,7 @@ static menu_entry e_menu_adv_options[] =
        mee_onoff_h   ("Disable XA Decoding",    0, menu_iopts[AMO_XA],   1, h_cfg_xa),
        mee_onoff_h   ("Disable CD Audio",       0, menu_iopts[AMO_CDDA], 1, h_cfg_cdda),
        mee_onoff_h   ("ICache emulation",       0, menu_iopts[AMO_IC],   1, h_cfg_icache),
+       mee_enum_h    ("GPU l-list slow walking",0, menu_iopts[AMO_GPUL], men_gpul, h_cfg_gpul),
 #if !defined(DRC_DISABLE) || defined(LIGHTREC)
        mee_onoff_h   ("Disable dynarec (slow!)",0, menu_iopts[AMO_CPU],  1, h_cfg_nodrc),
 #endif
@@ -1627,9 +1633,14 @@ static int menu_loop_adv_options(int id, int keys)
        int i;
        for (i = 0; i < ARRAY_SIZE(opts); i++)
                *opts[i].mopt = *opts[i].opt;
+       menu_iopts[AMO_GPUL] = Config.GpuListWalking + 1;
+
        me_loop(e_menu_adv_options, &sel);
+
        for (i = 0; i < ARRAY_SIZE(opts); i++)
                *opts[i].opt = *opts[i].mopt;
+       Config.GpuListWalking = menu_iopts[AMO_GPUL] - 1;
+
        return 0;
 }
 
index f947b06..ae6fe36 100644 (file)
@@ -18,6 +18,18 @@ static const char * const cdr_read_hack_db[] =
        "SLUS00787",
 };
 
+static const char * const gpu_slow_llist_db[] =
+{
+       /* Crash Bash */
+       "SCES02834", "SCUS94570", "SCUS94616", "SCUS94654",
+       /* Final Fantasy IV */
+       "SCES03840", "SLPM86028", "SLUS01360",
+       /* Spot Goes to Hollywood */
+       "SLES00330", "SLPS00394", "SLUS00014",
+       /* Vampire Hunter D */
+       "SLES02731", "SLPS02477", "SLPS03198", "SLUS01138",
+};
+
 #define HACK_ENTRY(var, list) \
        { #var, &Config.hacks.var, list, ARRAY_SIZE(list) }
 
@@ -31,6 +43,7 @@ static const struct
 hack_db[] =
 {
        HACK_ENTRY(cdr_read_timing, cdr_read_hack_db),
+       HACK_ENTRY(gpu_slow_list_walking, gpu_slow_llist_db),
 };
 
 static const struct
index ca42458..167a1cf 100644 (file)
@@ -476,6 +476,7 @@ void psxDma0(u32 adr, u32 bcr, u32 chcr) {
        int size;
 
        if (chcr != 0x01000201) {
+               log_unhandled("mdec0: invalid dma %08x\n", chcr);
                return;
        }
 
@@ -545,7 +546,10 @@ void psxDma1(u32 adr, u32 bcr, u32 chcr) {
        int size;
        u32 words;
 
-       if (chcr != 0x01000200) return;
+       if (chcr != 0x01000200) {
+               log_unhandled("mdec1: invalid dma %08x\n", chcr);
+               return;
+       }
 
        words = (bcr >> 16) * (bcr & 0xffff);
        /* size in byte */
index 178f83a..c997c61 100644 (file)
@@ -58,7 +58,7 @@ typedef void (CALLBACK* GPUwriteDataMem)(uint32_t *, int);
 typedef uint32_t (CALLBACK* GPUreadStatus)(void);\r
 typedef uint32_t (CALLBACK* GPUreadData)(void);\r
 typedef void (CALLBACK* GPUreadDataMem)(uint32_t *, int);\r
-typedef long (CALLBACK* GPUdmaChain)(uint32_t *,uint32_t);\r
+typedef long (CALLBACK* GPUdmaChain)(uint32_t *,uint32_t, uint32_t *);\r
 typedef void (CALLBACK* GPUupdateLace)(void);\r
 typedef long (CALLBACK* GPUconfigure)(void);\r
 typedef long (CALLBACK* GPUtest)(void);\r
index e0876cf..b621326 100644 (file)
@@ -141,12 +141,14 @@ typedef struct {
        boolean UseNet;
        boolean icache_emulation;
        boolean DisableStalls;
+       int GpuListWalking;
        int cycle_multiplier; // 100 for 1.0
        int cycle_multiplier_override;
        u8 Cpu; // CPU_DYNAREC or CPU_INTERPRETER
        u8 PsxType; // PSX_TYPE_NTSC or PSX_TYPE_PAL
        struct {
                boolean cdr_read_timing;
+               boolean gpu_slow_list_walking;
        } hacks;
 #ifdef _WIN32
        char Lang[256];
index d7c4cae..30aa9bd 100644 (file)
@@ -127,7 +127,8 @@ static u32 gpuDmaChainSize(u32 addr) {
 }
 
 void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
-       u32 *ptr;
+       u32 *ptr, madr_next, *madr_next_p;
+       int do_walking;
        u32 words;
        u32 size;
 
@@ -179,22 +180,25 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
 #ifdef PSXDMA_LOG
                        PSXDMA_LOG("*** DMA 2 - GPU dma chain *** %lx addr = %lx size = %lx\n", chcr, madr, bcr);
 #endif
+                       // when not emulating walking progress, end immediately
+                       madr_next = 0xffffff;
 
-                       size = GPU_dmaChain((u32 *)psxM, madr & 0x1fffff);
+                       do_walking = Config.GpuListWalking;
+                       if (do_walking < 0)
+                               do_walking = Config.hacks.gpu_slow_list_walking;
+                       madr_next_p = do_walking ? &madr_next : NULL;
+
+                       size = GPU_dmaChain((u32 *)psxM, madr & 0x1fffff, madr_next_p);
                        if ((int)size <= 0)
                                size = gpuDmaChainSize(madr);
-                       HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY);
 
-                       // we don't emulate progress, just busy flag and end irq,
-                       // so pretend we're already at the last block
-                       HW_DMA2_MADR = SWAPu32(0xffffff);
+                       HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY);
+                       HW_DMA2_MADR = SWAPu32(madr_next);
 
                        // Tekken 3 = use 1.0 only (not 1.5x)
 
                        // Einhander = parse linked list in pieces (todo)
-                       // Final Fantasy 4 = internal vram time (todo)
                        // Rebel Assault 2 = parse linked list in pieces (todo)
-                       // Vampire Hunter D = allow edits to linked list (todo)
                        GPUDMA_INT(size);
                        return;
 
@@ -208,6 +212,14 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
 }
 
 void gpuInterrupt() {
+       if (HW_DMA2_CHCR == SWAP32(0x01000401) && !(HW_DMA2_MADR & SWAP32(0x800000)))
+       {
+               u32 size, madr_next = 0xffffff;
+               size = GPU_dmaChain((u32 *)psxM, HW_DMA2_MADR & 0x1fffff, &madr_next);
+               HW_DMA2_MADR = SWAPu32(madr_next);
+               GPUDMA_INT(size);
+               return;
+       }
        if (HW_DMA2_CHCR & SWAP32(0x01000000))
        {
                HW_DMA2_CHCR &= SWAP32(~0x01000000);
index 483f496..27ddfea 100644 (file)
@@ -519,6 +519,8 @@ void psxHwWrite16(u32 add, u16 value) {
 }
 
 #define DmaExec(n) { \
+       if (value & SWAPu32(HW_DMA##n##_CHCR) & 0x01000000) \
+               log_unhandled("dma" #n " %08x -> %08x\n", HW_DMA##n##_CHCR, value); \
        HW_DMA##n##_CHCR = SWAPu32(value); \
 \
        if (SWAPu32(HW_DMA##n##_CHCR) & 0x01000000 && SWAPu32(HW_DMA_PCR) & (8 << (n * 4))) { \
index 32a797d..f468cf8 100644 (file)
@@ -527,7 +527,7 @@ void GPUwriteData(uint32_t data)
     flush_cmd_buffer();
 }
 
-long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
+long GPUdmaChain(uint32_t *rambase, uint32_t start_addr, uint32_t *progress_addr)
 {
   uint32_t addr, *list, ld_addr = 0;
   int len, left, count;
@@ -559,6 +559,10 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
         log_anomaly("GPUdmaChain: discarded %d/%d words\n", left, len);
     }
 
+    if (progress_addr) {
+      *progress_addr = addr;
+      break;
+    }
     #define LD_THRESHOLD (8*1024)
     if (count >= LD_THRESHOLD) {
       if (count == LD_THRESHOLD) {
index 42b2817..717d2fe 100644 (file)
@@ -122,7 +122,7 @@ struct GPUFreeze;
 long GPUinit(void);
 long GPUshutdown(void);
 void GPUwriteDataMem(uint32_t *mem, int count);
-long GPUdmaChain(uint32_t *rambase, uint32_t addr);
+long GPUdmaChain(uint32_t *rambase, uint32_t addr, uint32_t *progress_addr);
 void GPUwriteData(uint32_t data);
 void GPUreadDataMem(uint32_t *mem, int count);
 uint32_t GPUreadData(void);