Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
gte-rtps.c
Go to the documentation of this file.
1// RTPS/RTPT: perspective transformation (single and triple)
2// Also covers division table behavior and screen coordinate saturation.
3
4// clang-format off
5
6CESTER_TEST(rtps_identity_center, gte_tests,
8 gte_set_translation(0, 0, 1000);
9 gte_set_screen(160 << 16, 120 << 16, 200);
10 cop2_put(0, 0x00000000); // V0 = (0, 0)
11 cop2_put(1, 0); // VZ0 = 0
13 cop2_cmd(COP2_RTPS(1, 0));
14 uint32_t sz3, sxy2;
15 cop2_get(19, sz3);
16 cop2_get(14, sxy2);
18 cester_assert_int_eq(160, (int16_t)(sxy2 & 0xffff));
19 cester_assert_int_eq(120, (int16_t)(sxy2 >> 16));
20)
21
22CESTER_TEST(rtps_offset_vertex, gte_tests,
25 gte_set_screen(160 << 16, 120 << 16, 200);
26 cop2_put(0, (50 << 16) | (100 & 0xffff));
27 cop2_put(1, 500);
30 uint32_t sz3;
33 // SX = 160 + 100*200/500 = 160 + 40 ~ 199 (division rounding)
34 // SY = 120 + 50*200/500 = 120 + 20 ~ 139
35 uint32_t sxy2;
37 int16_t sx = (int16_t)(sxy2 & 0xffff);
38 int16_t sy = (int16_t)(sxy2 >> 16);
39 ramsyscall_printf("RTPS offset: SX=%d SY=%d\n", sx, sy);
43)
44
45// RTPS MAC output
46CESTER_TEST(rtps_mac_output, gte_tests,
48 gte_set_translation(100, 200, 300);
49 gte_set_screen(0, 0, 200);
50 cop2_put(0, (50 << 16) | 10); // V0 = (10, 50)
51 cop2_put(1, 500);
53 cop2_cmd(COP2_RTPS(1, 0));
54 int32_t mac1, mac2, mac3;
55 cop2_get(25, mac1);
56 cop2_get(26, mac2);
57 cop2_get(27, mac3);
58 // Identity rotation: MAC = V + TR
62)
63
64// RTPS with Z=0 (division overflow)
65CESTER_TEST(rtps_division_overflow, gte_tests,
67 gte_set_translation(0, 0, 0);
68 gte_set_screen(0, 0, 200);
69 cop2_put(0, (0 << 16) | 100);
70 cop2_put(1, 1); // VZ0 = 1, very small Z
72 cop2_cmd(COP2_RTPS(1, 0));
73 uint32_t flag;
74 flag = gte_read_flag();
75 // H=200, SZ3=1 -> H >= SZ3*2 (200 >= 2) -> division overflow FLAG.17
76 ramsyscall_printf("RTPS div overflow: FLAG=0x%08x (bit17=%u)\n", flag, (flag >> 17) & 1);
77 uint32_t flag17 = (flag >> 17) & 1;
79)
80
81// RTPS screen coordinate saturation
82CESTER_TEST(rtps_screen_saturation, gte_tests,
84 gte_set_translation(0, 0, 0);
85 gte_set_screen(0, 0, 200);
86 // Large X, small Z -> SX will exceed -0x400..0x3FF range
87 cop2_put(0, (0 << 16) | 0x7fff); // VX0 = 32767
88 cop2_put(1, 100); // VZ0 = 100
90 cop2_cmd(COP2_RTPS(1, 0));
91 uint32_t sxy2, flag;
92 cop2_get(14, sxy2);
93 flag = gte_read_flag();
94 int16_t sx = (int16_t)(sxy2 & 0xffff);
95 ramsyscall_printf("RTPS sat: SX=%d FLAG=0x%08x (bit14=%u)\n", sx, flag, (flag >> 14) & 1);
96 // SX should be saturated to 0x3FF
98 uint32_t flag14 = (flag >> 14) & 1;
99 cester_assert_uint_eq(1, flag14); // FLAG.14 = SX2 saturated
100)
101
102// RTPS depth cue output (MAC0/IR0)
103CESTER_TEST(rtps_depth_cue, gte_tests,
105 gte_set_translation(0, 0, 0);
106 cop2_putc(24, 0);
107 cop2_putc(25, 0);
108 cop2_putc(26, 200);
109 cop2_putc(27, 0xfffff880); // DQA = -1920 (negative)
110 cop2_putc(28, 0x01000000); // DQB = 16777216
111 cop2_put(0, 0x00000000);
112 cop2_put(1, 1000);
114 cop2_cmd(COP2_RTPS(1, 0));
115 int32_t mac0;
116 uint32_t ir0;
119 ramsyscall_printf("RTPS depth: MAC0=%d IR0=0x%04x\n", mac0, ir0 & 0xffff);
120 // IR0 should be clamped to [0, 0x1000]
123)
124
125// RTPS with sf=0
128 gte_set_translation(0, 0, 0x1000);
129 gte_set_screen(0, 0, 200);
130 cop2_put(0, 0x00000000);
131 cop2_put(1, 0);
133 cop2_cmd(COP2_RTPS(0, 0));
134 int32_t mac3;
135 uint32_t ir3, sz3, flag;
136 cop2_get(27, mac3);
137 cop2_get(11, ir3);
138 cop2_get(19, sz3);
139 flag = gte_read_flag();
140 ramsyscall_printf("RTPS sf=0: MAC3=%d IR3=0x%04x SZ3=%u FLAG=0x%08x\n",
141 mac3, ir3 & 0xffff, sz3, flag);
142 // sf=0: MAC3 = TRZ<<12 + rotation = 0x1000<<12 = 0x1000000 (no >>12 shift)
143 // IR3 uses Lm_B3_sf which checks MAC3>>12 for FLAG but clamps the unshifted value
144 cester_assert_int_eq(16777216, mac3);
145 cester_assert_uint_eq(0x7fff, ir3);
148)
149
150// RTPT: triple perspective transform
151CESTER_TEST(rtpt_three_vertices, gte_tests,
153 gte_set_translation(0, 0, 0);
154 gte_set_screen(160 << 16, 120 << 16, 200);
155 // V0 = (0, 0, 1000)
156 cop2_put(0, 0x00000000);
157 cop2_put(1, 1000);
158 // V1 = (100, 0, 1000)
159 cop2_put(2, (0 << 16) | 100);
160 cop2_put(3, 1000);
161 // V2 = (0, 100, 1000)
162 cop2_put(4, (100 << 16) | 0);
163 cop2_put(5, 1000);
166 uint32_t sxy0, sxy1, sxy2;
169 cop2_get(14, sxy2);
170 // V0 at origin -> (160, 120)
171 cester_assert_int_eq(160, (int16_t)(sxy0 & 0xffff));
172 cester_assert_int_eq(120, (int16_t)(sxy0 >> 16));
173 // V1 at (100,0,1000) -> SX ~ 180
174 int16_t sx1 = (int16_t)(sxy1 & 0xffff);
175 int16_t sy1 = (int16_t)(sxy1 >> 16);
176 ramsyscall_printf("RTPT: V1=(%d,%d) V2=(%d,%d)\n", sx1, sy1,
177 (int16_t)(sxy2 & 0xffff), (int16_t)(sxy2 >> 16));
178 cester_assert_int_eq(120, sy1); // Y unchanged
179)
180
181// RTPT: FLAG accumulates across all three vertices
182CESTER_TEST(rtpt_flag_accumulates, gte_tests,
184 gte_set_translation(0, 0, 0);
185 gte_set_screen(0, 0, 200);
186 // V0: normal
187 cop2_put(0, 0x00000000);
188 cop2_put(1, 1000);
189 // V1: will cause SX saturation (large X, small Z)
190 cop2_put(2, (0 << 16) | 0x7fff);
191 cop2_put(3, 100);
192 // V2: normal
193 cop2_put(4, 0x00000000);
194 cop2_put(5, 1000);
196 cop2_cmd(COP2_RTPT(1, 0));
197 uint32_t flag;
198 flag = gte_read_flag();
199 // FLAG should have SX2 saturation from V1, even though V2 was fine
200 ramsyscall_printf("RTPT flag accum: FLAG=0x%08x\n", flag);
201 // Division overflow from V1 (H=200, SZ3=100, 200 >= 200)
202 uint32_t flag17 = (flag >> 17) & 1;
204)
205
206// RTPT pushes SZ FIFO correctly
207CESTER_TEST(rtpt_sz_fifo, gte_tests,
209 gte_set_translation(0, 0, 0);
210 gte_set_screen(160 << 16, 120 << 16, 200);
211 cop2_put(0, 0x00000000);
212 cop2_put(1, 100);
213 cop2_put(2, 0x00000000);
214 cop2_put(3, 200);
215 cop2_put(4, 0x00000000);
216 cop2_put(5, 300);
218 cop2_cmd(COP2_RTPT(1, 0));
219 uint32_t sz1, sz2, sz3;
222 cop2_get(19, sz3);
226)
#define cop2_cmd(op)
Definition cop2.h:175
#define cop2_put(reg, val)
Definition cop2.h:191
#define COP2_RTPT(sf, lm)
Definition cop2.h:130
#define cop2_putc(reg, val)
Definition cop2.h:205
#define COP2_RTPS(sf, lm)
Definition cop2.h:129
#define cop2_get(reg, dest)
Definition cop2.h:198
int32_t mac1
Definition gte-depthcue.c:118
int32_t mac2
Definition gte-depthcue.c:118
int32_t mac3
Definition gte-depthcue.c:118
uint32_t ir3
Definition gte-precision.c:322
gte_set_identity_rotation()
uint32_t sz3
Definition gte-rtps.c:30
uint32_t sxy2
Definition gte-rtps.c:35
int16_t sy1
Definition gte-rtps.c:175
gte_tests
Definition gte-rtps.c:22
uint32_t flag
Definition gte-rtps.c:73
int16_t sx
Definition gte-rtps.c:37
uint32_t sxy0
Definition gte-rtps.c:166
uint32_t flag17
Definition gte-rtps.c:77
uint32_t sz1
Definition gte-rtps.c:219
gte_set_translation(0, 0, 0)
CESTER_TEST(rtps_identity_center, gte_tests, gte_set_identity_rotation();gte_set_translation(0, 0, 1000);gte_set_screen(160<< 16, 120<< 16, 200);cop2_put(0, 0x00000000);cop2_put(1, 0);gte_clear_flag();cop2_cmd(COP2_RTPS(1, 0));uint32_t sz3, sxy2;cop2_get(19, sz3);cop2_get(14, sxy2);cester_assert_uint_eq(1000, sz3);cester_assert_int_eq(160,(int16_t)(sxy2 &0xffff));cester_assert_int_eq(120,(int16_t)(sxy2 > > 16));) CESTER_TEST(rtps_offset_vertex
cester_assert_int_eq(199, sx)
uint32_t sz2
Definition gte-rtps.c:219
gte_set_screen(160<< 16, 120<< 16, 200)
uint32_t sxy1
Definition gte-rtps.c:166
gte_clear_flag()
uint32_t ir0
Definition gte-rtps.c:116
int16_t sy
Definition gte-rtps.c:38
int16_t sx1
Definition gte-rtps.c:174
ramsyscall_printf("RTPS offset: SX=%d SY=%d\n", sx, sy)
cester_assert_uint_eq(500, sz3)
int32_t mac0
Definition gte-rtps.c:115