[iterate-4A] intro-video ROOT #3: render the YUV movie in correct color
The intro video (ADV.wmv) now plays end-to-end in correct color. Three stacked host-render-path bugs, each masked by the prior: #3a Multi-texture render path. The host bound a single texture slot, so the YUV pixel shader's three plane fetches (Y 1280x720 + U/V 640x360, all k_8) collapsed onto one texture. Expanded the Xenos pipeline to 8 tex+1 sampler slots (xenos_pipeline.rs, xenos_interp.wgsl, translator.rs headers); each tfetch selects its texture by fetch-constant slot; the DrawCapture textures tuple now carries the slot; render.rs uploads+binds every plane per-draw. Also added the scalar-constant ALU ops MULSC/ADDSC/ SUBSC (42-47) the YUV->RGB shader uses. #3b tfetch destination swizzle. decode_fetch read the tfetch dest as a 4-bit write mask (w1 & 0xF), but Xenos tfetch dword1[0:11] is a 12-bit destination swizzle (3 bits/component: 0-3=xyzw, 4/5=const 0/1, 6/7=keep). The result: all three plane fetches did a full-vec4 overwrite of the dest register, so only the last plane survived. Decode the real 12-bit swizzle (dest_swizzle) and emit per-lane writes so Y/U/V coexist in r1.x/.y/.z. #3c Pixel-shader constant bank. Xenos splits the 512-entry float-constant file: the vertex shader addresses c0..255 -> physical 0..255, but the pixel shader's c0..255 map to physical 256..511. The game uploads the YUV->RGB coefficients to physical 510/511. Our translator indexed the low half for PS constants, reading all-zero -> R=B=Y^2, G=0 (magenta). emit_alu now adds a const_base of 256 for pixel-stage constant reads. Plus a bounded (FIFO, 64-entry) host texture cache: the movie streams ~3 new-VA planes per frame, and the previously-unbounded cache exhausted GPU memory into a device-lost crash mid-playback. Verified visually: the SQUARE ENIX logo and ADV.wmv footage render in correct color (was magenta); the translated movie shader now reads alu[510]/alu[511]; frame green channel is nonzero and R != B. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -81,7 +81,15 @@ pub struct TextureFetch {
|
||||
pub fetch_const: u8,
|
||||
pub src_register: u8,
|
||||
pub dest_register: u8,
|
||||
pub dest_write_mask: u8,
|
||||
/// Destination swizzle — 12 bits, 3 per output component (Xenos tfetch
|
||||
/// dword1 bits 0..11). Per canary `ucode.h`, each 3-bit code selects:
|
||||
/// 0..3 = sampled X/Y/Z/W, 4 = constant 0.0, 5 = constant 1.0,
|
||||
/// 6/7 = keep (destination component unwritten).
|
||||
/// The old `dest_write_mask: (w1 & 0xF)` read collapsed this to a bogus
|
||||
/// 4-bit mask, so multi-plane fetches (the intro video's Y/U/V, all
|
||||
/// targeting r1 but each in its own lane) each did a *full* `r1 = sample`
|
||||
/// overwrite — only the last plane survived → wrong-color video.
|
||||
pub dest_swizzle: u16,
|
||||
/// Dimension: 0=1D, 1=2D, 2=3D/stacked, 3=cube.
|
||||
pub dimension: u8,
|
||||
pub raw: [u32; 3],
|
||||
@@ -140,7 +148,7 @@ pub fn decode_fetch(words: [u32; 3]) -> FetchInstruction {
|
||||
fetch_const: ((w0 >> 20) & 0x1F) as u8,
|
||||
src_register: ((w0 >> 5) & 0x3F) as u8,
|
||||
dest_register: ((w0 >> 12) & 0x3F) as u8,
|
||||
dest_write_mask: (w1 & 0xF) as u8,
|
||||
dest_swizzle: (w1 & 0xFFF) as u16,
|
||||
dimension: ((w2 >> 14) & 0x3) as u8,
|
||||
raw: words,
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user