diff options
Diffstat (limited to 'libpsn00b/psxgpu/common.c')
| -rw-r--r-- | libpsn00b/psxgpu/common.c | 199 |
1 files changed, 75 insertions, 124 deletions
diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index e41bd31..7e0758b 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -1,6 +1,6 @@ /* * PSn00bSDK GPU library (common functions) - * (C) 2022 spicyjpeg - MPL licensed + * (C) 2022-2023 spicyjpeg - MPL licensed */ #include <stdint.h> @@ -10,9 +10,8 @@ #include <psxgpu.h> #include <hwregs_c.h> -#define QUEUE_LENGTH 16 -#define DMA_CHUNK_LENGTH 8 -#define VSYNC_TIMEOUT 0x100000 +#define QUEUE_LENGTH 16 +#define VSYNC_TIMEOUT 0x100000 static void _default_vsync_halt(void); @@ -21,7 +20,7 @@ static void _default_vsync_halt(void); typedef struct { void (*func)(uint32_t, uint32_t, uint32_t); uint32_t arg1, arg2, arg3; -} QueueEntry; +} DrawOp; /* Internal globals */ @@ -31,10 +30,10 @@ static void (*_vsync_halt_func)(void) = &_default_vsync_halt; static void (*_vsync_callback)(void) = (void *) 0; static void (*_drawsync_callback)(void) = (void *) 0; -static volatile QueueEntry _draw_queue[QUEUE_LENGTH]; -static volatile uint8_t _queue_head, _queue_tail, _queue_length; -static volatile uint32_t _vblank_counter; -static volatile uint16_t _last_hblank; +static volatile DrawOp _draw_queue[QUEUE_LENGTH]; +static volatile uint8_t _queue_head, _queue_tail, _queue_length, _drawop_type; +static volatile uint32_t _vblank_counter, _last_vblank; +static volatile uint16_t _last_hblank; /* Private interrupt handlers */ @@ -45,16 +44,16 @@ static void _vblank_handler(void) { _vsync_callback(); } -static void _gpu_dma_handler(void) { - //while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24))) - while (!(GPU_GP1 & (1 << 26))) - __asm__ volatile(""); +static void _process_drawop(void) { + int length = _queue_length; + if (!length) + return; - if (--_queue_length) { + if (--length) { int head = _queue_head; _queue_head = (head + 1) % QUEUE_LENGTH; - volatile QueueEntry *entry = &_draw_queue[head]; + volatile DrawOp *entry = &_draw_queue[head]; entry->func(entry->arg1, entry->arg2, entry->arg3); } else { GPU_GP1 = 0x04000000; // Disable DMA request @@ -62,16 +61,36 @@ static void _gpu_dma_handler(void) { if (_drawsync_callback) _drawsync_callback(); } + + _queue_length = length; +} + +static void _gpu_irq_handler(void) { + GPU_GP1 = 0x02000000; // Reset IRQ + + if (_drawop_type == DRAWOP_TYPE_GPU_IRQ) + _process_drawop(); +} + +static void _gpu_dma_handler(void) { + if (_drawop_type == DRAWOP_TYPE_DMA) + _process_drawop(); } /* GPU reset and system initialization */ void ResetGraph(int mode) { + _queue_head = 0; + _queue_tail = 0; + _queue_length = 0; + _drawop_type = 0; + // Perform some basic system initialization when ResetGraph() is called for // the first time. if (!ResetCallback()) { EnterCriticalSection(); InterruptCallback(IRQ_VBLANK, &_vblank_handler); + InterruptCallback(IRQ_GPU, &_gpu_irq_handler); DMACallback(DMA_GPU, &_gpu_dma_handler); _gpu_video_mode = (GPU_GP1 >> 20) & 1; @@ -80,28 +99,27 @@ void ResetGraph(int mode) { _sdk_log("setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); } - if (mode == 3) { + if (mode) { GPU_GP1 = 0x01000000; // Reset command buffer - return; - } - - DMA_DPCR |= 0x0b000b00; // Enable DMA2 and DMA6 - DMA_CHCR(2) = 0x00000201; // Stop DMA2 - DMA_CHCR(6) = 0x00000200; // Stop DMA6 + GPU_GP1 = 0x02000000; // Reset IRQ + GPU_GP1 = 0x04000000; // Disable DMA request - if (mode == 1) { - GPU_GP1 = 0x01000000; // Reset command buffer - return; + if (mode == 1) + return; + } else { + GPU_GP1 = 0x00000000; // Reset GPU } - GPU_GP1 = 0x00000000; // Reset GPU + SetDMAPriority(DMA_GPU, 3); + SetDMAPriority(DMA_OTC, 3); + DMA_CHCR(DMA_GPU) = 0x00000201; // Stop DMA + DMA_CHCR(DMA_OTC) = 0x00000200; // Stop DMA + TIMER_CTRL(0) = 0x0500; TIMER_CTRL(1) = 0x0500; - _queue_head = 0; - _queue_tail = 0; - _queue_length = 0; _vblank_counter = 0; + _last_vblank = 0; _last_hblank = 0; } @@ -127,10 +145,13 @@ int VSync(int mode) { if (mode < 0) return _vblank_counter; - uint32_t status = GPU_GP1; + // Wait for the specified number of vertical blank events since the last + // call to VSync() to occur (if mode >= 2) or just for a single vertical + // blank (if mode = 0). + uint32_t target = mode ? (_last_vblank + mode) : (_vblank_counter + 1); - // Wait for at least one vertical blank event to occur. - do { + while (_vblank_counter < target) { + uint32_t status = GPU_GP1; _vsync_halt_func(); // If interlaced mode is enabled, wait until the GPU starts displaying @@ -139,9 +160,11 @@ int VSync(int mode) { while (!((GPU_GP1 ^ status) & (1 << 31))) __asm__ volatile(""); } - } while ((--mode) > 0); + } + _last_vblank = _vblank_counter; _last_hblank = TIMER_VALUE(1); + return delta; } @@ -167,14 +190,13 @@ void *VSyncCallback(void (*func)(void)) { /* Command queue API */ -// This function is normally only used internally, but it is exposed for -// advanced use cases. -int EnqueueDrawOp( - void (*func)(uint32_t, uint32_t, uint32_t), - uint32_t arg1, - uint32_t arg2, - uint32_t arg3 -) { +void SetDrawOpType(GPU_DrawOpType type) { + _drawop_type = type; +} + +int EnqueueDrawOp(void (*func)(), uint32_t arg1, uint32_t arg2, uint32_t arg3) { + _sdk_validate_args(func, -1); + // If GPU DMA is currently busy, append the command to the queue instead of // executing it immediately. Note that interrupts must be disabled *prior* // to checking if DMA is busy; disabling them afterwards would create a @@ -202,7 +224,7 @@ int EnqueueDrawOp( _queue_tail = (tail + 1) % QUEUE_LENGTH; _queue_length = length + 1; - volatile QueueEntry *entry = &_draw_queue[tail]; + volatile DrawOp *entry = &_draw_queue[tail]; entry->func = func; entry->arg1 = arg1; entry->arg2 = arg2; @@ -225,7 +247,7 @@ int DrawSync(int mode) { if (!_queue_length) { // Wait for any DMA transfer to finish if DMA is enabled. if (GPU_GP1 & (3 << 29)) { - while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(2) & (1 << 24))) + while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(DMA_GPU) & (1 << 24))) __asm__ volatile(""); } @@ -248,88 +270,17 @@ void *DrawSyncCallback(void (*func)(void)) { return old_callback; } -/* OT and primitive drawing API */ - -void ClearOTagR(uint32_t *ot, size_t length) { - DMA_MADR(6) = (uint32_t) &ot[length - 1]; - DMA_BCR(6) = length & 0xffff; - DMA_CHCR(6) = 0x11000002; +/* Queue pause/resume API */ - while (DMA_CHCR(6) & (1 << 24)) - __asm__ volatile(""); -} +int IsIdleGPU(int timeout) { + if (timeout <= 0) + timeout = 1; -void ClearOTag(uint32_t *ot, size_t length) { - // DMA6 only supports writing to RAM in reverse order (last to first), so - // the OT has to be cleared in software here. This function is thus much - // slower than ClearOTagR(). - // https://problemkaputt.de/psx-spx.htm#dmachannels - for (int i = 0; i < (length - 1); i++) - ot[i] = (uint32_t) &ot[i + 1] & 0x00ffffff; - - ot[length - 1] = 0x00ffffff; -} - -void AddPrim(uint32_t *ot, const void *pri) { - addPrim(ot, pri); -} - -void DrawPrim(const uint32_t *pri) { - size_t length = getlen(pri); - - DrawSync(0); - GPU_GP1 = 0x04000002; - - // NOTE: if length >= DMA_CHUNK_LENGTH then it also has to be a multiple of - // DMA_CHUNK_LENGTH, otherwise the DMA channel will get stuck waiting for - // more data indefinitely. - DMA_MADR(2) = (uint32_t) &pri[1]; - if (length < DMA_CHUNK_LENGTH) - DMA_BCR(2) = 0x00010000 | length; - else - DMA_BCR(2) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); - - DMA_CHCR(2) = 0x01000201; -} - -int DrawOTag(const uint32_t *ot) { - return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) ot, 0, 0); -} - -void DrawOTag2(const uint32_t *ot) { - GPU_GP1 = 0x04000002; - - while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24))) - __asm__ volatile(""); - - DMA_MADR(2) = (uint32_t) ot; - DMA_BCR(2) = 0; - DMA_CHCR(2) = 0x01000401; -} - -/* Misc. functions */ - -GPU_VideoMode GetVideoMode(void) { - return _gpu_video_mode; -} - -void SetVideoMode(GPU_VideoMode mode) { - uint32_t _mode, stat = GPU_GP1; - - _gpu_video_mode = mode & 1; - - _mode = (mode & 1) << 3; - _mode |= (stat >> 17) & 0x37; // GPUSTAT 17-22 -> cmd bits 0-5 - _mode |= (stat >> 10) & 0x40; // GPUSTAT bit 16 -> cmd bit 6 - _mode |= (stat >> 7) & 0x80; // GPUSTAT bit 14 -> cmd bit 7 - - GPU_GP1 = 0x08000000 | mode; -} - -int GetODE(void) { - return (GPU_GP1 >> 31); -} + for (; timeout; timeout--) { + if (GPU_GP1 & (1 << 26)) + return 0; + } -void SetDispMask(int mask) { - GPU_GP1 = 0x03000000 | (mask ? 0 : 1); + //_sdk_log("IsIdleGPU() timeout\n"); + return -1; } |
