Resolved the "colours look odd" channel-order/sRGB question for k_8_8_8_8 (T8aD 2D UI textures) with no emulator run: - sRGB: Canary's Vulkan host-format table maps plain k_8_8_8_8 to R8G8B8A8_UNORM and contains no R8G8B8A8_SRGB anywhere — gamma is a separate explicit EDRAM path. So these are raw linear bytes; apply no sRGB/gamma decode. - Channel order: measured 789 real disc textures — byte0 is the opaque alpha (==0xFF-dominant) in 97% — so on-disk is ARGB. Cross-checked against xenia-rs decode_k8888_tiled, the Canary-validated M1/M2 path, which nets the same [A,R,G,B]->[R,G,B,A]. sylpheed-formats is correct. Promotes the k8888 entry HYPOTHESIS -> CONFIRMED; INDEX updated. XPR2 skybox tiling + viewer display-gamma remain separate open items. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.4 KiB
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:
- 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 also0x00-heavy from black backgrounds; the==0xFFdiscriminator isolates alpha cleanly.) - Cross-check vs our Canary-validated renderer —
xenia-rs'sdecode_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 Canaryvulkan_texture_cache.cchost-format table; noR8G8B8A8_SRGBentry exists → sRGB/UNORM claimCONFIRMED.2026-07-11— measured==0xFFalpha dominance over 789 disc T8aD textures (byte0 = alpha 97%) + cross-checked vsxenia-rs decode_k8888_tiled(the Canary-validated M1/M2 path). → channel-order claim promotedHYPOTHESIS → CONFIRMED.