aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxgpu/drawing.c
blob: 85bf6a8c5167367104449f8f8f616dd92760b1fe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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 void *pri) {
	_sdk_validate_args_void(pri);

	DrawSync(0);
	DrawBuffer2(((const uint32_t *) 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);
}