Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
stride-sweep.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-18 affine UV stride-magnitude sweep. Six triangles, identical
28// 10x10 screen footprint, varying K controls the per-axis UV stride:
29//
30// T_AXIS_K: A=(5, 5)/(0, 0) B=(15, 5)/(K, 0) C=(5, 15)/(0, K)
31//
32// Per-axis stride is K/10 (equal for U and V). K covers a wide range so
33// the hardware-sampled (u, v) plotted against K reveals which bias
34// model the GPU implements. Five probes per K, identical screen
35// positions across all K.
36
37// clang-format off
38
40
41// ---- T_AXIS_K01: dU/dx = dV/dy = 0.1 (very compressed) -----------------
42static void drawT_AXIS_K01(void) {
43 rasterReset();
44 rasterClearTestRegion(0, 0, 24, 16);
45 setTexpage(TEX17_TX, TEX17_TY, 2);
46 setTextureWindow(0, 0, 0, 0);
47 rasterTexTri(TEX_MOD_NEUTRAL,
48 5, 5, 0, 0,
49 15, 5, 1, 0,
50 5, 15, 0, 1,
52 rasterFlushPrimitive();
53}
54
55// ---- T_AXIS_K02: dU/dx = dV/dy = 0.2 ----------------------------------
56static void drawT_AXIS_K02(void) {
57 rasterReset();
58 rasterClearTestRegion(0, 0, 24, 16);
59 setTexpage(TEX17_TX, TEX17_TY, 2);
60 setTextureWindow(0, 0, 0, 0);
61 rasterTexTri(TEX_MOD_NEUTRAL,
62 5, 5, 0, 0,
63 15, 5, 2, 0,
64 5, 15, 0, 2,
66 rasterFlushPrimitive();
67}
68
69// ---- T_AXIS_K03: dU/dx = dV/dy = 0.3 ----------------------------------
70static void drawT_AXIS_K03(void) {
71 rasterReset();
72 rasterClearTestRegion(0, 0, 24, 16);
73 setTexpage(TEX17_TX, TEX17_TY, 2);
74 setTextureWindow(0, 0, 0, 0);
75 rasterTexTri(TEX_MOD_NEUTRAL,
76 5, 5, 0, 0,
77 15, 5, 3, 0,
78 5, 15, 0, 3,
80 rasterFlushPrimitive();
81}
82
83// ---- T_AXIS_K05: dU/dx = dV/dy = 0.5 (right at the half-step boundary) -
84static void drawT_AXIS_K05(void) {
85 rasterReset();
86 rasterClearTestRegion(0, 0, 24, 16);
87 setTexpage(TEX17_TX, TEX17_TY, 2);
88 setTextureWindow(0, 0, 0, 0);
89 rasterTexTri(TEX_MOD_NEUTRAL,
90 5, 5, 0, 0,
91 15, 5, 5, 0,
92 5, 15, 0, 5,
94 rasterFlushPrimitive();
95}
96
97// ---- T_AXIS_K08: dU/dx = dV/dy = 0.8 (near 1:1) ------------------------
98static void drawT_AXIS_K08(void) {
99 rasterReset();
100 rasterClearTestRegion(0, 0, 24, 16);
101 setTexpage(TEX17_TX, TEX17_TY, 2);
102 setTextureWindow(0, 0, 0, 0);
103 rasterTexTri(TEX_MOD_NEUTRAL,
104 5, 5, 0, 0,
105 15, 5, 8, 0,
106 5, 15, 0, 8,
108 rasterFlushPrimitive();
109}
110
111// ---- T_AXIS_K16: dU/dx = dV/dy = 1.6 (stretched) -----------------------
112static void drawT_AXIS_K16(void) {
113 rasterReset();
114 rasterClearTestRegion(0, 0, 24, 16);
115 setTexpage(TEX17_TX, TEX17_TY, 2);
116 setTextureWindow(0, 0, 0, 0);
117 rasterTexTri(TEX_MOD_NEUTRAL,
118 5, 5, 0, 0,
119 15, 5, 16, 0,
120 5, 15, 0, 16,
122 rasterFlushPrimitive();
123}
124
125) // CESTER_BODY
126
127// --------------------------------------------------------------------------
128// K=1 probes (stride = 0.1 per axis)
129// --------------------------------------------------------------------------
130
131CESTER_TEST(ar_axis_k01_vertex, gpu_raster_phase18,
132 drawT_AXIS_K01();
134)
135
136CESTER_TEST(ar_axis_k01_top_near, gpu_raster_phase18,
137 drawT_AXIS_K01();
139)
140
141CESTER_TEST(ar_axis_k01_left_near, gpu_raster_phase18,
142 drawT_AXIS_K01();
144)
145
146CESTER_TEST(ar_axis_k01_interior, gpu_raster_phase18,
147 drawT_AXIS_K01();
149)
150
151CESTER_TEST(ar_axis_k01_top_far, gpu_raster_phase18,
152 drawT_AXIS_K01();
154)
155
156// --------------------------------------------------------------------------
157// K=2 probes (stride = 0.2 per axis)
158// --------------------------------------------------------------------------
159
160CESTER_TEST(ar_axis_k02_vertex, gpu_raster_phase18,
161 drawT_AXIS_K02();
163)
164
165CESTER_TEST(ar_axis_k02_top_near, gpu_raster_phase18,
166 drawT_AXIS_K02();
168)
169
170CESTER_TEST(ar_axis_k02_left_near, gpu_raster_phase18,
171 drawT_AXIS_K02();
173)
174
175CESTER_TEST(ar_axis_k02_interior, gpu_raster_phase18,
176 drawT_AXIS_K02();
178)
179
180CESTER_TEST(ar_axis_k02_top_far, gpu_raster_phase18,
181 drawT_AXIS_K02();
183)
184
185// --------------------------------------------------------------------------
186// K=3 probes (stride = 0.3 per axis)
187// --------------------------------------------------------------------------
188
189CESTER_TEST(ar_axis_k03_vertex, gpu_raster_phase18,
190 drawT_AXIS_K03();
192)
193
194CESTER_TEST(ar_axis_k03_top_near, gpu_raster_phase18,
195 drawT_AXIS_K03();
197)
198
199CESTER_TEST(ar_axis_k03_left_near, gpu_raster_phase18,
200 drawT_AXIS_K03();
202)
203
204CESTER_TEST(ar_axis_k03_interior, gpu_raster_phase18,
205 drawT_AXIS_K03();
207)
208
209CESTER_TEST(ar_axis_k03_top_far, gpu_raster_phase18,
210 drawT_AXIS_K03();
212)
213
214// --------------------------------------------------------------------------
215// K=5 probes (stride = 0.5 per axis - right at the half-step boundary)
216// --------------------------------------------------------------------------
217
218CESTER_TEST(ar_axis_k05_vertex, gpu_raster_phase18,
219 drawT_AXIS_K05();
221)
222
223CESTER_TEST(ar_axis_k05_top_near, gpu_raster_phase18,
224 drawT_AXIS_K05();
226)
227
228CESTER_TEST(ar_axis_k05_left_near, gpu_raster_phase18,
229 drawT_AXIS_K05();
231)
232
233CESTER_TEST(ar_axis_k05_interior, gpu_raster_phase18,
234 drawT_AXIS_K05();
236)
237
238CESTER_TEST(ar_axis_k05_top_far, gpu_raster_phase18,
239 drawT_AXIS_K05();
241)
242
243// --------------------------------------------------------------------------
244// K=8 probes (stride = 0.8 per axis - near 1:1)
245// --------------------------------------------------------------------------
246
247CESTER_TEST(ar_axis_k08_vertex, gpu_raster_phase18,
248 drawT_AXIS_K08();
250)
251
252CESTER_TEST(ar_axis_k08_top_near, gpu_raster_phase18,
253 drawT_AXIS_K08();
255)
256
257CESTER_TEST(ar_axis_k08_left_near, gpu_raster_phase18,
258 drawT_AXIS_K08();
260)
261
262CESTER_TEST(ar_axis_k08_interior, gpu_raster_phase18,
263 drawT_AXIS_K08();
265)
266
267CESTER_TEST(ar_axis_k08_top_far, gpu_raster_phase18,
268 drawT_AXIS_K08();
270)
271
272// --------------------------------------------------------------------------
273// K=16 probes (stride = 1.6 per axis - stretched)
274// --------------------------------------------------------------------------
275
276CESTER_TEST(ar_axis_k16_vertex, gpu_raster_phase18,
277 drawT_AXIS_K16();
279)
280
281CESTER_TEST(ar_axis_k16_top_near, gpu_raster_phase18,
282 drawT_AXIS_K16();
284)
285
286CESTER_TEST(ar_axis_k16_left_near, gpu_raster_phase18,
287 drawT_AXIS_K16();
289)
290
291CESTER_TEST(ar_axis_k16_interior, gpu_raster_phase18,
292 drawT_AXIS_K16();
294)
295
296CESTER_TEST(ar_axis_k16_top_far, gpu_raster_phase18,
297 drawT_AXIS_K16();
299)
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_K01_LEFT_NEAR
Definition raster-expected-phase18.h:87
#define EXPECT_K05_VERTEX
Definition raster-expected-phase18.h:130
#define EXPECT_K05_TOP_NEAR
Definition raster-expected-phase18.h:131
#define EXPECT_K16_LEFT_NEAR
Definition raster-expected-phase18.h:162
#define EXPECT_K08_TOP_NEAR
Definition raster-expected-phase18.h:146
#define EXPECT_K01_TOP_NEAR
Definition raster-expected-phase18.h:86
#define EXPECT_K08_LEFT_NEAR
Definition raster-expected-phase18.h:147
#define EXPECT_K16_INTERIOR
Definition raster-expected-phase18.h:163
#define EXPECT_K03_INTERIOR
Definition raster-expected-phase18.h:118
#define EXPECT_K03_LEFT_NEAR
Definition raster-expected-phase18.h:117
#define EXPECT_K16_VERTEX
Definition raster-expected-phase18.h:160
#define EXPECT_K02_INTERIOR
Definition raster-expected-phase18.h:103
#define EXPECT_K05_TOP_FAR
Definition raster-expected-phase18.h:134
#define EXPECT_K02_TOP_NEAR
Definition raster-expected-phase18.h:101
#define EXPECT_K02_TOP_FAR
Definition raster-expected-phase18.h:104
#define EXPECT_K01_VERTEX
Definition raster-expected-phase18.h:85
#define EXPECT_K03_VERTEX
Definition raster-expected-phase18.h:115
#define EXPECT_K08_VERTEX
Definition raster-expected-phase18.h:145
#define EXPECT_K08_INTERIOR
Definition raster-expected-phase18.h:148
#define EXPECT_K02_LEFT_NEAR
Definition raster-expected-phase18.h:102
#define EXPECT_K03_TOP_NEAR
Definition raster-expected-phase18.h:116
#define EXPECT_K02_VERTEX
Definition raster-expected-phase18.h:100
#define EXPECT_K08_TOP_FAR
Definition raster-expected-phase18.h:149
#define EXPECT_K01_TOP_FAR
Definition raster-expected-phase18.h:89
#define EXPECT_K16_TOP_NEAR
Definition raster-expected-phase18.h:161
#define EXPECT_K03_TOP_FAR
Definition raster-expected-phase18.h:119
#define EXPECT_K05_LEFT_NEAR
Definition raster-expected-phase18.h:132
#define EXPECT_K05_INTERIOR
Definition raster-expected-phase18.h:133
#define EXPECT_K16_TOP_FAR
Definition raster-expected-phase18.h:164
#define EXPECT_K01_INTERIOR
Definition raster-expected-phase18.h:88
#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