diff --git a/crates/xenia-gpu/src/draw_capture.rs b/crates/xenia-gpu/src/draw_capture.rs index 18938f2..90db985 100644 --- a/crates/xenia-gpu/src/draw_capture.rs +++ b/crates/xenia-gpu/src/draw_capture.rs @@ -191,29 +191,42 @@ fn resolve_vertex_window( rf: &RegisterFile, mem: &dyn MemoryAccess, ) -> Option<(Vec, u32)> { - // The instruction block is 3 dwords per ALU/fetch triple. We don't have - // per-triple kind flags here, so we scan every triple and accept the - // first one that decodes as a *vertex* fetch with a plausible constant. + // iterate-3W (GPUBUG-109): the instruction block packs ALU and fetch + // instructions identically (96 bits / 3 dwords each); ONLY the owning + // `Exec` control-flow clause's `sequence` bitmap (2 bits per instruction, + // bit[2*i]=fetch/ALU) tells them apart. The previous blind triple-walk + // decoded ALU triples as fetches → garbage fetch-constant indices and a + // bogus `type==3` guard, never reaching the real vertex fetch. Walk the CF + // exec clauses exactly as the translator does (`translator.rs::emit_exec`) + // and take the FIRST sequence-flagged *vertex* fetch. let instrs = &parsed_vs.instructions; let mut fetch_const: Option = None; - let mut t = 0usize; - while t + 2 < instrs.len() { - let w0 = instrs[t]; - let w1 = instrs[t + 1]; - let w2 = instrs[t + 2]; - if let crate::ucode::fetch::FetchInstruction::Vertex(vf) = - crate::ucode::fetch::decode_fetch([w0, w1, w2]) - { - // Validate the referenced fetch constant is a real vertex fetch - // (type==3, kVertex) before trusting it. - let fc = vf.fetch_const as u32; - let dword0 = rf.read(CONST_BASE_FETCH + fc * 6); - if dword0 & 0x3 == 3 { - fetch_const = Some(vf.fetch_const); + 'clauses: for clause in &parsed_vs.cf { + let crate::ucode::control_flow::ControlFlowInstruction::Exec { + address, + count, + sequence, + .. + } = *clause + else { + continue; + }; + for i in 0..(count as usize) { + // bit[2*i] of the sequence bitmap: 1 = fetch, 0 = ALU. + if (sequence >> (i * 2)) & 1 == 0 { + continue; + } + let base = (address as usize + i) * 3; + if base + 2 >= instrs.len() { break; } + if let crate::ucode::fetch::FetchInstruction::Vertex(vf) = + crate::ucode::fetch::decode_fetch([instrs[base], instrs[base + 1], instrs[base + 2]]) + { + fetch_const = Some(vf.fetch_const); + break 'clauses; + } } - t += 3; } let fc = fetch_const? as u32; let dword0 = rf.read(CONST_BASE_FETCH + fc * 6);