diff --git a/code/duffle/gte.h b/code/duffle/gte.h index 4848d4e..9ed3143 100644 --- a/code/duffle/gte.h +++ b/code/duffle/gte.h @@ -1,4 +1,4 @@ -/* ============================================================================ +/* ============================================================================ * duffle DSL Suffix Conventions * ============================================================================ * @@ -442,6 +442,7 @@ enum { _C2_TX_SUBS_ = 0 #define gte_cmdw_op (gte_cmd_base | enc_gte_cmd(gte_cmd_op )) #define gte_cmdw_mvmva (gte_cmd_base | enc_gte_cmd(gte_cmd_mvmva)) +#define gte_cmdw_rotate_translate_perspective_single gte_cmdw_rtps #define gte_cmdw_rotate_translate_perspective_triple gte_cmdw_rtpt /* PsyQ compatibility bits for AVSZ3 (Bits 20, 22, 24 must be set) */ @@ -457,6 +458,8 @@ enum { _C2_TX_SUBS_ = 0 #define gte_cmd_avsz4 0x2E #define gte_cmdw_avsz4 (gte_cmd_base | enc_gte_cmd(gte_cmd_avsz4) | gte_cmdw_psyq_avsz3_compat) +#define gte_cmdw_avg_sort_z4 gte_cmdw_avsz4 + /** * @brief Loads a single SVECTOR to GTE vector register V0 * diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index f476812..84cbc27 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -124,8 +124,8 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli * Args: off = U4 byte offset, code = GP0 cmd byte (0 for c1/c2/c3 of * a Poly_G4), r/g/b = 8-bit RGB byte values. */ #define mac_pack_color_word(off, code, r,g,b) \ - load_upper_i(R_AT, (code) << 8 | (b)) \ - , or_i_self( R_AT, ((g) << 8) | (r)) \ + load_upper_i(R_AT, (code) << 8 | (b)) \ + , or_i_self( R_AT, ((g) << 8) | (r)) \ , store_word( R_AT, R_PrimCursor, (off)) /* Words: 3; Emits the F3 command+color word (cmd byte | BLUE | GREEN | RED) @@ -134,8 +134,11 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli * convention. */ #define mac_format_f3_color(r,g,b) mac_pack_color_word(O_(Poly_F3,color), gp0_cmd_poly_f3, r,g,b) -/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the F3 */ -#define mac_gte_store_f3() \ +/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the F3. + * PIPELINE: post-RTPT (SXY0=v0.screen, SXY1=v1.screen, SXY2=v2.screen). + * The macro name declares the pipeline position; check #6 (GTE state- + * machine validation) verifies the call site matches the declaration. */ +#define mac_gte_store_f3_post_rtpt() \ gte_sw(C2_SXY0, R_PrimCursor, O_(Poly_F3,p0)) \ , gte_sw(C2_SXY1, R_PrimCursor, O_(Poly_F3,p1)) \ , gte_sw(C2_SXY2, R_PrimCursor, O_(Poly_F3,p2)) @@ -149,17 +152,32 @@ FI_ Slice_U4 tb_slice(TapeBuilder tb) { return (Sli , mac_pack_color_word(O_(Poly_G4,c3), 0, r3,g3,b3) /* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices of the - * G4 triangle portion to p0/p1/p2. Call BEFORE the V3-RTPS, otherwise - * SXY0/SXY1/SXY2 get overwritten by the perspective transform. */ -#define mac_gte_store_g4_tri() \ - gte_sw(C2_SXY0, R_PrimCursor, O_(Poly_G4,p0)) \ - , gte_sw(C2_SXY1, R_PrimCursor, O_(Poly_G4,p1)) \ + * G4 triangle portion to p0/p1/p2. + * PIPELINE: post-RTPT, pre-RTPS (SXY0=v0.screen, SXY1=v1.screen, + * SXY2=v2.screen). MUST be called BEFORE V3-RTPS, otherwise SXY0/1/2 + * get overwritten with v3 (RTPS writes only to SXY2, but to keep the + * three registers aligned with v0/v1/v2 you must store before RTPS). + * The macro name declares the pipeline position; check #6 (GTE state- + * machine validation) verifies the call site matches the declaration. */ +#define mac_gte_store_g4_p012_post_rtpt_pre_rtps() \ + gte_sw(C2_SXY0, R_PrimCursor, O_(Poly_G4,p0)) \ + , gte_sw(C2_SXY1, R_PrimCursor, O_(Poly_G4,p1)) \ , gte_sw(C2_SXY2, R_PrimCursor, O_(Poly_G4,p2)) -/* Words: 1; Stores the V3 screen coord (now in SXY2 after V3-RTPS — RTPS - * writes its result into SXY2, not SXY0) to the G4's p3 slot. - * Call AFTER the V3-RTPS. */ -#define mac_gte_store_g4_p3() gte_sw(C2_SXY2, R_PrimCursor, O_(Poly_G4,p3)) +/* Words: 1; Stores the V3 screen coord to the G4's p3 slot. + * PIPELINE: post-RTPS (SXY2 holds v3.screen because RTPS writes its + * single-vertex result to SXY2; SXY0 still holds v0.screen from the + * earlier RTPT — DO NOT read SXY0 here, that's the bug this name + * prevents). + * The macro name declares the pipeline position; check #6 (GTE state- + * machine validation) verifies the call site matches the declaration. + * + * History: this macro was named `mac_gte_store_g4_p3` until 2026-07-09 + * when it was discovered to be reading C2_SXY0 (which held v0.screen) + * instead of C2_SXY2 (which holds v3.screen after RTPS). The rename + * encodes the pipeline position in the name so the next bug of this + * class is impossible. */ +#define mac_gte_store_g4_p3_post_rtps() gte_sw(C2_SXY2, R_PrimCursor, O_(Poly_G4,p3)) #pragma endregion Macro Atom Components diff --git a/code/gte_hello/gen/hello_gte_tape.offsets.h b/code/gte_hello/gen/hello_gte_tape.offsets.h index b8ddd9f..a20fdb0 100644 --- a/code/gte_hello/gen/hello_gte_tape.offsets.h +++ b/code/gte_hello/gen/hello_gte_tape.offsets.h @@ -5,14 +5,24 @@ #pragma region hello_gte_tape -// --- atom: floor_tri (49 words) --- +// --- atom: cube_g4_face (87 words) --- -#define _atom_offset_culling_floor_tri_exit 15 -#define _atom_offset_bounds_chk_floor_tri_exit 3 +#define _atom_offset_cull_cube_g4_face_exit 48 +#define _atom_offset_bounds_chk_cube_g4_face_exit 12 enum { - atom_offset_culling_floor_tri_exit = _atom_offset_culling_floor_tri_exit, - atom_offset_bounds_chk_floor_tri_exit = _atom_offset_bounds_chk_floor_tri_exit, + atom_offset_cull_cube_g4_face_exit = _atom_offset_cull_cube_g4_face_exit, + atom_offset_bounds_chk_cube_g4_face_exit = _atom_offset_bounds_chk_cube_g4_face_exit, +}; + +// --- atom: floor_f3_face (66 words) --- + +#define _atom_offset_culling_floor_f3_face_exit 29 +#define _atom_offset_bounds_chk_floor_f3_face_exit 13 + +enum { + atom_offset_culling_floor_f3_face_exit = _atom_offset_culling_floor_f3_face_exit, + atom_offset_bounds_chk_floor_f3_face_exit = _atom_offset_bounds_chk_floor_f3_face_exit, }; #pragma endregion hello_gte_tape diff --git a/code/gte_hello/hello_gte_tape.c b/code/gte_hello/hello_gte_tape.c index 799551c..078e2b8 100644 --- a/code/gte_hello/hello_gte_tape.c +++ b/code/gte_hello/hello_gte_tape.c @@ -56,11 +56,10 @@ MipsAtom_(cube_g4_face) { load_half_u(R_T3, R_FaceCursor, 3 * S_(S2)), /* ── 2. Load V0, V1, V2 into GTE (parallel to mac_load_tri_verts) ── */ - mac_load_tri_verts(R_T0, R_T1, R_T2), /* ── 3. RTPT — transforms V0/V1/V2 → SXY0/SXY1/SXY2 + SZ1/SZ2/SZ3 ─── */ - nop2, gte_cmdw_rtpt, + nop2, gte_cmdw_rotate_translate_perspective_triple, /* ── 4. NCLIP — backface culling on SXY0/SXY1/SXY2 (p0,p1,p2) ──────── */ /* MUST be done BEFORE V3-RTPS overwrites SXY0 with p3. */ @@ -81,7 +80,7 @@ MipsAtom_(cube_g4_face) { /* c3 green */ 0x00, 0xFF, 0x00), /* ── 7. Store p0..p2 BEFORE V3-RTPS overwrites SXY0 ─────────────────── */ - mac_gte_store_g4_tri(), + mac_gte_store_g4_p012_post_rtpt_pre_rtps(), /* ── 8. Load V3 = verts[face->w] into V0 ─────────────────────────────── */ shift_lleft(R_AT, R_T3, v3s2_byteoff), add_u(R_AT, R_AT, R_VertBase), @@ -89,11 +88,11 @@ MipsAtom_(cube_g4_face) { gte_mv_to_data_r(R_V0, C2_VXY0), gte_mv_to_data_r(R_V1, C2_VZ0), /* ── 9. RTPS — transforms V0 (now V3) → SXY0 (p3) + SZ3 ─────────────── */ - nop2, gte_cmdw_rtps, - mac_gte_store_g4_p3(), + nop2, gte_cmdw_rotate_translate_perspective_single, + mac_gte_store_g4_p3_post_rtps(), /* ── 10. AVSZ4 — average Z from SZ0/SZ1/SZ2/SZ3 ─────────────────────── */ - nop2, gte_cmdw_avsz4, + nop2, gte_cmdw_avg_sort_z4, nop2, gte_mv_from_data_r(R_T1, C2_OTZ), /* ── 11. Bounds check OTZ < OrderingTbl_Len ─────────────────────────── */ @@ -154,7 +153,7 @@ MipsAtom_(floor_f3_face) { /* Format Primitive */ // mac_format_f3_color(0x20FF, 0xFFFF), // works mac_format_f3_color(0xFF, 0xFF, 0xFF), // RGB-form (R=FF, G=FF, B=FF = white) - mac_gte_store_f3(), + mac_gte_store_f3_post_rtpt(), /* Calculate Depth */ nop2, gte_avg_sort_z3, diff --git a/code/gte_hello/tape_atom.metadata.h b/code/gte_hello/tape_atom.metadata.h index 86ccba2..c6af238 100644 --- a/code/gte_hello/tape_atom.metadata.h +++ b/code/gte_hello/tape_atom.metadata.h @@ -18,10 +18,10 @@ WORD_COUNT(call_addr, 1) WORD_COUNT(branch_le_zero, 1) WORD_COUNT(branch_equal, 1) WORD_COUNT(add_ui, 1) -WORD_COUNT(set_lt_u, 1) -WORD_COUNT(set_lt_s, 1) -WORD_COUNT(set_lt_si, 1) -WORD_COUNT(set_lt_ui, 1) +WORD_COUNT(set_lt_u, 1) +WORD_COUNT(set_lt_s, 1) +WORD_COUNT(set_lt_si, 1) +WORD_COUNT(set_lt_ui, 1) WORD_COUNT(load_word, 1) WORD_COUNT(load_half_u, 1) WORD_COUNT(store_word, 1) @@ -37,7 +37,7 @@ WORD_COUNT(shift_lleft_self, 1) WORD_COUNT(shift_lright, 1) WORD_COUNT(shift_aright, 1) WORD_COUNT(mask_upper, 2) -WORD_COUNT(gte_mv_from_data_r, 1) +WORD_COUNT(gte_mv_from_data_r, 1) WORD_COUNT(gte_mv_from_ctrl_r, 1) WORD_COUNT(gte_mv_to_data_r, 1) WORD_COUNT(gte_mv_to_ctrl_r, 1) @@ -50,11 +50,11 @@ WORD_COUNT(nop2, 2) WORD_COUNT(mac_load_tri_indices, 3) WORD_COUNT(mac_load_tri_verts, 18) WORD_COUNT(mac_format_f3_color, 3) -WORD_COUNT(mac_gte_store_f3, 3) +WORD_COUNT(mac_gte_store_f3_post_rtpt, 3) WORD_COUNT(mac_pack_color_word, 3) WORD_COUNT(mac_format_g4_color, 12) -WORD_COUNT(mac_gte_store_g4_tri, 3) -WORD_COUNT(mac_gte_store_g4_p3, 1) +WORD_COUNT(mac_gte_store_g4_p012_post_rtpt_pre_rtps, 3) +WORD_COUNT(mac_gte_store_g4_p3_post_rtps, 1) WORD_COUNT(mac_insert_ot_tag, 11) WORD_COUNT(mac_yield, 4)