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;
},
"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",
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 =
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),
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)";
#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[] =
{
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
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;
}
"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) }
hack_db[] =
{
HACK_ENTRY(cdr_read_timing, cdr_read_hack_db),
+ HACK_ENTRY(gpu_slow_list_walking, gpu_slow_llist_db),
};
static const struct
int size;
if (chcr != 0x01000201) {
+ log_unhandled("mdec0: invalid dma %08x\n", chcr);
return;
}
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 */
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
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];
}
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;
#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;
}
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);
}
#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))) { \
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;
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) {
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);