use crate::decode::{Declared, Decoded, Instruction, Operand, Register};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TextureRead {
pub word: usize,
pub opcode: u16,
pub texture: u32,
pub texture_indexed: bool,
pub sampler: Option<u32>,
pub sampler_indexed: bool,
pub comparison: bool,
pub sampler_mode: Option<u32>,
}
fn kind(name: &str) -> Option<(bool, bool)> {
Some(match name {
"sample"
| "sample_l"
| "sample_d"
| "sample_b"
| "lod"
| "gather4"
| "gather4_po"
| "gather4_feedback"
| "gather4_po_feedback"
| "sample_l_feedback"
| "sample_clamp_feedback"
| "sample_b_clamp_feedback"
| "sample_d_clamp_feedback" => (true, false),
"sample_c"
| "sample_c_lz"
| "gather4_c"
| "gather4_po_c"
| "gather4_c_feedback"
| "gather4_po_c_feedback"
| "sample_c_lz_feedback"
| "sample_c_clamp_feedback" => (true, true),
"ld"
| "ld_ms"
| "ld_raw"
| "ld_structured"
| "ld_feedback"
| "ld_ms_feedback"
| "ld_raw_feedback"
| "ld_structured_feedback" => (false, false),
_ => return None,
})
}
fn register(operand: &Operand) -> Option<(u32, bool)> {
let index = operand.indices.first()?;
Some((index.base, index.relative.is_some()))
}
fn first(instruction: &Instruction, wanted: Register) -> Option<&Operand> {
instruction.operands.iter().find(|o| o.register == wanted)
}
pub fn texture_reads(program: &Decoded) -> Vec<TextureRead> {
let modes: Vec<(u32, u32)> = program
.declarations
.iter()
.filter_map(|d| match d.kind {
Declared::Sampler { slot, mode } => Some((slot, mode)),
_ => None,
})
.collect();
let mut reads = Vec::new();
for instruction in &program.instructions {
let Some((sampled, comparison)) = kind(instruction.name()) else {
continue;
};
let Some((texture, texture_indexed)) = first(instruction, Register::Texture).and_then(register)
else {
continue;
};
let sampler = if sampled {
first(instruction, Register::Sampler).and_then(register)
} else {
None
};
reads.push(TextureRead {
word: instruction.word,
opcode: instruction.opcode,
texture,
texture_indexed,
sampler: sampler.map(|(slot, _)| slot),
sampler_indexed: sampler.is_some_and(|(_, indexed)| indexed),
comparison,
sampler_mode: sampler.and_then(|(slot, _)| {
modes
.iter()
.find(|(declared, _)| *declared == slot)
.map(|(_, mode)| *mode)
}),
});
}
reads
}