aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxgpu
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2022-10-19 17:57:06 +0800
committerGitHub <noreply@github.com>2022-10-19 17:57:06 +0800
commite08a3d9366f8ca14a76b3dd569dac1fb9f569748 (patch)
tree33654513b0b184c27f8035dbc405640fcbeb44ab /libpsn00b/psxgpu
parentc4a2533d21dfd05cde841ea48c67b05e0e6a853f (diff)
parent9b2ffc6078a850b7d354855cca7622090b41f30c (diff)
downloadpsn00bsdk-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.c187
-rw-r--r--libpsn00b/psxgpu/dbugfont.pngbin0 -> 1090 bytes
-rw-r--r--libpsn00b/psxgpu/dbugfont.timbin2112 -> 2112 bytes
-rw-r--r--libpsn00b/psxgpu/env.c4
-rw-r--r--libpsn00b/psxgpu/font.c36
-rw-r--r--libpsn00b/psxgpu/image.c57
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
new file mode 100644
index 0000000..ed84268
--- /dev/null
+++ b/libpsn00b/psxgpu/dbugfont.png
Binary files differ
diff --git a/libpsn00b/psxgpu/dbugfont.tim b/libpsn00b/psxgpu/dbugfont.tim
index 4e6cce2..1edd4af 100644
--- a/libpsn00b/psxgpu/dbugfont.tim
+++ b/libpsn00b/psxgpu/dbugfont.tim
Binary files differ
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 */