diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-01-13 18:04:49 +0100 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-01-13 18:04:49 +0100 |
| commit | 3095b4571dabc8d6cee90673d679f3e77b21b164 (patch) | |
| tree | 125ec0f4792fb9b9a213cbd6247e8e9518d14033 | |
| parent | 50faf92a8cb099420aa956dcac3a8105067e117c (diff) | |
Fix VSync() rate limiter, add missing tagless packets
| -rw-r--r-- | libpsn00b/include/psxetc.h | 9 | ||||
| -rw-r--r-- | libpsn00b/include/psxgpu.h | 90 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/common.c | 58 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/env.c | 60 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/image.c | 13 |
5 files changed, 128 insertions, 102 deletions
diff --git a/libpsn00b/include/psxetc.h b/libpsn00b/include/psxetc.h index ebf7966..e45abf4 100644 --- a/libpsn00b/include/psxetc.h +++ b/libpsn00b/include/psxetc.h @@ -1,6 +1,6 @@ /* * PSn00bSDK interrupt management library - * (C) 2019-2022 Lameguy64, spicyjpeg - MPL licensed + * (C) 2019-2023 Lameguy64, spicyjpeg - MPL licensed */ /** @@ -68,7 +68,7 @@ extern "C" { * | ID | Channel | Used by | * | --: | :--------------- | :-------------------------------------- | * | 0 | IRQ_VBLANK | psxgpu (use VSyncCallback() instead) | - * | 1 | IRQ_GPU | | + * | 1 | IRQ_GPU | psxgpu (use DrawSyncCallback() instead) | * | 2 | IRQ_CD | psxcd (use CdReadyCallback() instead) | * | 3 | IRQ_DMA | psxetc (use DMACallback() instead) | * | 4 | IRQ_TIMER0 | | @@ -227,6 +227,11 @@ void RestartCallback(void); * Note that interrupts are (obviously) disabled until RestartCallback() is * called. * + * WARNING: any ongoing background processing or DMA transfer must be stopped + * before calling StopCallback(), otherwise crashes may occur. This includes + * flushing psxgpu's command queue using DrawSync(), stopping CD-ROM reading + * and calling StopPAD() to disable the BIOS controller driver if used. + * * @see RestartCallback() */ void StopCallback(void); diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h index 4dbcc6c..2329908 100644 --- a/libpsn00b/include/psxgpu.h +++ b/libpsn00b/include/psxgpu.h @@ -1,6 +1,6 @@ /* * PSn00bSDK GPU library - * (C) 2019-2022 Lameguy64, spicyjpeg - MPL licensed + * (C) 2019-2023 Lameguy64, spicyjpeg - MPL licensed */ #ifndef __PSXGPU_H @@ -117,9 +117,13 @@ typedef enum _GPU_VideoMode { #define setSemiTrans(p, abe) \ ((abe) ? (getcode(p) |= 2) : (getcode(p) &= ~2)) +#define setSemiTrans_T(p, abe) \ + ((abe) ? (getcode_T(p) |= 2) : (getcode_T(p) &= ~2)) #define setShadeTex(p, tge) \ ((tge) ? (getcode(p) |= 1) : (getcode(p) &= ~1)) +#define setShadeTex_T(p, tge) \ + ((tge) ? (getcode_T(p) |= 1) : (getcode_T(p) &= ~1)) #define getTPage(tp, abr, x, y) ( \ (((x) / 64) & 15) | \ @@ -187,27 +191,26 @@ typedef enum _GPU_VideoMode { #define setBlit_T(p) setcode_T(p, 0x80), \ (p)->pad[0] = 0, (p)->pad[1] = 0, (p)->pad[2] = 0, (p)->pad[3] = 0 -#define setDrawTPage(p, dfe, dtd, tpage) \ - setlen(p, 1), \ +#define setDrawTPage_T(p, dfe, dtd, tpage) \ (p)->code[0] = (0xe1000000 | \ (tpage) | \ ((dtd) << 9) | \ ((dfe) << 10) \ ) +#define setDrawTPage(p, dfe, dtd, tpage) \ + setlen(p, 1), setDrawTPage_T(p, dfe, dtd, tpage) -#define setDrawOffset(p, _x, _y) \ - setlen(p, 1), \ - (p)->code[0] = (0xe5000000 | \ - ((_x) % 1024) | \ - (((_y) % 1024) << 11) \ +#define setTexWindow_T(p, r) \ + (p)->code[0] = (0xe2000000 | \ + ((r)->w % 32) | \ + (((r)->h % 32) << 5) | \ + (((r)->x % 32) << 10) | \ + (((r)->y % 32) << 15) \ ) +#define setTexWindow(p, r) \ + setlen(p, 1), setTexWindow_T(p, r) -#define setDrawMask(p, sb, mt) \ - setlen(p, 1), \ - (p)->code[0] = (0xe6000000 | (sb) | ((mt) << 1)) - -#define setDrawArea(p, r) \ - setlen(p, 2), \ +#define setDrawArea_T(p, r) \ (p)->code[0] = (0xe3000000 | \ ((r)->x % 1024) | \ (((r)->y % 1024) << 10) \ @@ -216,15 +219,21 @@ typedef enum _GPU_VideoMode { (((r)->x + (r)->w - 1) % 1024) | \ ((((r)->y + (r)->h - 1) % 1024) << 10) \ ) +#define setDrawArea(p, r) \ + setlen(p, 2), setDrawArea_T(p, r) -#define setTexWindow(p, r) \ - setlen(p, 1), \ - (p)->code[0] = (0xe2000000 | \ - ((r)->w % 32) | \ - (((r)->h % 32) << 5) | \ - (((r)->x % 32) << 10) | \ - (((r)->y % 32) << 15) \ +#define setDrawOffset_T(p, _x, _y) \ + (p)->code[0] = (0xe5000000 | \ + ((_x) % 1024) | \ + (((_y) % 1024) << 11) \ ) +#define setDrawOffset(p, _x, _y) \ + setlen(p, 1), setDrawOffset_T(p, _x, _y) + +#define setDrawMask_T(p, sb, mt) \ + (p)->code[0] = (0xe6000000 | (sb) | ((mt) << 1)) +#define setDrawMask(p, sb, mt) \ + setlen(p, 1), setDrawMask_T(p, sb, mt) /* Primitive structure definitions */ @@ -434,9 +443,20 @@ _DEF_PRIM(SPRT_1, _DEF_ALIAS(SPRT_8, SPRT_1) _DEF_ALIAS(SPRT_16, SPRT_1) -_DEF_PRIM(DR_ENV, - uint32_t code[8]; +_DEF_PRIM(FILL, + uint8_t r0, g0, b0, code; + uint16_t x0, y0; + uint16_t w, h; ) + +_DEF_PRIM(BLIT, + uint8_t p0, p1, p2, code; + uint16_t x0, y0; + uint16_t x1, y1; + uint16_t w, h; + uint32_t pad[4]; +) + _DEF_PRIM(DR_AREA, uint32_t code[2]; ) @@ -444,7 +464,7 @@ _DEF_PRIM(DR_OFFSET, uint32_t code[1]; ) _DEF_PRIM(DR_TWIN, - uint32_t code[2]; + uint32_t code[1]; ) _DEF_PRIM(DR_TPAGE, uint32_t code[1]; @@ -453,18 +473,12 @@ _DEF_PRIM(DR_MASK, uint32_t code[1]; ) -_DEF_PRIM(FILL, - uint8_t r0, g0, b0, code; - uint16_t x0, y0; - uint16_t w, h; -) - -_DEF_PRIM(BLIT, - uint8_t p0, p1, p2, code; - uint16_t x0, y0; - uint16_t x1, y1; - uint16_t w, h; - uint32_t pad[4]; +_DEF_PRIM(DR_ENV, + DR_TPAGE_T tpage; + DR_TWIN_T twin; + DR_AREA_T area; + DR_OFFSET_T offset; + FILL_T fill; ) /* Structure definitions */ @@ -488,13 +502,13 @@ typedef struct _DISPENV { typedef struct _DRAWENV { RECT clip; // Drawing area int16_t ofs[2]; // GPU draw offset (relative to draw area) - RECT tw; // Texture window (doesn't do anything atm) + RECT tw; // Texture window uint16_t tpage; // Initial tpage value uint8_t dtd; // Dither processing flag (simply OR'ed to tpage) uint8_t dfe; // Drawing to display area blocked/allowed (simply OR'ed to tpage) uint8_t isbg; // Clear draw area if non-zero uint8_t r0, g0, b0; // Draw area clear color (if isbg iz nonzero) - DR_ENV dr_env; // Draw mode packet area (used by PutDrawEnv) + DR_ENV dr_env; // GPU primitive cache area (used internally) } DRAWENV; typedef struct _TIM_IMAGE { diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index 8d2119b..c52ab8a 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> @@ -11,7 +11,7 @@ #include <hwregs_c.h> #define QUEUE_LENGTH 16 -#define DMA_CHUNK_LENGTH 8 +#define DMA_CHUNK_LENGTH 16 #define VSYNC_TIMEOUT 0x100000 static void _default_vsync_halt(void); @@ -33,7 +33,7 @@ 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 uint32_t _vblank_counter, _last_vblank; static volatile uint16_t _last_hblank; /* Private interrupt handlers */ @@ -47,9 +47,7 @@ static void _vblank_handler(void) { static void _gpu_dma_handler(void) { if (GPU_GP1 & (1 << 24)) - GPU_GP1 = 0x02000000; - while (!(GPU_GP1 & (1 << 26))) - __asm__ volatile(""); + GPU_GP1 = 0x02000000; // Reset IRQ if (--_queue_length) { int head = _queue_head; @@ -82,8 +80,14 @@ void ResetGraph(int mode) { _sdk_log("setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); } - if (mode == 3) { + _queue_head = 0; + _queue_tail = 0; + _queue_length = 0; + + if (mode == 1) { GPU_GP1 = 0x01000000; // Reset command buffer + GPU_GP1 = 0x02000000; // Reset IRQ + GPU_GP1 = 0x04000000; // Disable DMA request return; } @@ -92,20 +96,20 @@ void ResetGraph(int mode) { DMA_CHCR(DMA_GPU) = 0x00000201; // Stop DMA DMA_CHCR(DMA_OTC) = 0x00000200; // Stop DMA - if (mode == 1) { + if (mode) { GPU_GP1 = 0x01000000; // Reset command buffer - return; + GPU_GP1 = 0x02000000; // Reset IRQ + GPU_GP1 = 0x04000000; // Disable DMA request + } else { + GPU_GP1 = 0x00000000; // Reset GPU } - GPU_GP1 = 0x00000000; // Reset GPU - 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; + + TIMER_CTRL(0) = 0x0500; + TIMER_CTRL(1) = 0x0500; } /* VSync() API */ @@ -129,11 +133,13 @@ int VSync(int mode) { return delta; if (mode < 0) return _vblank_counter; + if (!mode) + mode = 1; // VSync(0) = wait for one vblank - uint32_t status = GPU_GP1; - - // Wait for at least one vertical blank event to occur. - do { + // Wait for at least one vertical blank event since the last call to + // VSync() to occur. + for (uint32_t target = _last_vblank + mode; _vblank_counter < target;) { + uint32_t status = GPU_GP1; _vsync_halt_func(); // If interlaced mode is enabled, wait until the GPU starts displaying @@ -142,9 +148,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; } @@ -269,8 +277,10 @@ void ClearOTag(uint32_t *ot, size_t length) { // https://problemkaputt.de/psx-spx.htm#dmachannels for (int i = 0; i < (length - 1); i++) ot[i] = (uint32_t) &ot[i + 1] & 0x00ffffff; + //setaddr(&ot[i], &ot[i + 1]); ot[length - 1] = 0x00ffffff; + //termPrim(&ot[length - 1]); } void AddPrim(uint32_t *ot, const void *pri) { @@ -281,7 +291,7 @@ void DrawPrim(const uint32_t *pri) { size_t length = getlen(pri); DrawSync(0); - GPU_GP1 = 0x04000002; + GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 // 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 @@ -301,9 +311,9 @@ int DrawOTag(const uint32_t *ot) { } void DrawOTag2(const uint32_t *ot) { - GPU_GP1 = 0x04000002; + GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 - while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(DMA_GPU) & (1 << 24))) + while (DMA_CHCR(DMA_GPU) & (1 << 24)) __asm__ volatile(""); DMA_MADR(DMA_GPU) = (uint32_t) ot; diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index 96e065e..b90a431 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -1,6 +1,6 @@ /* * PSn00bSDK GPU library (DRAWENV/DISPENV functions) - * (C) 2022 spicyjpeg - MPL licensed + * (C) 2022-2023 spicyjpeg - MPL licensed */ #include <stdint.h> @@ -60,54 +60,42 @@ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { } 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 (the GPU does not care about the grouping as the - // display list is parsed by the DMA unit in the CPU). + // performance reasons using tagless primitives (the GPU does not care + // about the grouping as the display list is parsed by the CPU). + DR_ENV *prim = &(env->dr_env); setaddr(prim, ot); 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; + setDrawTPage_T(&(prim->tpage), env->dfe & 1, env->dtd & 1, env->tpage); // 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[2] = 0xe3000000; - prim->code[2] |= env->clip.x & 0x3ff; - prim->code[2] |= (env->clip.y & 0x3ff) << 10; - - // Set drawing area bottom right - 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[4] = 0xe5000000; - prim->code[4] |= (env->clip.x + env->ofs[0]) & 0x7ff; - prim->code[4] |= ((env->clip.y + env->ofs[1]) & 0x7ff) << 11; + //setTexWindow_T(&(prim->twin), &(env->tw)); + prim->twin.code[0] = 0xe2000000; + prim->twin.code[0] |= _get_window_mask(env->tw.w); + prim->twin.code[0] |= _get_window_mask(env->tw.h) << 5; + prim->twin.code[0] |= (env->tw.x & 0xf8) << 7; // ((tw.x / 8) & 0x1f) << 10 + prim->twin.code[0] |= (env->tw.y & 0xf8) << 12; // ((tw.y / 8) & 0x1f) << 15 + + // Set drawing area + setDrawArea_T(&(prim->area), &(env->clip)); + setDrawOffset_T( + &(prim->offset), + env->clip.x + env->ofs[0], + env->clip.y + env->ofs[1] + ); if (env->isbg) { + FILL_T *fill = &(prim->fill); setlen(prim, 8); // Rectangle fill // FIXME: reportedly this command doesn't accept height values >511... - 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; + setFill_T(fill); + setColor0(fill, *((const uint32_t *) &(env->isbg)) >> 8); + setXY0(fill, env->clip.x, env->clip.y); + setWH(fill, env->clip.w, _min(env->clip.h, 0x1ff)); } return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) prim, 0, 0); diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index 09c7ab9..61ac484 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -1,6 +1,6 @@ /* * PSn00bSDK GPU library (image and VRAM transfer functions) - * (C) 2022 spicyjpeg - MPL licensed + * (C) 2022-2023 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 @@ -14,7 +14,7 @@ #include <hwregs_c.h> #define QUEUE_LENGTH 16 -#define DMA_CHUNK_LENGTH 8 +#define DMA_CHUNK_LENGTH 16 /* Internal globals */ @@ -38,6 +38,9 @@ static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { length += DMA_CHUNK_LENGTH - 1; } + while (!(GPU_GP1 & (1 << 26))) + __asm__ volatile(""); + GPU_GP1 = 0x04000000; // Disable DMA request GPU_GP0 = 0x01000000; // Flush cache @@ -50,6 +53,9 @@ static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { // Enable DMA request, route to GP0 (2) or from GPU_READ (3) GPU_GP1 = 0x04000002 | (write ^ 1); + while (DMA_CHCR(DMA_GPU) & (1 << 24)) + __asm__ volatile(""); + DMA_MADR(DMA_GPU) = (uint32_t) data; if (length < DMA_CHUNK_LENGTH) DMA_BCR(DMA_GPU) = 0x00010000 | length; @@ -103,6 +109,9 @@ void StoreImage2(const RECT *rect, uint32_t *data) { } void MoveImage2(const RECT *rect, int x, int y) { + while (!(GPU_GP1 & (1 << 26))) + __asm__ volatile(""); + GPU_GP0 = 0x80000000; //GPU_GP0 = rect->x | (rect->y << 16); GPU_GP0 = *((const uint32_t *) &(rect->x)); |
