Atoms 2-3 work for resolve look at. Don't need OA_ macro so going to stop using.

This commit is contained in:
ed
2026-08-11 21:35:59 -04:00
parent 7daeec0ee3
commit 7807047dc0
6 changed files with 100 additions and 62 deletions
+2 -2
View File
@@ -176,8 +176,8 @@ WORD_COUNT(mac_gte_sqr_v3, 8)
WORD_COUNT(mac_gte_gpf_scale, 13) WORD_COUNT(mac_gte_gpf_scale, 13)
#define mac_gcmd_push(cmd, reg_transfer, reg_base, port) \ #define mac_gcmd_push(cmd, reg_transfer, reg_base, port) \
load_upper_i(reg_transfer, cmd >> 16) \ load_upper_i(reg_transfer, u4_hi(cmd)) \
, or_i_self( reg_transfer, cmd & 0xFFFF) \ , or_i_self( reg_transfer, u4_lo(cmd)) /* load_upper_i(reg_transfer, cmd >> 16), // or_i_self( reg_transfer, cmd & 0xFFFF), */ \
, store_word( reg_transfer, reg_base, port) , store_word( reg_transfer, reg_base, port)
WORD_COUNT(mac_gcmd_push, 3) WORD_COUNT(mac_gcmd_push, 3)
+4 -4
View File
@@ -25,14 +25,14 @@
#pragma region duffle #pragma region duffle
// --- atom: normalize_v3s4 (63 words) --- // --- atom: normalize_v3s4 (66 words) ---
#define _atom_offset_srav_path_aligned_done 6 #define _atom_offset_aligned_done_srav_path 3
#define _atom_offset_aligned_done_srav_path 1 #define _atom_offset_srav_path_aligned_done 4
enum { enum {
atom_offset_srav_path_aligned_done = _atom_offset_srav_path_aligned_done,
atom_offset_aligned_done_srav_path = _atom_offset_aligned_done_srav_path, atom_offset_aligned_done_srav_path = _atom_offset_aligned_done_srav_path,
atom_offset_srav_path_aligned_done = _atom_offset_srav_path_aligned_done,
}; };
// --- atom: pad_bios_snapshot (84 words) --- // --- atom: pad_bios_snapshot (84 words) ---
+4 -2
View File
@@ -10,8 +10,10 @@ ATOM_FILE_DEBUGGER_LINE_MARKER(gp_atom_c);
FI_ Slice_MipsCode ac_gcmd_push(AtomBuilder_R ab, U4 cmd, U4 reg_transfer, U4 reg_base, U2 port) FI_ Slice_MipsCode ac_gcmd_push(AtomBuilder_R ab, U4 cmd, U4 reg_transfer, U4 reg_base, U2 port)
MipsAtomComp_Proc_(ac_gcmd_push, ab, { MipsAtomComp_Proc_(ac_gcmd_push, ab, {
load_upper_i(reg_transfer, cmd >> 16), load_upper_i(reg_transfer, u4_hi(cmd)),
or_i_self( reg_transfer, cmd & 0xFFFF), or_i_self( reg_transfer, u4_lo(cmd)),
// load_upper_i(reg_transfer, cmd >> 16),
// or_i_self( reg_transfer, cmd & 0xFFFF),
store_word( reg_transfer, reg_base, port), store_word( reg_transfer, reg_base, port),
}) })
+2 -2
View File
@@ -27,7 +27,7 @@
* to author and compose programs with. From here various conventions can be further applied. * to author and compose programs with. From here various conventions can be further applied.
* To make things easier to understand it may be better to focus on what this ABI does not have. * To make things easier to understand it may be better to focus on what this ABI does not have.
* It does not have have any branching within the tape but relative branches within atoms or between atoms. * It does not have have any branching within the tape but relative branches within atoms or between atoms.
* Branching nearly is always downstream. Atuomatic stack usage is non-existent. * Branching nearly is always downstream. Automatic stack usage is non-existent.
* Push/Pop, FIFO, or Arena/Bump data structures are used by atoms explicitly. * Push/Pop, FIFO, or Arena/Bump data structures are used by atoms explicitly.
* In it's current form with the C11 macro DSL, the user also has fullfill manual register allocation per atom. * In it's current form with the C11 macro DSL, the user also has fullfill manual register allocation per atom.
* *
@@ -39,7 +39,7 @@
* but, we can set the foundation for legoing whats required for eventually expanding this ABI's paradigm * but, we can set the foundation for legoing whats required for eventually expanding this ABI's paradigm
* and core atoms to take those newer hardware features into account. For example, you can easily expand * and core atoms to take those newer hardware features into account. For example, you can easily expand
* this to support wave-based execution model on a PS2 or PS3. Not having a stack or * this to support wave-based execution model on a PS2 or PS3. Not having a stack or
* automatic register allocation means the user cannott ignore excessive argument shuffle across workload or * automatic register allocation means the user cannot ignore excessive argument shuffle across workload or
* waves and thier phases. Crossing ABI boundaries to other runtimes that do has obviouss penalties. * waves and thier phases. Crossing ABI boundaries to other runtimes that do has obviouss penalties.
* *
* Learning data-oreinted code becomes a natural progression. Your not fighting a stack-based procedural * Learning data-oreinted code becomes a natural progression. Your not fighting a stack-based procedural
+74 -36
View File
@@ -293,7 +293,7 @@ I_ MipsAtom* resolve_look_at__cross_uz_up_in_to_right_proc(AtomArena_R aa, U4 r_
, U4 r_d /* load b.x */ , U4 r_d /* load b.x */
, U4 r_f, U4 r_g, U4 r_h /* r_f = &right (out ptr), r_g = &uz, r_h = &up_in */ , U4 r_f, U4 r_g, U4 r_h /* r_f = &right (out ptr), r_g = &uz, r_h = &up_in */
) MipsAtom_Proc_(resolve_look_at__cross_uz_up_in_to_right, aa, { ) MipsAtom_Proc_(resolve_look_at__cross_uz_up_in_to_right, aa, {
/* Compute the three scratch pointers from r_scratch. */ /* FIX: build packed RT22+RT33 with proper sign extension. */
add_si(r_g, r_scratch, O_(ResolveLookAtScratch,uz)), /* r_g = &uz */ 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_h, r_scratch, O_(ResolveLookAtScratch,up_in)), /* r_h = &up_in */
add_si(r_f, r_scratch, O_(ResolveLookAtScratch,right)), /* r_f = &right (out) */ add_si(r_f, r_scratch, O_(ResolveLookAtScratch,right)), /* r_f = &right (out) */
@@ -305,24 +305,51 @@ I_ MipsAtom* resolve_look_at__cross_uz_up_in_to_right_proc(AtomArena_R aa, U4 r_
load_word(r_c, r_g, O_(V3_S4,z)), load_word(r_c, r_g, O_(V3_S4,z)),
nop, nop,
/* Load b (up_in).x/y/z into r_d + R_AT/R_V0 /* Load b (up_in).x/y/z into r_d + R_AT/R_V0 (R_AT/R_V0 are hardcoded scratch). */
(hardcoded; reusing the body's last two loads is fine because the load-delay slot is the nop after the third load,
and mtc2 below doesn't read these regs). */
load_word(r_d, r_h, O_(V3_S4,x)), load_word(r_d, r_h, O_(V3_S4,x)),
load_word(R_AT, r_h, O_(V3_S4,y)), load_word(R_AT, r_h, O_(V3_S4,y)),
load_word(R_V0, r_h, O_(V3_S4,z)), load_word(R_V0, r_h, O_(V3_S4,z)),
nop, nop,
/* mtc2 a → IR1/2/3, b → D1/2/3 (VXY0/VZ0/VXY1). */ /* Save the two RT control-register slots OP will clobber. We reuse
gte_mv_to_data_r(r_a, C2_IR1), * r_g/r_h (scratch pointers, no longer needed) as the save targets. */
gte_mv_to_data_r(r_b, C2_IR2), gte_mv_from_ctrl_r(r_g, gte_cr_RT11), /* r_g = C2 r0 (RT11|RT12) */
gte_mv_to_data_r(r_c, C2_IR3), gte_mv_from_ctrl_r(r_h, gte_cr_RT22), /* r_h = C2 r4 (RT22|RT33) */
gte_mv_to_data_r(r_d, C2_VXY0), /* D1 = b.x */
gte_mv_to_data_r(R_AT, C2_VZ0), /* D2 = b.y */ /* Load uz.x/uz.y/uz.z into COP2 control registers.
gte_mv_to_data_r(R_V0, C2_VXY1), /* D3 = b.z */ * 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 EXACTLY. */
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 (low 16 of $0, sign-extended by OP). */
nop2, /* CTC2 retirement (CPU→COP2 2-slot delay) */
/* 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_V0, C2_IR3), /* IR3 = up_in.z */
nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */ nop2, /* MTC2 retirement (CPU→COP2 2-slot delay) */
gte_cmdw_outer_product, /* OP fires; MAC1/2/3 = a × b */ gte_cmdw_outer_product, /* 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_g, gte_cr_RT11), /* restore C2 r0 (RT11|RT12) */
gte_mv_to_ctrl_r(r_h, gte_cr_RT22), /* restore C2 r4 (RT22|RT33) */
/* mfc2 MAC1/2/3 → r_a/r_b/r_c (out.x/y/z). */ /* mfc2 MAC1/2/3 → r_a/r_b/r_c (out.x/y/z). */
gte_mv_from_data_r(r_a, C2_MAC1), gte_mv_from_data_r(r_a, C2_MAC1),
@@ -330,6 +357,12 @@ I_ MipsAtom* resolve_look_at__cross_uz_up_in_to_right_proc(AtomArena_R aa, U4 r_
gte_mv_from_data_r(r_c, C2_MAC3), gte_mv_from_data_r(r_c, C2_MAC3),
nop, /* MFC2 retirement */ 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. */
shift_aright(r_a, r_a, 12),
shift_aright(r_b, r_b, 12),
shift_aright(r_c, r_c, 12),
/* Store out.x/y/z to r_f (out ptr = scratch+32). */ /* Store out.x/y/z to r_f (out ptr = scratch+32). */
store_word(r_a, r_f, O_(V3_S4,x)), store_word(r_a, r_f, O_(V3_S4,x)),
store_word(r_b, r_f, O_(V3_S4,y)), store_word(r_b, r_f, O_(V3_S4,y)),
@@ -376,6 +409,11 @@ I_ MipsAtom* resolve_look_at__cross_uz_ux_to_up_proc(AtomArena_R aa, U4 r_scratc
gte_mv_from_data_r(r_b, C2_MAC2), gte_mv_from_data_r(r_b, C2_MAC2),
gte_mv_from_data_r(r_c, C2_MAC3), gte_mv_from_data_r(r_c, C2_MAC3),
nop, 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. */
shift_aright(r_a, r_a, 12),
shift_aright(r_b, r_b, 12),
shift_aright(r_c, r_c, 12),
store_word(r_a, r_f, O_(V3_S4,x)), store_word(r_a, r_f, O_(V3_S4,x)),
store_word(r_b, r_f, O_(V3_S4,y)), store_word(r_b, r_f, O_(V3_S4,y)),
store_word(r_c, r_f, O_(V3_S4,z)), store_word(r_c, r_f, O_(V3_S4,z)),
@@ -505,47 +543,47 @@ internal MipsAtom_(screen_env_init) atom_info(atom_phase(screen_init)
/* display[0] = (0, 0, 320, 240); rest of struct zeroed. */ /* display[0] = (0, 0, 320, 240); rest of struct zeroed. */
add_ui(R_ScreenX, R_0, ScreenRes_X), add_ui(R_ScreenY, R_0, ScreenRes_Y), add_ui(R_ScreenX, R_0, ScreenRes_X), add_ui(R_ScreenY, R_0, ScreenRes_Y),
mac_store_v2s2(R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DisplayEnv,display_area.width) + OA_(DoubleBuffer,display,0)), mac_store_v2s2(R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DisplayEnv,display_area.width) + OA_(DoubleBuffer,display,0)),
store_word(R_0, R_ScreenBuf, O_(DisplayEnv,display_area) + OA_(DoubleBuffer,display,0)), store_word(R_0, R_ScreenBuf, O_(DisplayEnv,display_area) + O_(DoubleBuffer,display[0])),
store_word(R_0, R_ScreenBuf, O_(DisplayEnv,screen) + OA_(DoubleBuffer,display,0)), store_word(R_0, R_ScreenBuf, O_(DisplayEnv,screen) + O_(DoubleBuffer,display[0])),
store_word(R_0, R_ScreenBuf, O_(DisplayEnv,vinterlace) + OA_(DoubleBuffer,display,0)), store_word(R_0, R_ScreenBuf, O_(DisplayEnv,vinterlace) + O_(DoubleBuffer,display[0])),
/* display[1] = (0, 240, 320, 240); rest of struct zeroed. */ /* display[1] = (0, 240, 320, 240); rest of struct zeroed. */
mac_store_rects2(R_0, R_ScreenY, R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DisplayEnv,display_area) + OA_(DoubleBuffer,display,1)), mac_store_rects2(R_0, R_ScreenY, R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DisplayEnv,display_area) + O_(DoubleBuffer,display[1])),
store_word(R_0, R_ScreenBuf, O_(DisplayEnv,screen) + OA_(DoubleBuffer,display,1)), store_word(R_0, R_ScreenBuf, O_(DisplayEnv,screen) + O_(DoubleBuffer,display[1])),
store_word(R_0, R_ScreenBuf, O_(DisplayEnv,vinterlace) + OA_(DoubleBuffer,display,1)), store_word(R_0, R_ScreenBuf, O_(DisplayEnv,vinterlace) + O_(DoubleBuffer,display[1])),
mac_store_rects2(R_0, R_ScreenY, R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DrawEnv,clip_area) + OA_(DoubleBuffer,draw,0)), /* draw[0].clip_area = (0, 240, 320, 240). C11's SetDefDrawEnv writes clip.y = y_arg. */ mac_store_rects2(R_0, R_ScreenY, R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DrawEnv,clip_area) + O_(DoubleBuffer,draw[0])), /* draw[0].clip_area = (0, 240, 320, 240). C11's SetDefDrawEnv writes clip.y = y_arg. */
mac_store_v2s2( R_0, R_ScreenY, R_ScreenBuf, O_(DrawEnv,drawing_offset[0]) + OA_(DoubleBuffer,draw,0)), /* draw[0].drawing_offset[0] = (0, 240); C11 passes y_arg as ofs. */ mac_store_v2s2( R_0, R_ScreenY, R_ScreenBuf, O_(DrawEnv,drawing_offset[0]) + O_(DoubleBuffer,draw[0])), /* draw[0].drawing_offset[0] = (0, 240); C11 passes y_arg as ofs. */
mac_store_v2s2(R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DrawEnv,clip_area.width) + OA_(DoubleBuffer,draw,1)), mac_store_v2s2(R_ScreenX, R_ScreenY, R_ScreenBuf, O_(DrawEnv,clip_area.width) + O_(DoubleBuffer,draw[1])),
/* draw[0].texture_window = (0, 0, 0, 0); two word-zeroes cover the full 8-byte tw field. */ /* draw[0].texture_window = (0, 0, 0, 0); two word-zeroes cover the full 8-byte tw field. */
store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.x) + OA_(DoubleBuffer,draw,0)), store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.x) + O_(DoubleBuffer,draw[0])),
store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.width) + OA_(DoubleBuffer,draw,0)), store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.width) + O_(DoubleBuffer,draw[0])),
store_word(R_0, R_ScreenBuf, O_(DrawEnv,drawing_offset[0].x) + OA_(DoubleBuffer,draw,1)), store_word(R_0, R_ScreenBuf, O_(DrawEnv,drawing_offset[0].x) + O_(DoubleBuffer,draw[1])),
store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.x) + OA_(DoubleBuffer,draw,1)), store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.x) + O_(DoubleBuffer,draw[1])),
store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.width) + OA_(DoubleBuffer,draw,1)), store_word(R_0, R_ScreenBuf, O_(DrawEnv,texture_window.width) + O_(DoubleBuffer,draw[1])),
/* draw[0].texture_page = 10 (gp0_tpage_default). C11 SetDefDrawEnv at C11_only.elf:0x8001273C writes the same 0x0A. . */ /* draw[0].texture_page = 10 (gp0_tpage_default). C11 SetDefDrawEnv at C11_only.elf:0x8001273C writes the same 0x0A. . */
add_ui(R_T0, R_0, gp0_tpage_default), add_ui(R_T0, R_0, gp0_tpage_default),
store_half(R_T0, R_ScreenBuf, O_(DrawEnv,texture_page) + OA_(DoubleBuffer,draw,0)), store_half(R_T0, R_ScreenBuf, O_(DrawEnv,texture_page) + O_(DoubleBuffer,draw[0])),
store_half(R_T0, R_ScreenBuf, O_(DrawEnv,texture_page) + OA_(DoubleBuffer,draw,1)), store_half(R_T0, R_ScreenBuf, O_(DrawEnv,texture_page) + O_(DoubleBuffer,draw[1])),
/* draw[0] control bytes: flag_dither=1, flag_draw_on_display=1 (the dfe bit per psx-spx; libpsyx sets it via `SetDefDrawEnv`'s conditional at C11_only.elf:0x80012728), enable_auto_clear=1. Each byte is named; /* draw[0] control bytes: flag_dither=1, flag_draw_on_display=1 (the dfe bit per psx-spx; libpsyx sets it via `SetDefDrawEnv`'s conditional at C11_only.elf:0x80012728), enable_auto_clear=1. Each byte is named;
* the previous `store_word(R_0, ..., +20)` overwrote all four with zero. */ * the previous `store_word(R_0, ..., +20)` overwrote all four with zero. */
add_ui(R_T0, R_0, 1), add_ui(R_T0, R_0, 1),
store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_dither) + OA_(DoubleBuffer,draw,0)), store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_dither) + O_(DoubleBuffer,draw[0])),
store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_draw_on_display) + OA_(DoubleBuffer,draw,0)), store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_draw_on_display) + O_(DoubleBuffer,draw[0])),
store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,enable_auto_clear) + OA_(DoubleBuffer,draw,0)), store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,enable_auto_clear) + O_(DoubleBuffer,draw[0])),
store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_dither) + OA_(DoubleBuffer,draw,1)), store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_dither) + O_(DoubleBuffer,draw[1])),
store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_draw_on_display) + OA_(DoubleBuffer,draw,1)), store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,flag_draw_on_display) + O_(DoubleBuffer,draw[1])),
store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,enable_auto_clear) + OA_(DoubleBuffer,draw,1)), store_byte(R_T0, R_ScreenBuf, O_(DrawEnv,enable_auto_clear) + O_(DoubleBuffer,draw[1])),
/* draw[0].initial_bg_color = (r=7, g=7, b=7). */ /* draw[0].initial_bg_color = (r=7, g=7, b=7). */
add_ui(R_T0, R_0, 7), add_ui(R_T0, R_0, 7),
mac_store_rgb8(R_T0,R_T0,R_T0, R_ScreenBuf, O_(DrawEnv,initial_bg_color) + OA_(DoubleBuffer,draw,0)), mac_store_rgb8(R_T0,R_T0,R_T0, R_ScreenBuf, O_(DrawEnv,initial_bg_color) + O_(DoubleBuffer,draw[0])),
mac_store_rgb8(R_T0,R_T0,R_T0, R_ScreenBuf, O_(DrawEnv,initial_bg_color) + OA_(DoubleBuffer,draw,1)), mac_store_rgb8(R_T0,R_T0,R_T0, R_ScreenBuf, O_(DrawEnv,initial_bg_color) + O_(DoubleBuffer,draw[1])),
mac_yield(), mac_yield(),
}; };
+6 -8
View File
@@ -276,10 +276,10 @@ I_ void resolve_look_at(
tb_data(tb, u4_(smem.scratchpad)); /* Binds_ResolveLookAtScratch.scratch_base */ tb_data(tb, u4_(smem.scratchpad)); /* Binds_ResolveLookAtScratch.scratch_base */
} }
/* Atoms 1-5: disabled (atom 1 verification below) */ /* Atoms 1 + 2: enabled. */
tb_emit(tb, smem.resolve_look_at_atom_addrs[1]); { } tb_emit(tb, smem.resolve_look_at_atom_addrs[1]); { }
// tb_emit(tb, smem.resolve_look_at_atom_addrs[2]); { } tb_emit(tb, smem.resolve_look_at_atom_addrs[2]); { }
// tb_emit(tb, smem.resolve_look_at_atom_addrs[3]); { } tb_emit(tb, smem.resolve_look_at_atom_addrs[3]); { }
// tb_emit(tb, smem.resolve_look_at_atom_addrs[4]); { } // tb_emit(tb, smem.resolve_look_at_atom_addrs[4]); { }
// tb_emit(tb, smem.resolve_look_at_atom_addrs[5]); { } // tb_emit(tb, smem.resolve_look_at_atom_addrs[5]); { }
@@ -357,12 +357,10 @@ void update(PrimitiveArena* pa, U4* ordering_buf)
// Atom 0: Works (tape emits fwd to scratch+0; C-side reads it back) // Atom 0: Works (tape emits fwd to scratch+0; C-side reads it back)
forward = scratch->fwd; forward = scratch->fwd;
uz = scratch->uz;
right = scratch->right;
ux = scratch->ux;
// C-side normalize fallback (atom 1 disabled)
// normalize_v3s4(& forward, & uz);
uz = scratch->uz; /* tape-side: enable after verifying atom 1 fix */
cross_v3s4(& uz, & v3s4(0, -fp_one, 0), & right); normalize_v3s4(& right, & ux);
cross_v3s4(& uz, & ux, & up); normalize_v3s4(& up, & uy); cross_v3s4(& uz, & ux, & up); normalize_v3s4(& up, & 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[0][0] = ux.x; smem.cam.look_at.m[0][1] = ux.y; smem.cam.look_at.m[0][2] = ux.z;