# Texture colour interpretation — `k_8_8_8_8` (32bpp UI/HUD textures) - **Confidence:** mixed — see per-claim tags below. - **Parser in:** `sylpheed-formats/src/t8ad.rs`, `src/texture.rs` (XPR2) - **Applies to:** T8aD 2D UI textures, XPR2 32bpp surfaces — the "colours look a bit odd" concern. - **Related:** [[reborn-dynamic-re-plan]], INDEX rows T8aD / XPR2. ## What this resolves Whether our decoded 32bpp textures use the right **sRGB-vs-linear** interpretation and the right **channel order**. Ground truth = Canary's Vulkan texture cache, which is the code that actually produces correct on-screen colour. ## Findings ### ✅ CONFIRMED — plain `k_8_8_8_8` is LINEAR (UNORM), never sRGB Canary's host-format table maps plain `k_8_8_8_8` → `VK_FORMAT_R8G8B8A8_UNORM` with a straight 32-bit copy load shader (`kLoadShaderIndex32bpb`) and an **identity** format swizzle (`XE_GPU_TEXTURE_SWIZZLE_RGBA`). There is **no** `..._SRGB` host format anywhere in the table; gamma is a separate explicit path (`k_8_8_8_8_GAMMA_EDRAM` only). Therefore a plain 32bpp texture is sampled as **raw UNORM bytes — apply no sRGB/gamma decode.** → *Implication:* if the viewer/engine applies an sRGB→linear (or linear→sRGB) step to these, that is wrong. Show the bytes as-is (raw RGBA8), gamma only where the game explicitly requests it. ### ✅ CONFIRMED — on-disk order is **ARGB** (alpha first); `[a,r,g,b]→[r,g,b,a]` is correct Settled by two independent lines that agree, without an emulator run: 1. **Measured on the disc data** — across 789 real T8aD textures (GP_HANGAR_ARSENAL, GP_MAIN_GAME_E, DefTables), the byte position that is most-often exactly `0xFF` (the opaque-alpha signature of UI art) is **byte 0 in 767/789 (97%)** — tf1 385/0, tf2 382/12. So texel byte 0 = alpha ⇒ on-disk layout is **A,R,G,B**. (An earlier bimodality test tied byte0/byte3 only because colour channels are also `0x00`-heavy from black backgrounds; the `==0xFF` discriminator isolates alpha cleanly.) 2. **Cross-check vs our Canary-validated renderer** — `xenia-rs`'s `decode_k8888_tiled` (the path behind the user-confirmed M1 splash / M2 video colours) nets memory-`ARGB` → endian-swap → `swap(0,2)` = `[A,R,G,B]→[R,G,B,A]`, identical to ours. Since that renderer was confirmed against Canary's output, Canary's ground truth is transitively in this chain. Net: our channel order and the linear/UNORM interpretation are both **correct** for the ~85% RGBA variants. A live Canary framebuffer capture would be redundant confirmation, not a new signal. ## Remaining / adjacent - **XPR2** shares the ARGB→RGBA reorder + the linear/UNORM finding, but its **tiling** (de-tile) is a separate path; if XPR2 skyboxes still look odd it's tiling or viewer display-gamma, not channel order. - **Viewer display gamma:** decode is correct; if egui shows these too dark/bright it's how egui interprets the RGBA8 (sRGB-encoded vs linear) at display time — a rendering nit, not a decode bug. ## Evidence log - `2026-07-11` — static read of Canary `vulkan_texture_cache.cc` host-format table; no `R8G8B8A8_SRGB` entry exists → sRGB/UNORM claim `CONFIRMED`. - `2026-07-11` — measured `==0xFF` alpha dominance over 789 disc T8aD textures (byte0 = alpha 97%) + cross-checked vs `xenia-rs decode_k8888_tiled` (the Canary-validated M1/M2 path). → channel-order claim promoted `HYPOTHESIS → CONFIRMED`.