aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxgpu/drawing.c
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2023-05-11 23:08:11 +0200
committerspicyjpeg <thatspicyjpeg@gmail.com>2023-05-11 23:08:11 +0200
commit2021cdfca29dc5c98e570a674ac97f92f47a1129 (patch)
treea7355b8852ae4e9d217560b0cab2dcc02ab8c249 /libpsn00b/psxgpu/drawing.c
parent3b696fc431a9c3f2aa7ea4f27aec20ce5dd67859 (diff)
downloadpsn00bsdk-2021cdfca29dc5c98e570a674ac97f92f47a1129.tar.gz
Add GPU IRQ variants of all display list APIs
Diffstat (limited to 'libpsn00b/psxgpu/drawing.c')
-rw-r--r--libpsn00b/psxgpu/drawing.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/libpsn00b/psxgpu/drawing.c b/libpsn00b/psxgpu/drawing.c
new file mode 100644
index 0000000..161b2f7
--- /dev/null
+++ b/libpsn00b/psxgpu/drawing.c
@@ -0,0 +1,148 @@
+/*
+ * PSn00bSDK GPU library (drawing/display list functions)
+ * (C) 2022-2023 spicyjpeg - MPL licensed
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <psxetc.h>
+#include <psxgpu.h>
+#include <hwregs_c.h>
+
+/* Private utilities */
+
+// This function is actually referenced in env.c as well, so it can't be static.
+void _send_linked_list(GPU_DrawOpType type, const uint32_t *ot) {
+ SetDrawOpType(type);
+ GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0
+
+ while (DMA_CHCR(DMA_GPU) & (1 << 24))
+ __asm__ volatile("");
+
+ DMA_MADR(DMA_GPU) = (uint32_t) ot;
+ DMA_BCR(DMA_GPU) = 0;
+ DMA_CHCR(DMA_GPU) = 0x01000401;
+}
+
+static void _send_buffer(
+ GPU_DrawOpType type, const uint32_t *buf, size_t length
+) {
+ SetDrawOpType(type);
+ GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0
+
+ while (DMA_CHCR(DMA_GPU) & (1 << 24))
+ __asm__ volatile("");
+
+ DMA_MADR(DMA_GPU) = (uint32_t) buf;
+ DMA_BCR(DMA_GPU) = 0x00000001 | (length << 16);
+ DMA_CHCR(DMA_GPU) = 0x01000201;
+}
+
+/* Buffer and primitive drawing API */
+
+int DrawOTag(const uint32_t *ot) {
+ _sdk_validate_args(ot, -1);
+
+ return EnqueueDrawOp(
+ (void *) &_send_linked_list,
+ (uint32_t) DRAWOP_TYPE_DMA,
+ (uint32_t) ot,
+ 0
+ );
+}
+
+int DrawOTagIRQ(const uint32_t *ot) {
+ _sdk_validate_args(ot, -1);
+
+ return EnqueueDrawOp(
+ (void *) &_send_linked_list,
+ (uint32_t) DRAWOP_TYPE_GPU_IRQ,
+ (uint32_t) ot,
+ 0
+ );
+}
+
+int DrawBuffer(const uint32_t *buf, size_t length) {
+ _sdk_validate_args(buf && length && (length <= 0xffff), -1);
+
+ return EnqueueDrawOp(
+ (void *) &DrawBuffer2,
+ (uint32_t) DRAWOP_TYPE_DMA,
+ (uint32_t) buf,
+ (uint32_t) length
+ );
+}
+
+int DrawBufferIRQ(const uint32_t *buf, size_t length) {
+ _sdk_validate_args(buf && length && (length <= 0xffff), -1);
+
+ return EnqueueDrawOp(
+ (void *) &DrawBuffer2,
+ (uint32_t) DRAWOP_TYPE_GPU_IRQ,
+ (uint32_t) buf,
+ (uint32_t) length
+ );
+}
+
+void DrawOTag2(const uint32_t *ot) {
+ _sdk_validate_args_void(ot);
+
+ _send_linked_list(DRAWOP_TYPE_DMA, ot);
+}
+
+void DrawOTagIRQ2(const uint32_t *ot) {
+ _sdk_validate_args_void(ot);
+
+ _send_linked_list(DRAWOP_TYPE_GPU_IRQ, ot);
+}
+
+void DrawBuffer2(const uint32_t *buf, size_t length) {
+ _sdk_validate_args_void(buf && length && (length <= 0xffff));
+
+ _send_buffer(DRAWOP_TYPE_DMA, buf, length);
+}
+
+void DrawBufferIRQ2(const uint32_t *buf, size_t length) {
+ _sdk_validate_args_void(buf && length && (length <= 0xffff));
+
+ _send_buffer(DRAWOP_TYPE_GPU_IRQ, buf, length);
+}
+
+void DrawPrim(const uint32_t *pri) {
+ _sdk_validate_args_void(pri);
+
+ DrawSync(0);
+ DrawBuffer2(&pri[1], getlen(pri));
+}
+
+/* Helper functions */
+
+void ClearOTagR(uint32_t *ot, size_t length) {
+ _sdk_validate_args_void(ot && length);
+
+ DMA_MADR(DMA_OTC) = (uint32_t) &ot[length - 1];
+ DMA_BCR(DMA_OTC) = length & 0xffff;
+ DMA_CHCR(DMA_OTC) = 0x11000002;
+
+ while (DMA_CHCR(DMA_OTC) & (1 << 24))
+ __asm__ volatile("");
+}
+
+void ClearOTag(uint32_t *ot, size_t length) {
+ _sdk_validate_args_void(ot && length);
+
+ // DMA6 only supports writing to RAM in reverse order (last to first), so
+ // the OT has to be cleared in software here. This function is thus much
+ // slower than ClearOTagR().
+ // https://problemkaputt.de/psx-spx.htm#dmachannels
+ for (int i = 0; i < (length - 1); i++)
+ ot[i] = (uint32_t) &ot[i + 1] & 0x7fffff;
+
+ ot[length - 1] = 0xffffff;
+}
+
+void AddPrim(uint32_t *ot, const void *pri) {
+ _sdk_validate_args_void(ot && pri);
+
+ addPrim(ot, pri);
+}