aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxgpu/image.c
diff options
context:
space:
mode:
authorspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2022-06-29 12:40:46 +0200
committerspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2022-06-29 12:40:46 +0200
commit6120304537470e7e5ff94b3bf19a33787ca69083 (patch)
treef489c6dceae0846184dddd38444ef8519f799f7b /libpsn00b/psxgpu/image.c
parent578181ace1374e72cb93d69d2c201ce7a0a2300c (diff)
downloadpsn00bsdk-6120304537470e7e5ff94b3bf19a33787ca69083.tar.gz
Refactor libpsxgpu in C, add OT drawing queue
Diffstat (limited to 'libpsn00b/psxgpu/image.c')
-rw-r--r--libpsn00b/psxgpu/image.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c
new file mode 100644
index 0000000..3633c7c
--- /dev/null
+++ b/libpsn00b/psxgpu/image.c
@@ -0,0 +1,116 @@
+/*
+ * PSn00bSDK GPU library (image and VRAM transfer functions)
+ * (C) 2022 spicyjpeg - MPL licensed
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <psxgpu.h>
+#include <hwregs_c.h>
+
+#define DMA_CHUNK_LENGTH 8
+
+/* Common internal load/store function */
+
+static void _load_store_image(
+ uint32_t command,
+ int mode,
+ const RECT *rect,
+ uint32_t *data
+) {
+ size_t length = rect->w * rect->h;
+ if (length % 2)
+ printf("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\n", length, DMA_CHUNK_LENGTH);
+
+ DrawSync(0);
+ GPU_GP1 = 0x04000000; // Disable DMA request
+ GPU_GP0 = 0x01000000; // Flush cache
+
+ GPU_GP0 = command;
+ //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;
+
+ DMA_MADR(2) = (uint32_t) data;
+ if (length < DMA_CHUNK_LENGTH)
+ DMA_BCR(2) = 0x00010000 | length;
+ else
+ DMA_BCR(2) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16);
+
+ DMA_CHCR(2) = 0x01000200 | !(mode & 1);
+}
+
+/* Public VRAM API */
+
+void LoadImage(const RECT *rect, const u_long *data) {
+ _load_store_image(0xa0000000, 2, rect, (uint32_t *) data);
+}
+
+void StoreImage(const RECT *rect, u_long *data) {
+ _load_store_image(0xc0000000, 3, rect, (uint32_t *) data);
+}
+
+/* .TIM image parsers */
+
+// This is the only libgs function PSn00bSDK is ever going to implement. The
+// difference from GetTimInfo() is that it copies RECTs rather than merely
+// returning pointers to them, which become useless once the .TIM file is
+// unloaded from main RAM.
+int GsGetTimInfo(const u_long *tim, GsIMAGE *info) {
+ if ((*(tim++) & 0xffff) != 0x0010)
+ return 1;
+
+ info->pmode = *(tim++);
+ if (info->pmode & 8) {
+ const u_long *palette_end = tim;
+ palette_end += *(tim++) / 4;
+
+ *((u_long *) &(info->cx)) = *(tim++);
+ *((u_long *) &(info->cw)) = *(tim++);
+ info->clut = (u_long *) tim;
+
+ tim = palette_end;
+ } else {
+ info->clut = 0;
+ }
+
+ tim++;
+ *((u_long *) &(info->px)) = *(tim++);
+ *((u_long *) &(info->pw)) = *(tim++);
+ info->pixel = (u_long *) tim;
+
+ return 0;
+}
+
+int GetTimInfo(const u_long *tim, TIM_IMAGE *info) {
+ if ((*(tim++) & 0xffff) != 0x0010)
+ return 1;
+
+ info->mode = *(tim++);
+ if (info->mode & 8) {
+ const u_long *palette_end = tim;
+ palette_end += *(tim++) / 4;
+
+ info->crect = (RECT *) tim;
+ info->caddr = (u_long *) &tim[2];
+
+ tim = palette_end;
+ } else {
+ info->caddr = 0;
+ }
+
+ tim++;
+ info->prect = (RECT *) tim;
+ info->paddr = (u_long *) &tim[2];
+
+ return 0;
+}