use crate::decode::{Declaration, Declared, Instruction};
fn low8(v: u32) -> u8 {
let [byte, ..] = v.to_le_bytes();
byte
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct SyncFlags {
pub threads_in_group: bool,
pub group_shared_memory: bool,
pub uav_group: bool,
pub uav_global: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum InfoReturn {
Float,
ReciprocalFloat,
Uint,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct GlobalFlags {
pub refactoring_allowed: bool,
pub double_precision: bool,
pub force_early_depth_stencil: bool,
pub raw_and_structured_buffers: bool,
pub skip_optimization: bool,
pub minimum_precision: bool,
pub other: u32,
}
impl GlobalFlags {
pub fn from_bits(control: u32) -> Self {
let bit = |n: u32| (control >> n) & 1 != 0;
GlobalFlags {
refactoring_allowed: bit(0),
double_precision: bit(1),
force_early_depth_stencil: bit(2),
raw_and_structured_buffers: bit(3),
skip_optimization: bit(4),
minimum_precision: bit(5),
other: control >> 6,
}
}
}
const RESINFO: u16 = 61;
const SAMPLE_INFO: u16 = 111;
const SYNC: u16 = 190;
const GS_OUTPUT_TOPOLOGY: u16 = 92;
const GS_INPUT_PRIMITIVE: u16 = 93;
const GS_MAX_OUTPUT_VERTICES: u16 = 94;
const INPUT_CONTROL_POINTS: u16 = 147;
const OUTPUT_CONTROL_POINTS: u16 = 148;
const TESS_DOMAIN: u16 = 149;
const TESS_PARTITIONING: u16 = 150;
const TESS_OUTPUT_PRIMITIVE: u16 = 151;
const HS_MAX_TESS_FACTOR: u16 = 152;
const HS_FORK_INSTANCES: u16 = 153;
const HS_JOIN_INSTANCES: u16 = 154;
impl Instruction {
pub fn precise_mask(&self) -> u8 {
low8((self.control >> 8) & 15)
}
pub fn sync_flags(&self) -> Option<SyncFlags> {
(self.opcode == SYNC).then(|| {
let bit = |n: u32| (self.control >> n) & 1 != 0;
SyncFlags {
threads_in_group: bit(0),
group_shared_memory: bit(1),
uav_group: bit(2),
uav_global: bit(3),
}
})
}
pub fn info_return(&self) -> Option<InfoReturn> {
match (self.opcode, self.control & 3) {
(RESINFO | SAMPLE_INFO, 0) => Some(InfoReturn::Float),
(RESINFO, 1) => Some(InfoReturn::ReciprocalFloat),
(RESINFO, 2) | (SAMPLE_INFO, 1) => Some(InfoReturn::Uint),
_ => None,
}
}
}
impl Declaration {
pub fn global_flags(&self) -> Option<GlobalFlags> {
match self.kind {
Declared::GlobalFlags(bits) => Some(GlobalFlags::from_bits(bits)),
_ => None,
}
}
fn first_word(&self, opcode: u16) -> Option<u32> {
match &self.kind {
Declared::Other { words, .. } if self.opcode == opcode => words.first().copied(),
_ => None,
}
}
fn control_value(&self, opcode: u16, mask: u32) -> Option<u32> {
(self.opcode == opcode).then_some(self.control & mask)
}
pub fn geometry_input_primitive(&self) -> Option<u32> {
self.control_value(GS_INPUT_PRIMITIVE, 63)
}
pub fn geometry_output_topology(&self) -> Option<u32> {
self.control_value(GS_OUTPUT_TOPOLOGY, 63)
}
pub fn max_output_vertex_count(&self) -> Option<u32> {
self.first_word(GS_MAX_OUTPUT_VERTICES)
}
pub fn input_control_point_count(&self) -> Option<u32> {
self.control_value(INPUT_CONTROL_POINTS, 63)
}
pub fn output_control_point_count(&self) -> Option<u32> {
self.control_value(OUTPUT_CONTROL_POINTS, 63)
}
pub fn tessellator_domain(&self) -> Option<u32> {
self.control_value(TESS_DOMAIN, 7)
}
pub fn tessellator_partitioning(&self) -> Option<u32> {
self.control_value(TESS_PARTITIONING, 7)
}
pub fn tessellator_output_primitive(&self) -> Option<u32> {
self.control_value(TESS_OUTPUT_PRIMITIVE, 7)
}
pub fn hull_max_tess_factor(&self) -> Option<f32> {
self.first_word(HS_MAX_TESS_FACTOR).map(f32::from_bits)
}
pub fn fork_phase_instance_count(&self) -> Option<u32> {
self.first_word(HS_FORK_INSTANCES)
}
pub fn join_phase_instance_count(&self) -> Option<u32> {
self.first_word(HS_JOIN_INSTANCES)
}
}