use crate::{Result, error, parts};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Statistics {
pub words: Vec<u32>,
}
macro_rules! counters {
($($(#[$doc:meta])* $name:ident = $at:literal;)+) => {
impl Statistics {
$(
$(#[$doc])*
pub fn $name(&self) -> Option<u32> {
self.words.get($at).copied()
}
)+
}
};
}
counters! {
instructions = 0;
temp_registers = 1;
declarations = 3;
float_instructions = 4;
int_instructions = 5;
uint_instructions = 6;
static_flow_control = 7;
dynamic_flow_control = 8;
texture_normal = 14;
texture_load = 15;
texture_comparison = 16;
texture_gradient = 18;
movc_instructions = 20;
sample_frequency = 28;
control_points = 30;
tessellator_output_primitive = 31;
tessellator_partitioning = 32;
tessellator_domain = 33;
}
pub fn statistics(bytes: &[u8]) -> Result<Option<Statistics>> {
let directory = parts(bytes)?;
let Some(stat) = directory.iter().find(|c| &c.kind == b"STAT") else {
return Ok(None);
};
if directory.iter().any(|c| &c.kind == b"DXIL") {
return Err(error(
0,
"the STAT part of a DXIL container is a bitcode module, not counters",
));
}
let (words, rest) = stat.data.as_chunks::<4>();
if !rest.is_empty() {
return Err(error(
stat.data.len() / 4,
format!("the STAT part has {} bytes, not a multiple of 4", stat.data.len()),
));
}
Ok(Some(Statistics {
words: words.iter().map(|w| u32::from_le_bytes(*w)).collect(),
}))
}