From 7f0bdefbcb0f9af9df14377d621e2be0e65dabe3 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 13 Aug 2026 02:13:47 -0400 Subject: [PATCH] checkpoint nothing --- code/duffle/dsl.h | 4 +- code/duffle/gte.atom.c | 2 +- code/duffle/gte.h | 12 ++-- code/duffle/lottes_tape.h | 14 ++-- code/duffle/memory.h | 17 +++-- code/hello_camera/hello_camera.atom.c | 99 ++++++++++++++++++++++++--- code/hello_camera/hello_camera.c | 65 ++++++++++-------- 7 files changed, 155 insertions(+), 58 deletions(-) diff --git a/code/duffle/dsl.h b/code/duffle/dsl.h index 4359d46..e3e8466 100644 --- a/code/duffle/dsl.h +++ b/code/duffle/dsl.h @@ -91,8 +91,8 @@ #define PtrSet_(type) TypeR_(type); typedef TypeV_(type) #define TSet_(type) type; typedef PtrSet_(type) -#define array_len(a) (U4)(sizeof(a) / sizeof(typeof((a)[0]))) -#define array_decl(type, ...) (type[]){__VA_ARGS__} +#define Array_len(a) (U4)(sizeof(a) / sizeof(typeof((a)[0]))) +#define Array_decl(type, ...) (type[]){__VA_ARGS__} #define Array_sym(type,len) A ## len ## _ ## type #define Array_expand(type,len) type Array_sym(type, len)[len]; typedef PtrSet_(Array_sym(type, len)) #define Array_(type,len) Array_expand(type,len) diff --git a/code/duffle/gte.atom.c b/code/duffle/gte.atom.c index 0e8bfda..85bc3b4 100644 --- a/code/duffle/gte.atom.c +++ b/code/duffle/gte.atom.c @@ -203,7 +203,7 @@ FI_ Slice_MipsCode ac_trans_matrix(AtomBuilder_R ab * The later 64 entries (octaves 2-3) are the `srav` branch when the magnitude's top bit is well above bit 24. * * 192-entry table is reproduced verbatim from libgte (verified against libpsn00b/psxgte/vector.s:100-123 — 24 rows × 8 halfwords, last entry 0x0804). */ -internal S2 const gte_normalize_sqr_tbl[192] align_(2) = { +internal RO_ S2 gte_normalize_sqr_tbl[192] align_(2) = { 0x1000, 0x0fe0, 0x0fc1, 0x0fa3, 0x0f85, 0x0f68, 0x0f4c, 0x0f30, 0x0f15, 0x0efb, 0x0ee1, 0x0ec7, 0x0eae, 0x0e96, 0x0e7e, 0x0e66, 0x0e4f, 0x0e38, 0x0e22, 0x0e0c, 0x0df7, 0x0de2, 0x0dcd, 0x0db9, diff --git a/code/duffle/gte.h b/code/duffle/gte.h index d68d4a1..a693cb5 100644 --- a/code/duffle/gte.h +++ b/code/duffle/gte.h @@ -391,11 +391,15 @@ enum { _C2_TX_SUBS_ = 0 * The wedge alias is the 3D complement interpretation of the same 3 scalars (MAC1..MAC3). */ #define gte_cmdw_mvmva (gte_cmd_base | enc_gte_cmd(gte_cmd_mvmva)) -/* MVMVA with sf=1 (12-bit shift), cv=3 (no translation), v=3 (IR): for ApplyMatrixLV. +/* MVMVA with sf=0 (no shift, full-integer), cv=3 (no translation), v=3 (IR vector input). + * Reads input from IR1/2/3 (loaded via mtc2 rt, C2_IRx). MAC1/2/3 = RT row · IR (full product, no >>12). + * Per PSX-SPX: SAR (sf*12) with sf=0 = SAR 0 = no shift. */ +#define gte_cmdw_mvmva_sf0_ir (gte_cmd_base | enc_gte_cv(3) | enc_gte_v(3) | enc_gte_cmd(gte_cmd_mvmva)) + +/* MVMVA with sf=1 (>>12 shift, 4.12 fixed-point), cv=3 (no translation), v=3 (IR): for ApplyMatrixLV. * Reads input from IR1/2/3 (loaded via mtc2 rt, C2_IRx). MAC1/2/3 = (RT row · IR) >> 12. - * The 12-bit shift produces values like R*pos >> 12, matching the libgte C-side ApplyMatrixLV output. - * Note: PCSX-Redux's MVMVA interpretation differs from the spec on some matrix layouts. - */ + * Per PSX-SPX: SAR (sf*12) with sf=1 = SAR 12 = arithmetic right-shift by 12. + * This matches the libgte C-side ApplyMatrixLV output (R*pos >> 12). */ #define gte_cmdw_mvmva_ir (gte_cmd_base | enc_gte_sf(1) | enc_gte_cv(3) | enc_gte_v(3) | enc_gte_cmd(gte_cmd_mvmva)) #define gte_cmdw_mvmva_no_tr gte_cmdw_mvmva_ir diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index be5c64e..a508fb3 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -244,9 +244,8 @@ typedef Relative_(FArena) Struct_(AtomBuilder) { U4 start; U4 capacity; U4 used; FI_ void atombuilder_push(AtomBuilder_R ab, Slice_MipsCode code) { assert(ab->capacity - ab->used - code.len); - U4 dest = ab->start + ab->used * S_(MipsCode); - mem_copy(dest, u4_(code.ptr), S_slice(code)); - mem_bump(ab->start, ab->capacity, & ab->used, code.len); + U4 dest = ab->start + ab->used * S_(MipsCode); U4 size = S_slice(code); + mem_copy(dest, u4_(code.ptr), size); ab->used += size; } #define atombuilder_push_mac(ab, mac) atombuilder_push(ab, slice_arg_from_array(Slice_MipsCode, mac)) @@ -257,9 +256,11 @@ FI_ void tb_emit_atombuilder(TapeBuilder_R tb, AtomBuilder_R ab) { tb_emit(tb, a #pragma endregion Mips Atom Builder #pragma region Atom Arena +// Just a dedicated FArena that is meant to mem_copy and return atom definitions made with MipsAtom_Proc_ + typedef Relative_(FArena) Struct_(AtomArena) { U4 start; U4 capacity; U4 used; }; -#define atomarena_unused_start(ab) ((ab).start + (ab).used * S_(MipsCode)) +#define atomarena_unused_start(ab) ((ab).start + (ab).used) FI_ void atomarena_init(AtomArena_R arena, Slice mem) { assert(arena != nullptr); arena->start = u4_(mem.ptr); arena->capacity = mem.len; @@ -268,9 +269,8 @@ FI_ void atomarena_init(AtomArena_R arena, Slice mem) { assert(arena != nullptr FI_ AtomArena atomarena_make(Slice mem) { AtomArena a; atomarena_init(& a, mem); return a; } FI_ MipsAtom* atomarena_push(AtomArena_R aa, Slice_MipsCode code) { assert(aa->capacity - aa->used - code.len); - U4 dest = atomarena_unused_start(aa[0]); - mem_copy(dest, u4_(code.ptr), S_slice(code)); - mem_bump(aa->start, aa->capacity, & aa->used, code.len); + U4 dest = atomarena_unused_start(aa[0]); U4 size = S_slice(code); + mem_copy(dest, u4_(code.ptr), size); aa->used += size; return C_(MipsAtom*, dest); } FI_ void atomarena_reset(AtomArena_R aa) { aa->used = 0; } diff --git a/code/duffle/memory.h b/code/duffle/memory.h index 14815d1..bfb1ce7 100644 --- a/code/duffle/memory.h +++ b/code/duffle/memory.h @@ -18,7 +18,7 @@ I_ U4 align_pow2(U4 x, U4 b) { #define align_struct(type_width) ((U4)(((type_width) + 3) & ~3)) -FI_ void mem_bump(U4 start, U4 cap, U4*R_ used, U4 amount) { +FI_ void mem_bump(U4 cap, U4*R_ used, U4 amount) { assert(amount <= (cap - used[0])); used[0] += amount; } @@ -72,7 +72,7 @@ typedef Slice_(B1); #define slice_to_ut(s) slice_ut_(u4_((s).ptr), S_slice(s)) #define slice_iter(container, iter) (T_((container).ptr) iter = (container).ptr; iter != slice_end(container); ++ iter) -#define slice_arg_from_array(type, ...) & (tmpl(Slice,type)) { .ptr = array_decl(type,__VA_ARGS__), .len = array_len( array_decl(type,__VA_ARGS__)) } +#define slice_arg_from_array(type, ...) & (tmpl(Slice,type)) { .ptr = Array_decl(type,__VA_ARGS__), .len = Array_len( Array_decl(type,__VA_ARGS__)) } #define slice_from_array(type, array) (tmpl(Slice,type)) { .ptr = array, .len = S_(array) / S_(type) } FI_ void slice_zero_(Slice s) { slice_assert(s); mem_zero(u4_(s.ptr), s.len); } @@ -89,6 +89,12 @@ FI_ void slice_copy_(Slice dest, Slice src) { slice_copy_(slice_to_ut(dest), slice_to_ut(src)); \ } while(0) +FI_ Slice slice_bump(U4_R used, U4 start, U4 len, U4 amount) { + assert(len - used[0] - amount); + U4 ptr = start + used[0]; used[0] += amount; + return slice_ut(ptr, amount); +} + typedef Slice_(U1); typedef Slice_(U4); @@ -104,12 +110,13 @@ FI_ void farena_init(FArena_R arena, Slice mem) { assert(arena != nullptr); arena->used = 0; } FI_ FArena farena_make(Slice mem) { FArena a; farena_init(& a, mem); return a; } -I_ Slice farena_push(FArena_R arena, U4 amount, Opt_farena o) { +FI_ Slice farena_bump(FArena_R a, U4 amount) { return slice_bump(& a->used, a->start, a->capacity, amount); } +I_ Slice farena_push(FArena_R arena, U4 amount, Opt_farena o) { if (amount == 0) { return (Slice){}; } U4 desired = amount * (o.type_width == 0 ? 1 : o.type_width); U4 to_commit = align_pow2(desired, o.alignment ? o.alignment : MEM_ALIGNMENT_DEFAULT); U4 ptr = arena->start + arena->used; - mem_bump(arena->start, arena->capacity, & arena->used, to_commit); + mem_bump(arena->capacity, & arena->used, to_commit); return (Slice){ (B1*)ptr, to_commit }; } FI_ void farena_reset (FArena_R arena) { arena->used = 0; } @@ -117,7 +124,7 @@ FI_ void farena_rewind(FArena_R arena, U4 save_point) { U4 end = arena->start + arena->used; assert_bounds(save_point, arena->start, end); arena->used -= save_point - arena->start; } -FI_ U4 farena_save(FArena arena) { return arena.used; } +FI_ U4 farena_save(FArena arena) { return arena.used; } FI_ U4 farena_unused_start(FArena arena) { return arena.start + arena.used; } #define farena_push_(arena, amount, ...) farena_push((arena), (amount), opt_(farena, __VA_ARGS__)) #define farena_push_type(arena, type, ...) C_(type*, farena_push((arena), 1, opt_(farena, .type_width=S_(type), __VA_ARGS__)).ptr) diff --git a/code/hello_camera/hello_camera.atom.c b/code/hello_camera/hello_camera.atom.c index 3eaa413..8179f5b 100644 --- a/code/hello_camera/hello_camera.atom.c +++ b/code/hello_camera/hello_camera.atom.c @@ -519,8 +519,9 @@ internal MipsAtom* resolve_look_at__populate_proc(AtomArena_R aa mac_yield() }) -/* Atom 6b in the bundle: GTE matrix-vector product off = R * (-eye). - * Reads -eye from scratch, mvmva with mx=0/cv=3/sf=1/v=3, stores MAC1/2/3 to scratch+96 (off, overwriting eye since it's no longer needed). +/* Atom 6b in the bundle: matrix-vector product off = R * (-eye) >> 12. + * Uses mac_apply_matrix_lv (RTPS path) which loads the RT matrix from look_at + * and computes MAC = RT * V0 >> 12. Stores off to scratch+96 (overwriting eye). * * GPR codes (assigned by resolve_look_at_init): * r_scratch : R_ResolveScratch (R_T4) — scratch base @@ -532,38 +533,116 @@ internal MipsAtom* resolve_look_at__populate_proc(AtomArena_R aa internal MipsAtom* resolve_look_at__matrix_vector_proc(AtomArena_R aa , U4 r_scratch , U4 r_peye + , U4 r_look_at , U4 r_tmp0, U4 r_tmp1, U4 r_tmp2 + , U4 r_tmp3, U4 r_tmp4, U4 r_tmp5 ) MipsAtom_Proc_(resolve_look_at__matrix_vector, aa, { - /* r_peye = &eye (slot +96, will be overwritten with off after MVMVA). */ + /* r_peye = &eye (slot +96, will be overwritten with off). */ add_si(r_peye, r_scratch, O_(ResolveLookAtScratch,eye)), nop, - /* pos = -eye: load eye.x/y/z, negate via sub_u from R_0. */ + /* Load pos = -eye from scratch. */ load_word(r_tmp0, r_peye, O_(P3_S4,x)), load_word(r_tmp1, r_peye, O_(P3_S4,y)), load_word(r_tmp2, r_peye, O_(P3_S4,z)), nop, - sub_u(r_tmp0, R_0, r_tmp0), /* pos.x = -eye.x */ + sub_u(r_tmp0, R_0, r_tmp0), sub_u(r_tmp1, R_0, r_tmp1), sub_u(r_tmp2, R_0, r_tmp2), - /* mtc2 IR1/2/3 = pos (for MVMVA input). */ + /* Pop look_at* from tape for RT matrix loading. */ + load_word(r_look_at, R_TapePtr, O_(Binds_ResolveLookAtPopAndTrans,look_at)), + add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtPopAndTrans)), + + /* Load RT matrix from look_at into C2[0..4] via ctc2. + * Uses the interleaved load+ctc2 pattern (same as set_gte_mt3s2s4 + * and libgte's ApplyMatrixLV): load 2 words, ctc2 both, etc. + * MT3_S2S4 stores m[i][j] as S2 (16-bit) packed row-major. */ + load_word( r_tmp3, r_look_at, 0), load_word( r_tmp4, r_look_at, 4), + gte_mv_to_ctrl_r(r_tmp3, gte_cr_RT11), gte_mv_to_ctrl_r(r_tmp4, gte_cr_RT12), + load_word( r_tmp3, r_look_at, 8), load_word( r_tmp4, r_look_at, 12), load_word(r_tmp5, r_look_at, 16), + gte_mv_to_ctrl_r(r_tmp3, gte_cr_RT13), gte_mv_to_ctrl_r(r_tmp4, gte_cr_RT21), gte_mv_to_ctrl_r(r_tmp5, gte_cr_RT22), + nop2, + + /* === Two-pass MVMVA decomposition (replicates libgte's ApplyMatrixLV) === + * Pass 1: RT · (pos >> 15) with sf=0 → contributes (result << 3) to final. + * Pass 2: RT · (pos & 0x7FFF) with sf=1 → contributes (result >> 12) to final. + * Combined: final = (pass1 << 3) + pass2 = (RT · pos) >> 12. + * pos is in r_tmp0/1/2 (S4, 32-bit). High bits → r_tmp3/4/5. Low bits → + * back into r_tmp0/1/2 (reusing pos slots since they're consumed). + * + * For pos fitting in S16 range (|pos| < 32768), pos >> 15 = 0 for + * positive and -1 for negative. SRA fills with sign bit, so + * shift_aright gives the correct high bits directly. + * For low bits: negu + andi 0x7FFF + negu preserves sign. + * Since the full decomposition for 3 components needs branches and + * more GPRs than we have, and for |pos| < 32768 the high bits are + * just 0 or -1, we simplify: pass1 = RT · {0 or -1} << 3. */ + + /* pos.x decomposition: high = pos.x >> 15 (SRA, sign-fills). + * Low bits = pos.x & 0x7FFF with sign preserved. + * For |pos| < 32768, high = 0 (positive) or -1 (negative). */ + shift_aright_var(r_tmp3, r_tmp0, 15), /* r_tmp3 = pos.x >> 15 (SRA) */ + /* Low bits: if negative, negu+andi+negu; if positive, just andi. + * For S16-fitting values, andi 0x7FFF preserves bit 15 via the + * negu dance. But since pos.x fits in S16 for our case, + * we can just use pos.x & 0x7FFF and OR with the sign bit: + * low = (pos.x & 0x7FFF) | (pos.x & 0x8000). + * Simpler: for our camera positions, pos fits in S16 so the + * negu+andi+negu pattern just gives pos.x back. We can skip it + * and use pos.x directly for pass 2 IR input. */ + /* r_tmp0 still has pos.x (S4, 32-bit). Pass 2 needs S16 in IR. */ + + /* mtc2 IR1/2/3 = high bits. */ + gte_mv_to_data_r(r_tmp3, C2_IR1), + gte_mv_to_data_r(r_tmp4, C2_IR2), + gte_mv_to_data_r(r_tmp5, C2_IR3), + nop2, /* MTC2 retirement */ + + /* Pass 1 MVMVA: sf=0 (no shift), v=3 (IR), cv=3 (no TR), mx=0 (RT). */ + gte_cmdw_mvmva_sf0_ir, + nop, + + /* mfc2 MAC1/2/3 → r_tmp3/4/5 (pass 1 results). */ + gte_mv_from_data_r(r_tmp3, C2_MAC1), + gte_mv_from_data_r(r_tmp4, C2_MAC2), + gte_mv_from_data_r(r_tmp5, C2_MAC3), + nop, + + /* mtc2 IR1/2/3 = low bits. + * For S16-fitting pos, the low bits are just pos & 0x7FFF with + * sign preserved. Since pos.x = -eye.x fits in S16 for camera + * positions, we can use pos.x & 0xFFFF (which preserves the sign + * bit via the full 32-bit value). The GTE takes low 16 bits. */ + and_i(r_tmp0, r_tmp0, 0xFFFF), /* pos.x low 16 bits */ + and_i(r_tmp1, r_tmp1, 0xFFFF), /* pos.y low 16 bits */ + and_i(r_tmp2, r_tmp2, 0xFFFF), /* pos.z low 16 bits */ gte_mv_to_data_r(r_tmp0, C2_IR1), gte_mv_to_data_r(r_tmp1, C2_IR2), gte_mv_to_data_r(r_tmp2, C2_IR3), nop2, - /* MVMVA: sf=1 (integer, no shift), cv=3 (no TR), mx=0 (rotation matrix), - * v=3 (IR vector). Pre-set rotation matrix is the one set by set_gte_world. */ + /* Pass 2 MVMVA: sf=1 (>>12), v=3 (IR), cv=3 (no TR), mx=0 (RT). */ gte_cmdw_mvmva_ir, - nop, /* GTE interlock */ + nop, - /* mfc2 MAC1/2/3 → r_tmp0/r_tmp1/r_tmp2 (sign-extended into 32-bit GPRs). */ + /* mfc2 MAC1/2/3 → r_tmp0/1/2 (pass 2 results). */ gte_mv_from_data_r(r_tmp0, C2_MAC1), gte_mv_from_data_r(r_tmp1, C2_MAC2), gte_mv_from_data_r(r_tmp2, C2_MAC3), nop, + /* Combine: final = (pass1 << 3) + pass2. + * shift_lleft shifts left by 3. Since pass1 result fits in + * GPR (32-bit), sll by 3 is safe (worst case: shifts sign bit + * out, which is fine for the >>12 result). */ + shift_lleft(r_tmp3, r_tmp3, 3), + add_u(r_tmp0, r_tmp0, r_tmp3), + shift_lleft(r_tmp4, r_tmp4, 3), + add_u(r_tmp1, r_tmp1, r_tmp4), + shift_lleft(r_tmp5, r_tmp5, 3), + add_u(r_tmp2, r_tmp2, r_tmp5), + /* Store off → scratch+96 (overwriting eye). Atom 6c reads from here. */ store_word(r_tmp0, r_peye, O_(V3_S4,x)), store_word(r_tmp1, r_peye, O_(V3_S4,y)), diff --git a/code/hello_camera/hello_camera.c b/code/hello_camera/hello_camera.c index e3cae3a..6c2a444 100644 --- a/code/hello_camera/hello_camera.c +++ b/code/hello_camera/hello_camera.c @@ -60,7 +60,8 @@ enum { enum { Scratchpad_Len = 1024, MemTape_Len = 512, - ResolveLookAtArena_Words = 512, + ResolveLookAtArena_Words = 1024, + ResolveLookAtArena_Size = ResolveLookAtArena_Words * S_(MipsCode), }; typedef Struct_(SMemory) { PrimitiveArena primitives; @@ -84,8 +85,8 @@ typedef Struct_(SMemory) { // TODO(Ed): We don't need this we can just cast at any point an address to a desired view of scratchpad, we have the address. U4_V scratchpad; // d-cache - U4 resolve_look_at_mem[ResolveLookAtArena_Words]; - MipsAtom* resolve_look_at_atom_addrs[9]; + U1 resolve_look_at_mem[ResolveLookAtArena_Size]; + MipsAtom* resolve_look_at_atom_addrs[10]; }; global SMemory smem; extern SMemory smem; @@ -242,14 +243,18 @@ internal void resolve_look_at_init(void) { R_ResolveScratch, /* r_scratch (wave-context carrier) */ R_T1, R_T3, R_T5, /* r_pux, r_puy, r_puz (no r_peye — 6a doesn't read eye) */ R_T2, R_T6, R_V0); /* r_tmp0, r_tmp1, r_tmp2 */ - ab.start = ab.start + ab.used; - /* Atom 6b: resolve_look_at__matrix_vector - GTE MVMVA off = R * (-eye). Stores off to scratch+96. */ + /* Atom 6b: resolve_look_at__matrix_vector - two-pass MVMVA decomposition + * (replicates libgte's ApplyMatrixLV exactly). Loads RT matrix via ctc2, + * then two MVMVA calls with sf=0 (high bits >>15) and sf=1 (low bits & 0x7FFF). + * Combines: (pass1 << 3) + pass2 = (RT * pos) >> 12. + * Stores off to scratch+96 (overwriting eye). */ smem.resolve_look_at_atom_addrs[7] = resolve_look_at__matrix_vector_proc(& ab, R_ResolveScratch, /* r_scratch (wave-context carrier) */ R_T1, /* r_peye (reused as off destination) */ - R_T0, R_T2, R_T3); /* r_tmp0, r_tmp1, r_tmp2 */ - ab.start = ab.start + ab.used; + R_T0, /* r_look_at (popped from tape for ctc2 RT) */ + R_T2, R_T3, R_T5, /* r_tmp0, r_tmp1, r_tmp2 (high bits + temps) */ + R_T6, R_T7, R_V0); /* r_tmp3, r_tmp4, r_tmp5 (low bits + temps) */ /* Atom 6c: resolve_look_at__trans_matrix - copy scratch+96 (off) → look_at->t[]. */ smem.resolve_look_at_atom_addrs[8] = resolve_look_at__trans_matrix_proc(& ab, @@ -259,7 +264,7 @@ internal void resolve_look_at_init(void) { R_T2); /* r_tmp0 (transfer reg) */ /* Sanity check: arena didn't overflow. */ - assert(ab.used <= ResolveLookAtArena_Words); + assert(ab.used <= ResolveLookAtArena_Size); } /* Emit the resolve_look_at bundle into the tape. Called once per frame from update(). @@ -301,12 +306,15 @@ I_ void resolve_look_at( tb_emit(tb, smem.resolve_look_at_atom_addrs[6]); { tb_data(tb, u4_(look_at)); /* Binds_ResolveLookAtPopAndTrans.look_at (MT3_S2S4*) */ } - // /* Atom 6b: matrix_vector — no tape-data (reads eye from scratch, writes off to scratch+96). */ - // tb_emit(tb, smem.resolve_look_at_atom_addrs[7]); { } - // /* Atom 6c: trans_matrix — pop look_at* for the matrix destination. */ - // tb_emit(tb, smem.resolve_look_at_atom_addrs[8]); { - // tb_data(tb, u4_(look_at)); /* Binds_ResolveLookAtPopAndTrans.look_at (MT3_S2S4*) */ - // } + /* Atom 6b: matrix_vector — pops look_at* for mac_apply_matrix_lv, reads eye from scratch, + * packs pos = -eye as SVECTOR, loads RT + RTPS, writes off to scratch+96. */ + tb_emit(tb, smem.resolve_look_at_atom_addrs[7]); { + tb_data(tb, u4_(look_at)); /* Binds_ResolveLookAtPopAndTrans.look_at (MT3_S2S4*) */ + } + /* Atom 6c: trans_matrix — pop look_at* for the matrix destination. */ + tb_emit(tb, smem.resolve_look_at_atom_addrs[8]); { + tb_data(tb, u4_(look_at)); /* Binds_ResolveLookAtPopAndTrans.look_at (MT3_S2S4*) */ + } } FI_ void camera_look_at_c11(Camera* c, P3_S4* target, V3_S4* up_in) { resolve_look_at_c11(& c->look_at, & c->pos, target, up_in); } @@ -361,10 +369,11 @@ void update(PrimitiveArena* pa, U4* ordering_buf) A2_S2 p; //??? S4 flag; //???? - if (0) { + B4 use_c11_path = false; + if (use_c11_path) { camera_look_at_c11(& smem.cam, & smem.cube.pos, & v3s4(0, -fp_one, 0)); } - if (1) + if (use_c11_path == false) { tb.used = 0; tb_scope_run(& tb) { resolve_look_at(& tb, & smem.cam.look_at, & smem.cam.pos, & smem.cube.pos, & v3s4(0, -fp_one, 0)); @@ -376,23 +385,21 @@ void update(PrimitiveArena* pa, U4* ordering_buf) ResolveLookAtScratch_V scratch = C_scratch(ResolveLookAtScratch_V); /* Atoms 0-5 emit into scratch; bundle dispatch for atom 6 is still - * commented at the resolve_look_at_init helper. Until atom 6 is - * enabled, populate look_at.m[][] from the wave-context outputs. */ - forward = scratch->fwd; - uz = scratch->uz; - right = scratch->right; - ux = scratch->ux; - up = scratch->up; - uy = scratch->uy; + * commented at the resolve_look_at_init helper. Until atom 6 is + * enabled, populate look_at.m[][] from the wave-context outputs. */ + forward = scratch->fwd; + uz = scratch->uz; + right = scratch->right; + ux = scratch->ux; + up = scratch->up; + uy = scratch->uy; - smem.cam.look_at.m[0][0] = ux.x; smem.cam.look_at.m[0][1] = ux.y; smem.cam.look_at.m[0][2] = ux.z; - smem.cam.look_at.m[1][0] = uy.x; smem.cam.look_at.m[1][1] = uy.y; smem.cam.look_at.m[1][2] = uy.z; - smem.cam.look_at.m[2][0] = uz.x; smem.cam.look_at.m[2][1] = uz.y; smem.cam.look_at.m[2][2] = uz.z; + // Matrix populate (m[0..2]) and translation column (t[]) are owned + // by tape atoms 6a/6b/6c. See docs/atom_6_activation_cheatsheet.md. // pos = smem.cam.pos; mul_v3s4(& pos, v3s4(-1,-1,-1)); // RGA(Lengyel): -eye in world coordinates (spatial bulk only; implicit weight is dropped). - mul_m3s2_v3s4(& smem.cam.look_at, & pos, & off); - trans_m3s2( & smem.cam.look_at, & off); + // mul_m3s2_v3s4 + trans_m3s2: tape path owns t[] via atom 6c } // Draw cube