diff options
| author | John "Lameguy" Wilbert Villamor <lameguy64@gmail.com> | 2022-10-19 17:57:06 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-19 17:57:06 +0800 |
| commit | e08a3d9366f8ca14a76b3dd569dac1fb9f569748 (patch) | |
| tree | 33654513b0b184c27f8035dbc405640fcbeb44ab /libpsn00b/psxgpu | |
| parent | c4a2533d21dfd05cde841ea48c67b05e0e6a853f (diff) | |
| parent | 9b2ffc6078a850b7d354855cca7622090b41f30c (diff) | |
| download | psn00bsdk-e08a3d9366f8ca14a76b3dd569dac1fb9f569748.tar.gz | |
Merge pull request #59 from spicyjpeg/psxmdec
IRQ handler fix, .STR playback example, multiple library builds (v0.21)
Diffstat (limited to 'libpsn00b/psxgpu')
| -rw-r--r-- | libpsn00b/psxgpu/common.c | 187 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/dbugfont.png | bin | 0 -> 1090 bytes | |||
| -rw-r--r-- | libpsn00b/psxgpu/dbugfont.tim | bin | 2112 -> 2112 bytes | |||
| -rw-r--r-- | libpsn00b/psxgpu/env.c | 4 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/font.c | 36 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/image.c | 57 |
6 files changed, 171 insertions, 113 deletions
diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index cef1508..a262472 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -4,7 +4,6 @@ */ #include <stdint.h> -#include <stdio.h> #include <psxetc.h> #include <psxapi.h> #include <psxgpu.h> @@ -16,6 +15,13 @@ static void _default_vsync_halt(void); +/* Private types */ + +typedef struct { + void (*func)(uint32_t, uint32_t, uint32_t); + uint32_t arg1, arg2, arg3; +} QueueEntry; + /* Internal globals */ GPU_VideoMode _gpu_video_mode; @@ -24,12 +30,12 @@ static void (*_vsync_halt_func)(void) = &_default_vsync_halt; static void (*_vsync_callback)(void) = (void *) 0; static void (*_drawsync_callback)(void) = (void *) 0; -static const uint32_t *volatile _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 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; -/* Interrupt handlers */ +/* Private interrupt handlers */ static void _vblank_handler(void) { _vblank_counter++; @@ -43,11 +49,11 @@ static void _gpu_dma_handler(void) { while (!(GPU_GP1 & (1 << 26))) __asm__ volatile(""); - if (_queue_length) { - DrawOTag2(_draw_queue[_queue_head++]); - - _queue_length--; + if (--_queue_length) { + volatile QueueEntry *entry = &_draw_queue[_queue_head++]; _queue_head %= QUEUE_LENGTH; + + entry->func(entry->arg1, entry->arg2, entry->arg3); } else { GPU_GP1 = 0x04000000; // Disable DMA request @@ -69,7 +75,7 @@ void ResetGraph(int mode) { _gpu_video_mode = (GPU_GP1 >> 20) & 1; ExitCriticalSection(); - printf("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); + _sdk_log("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); } if (mode == 3) { @@ -97,18 +103,18 @@ void ResetGraph(int mode) { _last_hblank = 0; } -/* Syncing API */ +/* VSync() API */ // TODO: add support for no$psx's "halt" register static void _default_vsync_halt(void) { int counter = _vblank_counter; - for (int i = VSYNC_TIMEOUT; i; i--) { if (counter != _vblank_counter) return; } - printf("psxgpu: VSync() timeout\n"); + _sdk_log("psxgpu: VSync() timeout\n"); + _sdk_dump_log(); ChangeClearPAD(0); ChangeClearRCnt(3, 0); } @@ -124,6 +130,7 @@ int VSync(int mode) { // Wait for at least one vertical blank event to occur. do { + _sdk_dump_log(); _vsync_halt_func(); // If interlaced mode is enabled, wait until the GPU starts displaying @@ -138,27 +145,6 @@ int VSync(int mode) { return delta; } -int DrawSync(int mode) { - if (mode) - return (DMA_BCR(2) >> 16); - - // Wait for the queue to become empty. - // TODO: add a timeout - while (_queue_length) - __asm__ volatile(""); - - // 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))) - __asm__ volatile(""); - } - - while (!(GPU_GP1 & (1 << 26))) - __asm__ volatile(""); - - return 0; -} - void *VSyncHaltFunction(void (*func)(void)) { void *old_callback = _vsync_halt_func; _vsync_halt_func = func; @@ -176,6 +162,81 @@ void *VSyncCallback(void (*func)(void)) { return old_callback; } +/* 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 +) { + // 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 + // race condition where the DMA transfer could end while interrupts are + // being disabled. Interrupts are disabled through the IRQ_MASK register + // rather than by calling EnterCriticalSection() for performance reasons. + uint16_t mask = IRQ_MASK; + IRQ_MASK = 0; + + if (_queue_length) { + if (_queue_length >= QUEUE_LENGTH) { + IRQ_MASK = mask; + _sdk_log("psxgpu: draw queue overflow, dropping commands\n"); + return -1; + } + + int length = _queue_length; + _queue_length = length + 1; + + volatile QueueEntry *entry = &_draw_queue[_queue_tail++]; + _queue_tail %= QUEUE_LENGTH; + + entry->func = func; + entry->arg1 = arg1; + entry->arg2 = arg2; + entry->arg3 = arg3; + + IRQ_MASK = mask; + return length; + } + + _queue_length = 1; + + IRQ_MASK = mask; + func(arg1, arg2, arg3); + return 0; +} + +int DrawSync(int mode) { + if (mode) + return _queue_length; + + // Wait for the queue to become empty. + for (int i = VSYNC_TIMEOUT; i; i--) { + if (!_queue_length) + break; + } + + 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))) + __asm__ volatile(""); + } + + while (!(GPU_GP1 & (1 << 26))) + __asm__ volatile(""); + } else { + _sdk_log("psxgpu: DrawSync() timeout\n"); + _sdk_dump_log(); + } + + return _queue_length; +} + void *DrawSyncCallback(void (*func)(void)) { EnterCriticalSection(); @@ -208,45 +269,8 @@ void ClearOTag(uint32_t *ot, size_t length) { ot[length - 1] = 0x00ffffff; } -void DrawOTag(const uint32_t *ot) { - // If GPU DMA is currently busy, append the OT to the queue instead of - // drawing it immediately. Note that interrupts must be disabled *prior* to - // checking if DMA is busy; disabling them afterwards would create a race - // condition where the DMA transfer could end while interrupts are being - // disabled. Interrupts are disabled through the IRQ_MASK register rather - // than by calling EnterCriticalSection() for performance reasons. - uint16_t mask = IRQ_MASK; - IRQ_MASK = 0; - - if (DMA_CHCR(2) & (1 << 24)) { - if (_queue_length < QUEUE_LENGTH) { - _draw_queue[_queue_tail++] = ot; - - _queue_length++; - _queue_tail %= QUEUE_LENGTH; - - IRQ_MASK = mask; - return; - } - - IRQ_MASK = mask; - printf("psxgpu: DrawOTag() failed, draw queue full\n"); - return; - } - - IRQ_MASK = mask; - DrawOTag2(ot); -} - -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; +void AddPrim(uint32_t *ot, const void *pri) { + addPrim(ot, pri); } void DrawPrim(const uint32_t *pri) { @@ -267,8 +291,19 @@ void DrawPrim(const uint32_t *pri) { DMA_CHCR(2) = 0x01000201; } -void AddPrim(uint32_t *ot, const void *pri) { - addPrim(ot, pri); +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 */ diff --git a/libpsn00b/psxgpu/dbugfont.png b/libpsn00b/psxgpu/dbugfont.png Binary files differnew file mode 100644 index 0000000..ed84268 --- /dev/null +++ b/libpsn00b/psxgpu/dbugfont.png diff --git a/libpsn00b/psxgpu/dbugfont.tim b/libpsn00b/psxgpu/dbugfont.tim Binary files differindex 4e6cce2..1edd4af 100644 --- a/libpsn00b/psxgpu/dbugfont.tim +++ b/libpsn00b/psxgpu/dbugfont.tim diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index 5642ad4..f513727 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -37,7 +37,7 @@ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { return env; } -void DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { +int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { DR_ENV *prim = &(env->dr_env); // All commands are grouped into a single display list packet for @@ -85,7 +85,7 @@ void DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { //while (!(GPU_GP1 & (1 << 26))) //__asm__ volatile(""); - DrawOTag((const uint32_t *) prim); + return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) prim, 0, 0); } void PutDrawEnv(DRAWENV *env) { diff --git a/libpsn00b/psxgpu/font.c b/libpsn00b/psxgpu/font.c index 2d4105f..b1c3c7a 100644 --- a/libpsn00b/psxgpu/font.c +++ b/libpsn00b/psxgpu/font.c @@ -27,16 +27,16 @@ void FntLoad(int x, int y) { RECT pos; TIM_IMAGE tim; - GetTimInfo( (const uint32_t *) _gpu_debug_font, &tim ); + GetTimInfo((const uint32_t *) _gpu_debug_font, &tim); // Load font image pos = *tim.prect; pos.x = x; pos.y = y; - _font_tpage = getTPage( 0, 0, pos.x, pos.y ); + _font_tpage = getTPage(0, 0, pos.x, pos.y); - LoadImage( &pos, tim.paddr ); + LoadImage(&pos, tim.paddr); DrawSync(0); // Load font clut @@ -44,9 +44,9 @@ void FntLoad(int x, int y) { pos.x = x; pos.y = y+tim.prect->h; - _font_clut = getClut( pos.x, pos.y ); + _font_clut = getClut(pos.x, pos.y); - LoadImage( &pos, tim.caddr ); + LoadImage(&pos, tim.caddr); DrawSync(0); // Clear previously opened text streams @@ -193,10 +193,11 @@ char *FntFlush(int id) { if( i > 0 ) { i--; - setSprt8( sprt ); - setRGB0( sprt, 128, 128, 128 ); - setXY0( sprt, sx, sy ); - setUV0( sprt, (i%16)<<3, (i>>4)<<3 ); + setSprt8(sprt); + setShadeTex(sprt, 1); + setSemiTrans(sprt, 1); + setXY0(sprt, sx, sy); + setUV0(sprt, (i % 16) * 8, (i / 16) * 8); sprt->clut = _font_clut; setaddr(opri, sprt); opri = (char*)sprt; @@ -237,12 +238,13 @@ char *FntSort(uint32_t *ot, char *pri, int x, int y, const char *text) { if( i > 0 ) { i--; - setSprt8( sprt ); - setRGB0( sprt, 128, 128, 128 ); - setXY0( sprt, x, y ); - setUV0( sprt, (i%16)<<3, (i>>4)<<3 ); + setSprt8(sprt); + setShadeTex(sprt, 1); + setSemiTrans(sprt, 1); + setXY0(sprt, x, y); + setUV0(sprt, (i % 16) * 8, (i / 16) * 8); sprt->clut = _font_clut; - addPrim( ot, sprt ); + addPrim(ot, sprt); sprt++; } @@ -256,9 +258,9 @@ char *FntSort(uint32_t *ot, char *pri, int x, int y, const char *text) { tpage = (DR_TPAGE*)pri; tpage->code[0] = _font_tpage; - setlen( tpage, 1 ); - setcode( tpage, 0xe1 ); - addPrim( ot, pri ); + setlen(tpage, 1); + setcode(tpage, 0xe1); + addPrim(ot, pri); pri += sizeof(DR_TPAGE); return pri; diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index da51e7d..968dde5 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -4,42 +4,36 @@ */ #include <stdint.h> -#include <stdio.h> +#include <psxetc.h> #include <psxgpu.h> #include <hwregs_c.h> #define DMA_CHUNK_LENGTH 8 -/* VRAM transfer API */ +/* Private utilities */ -static void _load_store_image( - uint32_t command, - int mode, - const RECT *rect, - uint32_t *data -) { +static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { size_t length = rect->w * rect->h; if (length % 2) - printf("psxgpu: can't transfer an odd number of pixels\n"); + _sdk_log("psxgpu: can't transfer an odd number of pixels\n"); length /= 2; if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - printf("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _sdk_log("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } - DrawSync(0); GPU_GP1 = 0x04000000; // Disable DMA request GPU_GP0 = 0x01000000; // Flush cache - GPU_GP0 = command; + GPU_GP0 = write ? 0xa0000000 : 0xc0000000; //GPU_GP0 = rect->x | (rect->y << 16); GPU_GP0 = *((const uint32_t *) &(rect->x)); //GPU_GP0 = rect->w | (rect->h << 16); GPU_GP0 = *((const uint32_t *) &(rect->w)); // Enable DMA request, route to GP0 (2) or from GPU_READ (3) - GPU_GP1 = 0x04000000 | mode; + GPU_GP1 = 0x04000002 | (write ^ 1); DMA_MADR(2) = (uint32_t) data; if (length < DMA_CHUNK_LENGTH) @@ -47,15 +41,42 @@ static void _load_store_image( else DMA_BCR(2) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); - DMA_CHCR(2) = 0x01000200 | ((mode & 1) ^ 1); + DMA_CHCR(2) = 0x01000200 | write; +} + +/* VRAM transfer API */ + +int LoadImage(const RECT *rect, const uint32_t *data) { + return EnqueueDrawOp( + (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 1 + ); +} + +int StoreImage(const RECT *rect, uint32_t *data) { + return EnqueueDrawOp( + (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 0 + ); } -void LoadImage(const RECT *rect, const uint32_t *data) { - _load_store_image(0xa0000000, 2, rect, (uint32_t *) data); +int MoveImage(const RECT *rect, int x, int y) { + return EnqueueDrawOp((void *) &MoveImage2, (uint32_t) rect, x, y); } -void StoreImage(const RECT *rect, uint32_t *data) { - _load_store_image(0xc0000000, 3, rect, data); +void LoadImage2(const RECT *rect, const uint32_t *data) { + _dma_transfer(rect, (uint32_t *) data, 1); +} + +void StoreImage2(const RECT *rect, uint32_t *data) { + _dma_transfer(rect, data, 0); +} + +void MoveImage2(const RECT *rect, int x, int y) { + GPU_GP0 = 0x80000000; + //GPU_GP0 = rect->x | (rect->y << 16); + GPU_GP0 = *((const uint32_t *) &(rect->x)); + GPU_GP0 = (x & 0xffff) | (y << 16); + //GPU_GP0 = rect->w | (rect->h << 16); + GPU_GP0 = *((const uint32_t *) &(rect->w)); } /* .TIM image parsers */ |
