diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2022-12-18 16:30:02 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-18 16:30:02 +0100 |
| commit | b12b716a9e54c4f1892795a136d6ffeb088ff001 (patch) | |
| tree | 5888e4a77b207f24ccd9ad148d1c74e9c33400e9 /libpsn00b/psxgpu | |
| parent | 77306e187ef1a7ad5d3508ae9acb38edc5b68255 (diff) | |
| parent | a3359c0e7d85bf4752cda3b00892ecd5ef691077 (diff) | |
| download | psn00bsdk-b12b716a9e54c4f1892795a136d6ffeb088ff001.tar.gz | |
Merge pull request #68 from spicyjpeg/bugfix
Bugfixes, psxcd rewrite, psxgpu and CMake tweaks (v0.22)
Diffstat (limited to 'libpsn00b/psxgpu')
| -rw-r--r-- | libpsn00b/psxgpu/common.c | 31 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/env.c | 99 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/image.c | 44 |
3 files changed, 110 insertions, 64 deletions
diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index 9f45f10..e41bd31 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -38,9 +38,6 @@ static volatile uint16_t _last_hblank; /* Private interrupt handlers */ -#define _ENTER_CRITICAL() uint16_t mask = IRQ_MASK; IRQ_MASK = 0; -#define _EXIT_CRITICAL() IRQ_MASK = mask; - static void _vblank_handler(void) { _vblank_counter++; @@ -74,8 +71,8 @@ void ResetGraph(int mode) { // the first time. if (!ResetCallback()) { EnterCriticalSection(); - InterruptCallback(0, &_vblank_handler); - DMACallback(2, &_gpu_dma_handler); + InterruptCallback(IRQ_VBLANK, &_vblank_handler); + DMACallback(DMA_GPU, &_gpu_dma_handler); _gpu_video_mode = (GPU_GP1 >> 20) & 1; ExitCriticalSection(); @@ -149,22 +146,22 @@ int VSync(int mode) { } void *VSyncHaltFunction(void (*func)(void)) { - //_ENTER_CRITICAL(); + //FastEnterCriticalSection(); void *old_callback = _vsync_halt_func; _vsync_halt_func = func; - //_EXIT_CRITICAL(); + //FastExitCriticalSection(); return old_callback; } void *VSyncCallback(void (*func)(void)) { - _ENTER_CRITICAL(); + FastEnterCriticalSection(); void *old_callback = _vsync_callback; _vsync_callback = func; - _EXIT_CRITICAL(); + FastExitCriticalSection(); return old_callback; } @@ -184,18 +181,18 @@ int EnqueueDrawOp( // race condition where the DMA transfer could end while interrupts are // being disabled. Interrupts are disabled through the IRQ_MASK register // rather than via syscalls for performance reasons. - _ENTER_CRITICAL(); + FastEnterCriticalSection(); int length = _queue_length; if (!length) { _queue_length = 1; - _EXIT_CRITICAL(); + FastExitCriticalSection(); func(arg1, arg2, arg3); return 0; } if (length >= QUEUE_LENGTH) { - _EXIT_CRITICAL(); + FastExitCriticalSection(); _sdk_log("draw queue overflow, dropping commands\n"); return -1; @@ -211,7 +208,7 @@ int EnqueueDrawOp( entry->arg2 = arg2; entry->arg3 = arg3; - _EXIT_CRITICAL(); + FastExitCriticalSection(); return length; } @@ -242,12 +239,12 @@ int DrawSync(int mode) { } void *DrawSyncCallback(void (*func)(void)) { - _ENTER_CRITICAL(); + FastEnterCriticalSection(); void *old_callback = _drawsync_callback; _drawsync_callback = func; - _EXIT_CRITICAL(); + FastExitCriticalSection(); return old_callback; } @@ -258,8 +255,8 @@ void ClearOTagR(uint32_t *ot, size_t length) { DMA_BCR(6) = length & 0xffff; DMA_CHCR(6) = 0x11000002; - //while (DMA_CHCR(6) & (1 << 24)) - //__asm__ volatile(""); + while (DMA_CHCR(6) & (1 << 24)) + __asm__ volatile(""); } void ClearOTag(uint32_t *ot, size_t length) { diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index f513727..8784947 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -11,6 +11,28 @@ extern GPU_VideoMode _gpu_video_mode; +/* Private utilities */ + +// Converts a texture window size value (a power of two in 8-128 range) into a +// bit mask by setting the leading zeroes of the value: +// 0 = 0b00000000 -> 0b00000 +// 8 = 0b00001000 -> 0b11111 +// 16 = 0b00010000 -> 0b11110 +// 32 = 0b00100000 -> 0b11100 +// 64 = 0b01000000 -> 0b11000 +// 128 = 0b10000000 -> 0b10000 +// The GPU uses the mask to process texture coordinates as follows: +// x &= ~(mask << 3) +// x |= (offset << 3) & (mask << 3) +static inline uint32_t _get_window_mask(int size) { + uint32_t mask = size >> 3; + + mask |= mask << 1; + mask |= mask << 2; + mask |= mask << 4; + return mask & 0x1f; +} + /* Drawing API */ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { @@ -24,8 +46,8 @@ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { env->tw.x = 0; env->tw.y = 0; - env->tw.w = 0; - env->tw.h = 0; + env->tw.w = 256; + env->tw.h = 256; env->tpage = 0x0a; env->dtd = 1; @@ -41,50 +63,53 @@ 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 - // performance reasons (keep in mind that the GPU doesn't care about this - // as the display list is parsed by the DMA unit in the CPU and only the - // payload is sent to the GPU). + // performance reasons (the GPU does not care about the grouping as the + // display list is parsed by the DMA unit in the CPU). setaddr(prim, ot); - setlen(prim, 4); + setlen(prim, 5); + + // Texture page (reset active page and set dither/mask bits) + prim->code[0] = 0xe1000000 | env->tpage; + prim->code[0] |= (env->dtd & 1) << 9; + prim->code[0] |= (env->dfe & 1) << 10; + + // Texture window + prim->code[1] = 0xe2000000; + prim->code[1] |= _get_window_mask(env->tw.w); + prim->code[1] |= _get_window_mask(env->tw.h) << 5; + prim->code[1] |= (env->tw.x & 0xf8) << 7; // ((tw.x / 8) & 0x1f) << 10 + prim->code[1] |= (env->tw.y & 0xf8) << 12; // ((tw.y / 8) & 0x1f) << 15 // Set drawing area top left - prim->code[0] = 0xe3000000; - prim->code[0] |= env->clip.x & 0x3ff; - prim->code[0] |= (env->clip.y & 0x3ff) << 10; + prim->code[2] = 0xe3000000; + prim->code[2] |= env->clip.x & 0x3ff; + prim->code[2] |= (env->clip.y & 0x3ff) << 10; // Set drawing area bottom right - prim->code[1] = 0xe4000000; - prim->code[1] |= (env->clip.x + (env->clip.w - 1)) & 0x3ff; - prim->code[1] |= ((env->clip.y + (env->clip.h - 1)) & 0x3ff) << 10; + prim->code[3] = 0xe4000000; + prim->code[3] |= (env->clip.x + (env->clip.w - 1)) & 0x3ff; + prim->code[3] |= ((env->clip.y + (env->clip.h - 1)) & 0x3ff) << 10; // Set drawing offset - prim->code[2] = 0xe5000000; - prim->code[2] |= (env->clip.x + env->ofs[0]) & 0x7ff; - prim->code[2] |= ((env->clip.y + env->ofs[1]) & 0x7ff) << 11; - - // Texture page (reset active page and set dither/mask bits) - prim->code[3] = 0xe1000000; - prim->code[3] |= (env->dtd & 1) << 9; - prim->code[3] |= (env->dfe & 1) << 10; + prim->code[4] = 0xe5000000; + prim->code[4] |= (env->clip.x + env->ofs[0]) & 0x7ff; + prim->code[4] |= ((env->clip.y + env->ofs[1]) & 0x7ff) << 11; if (env->isbg) { - setlen(prim, 7); + setlen(prim, 8); // Rectangle fill // FIXME: reportedly this command doesn't accept height values >511... - prim->code[4] = 0x02000000; - //prim->code[4] |= env->r0 | (env->g0 << 8) | (env->b0 << 16); - prim->code[4] |= *((const uint32_t *) &(env->isbg)) >> 8; - //prim->code[5] = env->clip.x; - //prim->code[5] |= env->clip.y << 16; - prim->code[5] = *((const uint32_t *) &(env->clip.x)); - prim->code[6] = env->clip.w; - prim->code[6] |= _min(env->clip.h, 0x1ff) << 16; + prim->code[5] = 0x02000000; + //prim->code[5] |= env->r0 | (env->g0 << 8) | (env->b0 << 16); + //prim->code[6] = env->clip.x; + //prim->code[6] |= env->clip.y << 16; + prim->code[5] |= *((const uint32_t *) &(env->isbg)) >> 8; + prim->code[6] = *((const uint32_t *) &(env->clip.x)); + prim->code[7] = env->clip.w; + prim->code[7] |= _min(env->clip.h, 0x1ff) << 16; } - //while (!(GPU_GP1 & (1 << 26))) - //__asm__ volatile(""); - return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) prim, 0, 0); } @@ -96,12 +121,10 @@ void PutDrawEnv(DRAWENV *env) { // useful if the DRAWENV structure is never modified (which is the case most of // the time). void PutDrawEnvFast(DRAWENV *env) { - if (!(env->dr_env.tag)) { + if (!(env->dr_env.tag)) DrawOTagEnv((const uint32_t *) 0x00ffffff, env); - return; - } - - DrawOTag((const uint32_t *) &(env->dr_env)); + else + DrawOTag((const uint32_t *) &(env->dr_env)); } /* Display API */ @@ -132,7 +155,7 @@ void PutDispEnv(const DISPENV *env) { mode |= (env->isinter & 1) << 5; mode |= (env->reverse & 1) << 7; - if (env->disp.h >= 256) + if (env->disp.h > 256) mode |= 1 << 2; // Calculate the horizontal display range values. The original code was diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index bbdb7c8..fc018a4 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -1,6 +1,10 @@ /* * PSn00bSDK GPU library (image and VRAM transfer functions) * (C) 2022 spicyjpeg - MPL licensed + * + * TODO: MoveImage() is currently commented out as it won't trigger a DMA IRQ, + * making it unusable as a draw queue command. A way around this (perhaps using + * the GPU IRQ?) shall be found. */ #include <stdint.h> @@ -8,7 +12,17 @@ #include <psxgpu.h> #include <hwregs_c.h> -#define DMA_CHUNK_LENGTH 8 +#define QUEUE_LENGTH 16 +#define DMA_CHUNK_LENGTH 8 + +/* Internal globals */ + +// LoadImage() and StoreImage() run asynchronously but may be called with a +// pointer to a RECT struct in the stack, which might no longer be valid by the +// time the transfer is actually started. This buffer is used to store a copy +// of all RECTs passed to LoadImage()/StoreImage() as a workaround. +static RECT _saved_rects[QUEUE_LENGTH]; +static int _next_saved_rect = 0; /* Private utilities */ @@ -47,21 +61,33 @@ static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { /* VRAM transfer API */ int LoadImage(const RECT *rect, const uint32_t *data) { + int index = _next_saved_rect; + + _saved_rects[index] = *rect; + _next_saved_rect = (index + 1) % QUEUE_LENGTH; + return EnqueueDrawOp( - (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 1 + (void *) &_dma_transfer, + (uint32_t) &_saved_rects[index], + (uint32_t) data, + 1 ); } int StoreImage(const RECT *rect, uint32_t *data) { + int index = _next_saved_rect; + + _saved_rects[index] = *rect; + _next_saved_rect = (index + 1) % QUEUE_LENGTH; + return EnqueueDrawOp( - (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 0 + (void *) &_dma_transfer, + (uint32_t) &_saved_rects[index], + (uint32_t) data, + 0 ); } -int MoveImage(const RECT *rect, int x, int y) { - return EnqueueDrawOp((void *) &MoveImage2, (uint32_t) rect, x, y); -} - void LoadImage2(const RECT *rect, const uint32_t *data) { _dma_transfer(rect, (uint32_t *) data, 1); } @@ -70,14 +96,14 @@ void StoreImage2(const RECT *rect, uint32_t *data) { _dma_transfer(rect, data, 0); } -void MoveImage2(const RECT *rect, int x, int y) { +/*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 */ |
