reducing cross product atom procs to a single one in gte for once.

This commit is contained in:
ed
2026-08-17 01:05:58 -04:00
parent 18b1d5a04b
commit e79c364b40
8 changed files with 128 additions and 186 deletions
+21
View File
@@ -171,18 +171,27 @@ WORD_COUNT(mac_load_word_imm, 2)
, shift_aright(dt_z, dt_z, shift_amount) , shift_aright(dt_z, dt_z, shift_amount)
WORD_COUNT(mac_shift_aright_v3_self, 3) WORD_COUNT(mac_shift_aright_v3_self, 3)
#define mac_shift_aright_v3s4_self(dt, shift) \
mac_shift_aright_v3_self(dt.x, dt.y, dt.z, shift)
WORD_COUNT(mac_shift_aright_v3s4_self, 3)
#define mac_shift_aright_var_v3(rd_v0, rd_v1, rd_v2, rs_v0, rs_v1, rs_v2, r_shift) \ #define mac_shift_aright_var_v3(rd_v0, rd_v1, rd_v2, rs_v0, rs_v1, rs_v2, r_shift) \
shift_aright_var(rd_v0, rs_v0, r_shift) \ shift_aright_var(rd_v0, rs_v0, r_shift) \
, shift_aright_var(rd_v1, rs_v1, r_shift) \ , shift_aright_var(rd_v1, rs_v1, r_shift) \
, shift_aright_var(rd_v2, rs_v2, r_shift) , shift_aright_var(rd_v2, rs_v2, r_shift)
WORD_COUNT(mac_shift_aright_var_v3, 3) WORD_COUNT(mac_shift_aright_var_v3, 3)
/* atom_dbg_skip */
#define mac_shift_aright_var_v3_self(rds_v0, rds_v1, rds_v2, r_shift) \ #define mac_shift_aright_var_v3_self(rds_v0, rds_v1, rds_v2, r_shift) \
shift_aright_var(rds_v0, rds_v0, r_shift) \ shift_aright_var(rds_v0, rds_v0, r_shift) \
, shift_aright_var(rds_v1, rds_v1, r_shift) \ , shift_aright_var(rds_v1, rds_v1, r_shift) \
, shift_aright_var(rds_v2, rds_v2, r_shift) , shift_aright_var(rds_v2, rds_v2, r_shift)
WORD_COUNT(mac_shift_aright_var_v3_self, 3) WORD_COUNT(mac_shift_aright_var_v3_self, 3)
#define mac_shift_aright_var_v3s4_self(ds, shift) \
mac_shift_aright_var_v3_self(ds.x, ds.y, ds.z, shift)
WORD_COUNT(mac_shift_aright_var_v3s4_self, 3)
/* atom_dbg_skip */ /* atom_dbg_skip */
#define mac_load_tri_indices(r_face_cusor, r_i0, r_i1, r_i2) \ #define mac_load_tri_indices(r_face_cusor, r_i0, r_i1, r_i2) \
load_half_u(r_i0, r_face_cusor, 0 * S_(S2)) \ load_half_u(r_i0, r_face_cusor, 0 * S_(S2)) \
@@ -190,6 +199,18 @@ WORD_COUNT(mac_shift_aright_var_v3_self, 3)
, load_half_u(r_i2, r_face_cusor, 2 * S_(S2)) , load_half_u(r_i2, r_face_cusor, 2 * S_(S2))
WORD_COUNT(mac_load_tri_indices, 3) WORD_COUNT(mac_load_tri_indices, 3)
#define mac_gte_mv_to_cr_diag_v3s4(v) \
gte_mv_to_ctrl_r(v.y, gte_cr_RT13) \
, gte_mv_to_ctrl_r(v.z, gte_cr_RT22) \
, gte_mv_to_ctrl_r(v.x, gte_cr_RT11)
WORD_COUNT(mac_gte_mv_to_cr_diag_v3s4, 3)
#define mac_gte_ld_ir123_v3s4(v) \
gte_mv_to_data_r(v.x, C2_IR1) \
, gte_mv_to_data_r(v.y, C2_IR2) \
, gte_mv_to_data_r(v.z, C2_IR3)
WORD_COUNT(mac_gte_ld_ir123_v3s4, 3)
/* atom_dbg_skip */ /* atom_dbg_skip */
#define mac_gte_store_f3(r_primitive_cursor) \ #define mac_gte_store_f3(r_primitive_cursor) \
gte_sw(C2_SXY0, r_primitive_cursor, O_(Poly_F3,p0)) \ gte_sw(C2_SXY0, r_primitive_cursor, O_(Poly_F3,p0)) \
+41
View File
@@ -18,6 +18,18 @@ atom_dbg_skip MipsAtomComp_Proc_(ab, {
load_half_u(r_i2, r_face_cusor, 2 * S_(S2)), load_half_u(r_i2, r_face_cusor, 2 * S_(S2)),
}) })
FI_ Slice_MipsCode ac_gte_mv_to_cr_diag_v3s4(AtomBuilder_R ab, Reg_(V3_S4) v) MipsAtomComp_Proc_(ab, {
gte_mv_to_ctrl_r(v.y, gte_cr_RT13),
gte_mv_to_ctrl_r(v.z, gte_cr_RT22),
gte_mv_to_ctrl_r(v.x, gte_cr_RT11),
})
FI_ Slice_MipsCode ac_gte_ld_ir123_v3s4(AtomBuilder_R ab, Reg_(V3_S4) v) MipsAtomComp_Proc_(ab, {
gte_mv_to_data_r(v.x, C2_IR1),
gte_mv_to_data_r(v.y, C2_IR2),
gte_mv_to_data_r(v.z, C2_IR3),
})
/* Words: 3; Stores the 3 transformed (V2_S2 screen) vertices to the 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). */ * PIPELINE: post-RTPT (SXY0=v0.screen, SXY1=v1.screen, SXY2=v2.screen). */
FI_ Slice_MipsCode ac_gte_store_f3(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ab, { FI_ Slice_MipsCode ac_gte_store_f3(AtomBuilder_R ab, U4 r_primitive_cursor) atom_dbg_skip MipsAtomComp_Proc_(ab, {
@@ -319,6 +331,35 @@ MipsAtom_Proc_(aa, {
mac_yield() mac_yield()
}) })
typedef Struct_(Binds_gte_cross_v3s4) { V3_S4* src_a; V3_S4* src_b; V3_S4* out; };
typedef Struct_(RegUse_gte_cross_v3s4) {
Reg_(V3_S4) a;
Reg_(V3_S4) b;
union { Reg t0, out; };
union { Reg t1, src_a, rt11; };
union { Reg t2, src_b, rt22; };
};
internal MipsAtom* gte_cross_v3s4(AtomArena_R aa, RegUse_gte_cross_v3s4 r)
atom_info(atom_bind(Binds_gte_cross_v3s4)) MipsAtom_Proc_(aa, {
load_word(r.src_a, R_TapePtr, O_(Binds_gte_cross_v3s4,src_a)),
load_word(r.src_b, R_TapePtr, O_(Binds_gte_cross_v3s4,src_b)),
load_word(r.out, R_TapePtr, O_(Binds_gte_cross_v3s4,out)),
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_gte_cross_v3s4)),
mac_load_v3s4(r.a, r.src_a, 0), LdSlot_
mac_load_v3s4(r.b, r.src_b, 0), LdSlot_
mac_gte_mv_to_cr_diag_v3s4(r.a), GteDelay_ /* RT diagonal: D1 = a.x, D2 = a.y, D3 = a.z. */
mac_gte_ld_ir123_v3s4(r.b), GteDelay_ /* IR: second operand. */
gte_cmdw_cross, /* MAC1/2/3 = a × b */
mac_gte_mv_from_data_r_mac123(r.a.x, r.a.y, r.a.z), GteDelay_ //nop,
mac_shift_aright_v3s4_self(r.a, 12),
mac_store_v3s4(r.a, r.out, 0),
mac_yield()
})
#pragma endregion Atom Procs #pragma endregion Atom Procs
#pragma region Baked Atoms #pragma region Baked Atoms
+14 -14
View File
@@ -101,20 +101,20 @@ enum {
/* Semantic Aliases for GTE Data Registers */ /* Semantic Aliases for GTE Data Registers */
enum { enum {
gte_in_v0_xy = C2_VXY0, /* Input Vector 0 (X, Y) */ C2_InV0_XY = C2_VXY0, /* Input Vector 0 (X, Y) */
gte_in_v0_z = C2_VZ0, /* Input Vector 0 (Z) */ C2_InV0_Z = C2_VZ0, /* Input Vector 0 (Z) */
gte_in_v1_xy = C2_VXY1, /* Input Vector 1 (X, Y) */ C2_InV1_XY = C2_VXY1, /* Input Vector 1 (X, Y) */
gte_in_v1_z = C2_VZ1, /* Input Vector 1 (Z) */ C2_InV1_Z = C2_VZ1, /* Input Vector 1 (Z) */
gte_in_v2_xy = C2_VXY2, /* Input Vector 2 (X, Y) */ C2_InV2_XY = C2_VXY2, /* Input Vector 2 (X, Y) */
gte_in_v2_z = C2_VZ2, /* Input Vector 2 (Z) */ C2_InV2_Z = C2_VZ2, /* Input Vector 2 (Z) */
gte_in_rgb = C2_RGB, /* Input Color (R, G, B, MipsCode) */ C2_In_RGB = C2_RGB, /* Input Color (R, G, B, MipsCode) */
gte_out_scr_xy0 = C2_SXY0, /* Output Screen Coord 0 (X, Y) */ C2_OutSrc_XY0 = C2_SXY0, /* Output Screen Coord 0 (X, Y) */
gte_out_scr_xy1 = C2_SXY1, /* Output Screen Coord 1 (X, Y) */ C2_OutSrc_XY1 = C2_SXY1, /* Output Screen Coord 1 (X, Y) */
gte_out_scr_xy2 = C2_SXY2, /* Output Screen Coord 2 (X, Y) */ C2_OutSrc_XY2 = C2_SXY2, /* Output Screen Coord 2 (X, Y) */
gte_out_depth = C2_OTZ, /* Output Ordering Table Z (Depth) */ C2_OutDepth = C2_OTZ, /* Output Ordering Table Z (Depth) */
gte_math_accum0 = C2_MAC0, /* Math Accumulator 0 */ C2_MathAccu0 = C2_MAC0, /* Math Accumulator 0 */
gte_math_accum1 = C2_MAC1, /* Math Accumulator 1 */ C2_MathAccu1 = C2_MAC1, /* Math Accumulator 1 */
gte_math_accum2 = C2_MAC2, /* Math Accumulator 2 */ C2_MathAccu2 = C2_MAC2, /* Math Accumulator 2 */
}; };
/* --- GTE Command Semantics (The Bitfield Meanings) --- /* --- GTE Command Semantics (The Bitfield Meanings) ---
+1 -1
View File
@@ -110,7 +110,7 @@ typedef Slice_(MipsAtom);
// Sometimes a user will define a bundle of atoms that represent a procedure of work as: // Sometimes a user will define a bundle of atoms that represent a procedure of work as:
// MipsAtom* <identifier>[...]; // MipsAtom* <identifier>[...];
// Unfortuantely if using slice_from_array it will make the slice's pointer: MipsAtom** so this enforce its defined as MipsAtom* // Unfortuantely if using slice_from_array it will make the slice's pointer: MipsAtom** so this enforce its defined as MipsAtom*
// TODO(Ed): Alternatively we can make the MipsAtom an opaque pointer to the atom... so that the blow returns 'MipsAtom'. // TODO(Ed): Alternatively we can make the MipsAtom an opaque pointer to the atom... so that the proc returns 'MipsAtom'.
#define atombundle_from_array(array) (Slice_MipsAtom){.ptr=array[0],.len=Array_len(array)} #define atombundle_from_array(array) (Slice_MipsAtom){.ptr=array[0],.len=Array_len(array)}
// Underlying type to an ptr to an array of mips asm words that must terminate with an ac_yield. // Underlying type to an ptr to an array of mips asm words that must terminate with an ac_yield.
+6 -4
View File
@@ -23,6 +23,8 @@ MipsAtomComp_Proc_( ab, {
shift_aright(dt_z, dt_z, shift_amount), shift_aright(dt_z, dt_z, shift_amount),
}) })
FI_ Slice_MipsCode ac_shift_aright_v3s4_self(AtomBuilder_R ab, Reg_(V3_S4) dt, U2 shift) MipsAtomComp_ProcMap_(ab, mac_shift_aright_v3_self(dt.x, dt.y, dt.z, shift))
FI_ Slice_MipsCode ac_shift_aright_var_v3(AtomBuilder_R ab FI_ Slice_MipsCode ac_shift_aright_var_v3(AtomBuilder_R ab
, Reg rd_v0, Reg rd_v1, Reg rd_v2 , Reg rd_v0, Reg rd_v1, Reg rd_v2
, Reg rs_v0, Reg rs_v1, Reg rs_v2 , Reg rs_v0, Reg rs_v1, Reg rs_v2
@@ -33,15 +35,15 @@ MipsAtomComp_Proc_(ab, {
shift_aright_var(rd_v2, rs_v2, r_shift), shift_aright_var(rd_v2, rs_v2, r_shift),
}) })
FI_ Slice_MipsCode ac_shift_aright_var_v3_self(AtomBuilder_R ab FI_ Slice_MipsCode ac_shift_aright_var_v3_self(AtomBuilder_R ab, Reg rds_v0, Reg rds_v1, Reg rds_v2, Reg r_shift)
, Reg rds_v0, Reg rds_v1, Reg rds_v2 atom_dbg_skip MipsAtomComp_Proc_(ab, {
, Reg r_shift)
MipsAtomComp_Proc_(ab, {
shift_aright_var(rds_v0, rds_v0, r_shift), shift_aright_var(rds_v0, rds_v0, r_shift),
shift_aright_var(rds_v1, rds_v1, r_shift), shift_aright_var(rds_v1, rds_v1, r_shift),
shift_aright_var(rds_v2, rds_v2, r_shift), shift_aright_var(rds_v2, rds_v2, r_shift),
}) })
FI_ Slice_MipsCode ac_shift_aright_var_v3s4_self(AtomBuilder_R ab, Reg_(V3_S4) ds, Reg shift) MipsAtomComp_ProcMap_(ab, mac_shift_aright_var_v3_self(ds.x, ds.y, ds.z, shift))
#pragma endregion MACs (Mips Atom Components) #pragma endregion MACs (Mips Atom Components)
#pragma region Baked Atoms #pragma region Baked Atoms
+1
View File
@@ -55,6 +55,7 @@ WORD_COUNT(gte_mv_to_ctrl_r, 1)
WORD_COUNT(gte_sw, 1) WORD_COUNT(gte_sw, 1)
WORD_COUNT(gte_cmdw_rtpt, 1) WORD_COUNT(gte_cmdw_rtpt, 1)
WORD_COUNT(gte_cmdw_nclip, 1) WORD_COUNT(gte_cmdw_nclip, 1)
WORD_COUNT(gte_cmdw_op, 1)
WORD_COUNT(gte_avg_sort_z3, 1) WORD_COUNT(gte_avg_sort_z3, 1)
WORD_COUNT(gte_cmdw_sqr, 1) WORD_COUNT(gte_cmdw_sqr, 1)
WORD_COUNT(gte_cmdw_gpf, 1) WORD_COUNT(gte_cmdw_gpf, 1)
+3 -138
View File
@@ -104,9 +104,9 @@ MipsAtomComp_Proc_(ab, {
typedef AtomBundle_(resolve_look_at) { MipsAtom* typedef AtomBundle_(resolve_look_at) { MipsAtom*
input_and_sub, input_and_sub,
normalize_fwd_uz, normalize_fwd_uz,
cross_uz_up_into_right, cross_to_right,
normalize_right_ux, normalize_right_ux,
cross_uz_ux_to_up, cross_to_up,
normalize_up_uy, normalize_up_uy,
populate, populate,
set_gte_mt3s2s4, set_gte_mt3s2s4,
@@ -178,141 +178,6 @@ atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
mac_yield() mac_yield()
}) })
typedef Struct_(RegUse_resolve_look_at_cross_uz_up_into_right) {
Reg scratch;
Reg a; Reg b; Reg c; /* load a.x/y/z; result out.x/y/z */
Reg d; /* load b.x */
Reg f; /* r_f = &right (out ptr), r_g = &uz, r_h = &up_in */
union { Reg t1, g, target0; };
union { Reg t2, h, target1; };
Reg t0;
};
/* Atom 2: cross uz × up_in → right. */
// internal MipsAtom* AtomBundleEntry_(resolve_look_at, cross_uz_up_to_right)(AtomArena_R aa,
internal MipsAtom* resolve_look_at_cross_uz_up_into_right(AtomArena_R aa,
RegUse_resolve_look_at_cross_uz_up_into_right r
) MipsAtom_Proc_(aa, {
/* FIX: build packed RT22+RT33 with proper sign extension. */
add_si(r.g, r.scratch, O_(ResolveLookAtScratch,uz)), /* r_g = &uz */
add_si(r.h, r.scratch, O_(ResolveLookAtScratch,up_in)), /* r_h = &up_in */
add_si(r.f, r.scratch, O_(ResolveLookAtScratch,right)), /* r_f = &right (out) */
nop,
/* Load a (uz).x/y/z into r_a/r_b/r_c. */
mac_load_word_v3(r.a, r.b, r.c, r.g, 0), LdSlot_
/* Load b (up_in).x/y/z into r_d + R_AT/R_V0 (R_AT/R_V0 are hardcoded scratch). */
mac_load_word_v3(r.d, R_AT, r.t0, r.h, 0), LdSlot_ // (taken by gte_mv_from_ctrl_r)
/* Save the two RT control-register slots OP will clobber. We reuse r_g/r_h (scratch pointers, no longer needed) as the save targets. */
gte_mv_from_ctrl_r(r.target0, gte_cr_RT11), /* r_g = C2 r0 (RT11|RT12) */
gte_mv_from_ctrl_r(r.target1, gte_cr_RT22), /* r_h = C2 r4 (RT22|RT33) */
/* Load uz.x/uz.y/uz.z into COP2 control registers.
* OP reads D1 = RT11 from $0.low, D2 = RT22 from $2.high, D3 = RT33 from $4.high.
* RT22 is in BOTH $2.high AND $4.low (shared bit position). OP reads from $2.high.
* So set RT22 via ctc2 r_b, $2 (sets $2.high = a.y.high = RT22, $2.low = a.y.low = RT13).
* Then set RT33 via ctc2 r_c, $4 (sets $4.high = a.z.high = RT33, $4.low = a.z.low).
* The $2 and $4 writes don't clobber each other (separate registers).
* The 2nd ctc2 DOES clobber $4.low (becomes a.z.low, NOT a.y.high), but since OP
* reads RT22 from $2.high (which the 2nd ctc2 doesn't touch), D2 is still a.y.high.
* This is libpsyx's OuterProduct12 convention. */
gte_mv_to_ctrl_r(r.b, gte_cr_RT13), /* $2 = r_b = a.y. RT13=a.y.low, RT22=a.y.high. */
gte_mv_to_ctrl_r(r.c, gte_cr_RT22), /* $4 = r_c = a.z. RT22=a.z.low, RT33=a.z.high. */
/* Load uz into the RT diagonal. */
gte_mv_to_ctrl_r(r.a, gte_cr_RT11), /* D1 = RT11 = uz.x. */
GteDelay_ nop2, /* CTC2 retirement */
/* Load up_in into IR (the second operand for OP). */
gte_mv_to_data_r(r.d, C2_IR1), /* IR1 = up_in.x */
gte_mv_to_data_r(R_AT, C2_IR2), /* IR2 = up_in.y */
gte_mv_to_data_r(r.t0, C2_IR3), /* IR3 = up_in.z */
GteDelay_ nop2, /* MTC2 retirement */
gte_cmdw_cross, /* OP: MAC1/2/3 = uz × up_in
* MAC1 = IR3*D2 - IR2*D3 = up_in.z*uz.y.high - up_in.y*uz.z.high
* MAC2 = IR1*D3 - IR3*D1 = up_in.x*uz.z.high - up_in.z*uz.x
* MAC3 = IR2*D1 - IR1*D2 = up_in.y*uz.x - up_in.x*uz.y.high
* For up_in = (0, -fp_one, 0):
* MAC1 = 0 - (-fp_one)*uz.z.high = fp_one*uz.z.high
* MAC2 = 0 - 0 = 0
* MAC3 = (-fp_one)*uz.x - 0 = -fp_one*uz.x */
/* Restore the RT slots we clobbered. */
gte_mv_to_ctrl_r(r.target0, gte_cr_RT11), /* restore C2 r0 (RT11|RT12) */
gte_mv_to_ctrl_r(r.target1, gte_cr_RT22), /* restore C2 r4 (RT22|RT33) */
/* mfc2 MAC1/2/3 → r_a/r_b/r_c (out.x/y/z). */
mac_gte_mv_from_data_r_mac123(r.a, r.b, r.c),
GteDelay_ nop, /* MFC2 retirement */
/* Right-shift MAC by 12 to convert from GTE's S12.20 fixed-point scale back to libpsyx OuterProduct12 convention (S12.0, fp_one=4096=1<<12).
* Without this, MAC values (~16M for unit-vector cross products) overflow the GTE's 16-bit IR registers when atom 3 normalizes via mtc2. */
mac_shift_aright_v3_self(r.a, r.b, r.c, 12),
/* Store out.x/y/z to r_f (out ptr = scratch+32). */
mac_store_word_v3(r.a, r.b, r.c, r.f, 0),
mac_yield()
})
typedef Struct_(RegUse_resolve_look_at__cross_uz_ux_to_up_proc) {
Reg const scratch; /* pinned T4 */
Reg_(V3_S4) a; /* uz components, then MAC / out */
Reg_(V3_S4) b; /* ux components */
union { Reg t0, up; }; /* &up, dedicated */
union { Reg t1, uz, rt11; }; /* &uz, then RT11 save */
union { Reg t2, ux, rt22; }; /* &ux, then RT22 save */
};
/* Atom 4: cross uz × ux → up. */
internal MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa,
RegUse_resolve_look_at__cross_uz_ux_to_up_proc r
) MipsAtom_Proc_(aa, {
add_si(r.uz, r.scratch, O_(ResolveLookAtScratch,uz)), /* r.uz = &uz */
add_si(r.ux, r.scratch, O_(ResolveLookAtScratch,ux)), /* r.ux = &ux */
add_si(r.up, r.scratch, O_(ResolveLookAtScratch,up)), /* r.up = &up (out) */
mac_load_v3s4(r.a, r.uz, 0), LdSlot_
mac_load_v3s4(r.b, r.ux, 0), LdSlot_ /* taken by gte_mv_from_ctrl_r */
/* OP reads D1/D2/D3 from RT11/RT22/RT33 ($0/$2/$4), not V0/V1/V2.
* Mirror atom 1: cfc2 RT save, ctc2 RT diagonal from uz, mtc2 IR from ux, ctc2 RT restore. */
/* Save the two RT control-register slots OP will clobber (reusing r.uz/r.ux — they're no longer needed as scratch pointers). */
gte_mv_from_ctrl_r(r.rt11, gte_cr_RT11), /* r.rt11 = C2 $0 (RT11|RT12) */
gte_mv_from_ctrl_r(r.rt22, gte_cr_RT22), /* r.rt22 = C2 $4 (RT22|RT33) */
/* Load uz into the RT diagonal — same packing as atom 1.
* OP reads D1 = RT11 from $0.low, D2 = RT22 from $2.high, D3 = RT33 from $4.high.
* RT22 is shared between $2.high and $4.low — the ctc2 sequence to $2 then $4
* sets RT22 to uz.y.high (via $2), then to uz.z.low (via $4).
* OP reads RT22 from $2.high which the second ctc2 doesn't touch, so D2 stays uz.y.high. */
gte_mv_to_ctrl_r(r.a.y, gte_cr_RT13), /* $2 = uz.y. RT13=uz.y.low, RT22=uz.y.high. */
gte_mv_to_ctrl_r(r.a.z, gte_cr_RT22), /* $4 = uz.z. RT22=uz.z.low, RT33=uz.z.high. */
gte_mv_to_ctrl_r(r.a.x, gte_cr_RT11), /* $0 = uz.x. RT11=uz.x. */
GteDelay_ nop2, /* CTC2 retirement (CPU→COP2 2-slot delay) */
/* Load ux into the IR registers (the second operand for OP). */
gte_mv_to_data_r(r.b.x, C2_IR1), /* IR1 = ux.x */
gte_mv_to_data_r(r.b.y, C2_IR2), /* IR2 = ux.y */
gte_mv_to_data_r(r.b.z, C2_IR3), /* IR3 = ux.z */
GteDelay_ nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */
gte_cmdw_cross,
/* Restore the RT slots we clobbered. */
gte_mv_to_ctrl_r(r.rt11, gte_cr_RT11), /* restore C2 $0 (RT11|RT12) */
gte_mv_to_ctrl_r(r.rt22, gte_cr_RT22), /* restore C2 $4 (RT22|RT33) */
mac_gte_mv_from_data_r_mac123(r.a.x, r.a.y, r.a.z),
GteDelay_ nop,
/* Right-shift MAC by 12 to convert from GTE's S12.20 scale back to libpsyx
* OuterProduct12 convention (S12.0, fp_one=4096). See atom 1 for rationale. */
mac_shift_aright_v3_self(r.a.x, r.a.y, r.a.z, 12),
mac_store_v3s4(r.a, r.up, 0),
mac_yield()
})
typedef Struct_(Binds_ResolveLookAtPopAndTrans) { typedef Struct_(Binds_ResolveLookAtPopAndTrans) {
U4 look_at; /* U4 (MT3_S2S4* — destination matrix address) */ U4 look_at; /* U4 (MT3_S2S4* — destination matrix address) */
@@ -407,7 +272,7 @@ internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa,
* *
* Pool cost: r_look_at (1) + r_scratch (carrier) + r_off_ptr + 1 clobber = 4 GPRs. * Pool cost: r_look_at (1) + r_scratch (carrier) + r_off_ptr + 1 clobber = 4 GPRs.
*/ */
I_ MipsAtom* resolve_look_at__trans_matrix_proc(AtomArena_R aa I_ MipsAtom* AtomBundleEntry_(resolve_look_at,trans_matrix)(AtomArena_R aa
, U4 r_look_at, U4 r_scratch, U4 r_off_ptr , U4 r_look_at, U4 r_scratch, U4 r_off_ptr
, U4 r_tmp0, U4 r_tmp1, U4 r_tmp2 , U4 r_tmp0, U4 r_tmp1, U4 r_tmp2
) MipsAtom_Proc_(aa, { ) MipsAtom_Proc_(aa, {
+36 -24
View File
@@ -186,19 +186,14 @@ internal void compile_resolve_look_at(void) {
}); });
regfile_reset_to_mask(& rf, pin_mask); regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 2: cross uz×up_in→right === */ /* === ATOM 2: cross uz×up_in→right (Binds_gte_cross_v3s4) === */
// smem.resolve_look_at_bundle[2] = AtomBundleEntry_(resolve_look_at,cross_uz_up_to_right)(& ab, smem.resolve_look_at_bundle[2] = gte_cross_v3s4(& ab,
smem.resolve_look_at_bundle[2] = resolve_look_at_cross_uz_up_into_right(& ab, RegUse_(gte_cross_v3s4) {
RegUse_(resolve_look_at_cross_uz_up_into_right) { .a = ralloc_v3(),
.scratch = R_ResolveScratch, .b = ralloc_v3(),
.a = ralloc(), .t0 = ralloc(),
.b = ralloc(),
.c = ralloc(),
.d = ralloc(),
.f = ralloc(),
.t1 = ralloc(), .t1 = ralloc(),
.t2 = ralloc(), .t2 = ralloc(),
.t0 = ralloc(),
}); });
regfile_reset_to_mask(& rf, pin_mask); regfile_reset_to_mask(& rf, pin_mask);
@@ -220,15 +215,14 @@ internal void compile_resolve_look_at(void) {
}); });
regfile_reset_to_mask(& rf, pin_mask); regfile_reset_to_mask(& rf, pin_mask);
/* === ATOM 4: cross uz×ux→up === */ /* === ATOM 4: cross uz×ux→up (Binds_gte_cross_v3s4) === */
smem.resolve_look_at_bundle[4] = resolve_look_at__cross_uz_ux_to_up_proc(& ab, smem.resolve_look_at_bundle[4] = gte_cross_v3s4(& ab,
RegUse_(resolve_look_at__cross_uz_ux_to_up_proc){ RegUse_(gte_cross_v3s4) {
.scratch = R_ResolveScratch, .a = ralloc_v3(),
.a = ralloc_v3(), /* T0 T1 T2 */ .b = ralloc_v3(),
.b = ralloc_v3(), /* T3 T5 T6 */ .t0 = ralloc(),
.t0 = ralloc(), /* T7 = up */ .t1 = ralloc(),
.t1 = ralloc(), /* V0 = uz / rt11 */ .t2 = ralloc(),
.t2 = ralloc(), /* V1 = ux / rt22 */
}); });
regfile_reset_to_mask(& rf, pin_mask); regfile_reset_to_mask(& rf, pin_mask);
@@ -280,8 +274,13 @@ internal void compile_resolve_look_at(void) {
U4 r_scratch_6c = R_ResolveScratch; U4 r_scratch_6c = R_ResolveScratch;
U4 r_off_ptr_6c = R_T1; /* &scratch.eye (= off dst) */ U4 r_off_ptr_6c = R_T1; /* &scratch.eye (= off dst) */
U4 r_tmp0_6c = R_T2; U4 r_tmp0_6c = R_T2;
smem.resolve_look_at_bundle[9] = resolve_look_at__trans_matrix_proc(& ab, smem.resolve_look_at_bundle[9] = AtomBundleEntry_(resolve_look_at,trans_matrix)(& ab,
r_look_at_6c, r_scratch_6c, r_off_ptr_6c, r_tmp0_6c, R_T3, R_T4); r_look_at_6c,
r_scratch_6c,
r_off_ptr_6c,
r_tmp0_6c,
R_T3,
R_T4);
/* Sanity check: arena didn't overflow. */ /* Sanity check: arena didn't overflow. */
assert(ab.used <= ResolveLookAtArena_Size); assert(ab.used <= ResolveLookAtArena_Size);
@@ -295,6 +294,9 @@ I_ void resolve_look_at(TapeBuilder_R tb
, P3_S4* target , P3_S4* target
, V3_S4* up_in , V3_S4* up_in
){ ){
/* Typed view of the scratchpad for field-address arithmetic. */
ResolveLookAtScratch* sp = C_scratch(ResolveLookAtScratch*);
tb_emit(tb, smem.resolve_look_at_bundle[0]); { tb_emit(tb, smem.resolve_look_at_bundle[0]); {
tb_data(tb, u4_(target)); tb_data(tb, u4_(target));
tb_data(tb, u4_(eye)); tb_data(tb, u4_(eye));
@@ -305,11 +307,21 @@ I_ void resolve_look_at(TapeBuilder_R tb
tb_emit(tb, smem.resolve_look_at_bundle[1]); { tb_emit(tb, smem.resolve_look_at_bundle[1]); {
// tb_data(tb, u4_(Scratchpad_Loc)); // tb_data(tb, u4_(Scratchpad_Loc));
} }
tb_emit(tb, smem.resolve_look_at_bundle[2]); { } tb_emit(tb, smem.resolve_look_at_bundle[2]); {
/* Binds_gte_cross_v3s4: src_a, src_b, out (3 pointers). */
tb_data(tb, u4_(& sp->uz)); /* src_a */
tb_data(tb, u4_(& sp->up_in)); /* src_b */
tb_data(tb, u4_(& sp->right)); /* out */
}
tb_emit(tb, smem.resolve_look_at_bundle[3]); { tb_emit(tb, smem.resolve_look_at_bundle[3]); {
// tb_data(tb, u4_(Scratchpad_Loc)); // tb_data(tb, u4_(Scratchpad_Loc));
} }
tb_emit(tb, smem.resolve_look_at_bundle[4]); { } tb_emit(tb, smem.resolve_look_at_bundle[4]); {
/* Binds_gte_cross_v3s4: src_a, src_b, out (3 pointers). */
tb_data(tb, u4_(& sp->uz)); /* src_a */
tb_data(tb, u4_(& sp->ux)); /* src_b */
tb_data(tb, u4_(& sp->up)); /* out */
}
tb_emit(tb, smem.resolve_look_at_bundle[5]); { tb_emit(tb, smem.resolve_look_at_bundle[5]); {
// tb_data(tb, u4_(Scratchpad_Loc)); // tb_data(tb, u4_(Scratchpad_Loc));
} }