Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
affine-triangles.c
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2026 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27// Phase-17 affine UV-mapping triangle suite. Eight triangles spanning
28// the parameter space: UV-vs-screen rotation, scale ratios, and
29// stress geometries (narrow-tall, flat-wide).
30//
31// All draws use the phase-17 TEX17 signature texture (texpage cell
32// TX=11, 32x32 15-bit direct). Texel(u, v) encodes (u, v) uniquely in
33// (red, green) channels so probe failures decode directly into the
34// (u, v) the rasterizer actually sampled.
35
36// clang-format off
37
39
40// ---- T1 AR_AXIS_BASE -----------------------------------------------------
41// A=(5,5)/(0,0) B=(25,5)/(20,0) C=(5,15)/(0,10)
42// Affine: UV(x, y) = (x - 5, y - 5). 1:1 ratio, axis-aligned.
43
44static void drawAR_AXIS_BASE(void) {
45 rasterReset();
46 rasterClearTestRegion(0, 0, 32, 16);
47 setTexpage(TEX17_TX, TEX17_TY, 2);
48 setTextureWindow(0, 0, 0, 0);
49 rasterTexTri(TEX_MOD_NEUTRAL,
50 5, 5, 0, 0,
51 25, 5, 20, 0,
52 5, 15, 0, 10,
54 rasterFlushPrimitive();
55}
56
57// ---- T2 AR_COMPRESS ------------------------------------------------------
58// A=(5,5)/(0,0) B=(35,5)/(6,0) C=(5,15)/(0,3)
59// 30x10 screen -> 6x3 UV. Sub-unit per-pixel UV step.
60
61static void drawAR_COMPRESS(void) {
62 rasterReset();
63 rasterClearTestRegion(0, 0, 48, 16);
64 setTexpage(TEX17_TX, TEX17_TY, 2);
65 setTextureWindow(0, 0, 0, 0);
66 rasterTexTri(TEX_MOD_NEUTRAL,
67 5, 5, 0, 0,
68 35, 5, 6, 0,
69 5, 15, 0, 3,
71 rasterFlushPrimitive();
72}
73
74// ---- T3 AR_STRETCH -------------------------------------------------------
75// A=(5,5)/(0,0) B=(15,5)/(30,0) C=(5,10)/(0,20)
76// 10x5 screen -> 30x20 UV. Per-pixel UV step ~3x and ~4x.
77
78static void drawAR_STRETCH(void) {
79 rasterReset();
80 rasterClearTestRegion(0, 0, 16, 16);
81 setTexpage(TEX17_TX, TEX17_TY, 2);
82 setTextureWindow(0, 0, 0, 0);
83 rasterTexTri(TEX_MOD_NEUTRAL,
84 5, 5, 0, 0,
85 15, 5, 30, 0,
86 5, 10, 0, 20,
88 rasterFlushPrimitive();
89}
90
91// ---- T4 AR_TWIST_90 ------------------------------------------------------
92// A=(4,4)/(0,0) B=(20,4)/(0,16) C=(4,20)/(16,0)
93// UV axes swapped. UV(x, y) = (y - 4, x - 4) inside triangle.
94// Tests cross-span UV step at maximum rate vs zero row-edge step.
95
96static void drawAR_TWIST_90(void) {
97 rasterReset();
98 rasterClearTestRegion(0, 0, 24, 24);
99 setTexpage(TEX17_TX, TEX17_TY, 2);
100 setTextureWindow(0, 0, 0, 0);
101 rasterTexTri(TEX_MOD_NEUTRAL,
102 4, 4, 0, 0,
103 20, 4, 0, 16,
104 4, 20, 16, 0,
106 rasterFlushPrimitive();
107}
108
109// ---- T5 AR_TWIST_45 ------------------------------------------------------
110// A=(4,4)/(8,0) B=(20,4)/(16,8) C=(4,20)/(0,8)
111// UV rotated 45 degrees. dU/dX = 0.5, dU/dY = -0.5, dV/dX = 0.5,
112// dV/dY = 0.5 (uniform-magnitude in both UV axes).
113
114static void drawAR_TWIST_45(void) {
115 rasterReset();
116 rasterClearTestRegion(0, 0, 24, 24);
117 setTexpage(TEX17_TX, TEX17_TY, 2);
118 setTextureWindow(0, 0, 0, 0);
119 rasterTexTri(TEX_MOD_NEUTRAL,
120 4, 4, 8, 0,
121 20, 4, 16, 8,
122 4, 20, 0, 8,
124 rasterFlushPrimitive();
125}
126
127// ---- T6 AR_NATURAL -------------------------------------------------------
128// A=(5,5)/(3,2) B=(25,9)/(20,5) C=(8,22)/(8,22)
129// Arbitrary triangle, arbitrary UV. No symmetry, no special structure.
130
131static void drawAR_NATURAL(void) {
132 rasterReset();
133 rasterClearTestRegion(0, 0, 32, 24);
134 setTexpage(TEX17_TX, TEX17_TY, 2);
135 setTextureWindow(0, 0, 0, 0);
136 rasterTexTri(TEX_MOD_NEUTRAL,
137 5, 5, 3, 2,
138 25, 9, 20, 5,
139 8, 22, 8, 22,
141 rasterFlushPrimitive();
142}
143
144// ---- T7 AR_NARROW_TALL ---------------------------------------------------
145// A=(10,4)/(0,0) B=(14,4)/(20,0) C=(12,24)/(10,30)
146// 4 wide, 20 tall. Cross-span UV step dominates row edge step.
147
148static void drawAR_NARROW_TALL(void) {
149 rasterReset();
150 rasterClearTestRegion(4, 0, 16, 28);
151 setTexpage(TEX17_TX, TEX17_TY, 2);
152 setTextureWindow(0, 0, 0, 0);
153 rasterTexTri(TEX_MOD_NEUTRAL,
154 10, 4, 0, 0,
155 14, 4, 20, 0,
156 12, 24, 10, 30,
158 rasterFlushPrimitive();
159}
160
161// ---- T8 AR_FLAT_WIDE -----------------------------------------------------
162// A=(4,8)/(0,0) B=(34,9)/(30,0) C=(4,11)/(0,4)
163// 30 wide, 3 tall. Row edge step dominates cross-span step.
164
165static void drawAR_FLAT_WIDE(void) {
166 rasterReset();
167 rasterClearTestRegion(0, 0, 48, 16);
168 setTexpage(TEX17_TX, TEX17_TY, 2);
169 setTextureWindow(0, 0, 0, 0);
170 rasterTexTri(TEX_MOD_NEUTRAL,
171 4, 8, 0, 0,
172 34, 9, 30, 0,
173 4, 11, 0, 4,
175 rasterFlushPrimitive();
176}
177
178) // CESTER_BODY
179
180// --------------------------------------------------------------------------
181// T1 AR_AXIS_BASE assertions
182// --------------------------------------------------------------------------
183
184CESTER_TEST(ar_axis_base_10_8, gpu_raster_phase17,
185 drawAR_AXIS_BASE();
187)
188
189CESTER_TEST(ar_axis_base_20_6, gpu_raster_phase17,
190 drawAR_AXIS_BASE();
192)
193
194CESTER_TEST(ar_axis_base_8_12, gpu_raster_phase17,
195 drawAR_AXIS_BASE();
197)
198
199CESTER_TEST(ar_axis_base_24_5_top_edge, gpu_raster_phase17,
200 drawAR_AXIS_BASE();
202)
203
204CESTER_TEST(ar_axis_base_25_5_right_vert_excluded, gpu_raster_phase17,
205 drawAR_AXIS_BASE();
207)
208
209// --------------------------------------------------------------------------
210// T2 AR_COMPRESS assertions
211// --------------------------------------------------------------------------
212
213CESTER_TEST(ar_compress_10_7, gpu_raster_phase17,
214 drawAR_COMPRESS();
216)
217
218CESTER_TEST(ar_compress_20_8, gpu_raster_phase17,
219 drawAR_COMPRESS();
221)
222
223CESTER_TEST(ar_compress_15_10, gpu_raster_phase17,
224 drawAR_COMPRESS();
226)
227
228CESTER_TEST(ar_compress_30_5, gpu_raster_phase17,
229 drawAR_COMPRESS();
231)
232
233// --------------------------------------------------------------------------
234// T3 AR_STRETCH assertions
235// --------------------------------------------------------------------------
236
237CESTER_TEST(ar_stretch_6_6, gpu_raster_phase17,
238 drawAR_STRETCH();
240)
241
242CESTER_TEST(ar_stretch_10_7, gpu_raster_phase17,
243 drawAR_STRETCH();
245)
246
247CESTER_TEST(ar_stretch_8_8, gpu_raster_phase17,
248 drawAR_STRETCH();
250)
251
252CESTER_TEST(ar_stretch_5_5_a_vert, gpu_raster_phase17,
253 drawAR_STRETCH();
255)
256
257// --------------------------------------------------------------------------
258// T4 AR_TWIST_90 assertions
259// --------------------------------------------------------------------------
260
261CESTER_TEST(ar_twist_90_10_10, gpu_raster_phase17,
262 drawAR_TWIST_90();
264)
265
266CESTER_TEST(ar_twist_90_6_10, gpu_raster_phase17,
267 drawAR_TWIST_90();
269)
270
271CESTER_TEST(ar_twist_90_10_6, gpu_raster_phase17,
272 drawAR_TWIST_90();
274)
275
276CESTER_TEST(ar_twist_90_4_4_a_vert, gpu_raster_phase17,
277 drawAR_TWIST_90();
279)
280
281// --------------------------------------------------------------------------
282// T5 AR_TWIST_45 assertions
283// --------------------------------------------------------------------------
284
285CESTER_TEST(ar_twist_45_12_4_ab_mid, gpu_raster_phase17,
286 drawAR_TWIST_45();
288)
289
290CESTER_TEST(ar_twist_45_4_12_ac_mid, gpu_raster_phase17,
291 drawAR_TWIST_45();
293)
294
295CESTER_TEST(ar_twist_45_8_8, gpu_raster_phase17,
296 drawAR_TWIST_45();
298)
299
300CESTER_TEST(ar_twist_45_12_12_bc_mid, gpu_raster_phase17,
301 drawAR_TWIST_45();
303)
304
305// --------------------------------------------------------------------------
306// T6 AR_NATURAL assertions
307// --------------------------------------------------------------------------
308
309CESTER_TEST(ar_natural_12_10, gpu_raster_phase17,
310 drawAR_NATURAL();
312)
313
314CESTER_TEST(ar_natural_18_15, gpu_raster_phase17,
315 drawAR_NATURAL();
317)
318
319CESTER_TEST(ar_natural_10_18, gpu_raster_phase17,
320 drawAR_NATURAL();
322)
323
324CESTER_TEST(ar_natural_5_5_a_vert, gpu_raster_phase17,
325 drawAR_NATURAL();
327)
328
329// --------------------------------------------------------------------------
330// T7 AR_NARROW_TALL assertions
331// --------------------------------------------------------------------------
332
333CESTER_TEST(ar_narrow_tall_11_8, gpu_raster_phase17,
334 drawAR_NARROW_TALL();
336)
337
338CESTER_TEST(ar_narrow_tall_12_14, gpu_raster_phase17,
339 drawAR_NARROW_TALL();
341)
342
343CESTER_TEST(ar_narrow_tall_11_20, gpu_raster_phase17,
344 drawAR_NARROW_TALL();
346)
347
348CESTER_TEST(ar_narrow_tall_13_6, gpu_raster_phase17,
349 drawAR_NARROW_TALL();
351)
352
353// --------------------------------------------------------------------------
354// T8 AR_FLAT_WIDE assertions
355// --------------------------------------------------------------------------
356
357CESTER_TEST(ar_flat_wide_8_9, gpu_raster_phase17,
358 drawAR_FLAT_WIDE();
360)
361
362CESTER_TEST(ar_flat_wide_20_9, gpu_raster_phase17,
363 drawAR_FLAT_WIDE();
365)
366
367CESTER_TEST(ar_flat_wide_30_9, gpu_raster_phase17,
368 drawAR_FLAT_WIDE();
370)
371
372CESTER_TEST(ar_flat_wide_6_10, gpu_raster_phase17,
373 drawAR_FLAT_WIDE();
375)
CESTER_TEST(cddaLevelHalf, test_instances, static const uint8_t atv[4]={0x40, 0x00, 0x40, 0x00};unsigned changes=0;int peak=cddaPeak(atv, 1, &changes);ramsyscall_printf("CD-DA level at half ATV: peak %i, %u sign changes\n", peak, changes);cester_assert_int_ge(peak, 11300);cester_assert_int_le(peak, 11800);cester_assert_uint_ge(changes, 4);) CESTER_TEST(cddaLevelClipped
CESTER_BODY(static uint16_t s_cddaCapture;static int cddaSpuDma(uint32_t spuAddr, void *buf, uint32_t bytes, int isRead) { const uint16_t tsa=spuAddr > > 3;const uint16_t mode=isRead ? 0x30 :0x20;SPU_RAM_DTA=tsa;for(int i=0;i< 0xf01 &&SPU_RAM_DTA !=tsa;i++);SPU_CTRL=(SPU_CTRL &~0x30)|mode;for(volatile int i=0;i< 60;i++);for(int i=0;i< 0xf01 &&(SPU_STATUS &0x30) !=mode;i++);CDDA_SPU_DELAY=(CDDA_SPU_DELAY &0xf0ffffff)|(isRead ? 0x22000000 :0x20000000);DMA_CTRL[DMA_SPU].MADR=(uint32_t) buf &0x1fffffff;DMA_CTRL[DMA_SPU].BCR=((bytes > > 6)<< 16)|0x10;DMA_CTRL[DMA_SPU].CHCR=isRead ? 0x01000200 :0x01000201;int ok=0;for(unsigned t=0;t< 4000000u;t++) { if((DMA_CTRL[DMA_SPU].CHCR &0x01000000)==0) { ok=1;break;} } SPU_CTRL=SPU_CTRL &~0x30;for(volatile int i=0;i< 60;i++);return ok;} static int cddaSimpleCmd(uint8_t cmd) { uint8_t response[16];CDROM_REG0=0;CDROM_REG1=cmd;uint32_t timeout=2000000;int ok=waitCDRomIRQWithTimeout(&timeout);ackCDRomCause();readResponse(response);return ok;} static void cddaWaitPauseComplete() { initializeTime();uint32_t elapsed=0;while(elapsed< 5000000u) { uint32_t budget=200000u;int ok=waitCDRomIRQWithTimeout(&budget);elapsed=budget;if(!ok) continue;uint8_t cause=ackCDRomCause();uint8_t response[16];readResponse(response);if(cause==2) return;} } static int cddaAudioSetup(const uint8_t atv[4], int demute) { if(!resetCDRom()) return 0;DPCR|=0x000b0000;SPU_CTRL=0;for(volatile int i=0;i< 20000;i++);SPU_VOL_MAIN_LEFT=0;SPU_VOL_MAIN_RIGHT=0;SPU_KEY_OFF_LOW=0xffff;SPU_KEY_OFF_HIGH=0xffff;SPU_RAM_DTC=4;SPU_CTRL=0x8001;for(volatile int i=0;i< 20000;i++);for(int i=0;i< 0x400;i++) s_cddaCapture[i]=CDDA_MARKER;if(!cddaSpuDma(0x000, s_cddaCapture, 0x800, 0)) return 0;if(!cddaSimpleCmd(demute ? CDL_DEMUTE :CDL_MUTE)) return 0;CDROM_REG0=2;CDROM_REG2=atv[0];CDROM_REG3=atv[1];CDROM_REG0=3;CDROM_REG1=atv[2];CDROM_REG2=atv[3];CDROM_REG0=3;CDROM_REG3=0x20;CDROM_REG0=0;SPU_VOL_CD_LEFT=0x7fff;SPU_VOL_CD_RIGHT=0x7fff;SPU_CTRL=SPU_CTRL|0x8001;return 1;} static int cddaBufferPeak(unsigned *signChanges) { int peak=0;unsigned changes=0;int prev=0;for(int i=0;i< 0x200;i++) { int v=(int16_t) s_cddaCapture[i];int a=v< 0 ? -v :v;if(a > peak) peak=a;int sign=v >=0 ? 1 :-1;if(i &&sign !=prev) changes++;prev=sign;} *signChanges=changes;return peak;} static int cddaCapturePeak(unsigned *signChanges) { int peak=0;for(unsigned attempt=0;attempt< 8;attempt++) { if(attempt) { initializeTime();while(updateTime()< 250000u);} if(!cddaSpuDma(0x000, s_cddaCapture, 0x800, 1)) return -1;peak=cddaBufferPeak(signChanges);if(peak) { if(attempt) ramsyscall_printf("capture was empty %u time(s) before audio\n", attempt);break;} } return peak;} static int cddaPeak(const uint8_t atv[4], int demute, unsigned *signChanges) { if(!cddaAudioSetup(atv, demute)) return -1;if(!setMode(0)) return -1;CDROM_REG0=0;CDROM_REG2=0x02;if(!cddaSimpleCmd(CDL_PLAY)) return -1;initializeTime();while(updateTime()< 1500000u);int peak=cddaCapturePeak(signChanges);CDROM_REG0=0;CDROM_REG1=CDL_PAUSE;cddaWaitPauseComplete();CDROM_REG0=0;CDROM_REG2=0x00;CDROM_REG2=0x02;CDROM_REG2=0x16;if(cddaSimpleCmd(CDL_SETLOC) &&cddaSimpleCmd(CDL_SEEKL)) cddaWaitPauseComplete();return peak;}[0x400])
Definition cdda.c:37
#define EXPECT_AR_NARROW_TALL_11_20
Definition raster-expected-phase17.h:161
#define EXPECT_AR_STRETCH_8_8
Definition raster-expected-phase17.h:120
#define EXPECT_AR_COMPRESS_30_5
Definition raster-expected-phase17.h:109
#define EXPECT_AR_AXIS_BASE_10_8
Definition raster-expected-phase17.h:95
#define EXPECT_AR_STRETCH_6_6
Definition raster-expected-phase17.h:118
#define EXPECT_AR_NARROW_TALL_11_8
Definition raster-expected-phase17.h:159
#define EXPECT_AR_FLAT_WIDE_30_9
Definition raster-expected-phase17.h:171
#define EXPECT_AR_TWIST_45_8_8
Definition raster-expected-phase17.h:141
#define EXPECT_AR_NATURAL_18_15
Definition raster-expected-phase17.h:150
#define EXPECT_AR_FLAT_WIDE_6_10
Definition raster-expected-phase17.h:172
#define EXPECT_AR_STRETCH_10_7
Definition raster-expected-phase17.h:119
#define EXPECT_AR_AXIS_BASE_25_5
Definition raster-expected-phase17.h:99
#define EXPECT_AR_NATURAL_10_18
Definition raster-expected-phase17.h:151
#define EXPECT_AR_AXIS_BASE_20_6
Definition raster-expected-phase17.h:96
#define EXPECT_AR_NATURAL_5_5
Definition raster-expected-phase17.h:152
#define EXPECT_AR_TWIST_90_10_10
Definition raster-expected-phase17.h:129
#define EXPECT_AR_TWIST_45_12_12
Definition raster-expected-phase17.h:142
#define EXPECT_AR_FLAT_WIDE_8_9
Definition raster-expected-phase17.h:169
#define EXPECT_AR_AXIS_BASE_8_12
Definition raster-expected-phase17.h:97
#define EXPECT_AR_FLAT_WIDE_20_9
Definition raster-expected-phase17.h:170
#define EXPECT_AR_NARROW_TALL_12_14
Definition raster-expected-phase17.h:160
#define EXPECT_AR_AXIS_BASE_24_5
Definition raster-expected-phase17.h:98
#define EXPECT_AR_NARROW_TALL_13_6
Definition raster-expected-phase17.h:162
#define EXPECT_AR_COMPRESS_15_10
Definition raster-expected-phase17.h:108
#define EXPECT_AR_TWIST_45_12_4
Definition raster-expected-phase17.h:139
#define EXPECT_AR_TWIST_90_10_6
Definition raster-expected-phase17.h:131
#define EXPECT_AR_COMPRESS_10_7
Definition raster-expected-phase17.h:106
#define EXPECT_AR_NATURAL_12_10
Definition raster-expected-phase17.h:149
#define EXPECT_AR_TWIST_90_4_4
Definition raster-expected-phase17.h:132
#define EXPECT_AR_TWIST_45_4_12
Definition raster-expected-phase17.h:140
#define EXPECT_AR_COMPRESS_20_8
Definition raster-expected-phase17.h:107
#define EXPECT_AR_STRETCH_5_5
Definition raster-expected-phase17.h:121
#define EXPECT_AR_TWIST_90_6_10
Definition raster-expected-phase17.h:130
#define TEX17_TY
Definition texture-fixture-phase17.h:58
#define TEX17_TPAGE
Definition texture-fixture-phase17.h:65
#define TEX17_TX
Definition texture-fixture-phase17.h:57
#define PHASE17_ASSERT_PIXEL_EQ(expected, x_, y_)
Definition texture-fixture-phase17.h:102
#define TEX17_CLUT_FIELD
Definition texture-fixture-phase17.h:66
#define TEX_MOD_NEUTRAL
Definition texture-fixtures.h:308