Skip to main content
← PSoXide SDK guides and examples · SDK f2fec1c301f1 · All Cargo features enabled; check feature gates before use.

psx_gpu/
compat.rs

1//! Free functions from before [`crate::Gpu`], kept for one stage so games
2//! that have not repinned keep compiling. Each forwards to the code the
3//! driver method runs; `sdk/docs/MIGRATION-psx-gpu.md` lists the
4//! replacements and every downstream call site.
5
6#![allow(
7    deprecated,
8    reason = "the forwarders use the deprecated types they kept"
9)]
10
11use crate::display::{DisplayConfig, Resolution, VideoMode};
12use crate::gpu;
13use crate::material::{BlendMode, TextureMaterial};
14use crate::prim::{
15    FillRect, LineMono, QuadFlat, QuadTexturedGouraud, QuadTexturedMaterial, Sprite, TriFlat,
16    TriGouraud,
17};
18use psx_io::timers;
19
20/// Initialise the GPU: reset, display mode, display window, DMA direction,
21/// display on.
22#[deprecated(note = "use `Gpu::new(dma, DisplayConfig::new(mode, res))`")]
23#[doc(alias = "ResetGraph")]
24pub fn init(mode: VideoMode, res: Resolution) {
25    gpu::reset(DisplayConfig::new(mode, res));
26}
27
28/// Block until the GPU has finished drawing everything sent to it.
29#[deprecated(note = "use `Gpu::wait_idle`")]
30#[doc(alias = "DrawSync")]
31#[inline]
32pub fn wait_idle() {
33    crate::wait_idle_impl();
34}
35
36/// Renamed to `Gpu::wait_idle`.
37#[deprecated(note = "use `Gpu::wait_idle`")]
38#[inline(always)]
39pub fn draw_sync() {
40    crate::wait_idle_impl();
41}
42
43/// Clear GPUSTAT bit 24 with GP1(02h).
44#[deprecated(note = "use `Gpu::arm_draw_done`")]
45#[inline]
46pub fn arm_draw_done() {
47    psx_io::gpu::write_display_control(psx_hw::gpu::gp1::ACK_IRQ);
48}
49
50/// Send GP0(1Fh) through the command port.
51#[deprecated(note = "use `Gpu::signal_draw_done`")]
52#[inline]
53pub fn signal_draw_done() {
54    psx_io::gpu::wait_command_ready();
55    psx_io::gpu::write_command(psx_hw::gpu::gp0::REQUEST_IRQ);
56}
57
58/// Set the drawing-area rectangle.
59#[deprecated(note = "use `Gpu::set_draw_area`")]
60pub fn set_draw_area(x0: u16, y0: u16, x1: u16, y1: u16) {
61    gpu::set_draw_area((x0, y0), (x1, y1));
62}
63
64/// Set the drawing offset.
65#[deprecated(note = "use `Gpu::set_draw_offset`")]
66pub fn set_draw_offset(x: i16, y: i16) {
67    gpu::set_draw_offset((x, y));
68}
69
70/// Fill a VRAM rectangle with a solid color.
71#[deprecated(note = "use `gpu.draw(&FillRect::new(origin, size, color))`")]
72pub fn fill_rect(x: u16, y: u16, w: u16, h: u16, r: u8, g: u8, b: u8) {
73    gpu::draw(&FillRect::new((x, y), (w, h), (r, g, b)));
74}
75
76/// Draw a flat-shaded triangle.
77#[deprecated(note = "use `gpu.draw(&TriFlat::new(..))`")]
78pub fn draw_tri_flat(verts: [(i16, i16); 3], r: u8, g: u8, b: u8) {
79    gpu::draw(&TriFlat::new(verts, r, g, b));
80}
81
82/// Draw a semi-transparent flat-shaded triangle.
83#[deprecated(
84    note = "use `gpu.set_draw_mode(material)` and `gpu.draw(&TriFlat::new(..).translucent())`"
85)]
86pub fn draw_tri_flat_blended(verts: [(i16, i16); 3], r: u8, g: u8, b: u8, blend_mode: BlendMode) {
87    if !blend_mode.is_translucent() {
88        gpu::draw(&TriFlat::new(verts, r, g, b));
89        return;
90    }
91    gpu::set_draw_mode(TextureMaterial::blended(0, 0, (r, g, b), blend_mode));
92    gpu::draw(&TriFlat::new(verts, r, g, b).translucent());
93}
94
95/// Draw a Gouraud-shaded triangle.
96#[deprecated(note = "use `gpu.draw(&TriGouraud::new(..))`")]
97pub fn draw_tri_gouraud(verts: [(i16, i16); 3], colors: [(u8, u8, u8); 3]) {
98    gpu::draw(&TriGouraud::new(verts, colors));
99}
100
101/// Draw a monochrome line.
102#[deprecated(note = "use `gpu.draw(&LineMono::new(..))`")]
103pub fn draw_line_mono(x0: i16, y0: i16, x1: i16, y1: i16, r: u8, g: u8, b: u8) {
104    gpu::draw(&LineMono::new(x0, y0, x1, y1, r, g, b));
105}
106
107/// Fill an axis-aligned rectangle with a flat color, as a polygon.
108#[deprecated(note = "use `gpu.draw(&QuadFlat::rect(origin, size, color))`")]
109pub fn draw_rect_flat(x: i16, y: i16, w: u16, h: u16, r: u8, g: u8, b: u8) {
110    gpu::draw(&QuadFlat::rect((x, y), (w, h), (r, g, b)));
111}
112
113/// Draw a flat-shaded quad.
114#[deprecated(note = "use `gpu.draw(&QuadFlat::new(..))`")]
115pub fn draw_quad_flat(verts: [(i16, i16); 4], r: u8, g: u8, b: u8) {
116    gpu::draw(&QuadFlat::new(verts, r, g, b));
117}
118
119/// Draw a textured quad with a single tint.
120#[deprecated(note = "use `gpu.draw(&QuadTexturedMaterial::with_material(..))`")]
121pub fn draw_quad_textured(
122    verts: [(i16, i16); 4],
123    uvs: [(u8, u8); 4],
124    clut_word: u16,
125    tpage_word: u16,
126    tint: (u8, u8, u8),
127) {
128    let material = TextureMaterial::opaque(clut_word, tpage_word, tint);
129    gpu::draw(&QuadTexturedMaterial::with_material(verts, uvs, material));
130}
131
132/// Draw a textured quad using a [`TextureMaterial`].
133#[deprecated(note = "use `gpu.draw(&QuadTexturedMaterial::with_material(..))`")]
134pub fn draw_quad_textured_material(
135    verts: [(i16, i16); 4],
136    uvs: [(u8, u8); 4],
137    material: TextureMaterial,
138) {
139    gpu::draw(&QuadTexturedMaterial::with_material(verts, uvs, material));
140}
141
142/// Draw a Gouraud-shaded textured quad using a [`TextureMaterial`].
143#[deprecated(note = "use `gpu.draw(&QuadTexturedGouraud::with_material(..))`")]
144pub fn draw_quad_textured_gouraud_material(
145    verts: [(i16, i16); 4],
146    uvs: [(u8, u8); 4],
147    colors: [(u8, u8, u8); 4],
148    material: TextureMaterial,
149) {
150    gpu::draw(&QuadTexturedGouraud::with_material(
151        verts, uvs, colors, material,
152    ));
153}
154
155/// Draw a variable-size textured sprite using a [`TextureMaterial`].
156#[deprecated(note = "use `gpu.set_draw_mode(material)` and `gpu.draw(&Sprite::with_material(..))`")]
157pub fn draw_sprite_material(
158    x: i16,
159    y: i16,
160    w: u16,
161    h: u16,
162    uv: (u8, u8),
163    material: TextureMaterial,
164) {
165    gpu::set_draw_mode(material);
166    gpu::draw(&Sprite::with_material(x, y, w, h, uv, material));
167}
168
169/// Program Timer 1 to count HBlanks, reset at VBlank.
170///
171/// Writing a timer's mode register resets its counter, so every call
172/// restarts the count from zero.
173fn configure_scanline_timer() {
174    use psx_hw::timers::mode;
175    timers::set_mode(
176        timers::Timer::Timer1,
177        mode::SYNC_ENABLE | mode::sync_mode(1) | mode::clock_source(1),
178    );
179}
180
181/// Wait 242 HBlank periods (~15.4ms) from the moment of the call.
182///
183/// Despite the name, this does NOT sync to the display: reconfiguring
184/// Timer 1 resets its counter, so the wait starts from zero at the call
185/// site. Frame time becomes `work + 15.4ms` instead of snapping to the
186/// next VBlank -- nearly right for light frames, badly slow for heavy
187/// ones. It cannot be repaired here: syncing needs the VBlank IRQ, which
188/// the runtime owns.
189#[deprecated(note = "busy-waits a fixed 242 HBlanks from the call site instead of \
190            syncing to the display; use psx_rt::interrupts::wait_vblank()")]
191pub fn vsync() {
192    configure_scanline_timer();
193    while timers::counter(timers::Timer::Timer1) < 242 {}
194}
195
196/// Kick a linked-list chain without waiting for the walk.
197///
198/// # Safety
199///
200/// As [`crate::chain::submit_async_raw`].
201#[deprecated(note = "use `chain::submit_async_raw`, which takes the `GpuDma` token")]
202#[doc(alias = "DrawOTag")]
203#[inline(always)]
204pub unsafe fn submit_linked_list_async_raw(head: *const u32) {
205    // SAFETY: forwarded contract.
206    unsafe { crate::chain::start_walk(head) }
207}
208
209/// Renamed to [`submit_linked_list_async_raw`].
210///
211/// # Safety
212///
213/// As [`crate::chain::submit_async_raw`].
214#[deprecated(note = "use `chain::submit_async_raw`, which takes the `GpuDma` token")]
215#[inline(always)]
216pub unsafe fn submit_linked_list_raw_async(head: *const u32) {
217    // SAFETY: forwarded contract.
218    unsafe { crate::chain::start_walk(head) }
219}
220
221/// Old name of [`submit_linked_list_async_raw`].
222///
223/// # Safety
224///
225/// As [`crate::chain::submit_async_raw`].
226#[deprecated(
227    note = "use `OrderingTable::frame`, `Gpu::submit_static`, or the unsafe `chain::submit_async_raw`"
228)]
229#[inline(always)]
230pub unsafe fn submit_linked_list_async(head: *const u32) {
231    // SAFETY: forwarded contract.
232    unsafe { crate::chain::start_walk(head) }
233}
234
235/// Kick a linked-list chain and wait for the walk.
236///
237/// # Safety
238///
239/// As [`crate::chain::submit_raw`].
240#[deprecated(note = "use `chain::submit_raw`, which takes the `GpuDma` token")]
241#[doc(alias = "DrawOTag")]
242#[inline(always)]
243pub unsafe fn submit_linked_list_raw(head: *const u32) {
244    // SAFETY: forwarded contract; the wait ends the walk before return.
245    unsafe { crate::chain::start_walk(head) };
246    crate::chain::wait_walk();
247}
248
249/// Wait until the linked-list walk kicked last has finished.
250#[deprecated(note = "use `chain::wait`, which takes the `GpuDma` token")]
251#[inline(always)]
252pub fn submit_linked_list_wait() {
253    crate::chain::wait_walk();
254}
255
256/// Each forwarder now sends a packet's payload; these tests check that
257/// payload against the word sequence the free function wrote before it
258/// forwarded, taken from its old body.
259#[cfg(test)]
260mod tests {
261    use super::*;
262    use crate::material::TextureWindow;
263    use crate::prim::{GpuPacket, LineGouraud};
264    use psx_hw::gpu::{gp0, pack_color, pack_texcoord, pack_vertex, pack_xy};
265
266    fn payload<P: GpuPacket>(packet: &P) -> &[u32] {
267        // SAFETY: `GpuPacket` promises a tag word, then `WORDS` initialised
268        // `u32`s, inside `packet`, which outlives the slice.
269        unsafe {
270            core::slice::from_raw_parts(
271                core::ptr::from_ref(packet).cast::<u32>().add(1),
272                P::WORDS as usize,
273            )
274        }
275    }
276
277    const VERTS3: [(i16, i16); 3] = [(1, -2), (300, 4), (-5, 239)];
278    const VERTS4: [(i16, i16); 4] = [(1, 2), (100, 3), (4, 90), (101, 91)];
279    const UVS4: [(u8, u8); 4] = [(0, 1), (63, 2), (4, 255), (200, 100)];
280    const COLORS4: [(u8, u8, u8); 4] = [(1, 2, 3), (40, 50, 60), (70, 80, 90), (255, 0, 128)];
281
282    fn material() -> TextureMaterial {
283        TextureMaterial::blended(0x1234, 0x0105, (90, 100, 110), BlendMode::Add)
284            .with_texture_window(TextureWindow::new(1, 2, 3, 4))
285    }
286
287    #[test]
288    fn fill_rect_matches_the_old_words() {
289        let old = [gp0::fill_rect(9, 8, 7), pack_xy(16, 32), pack_xy(320, 240)];
290        assert_eq!(
291            payload(&FillRect::new((16, 32), (320, 240), (9, 8, 7))),
292            old
293        );
294    }
295
296    #[test]
297    fn flat_and_gouraud_triangles_match_the_old_words() {
298        let flat = [
299            gp0::polygon_opcode(false, false, false, false, false) | pack_color(9, 8, 7),
300            pack_vertex(1, -2),
301            pack_vertex(300, 4),
302            pack_vertex(-5, 239),
303        ];
304        assert_eq!(payload(&TriFlat::new(VERTS3, 9, 8, 7)), flat);
305        let blended_op = gp0::polygon_opcode(false, false, false, true, false);
306        assert_eq!(
307            payload(&TriFlat::new(VERTS3, 9, 8, 7).translucent())[0],
308            blended_op | pack_color(9, 8, 7)
309        );
310
311        let colors = [(1, 2, 3), (4, 5, 6), (7, 8, 9)];
312        let gouraud = [
313            gp0::polygon_opcode(true, false, false, false, false) | pack_color(1, 2, 3),
314            pack_vertex(1, -2),
315            pack_color(4, 5, 6),
316            pack_vertex(300, 4),
317            pack_color(7, 8, 9),
318            pack_vertex(-5, 239),
319        ];
320        assert_eq!(payload(&TriGouraud::new(VERTS3, colors)), gouraud);
321        assert_eq!(
322            payload(&TriGouraud::new(VERTS3, colors).translucent())[0],
323            gp0::polygon_opcode(true, false, false, true, false) | pack_color(1, 2, 3)
324        );
325    }
326
327    #[test]
328    fn lines_match_the_old_words() {
329        let mono = [
330            0x4000_0000 | pack_color(9, 8, 7),
331            pack_vertex(1, 2),
332            pack_vertex(3, 4),
333        ];
334        assert_eq!(payload(&LineMono::new(1, 2, 3, 4, 9, 8, 7)), mono);
335        assert_eq!(
336            payload(&LineMono::new(1, 2, 3, 4, 9, 8, 7).translucent())[0],
337            0x4200_0000 | pack_color(9, 8, 7)
338        );
339        let gouraud = [
340            0x5000_0000 | pack_color(1, 2, 3),
341            pack_vertex(-1, 2),
342            pack_color(4, 5, 6),
343            pack_vertex(3, -4),
344        ];
345        assert_eq!(
346            payload(&LineGouraud::new((-1, 2), (1, 2, 3), (3, -4), (4, 5, 6))),
347            gouraud
348        );
349    }
350
351    #[test]
352    fn flat_quads_and_rects_match_the_old_words() {
353        let quad = [
354            gp0::polygon_opcode(false, true, false, false, false) | pack_color(9, 8, 7),
355            pack_vertex(1, 2),
356            pack_vertex(100, 3),
357            pack_vertex(4, 90),
358            pack_vertex(101, 91),
359        ];
360        assert_eq!(payload(&QuadFlat::new(VERTS4, 9, 8, 7)), quad);
361        // draw_rect_flat: corners (x, y), (x + w, y), (x, y + h), (x + w, y + h).
362        let rect = QuadFlat::new([(10, 20), (50, 20), (10, 25), (50, 25)], 1, 2, 3);
363        assert_eq!(QuadFlat::rect((10, 20), (40, 5), (1, 2, 3)), rect);
364    }
365
366    #[test]
367    fn textured_packets_match_the_old_words() {
368        let m = material();
369        let quad = [
370            m.texture_window_word(),
371            m.flat_textured_polygon_header(true),
372            pack_vertex(1, 2),
373            pack_texcoord(0, 1, m.clut_word()),
374            pack_vertex(100, 3),
375            pack_texcoord(63, 2, m.texture_page_word()),
376            pack_vertex(4, 90),
377            pack_texcoord(4, 255, 0),
378            pack_vertex(101, 91),
379            pack_texcoord(200, 100, 0),
380        ];
381        assert_eq!(
382            payload(&QuadTexturedMaterial::with_material(VERTS4, UVS4, m)),
383            quad
384        );
385
386        let c = COLORS4;
387        let gouraud = [
388            m.texture_window_word(),
389            m.textured_polygon_command(true, true) | pack_color(c[0].0, c[0].1, c[0].2),
390            pack_vertex(1, 2),
391            pack_texcoord(0, 1, m.clut_word()),
392            pack_color(c[1].0, c[1].1, c[1].2),
393            pack_vertex(100, 3),
394            pack_texcoord(63, 2, m.texture_page_word()),
395            pack_color(c[2].0, c[2].1, c[2].2),
396            pack_vertex(4, 90),
397            pack_texcoord(4, 255, 0),
398            pack_color(c[3].0, c[3].1, c[3].2),
399            pack_vertex(101, 91),
400            pack_texcoord(200, 100, 0),
401        ];
402        assert_eq!(
403            payload(&QuadTexturedGouraud::with_material(VERTS4, UVS4, c, m)),
404            gouraud
405        );
406
407        let sprite = [
408            m.textured_rect_header(),
409            pack_vertex(-3, 4),
410            pack_texcoord(5, 6, m.clut_word()),
411            pack_xy(16, 24),
412        ];
413        assert_eq!(
414            payload(&Sprite::with_material(-3, 4, 16, 24, (5, 6), m)),
415            sprite
416        );
417    }
418}