xenia-gpu: end-to-end Xenos pipeline (PM4, ucode, EDRAM, resolve)

First real GPU implementation. Ring/PM4 frontend (ring_view,
ring_drain, pm4) drains the command processor; gpu_system owns the
threaded backend (DrainFence RPC + parker/fence helpers from M1) and
the MMIO-mapped register block (mmio_region).

Xenos shader frontend: ucode/{alu,control_flow,fetch,mod}.rs decode
the Xbox 360 microcode, translator.rs lowers it onto the WGSL
xenos_interp interpreter shader (shaders/xenos_interp.wgsl).
shader_metrics.rs counts decode/translate work.

Render state: draw_state, primitive, render_target_cache,
texture_cache, tiled_address (Xenos's swizzled tiled-memory layout),
xenos_constants (register field constants), edram (the 10 MiB EDRAM
model with MSAA), and resolve.rs (TILE_FLUSH copy-out — clear-resolve
plus bitwise-equivalent 32 bpp + 64 bpp paths landed). handle.rs
owns the typed GPU-resource handles the kernel hands out.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-05-01 16:29:38 +02:00
parent 5f0d6487ea
commit 79eb52c378
24 changed files with 10984 additions and 18 deletions

View File

@@ -0,0 +1,117 @@
//! Xenos fetch (vertex + texture) instruction decoder.
//!
//! Like ALU instructions, fetches are 96 bits (3 dwords). The opcode lives
//! in the low 5 bits of word0. We split them into `VertexFetch` and
//! `TextureFetch` structurally because their operand layouts differ.
//!
//! Reference: `xenia-canary/src/xenia/gpu/ucode.h:690-877`.
/// Decoded fetch instruction.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FetchInstruction {
Vertex(VertexFetch),
Texture(TextureFetch),
/// Unknown / minor variants we don't model yet.
Unknown { opcode: u8, raw: [u32; 3] },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct VertexFetch {
/// Vertex fetch constant index (0..=95).
pub fetch_const: u8,
/// Source register index (vertex index in r#).
pub src_register: u8,
/// Destination register for the fetched value.
pub dest_register: u8,
/// 4-bit write mask.
pub dest_write_mask: u8,
pub raw: [u32; 3],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TextureFetch {
/// Texture fetch constant index (0..=31).
pub fetch_const: u8,
pub src_register: u8,
pub dest_register: u8,
pub dest_write_mask: u8,
/// Dimension: 0=1D, 1=2D, 2=3D/stacked, 3=cube.
pub dimension: u8,
pub raw: [u32; 3],
}
/// Opcodes (low 5 bits of word0). From `ucode.h`.
pub mod op {
pub const VERTEX_FETCH: u8 = 0x00;
pub const TEXTURE_FETCH: u8 = 0x01;
pub const GET_TEXTURE_BORDER_COLOR_FRAC: u8 = 0x16;
pub const GET_TEXTURE_COMPUTED_LOD: u8 = 0x17;
pub const GET_TEXTURE_WEIGHTS: u8 = 0x18;
pub const GET_TEXTURE_GRADIENTS: u8 = 0x19;
pub const SET_TEXTURE_LOD: u8 = 0x1A;
pub const SET_TEXTURE_GRADIENTS_HORZ: u8 = 0x1B;
pub const SET_TEXTURE_GRADIENTS_VERT: u8 = 0x1C;
}
pub fn decode_fetch(words: [u32; 3]) -> FetchInstruction {
let w0 = words[0];
let w1 = words[1];
let opcode = (w0 & 0x1F) as u8;
match opcode {
op::VERTEX_FETCH => FetchInstruction::Vertex(VertexFetch {
fetch_const: ((w0 >> 5) & 0x1F) as u8,
src_register: ((w0 >> 17) & 0x7F) as u8,
dest_register: ((w0 >> 10) & 0x7F) as u8,
dest_write_mask: ((w1 >> 23) & 0xF) as u8,
raw: words,
}),
op::TEXTURE_FETCH => FetchInstruction::Texture(TextureFetch {
fetch_const: ((w0 >> 5) & 0x1F) as u8,
src_register: ((w0 >> 17) & 0x7F) as u8,
dest_register: ((w0 >> 10) & 0x7F) as u8,
dest_write_mask: ((w1 >> 23) & 0xF) as u8,
dimension: ((w1 >> 29) & 0x3) as u8,
raw: words,
}),
_ => FetchInstruction::Unknown { opcode, raw: words },
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decode_vertex_fetch() {
// opcode=0 (vertex), fetch_const=5, src=2, dest=7.
let w0 = 0u32 | (5 << 5) | (7 << 10) | (2 << 17);
let v = decode_fetch([w0, 0, 0]);
match v {
FetchInstruction::Vertex(vf) => {
assert_eq!(vf.fetch_const, 5);
assert_eq!(vf.src_register, 2);
assert_eq!(vf.dest_register, 7);
}
other => panic!("expected Vertex, got {other:?}"),
}
}
#[test]
fn decode_texture_fetch() {
let w0 = 1u32 | (3 << 5) | (4 << 10) | (1 << 17);
let t = decode_fetch([w0, (2u32 << 29), 0]);
match t {
FetchInstruction::Texture(tf) => {
assert_eq!(tf.fetch_const, 3);
assert_eq!(tf.dimension, 2);
}
other => panic!("expected Texture, got {other:?}"),
}
}
#[test]
fn unknown_opcode_is_classified() {
let v = decode_fetch([0x16, 0, 0]); // GET_TEXTURE_BORDER_COLOR_FRAC
assert!(matches!(v, FetchInstruction::Unknown { opcode: 0x16, .. }));
}
}