1use crate::decode::{Declared, Decoded, Instruction, Operand, Register};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub struct TextureRead {
8 pub word: usize,
10 pub opcode: u16,
12 pub texture: u32,
14 pub texture_indexed: bool,
16 pub sampler: Option<u32>,
18 pub sampler_indexed: bool,
20 pub comparison: bool,
23 pub sampler_mode: Option<u32>,
26}
27
28fn kind(name: &str) -> Option<(bool, bool)> {
30 Some(match name {
31 "sample"
32 | "sample_l"
33 | "sample_d"
34 | "sample_b"
35 | "lod"
36 | "gather4"
37 | "gather4_po"
38 | "gather4_feedback"
39 | "gather4_po_feedback"
40 | "sample_l_feedback"
41 | "sample_clamp_feedback"
42 | "sample_b_clamp_feedback"
43 | "sample_d_clamp_feedback" => (true, false),
44 "sample_c"
45 | "sample_c_lz"
46 | "gather4_c"
47 | "gather4_po_c"
48 | "gather4_c_feedback"
49 | "gather4_po_c_feedback"
50 | "sample_c_lz_feedback"
51 | "sample_c_clamp_feedback" => (true, true),
52 "ld"
53 | "ld_ms"
54 | "ld_raw"
55 | "ld_structured"
56 | "ld_feedback"
57 | "ld_ms_feedback"
58 | "ld_raw_feedback"
59 | "ld_structured_feedback" => (false, false),
60 _ => return None,
61 })
62}
63
64fn register(operand: &Operand) -> Option<(u32, bool)> {
66 let index = operand.indices.first()?;
67 Some((index.base, index.relative.is_some()))
68}
69
70fn first(instruction: &Instruction, wanted: Register) -> Option<&Operand> {
71 instruction.operands.iter().find(|o| o.register == wanted)
72}
73
74pub fn texture_reads(program: &Decoded) -> Vec<TextureRead> {
78 let modes: Vec<(u32, u32)> = program
79 .declarations
80 .iter()
81 .filter_map(|d| match d.kind {
82 Declared::Sampler { slot, mode } => Some((slot, mode)),
83 _ => None,
84 })
85 .collect();
86 let mut reads = Vec::new();
87 for instruction in &program.instructions {
88 let Some((sampled, comparison)) = kind(instruction.name()) else {
89 continue;
90 };
91 let Some((texture, texture_indexed)) = first(instruction, Register::Texture).and_then(register)
92 else {
93 continue;
94 };
95 let sampler = if sampled {
96 first(instruction, Register::Sampler).and_then(register)
97 } else {
98 None
99 };
100 reads.push(TextureRead {
101 word: instruction.word,
102 opcode: instruction.opcode,
103 texture,
104 texture_indexed,
105 sampler: sampler.map(|(slot, _)| slot),
106 sampler_indexed: sampler.is_some_and(|(_, indexed)| indexed),
107 comparison,
108 sampler_mode: sampler.and_then(|(slot, _)| {
109 modes
110 .iter()
111 .find(|(declared, _)| *declared == slot)
112 .map(|(_, mode)| *mode)
113 }),
114 });
115 }
116 reads
117}