From a0f97d307d8bc8ff8b553b0afe2b486249f799de Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 13:17:47 +0000 Subject: [PATCH] Read packed three-byte vertex attributes without touching the next word load_u24 and raw_fetch_u8_3 read a whole 32-bit word pair even when the three bytes sit in the first word, so an attribute at the end of its binding read past it. Release builds disable Dawn's robustness, so that read isn't clamped. From upstream patchzyy/Wiicompiled 6f14bde (#244, KartPad 0f6b274). Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01Wg7mB8ogCWmp9GH19Uc82B --- aurora-main/lib/gx/shader.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/aurora-main/lib/gx/shader.cpp b/aurora-main/lib/gx/shader.cpp index 4b07fb2..4467a23 100644 --- a/aurora-main/lib/gx/shader.cpp +++ b/aurora-main/lib/gx/shader.cpp @@ -1739,8 +1739,22 @@ fn load_u16(p: ptr>, byte_off: u32, le: bool) -> u32 {{ return bswap16(raw, le); }} +fn load_u24_raw(p: ptr>, byte_off: u32) -> u32 {{ + let word_idx = byte_off >> 2u; + let sub = byte_off & 3u; + let word = p[word_idx]; + // Three bytes at offsets zero or one fit entirely in this word. Do not + // access the next word: this attribute may end at the binding boundary. + if (sub <= 1u) {{ + return (word >> (sub * 8u)) & 0x00FFFFFFu; + }} + let next = p[word_idx + 1u]; + let shift = sub * 8u; + return ((word >> shift) | (next << (32u - shift))) & 0x00FFFFFFu; +}} + fn load_u24(p: ptr>, byte_off: u32, le: bool) -> u32 {{ - let raw = load_u32_raw(p, byte_off) & 0x00FFFFFFu; + let raw = load_u24_raw(p, byte_off); if (le) {{ return raw; }} @@ -1780,7 +1794,7 @@ fn raw_fetch_u8_2(p: ptr>, byte_off: u32) -> vec2u {{ }} fn raw_fetch_u8_3(p: ptr>, byte_off: u32) -> vec3u {{ - let raw = load_u32_raw(p, byte_off); + let raw = load_u24_raw(p, byte_off); return vec3u( extractBits(raw, 0u, 8u), extractBits(raw, 8u, 8u),