aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2023-01-13 18:04:49 +0100
committerspicyjpeg <thatspicyjpeg@gmail.com>2023-01-13 18:04:49 +0100
commit3095b4571dabc8d6cee90673d679f3e77b21b164 (patch)
tree125ec0f4792fb9b9a213cbd6247e8e9518d14033
parent50faf92a8cb099420aa956dcac3a8105067e117c (diff)
Fix VSync() rate limiter, add missing tagless packets
-rw-r--r--libpsn00b/include/psxetc.h9
-rw-r--r--libpsn00b/include/psxgpu.h90
-rw-r--r--libpsn00b/psxgpu/common.c58
-rw-r--r--libpsn00b/psxgpu/env.c60
-rw-r--r--libpsn00b/psxgpu/image.c13
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));