From f8896d181bd26ef6fd18af17f01c77b73ae17a68 Mon Sep 17 00:00:00 2001 From: notaz Date: Tue, 17 Oct 2023 00:16:46 +0300 Subject: [PATCH] rework gpu busy timing previous implementation caused complications with dynarecs --- libpcsxcore/gpu.c | 7 +++---- libpcsxcore/misc.c | 5 +++-- libpcsxcore/psxbios.c | 1 - libpcsxcore/psxcounters.c | 2 ++ libpcsxcore/psxdma.c | 10 ++++------ libpcsxcore/psxhw.c | 7 ++++--- libpcsxcore/r3000a.h | 3 ++- 7 files changed, 18 insertions(+), 17 deletions(-) diff --git a/libpcsxcore/gpu.c b/libpcsxcore/gpu.c index 2416405e..425537d4 100644 --- a/libpcsxcore/gpu.c +++ b/libpcsxcore/gpu.c @@ -19,14 +19,13 @@ void gpu_state_change(int what) switch (state) { case PGS_VRAM_TRANSFER_START: - HW_GPU_STATUS &= ~SWAP32(PSXGPU_nBUSY); + psxRegs.gpuIdleAfter = psxRegs.cycle + PSXCLK / 50; break; case PGS_VRAM_TRANSFER_END: - HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY); + psxRegs.gpuIdleAfter = psxRegs.cycle; break; case PGS_PRIMITIVE_START: - HW_GPU_STATUS &= ~SWAP32(PSXGPU_nBUSY); - set_event(PSXINT_GPUDMA, 200); // see gpuInterrupt + psxRegs.gpuIdleAfter = psxRegs.cycle + 200; break; } } diff --git a/libpcsxcore/misc.c b/libpcsxcore/misc.c index f332f437..9486d23b 100644 --- a/libpcsxcore/misc.c +++ b/libpcsxcore/misc.c @@ -738,6 +738,8 @@ int LoadState(const char *file) { SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle)); psxRegs.gteBusyCycle = psxRegs.cycle; psxRegs.biosBranchCheck = ~0; + psxRegs.gpuIdleAfter = psxRegs.cycle - 1; + HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY); psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL); @@ -750,8 +752,7 @@ int LoadState(const char *file) { SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t)); GPU_freeze(0, gpufP); free(gpufP); - if (HW_GPU_STATUS == 0) - HW_GPU_STATUS = SWAP32(GPU_readStatus()); + gpuSyncPluginSR(); // spu SaveFuncs.read(f, &Size, 4); diff --git a/libpcsxcore/psxbios.c b/libpcsxcore/psxbios.c index af3c55fb..3671af5a 100644 --- a/libpcsxcore/psxbios.c +++ b/libpcsxcore/psxbios.c @@ -3322,7 +3322,6 @@ void psxBiosSetupBootState(void) GPU_writeStatus(gpu_ctl_def[i]); for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++) GPU_writeData(gpu_data_def[i]); - HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY); // spu for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++) diff --git a/libpcsxcore/psxcounters.c b/libpcsxcore/psxcounters.c index d0d45ec5..f7491b3d 100644 --- a/libpcsxcore/psxcounters.c +++ b/libpcsxcore/psxcounters.c @@ -397,6 +397,8 @@ void psxRcntUpdate() } HW_GPU_STATUS = SWAP32(status); GPU_vBlank(0, field); + if ((s32)(psxRegs.gpuIdleAfter - psxRegs.cycle) < 0) + psxRegs.gpuIdleAfter = psxRegs.cycle - 1; // prevent overflow if ((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) || (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2)) diff --git a/libpcsxcore/psxdma.c b/libpcsxcore/psxdma.c index 24570968..4db99ab1 100644 --- a/libpcsxcore/psxdma.c +++ b/libpcsxcore/psxdma.c @@ -157,7 +157,7 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU HW_DMA2_MADR = SWAPu32(madr + words_copy * 4); // careful: gpu_state_change() also messes with this - HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY); + psxRegs.gpuIdleAfter = psxRegs.cycle + words / 4 + 16; // already 32-bit word size ((size * 4) / 4) set_event(PSXINT_GPUDMA, words / 4); return; @@ -180,7 +180,7 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU HW_DMA2_MADR = SWAPu32(madr); // careful: gpu_state_change() also messes with this - HW_GPU_STATUS &= SWAP32(~PSXGPU_nBUSY); + psxRegs.gpuIdleAfter = psxRegs.cycle + words / 4 + 16; // already 32-bit word size ((size * 4) / 4) set_event(PSXINT_GPUDMA, words / 4); return; @@ -199,13 +199,13 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU if ((int)size <= 0) size = gpuDmaChainSize(madr); - 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) // Rebel Assault 2 = parse linked list in pieces (todo) + psxRegs.gpuIdleAfter = psxRegs.cycle + size + 16; set_event(PSXINT_GPUDMA, size); return; @@ -218,14 +218,13 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU DMA_INTERRUPT(2); } -// note: this is also (ab)used for non-dma prim command -// to delay gpu returning to idle state, see gpu_state_change() 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); + psxRegs.gpuIdleAfter = psxRegs.cycle + size + 64; set_event(PSXINT_GPUDMA, size); return; } @@ -234,7 +233,6 @@ void gpuInterrupt() { HW_DMA2_CHCR &= SWAP32(~0x01000000); DMA_INTERRUPT(2); } - HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY); // GPU no longer busy } void psxDma6(u32 madr, u32 bcr, u32 chcr) { diff --git a/libpcsxcore/psxhw.c b/libpcsxcore/psxhw.c index 8be775bc..4811f99b 100644 --- a/libpcsxcore/psxhw.c +++ b/libpcsxcore/psxhw.c @@ -41,7 +41,7 @@ void psxHwReset() { mdecInit(); // initialize mdec decoder cdrReset(); psxRcntInit(); - HW_GPU_STATUS = SWAP32(0x14802000); + HW_GPU_STATUS = SWAP32(0x10802000); psxHwReadGpuSRptr = Config.hacks.gpu_busy_hack ? psxHwReadGpuSRbusyHack : psxHwReadGpuSR; } @@ -91,16 +91,17 @@ void psxHwWriteGpuSR(u32 value) u32 psxHwReadGpuSR(void) { - u32 v; + u32 v, c = psxRegs.cycle; // meh2, syncing for img bit, might want to avoid it.. gpuSyncPluginSR(); v = SWAP32(HW_GPU_STATUS); + v |= ((s32)(psxRegs.gpuIdleAfter - c) >> 31) & PSXGPU_nBUSY; // XXX: because of large timeslices can't use hSyncCount, using rough // approximization instead. Perhaps better use hcounter code here or something. if (hSyncCount < 240 && (v & PSXGPU_ILACE_BITS) != PSXGPU_ILACE_BITS) - v |= PSXGPU_LCF & (psxRegs.cycle << 20); + v |= PSXGPU_LCF & (c << 20); return v; } diff --git a/libpcsxcore/r3000a.h b/libpcsxcore/r3000a.h index 4d2cfbd2..03aeee19 100644 --- a/libpcsxcore/r3000a.h +++ b/libpcsxcore/r3000a.h @@ -204,7 +204,8 @@ typedef struct { u32 dloadVal[2]; u32 biosBranchCheck; u32 cpuInRecursion; - u32 reserved[2]; + u32 gpuIdleAfter; + u32 reserved[1]; // warning: changing anything in psxRegisters requires update of all // asm in libpcsxcore/new_dynarec/ } psxRegisters; -- 2.39.2