From: notaz Date: Sun, 13 Nov 2022 21:33:49 +0000 (+0200) Subject: dma: add optional slow linked list walking X-Git-Tag: r24~280 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=commitdiff_plain;h=8c84ba5f4478dd4e7cc48e86f1b023bc6b99ea9c dma: add optional slow linked list walking libretro/pcsx_rearmed#478 libretro/pcsx_rearmed#264 libretro/pcsx_rearmed#132 notaz/pcsx_rearmed#95 --- diff --git a/frontend/libretro.c b/frontend/libretro.c index 42f6151f..3e74b230 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -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; diff --git a/frontend/libretro_core_options.h b/frontend/libretro_core_options.h index 39bc32b6..935c6f97 100644 --- a/frontend/libretro_core_options.h +++ b/frontend/libretro_core_options.h @@ -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", diff --git a/frontend/main.c b/frontend/main.c index dcac1d98..2773f7a1 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -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 = diff --git a/frontend/menu.c b/frontend/menu.c index d1e0413a..3a772d0e 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -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; } diff --git a/libpcsxcore/database.c b/libpcsxcore/database.c index f947b068..ae6fe368 100644 --- a/libpcsxcore/database.c +++ b/libpcsxcore/database.c @@ -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 diff --git a/libpcsxcore/mdec.c b/libpcsxcore/mdec.c index ca424585..167a1cff 100644 --- a/libpcsxcore/mdec.c +++ b/libpcsxcore/mdec.c @@ -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 */ diff --git a/libpcsxcore/plugins.h b/libpcsxcore/plugins.h index 178f83a8..c997c611 100644 --- a/libpcsxcore/plugins.h +++ b/libpcsxcore/plugins.h @@ -58,7 +58,7 @@ typedef void (CALLBACK* GPUwriteDataMem)(uint32_t *, int); typedef uint32_t (CALLBACK* GPUreadStatus)(void); typedef uint32_t (CALLBACK* GPUreadData)(void); typedef void (CALLBACK* GPUreadDataMem)(uint32_t *, int); -typedef long (CALLBACK* GPUdmaChain)(uint32_t *,uint32_t); +typedef long (CALLBACK* GPUdmaChain)(uint32_t *,uint32_t, uint32_t *); typedef void (CALLBACK* GPUupdateLace)(void); typedef long (CALLBACK* GPUconfigure)(void); typedef long (CALLBACK* GPUtest)(void); diff --git a/libpcsxcore/psxcommon.h b/libpcsxcore/psxcommon.h index e0876cf5..b621326c 100644 --- a/libpcsxcore/psxcommon.h +++ b/libpcsxcore/psxcommon.h @@ -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]; diff --git a/libpcsxcore/psxdma.c b/libpcsxcore/psxdma.c index d7c4caec..30aa9bdb 100644 --- a/libpcsxcore/psxdma.c +++ b/libpcsxcore/psxdma.c @@ -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); diff --git a/libpcsxcore/psxhw.c b/libpcsxcore/psxhw.c index 483f4962..27ddfeab 100644 --- a/libpcsxcore/psxhw.c +++ b/libpcsxcore/psxhw.c @@ -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))) { \ diff --git a/plugins/gpulib/gpu.c b/plugins/gpulib/gpu.c index 32a797d5..f468cf8b 100644 --- a/plugins/gpulib/gpu.c +++ b/plugins/gpulib/gpu.c @@ -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) { diff --git a/plugins/gpulib/gpu.h b/plugins/gpulib/gpu.h index 42b28176..717d2fe2 100644 --- a/plugins/gpulib/gpu.h +++ b/plugins/gpulib/gpu.h @@ -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);