mod io;
mod text;
mod validate;
pub use io::{
EntryIo, FnItem, FunctionSig, IoItem, IoType, ItemList, entry_io, mesh_vertex_io, stage_functions,
};
pub(crate) use validate::module_info;
pub use validate::{Problem, validate};
use std::collections::BTreeSet;
use naga::{Handle, Module};
use crate::{Interface, ResourceId, ShaderFormat, Stage};
pub const VERSION: u32 = 3;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ClipDepth {
ZeroToOne,
MinusOneToOne,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Origin {
TopLeft,
BottomLeft,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Conventions {
pub clip_depth: ClipDepth,
pub fragment_origin: Origin,
pub texture_origin: Origin,
}
impl Conventions {
pub const D3D: Self = Self {
clip_depth: ClipDepth::ZeroToOne,
fragment_origin: Origin::TopLeft,
texture_origin: Origin::TopLeft,
};
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct D3dModes {
pub divide_by_zero: bool,
pub float_to_int: bool,
pub min_max_nan: bool,
pub saturate_nan: bool,
pub flush_denormals: bool,
}
impl D3dModes {
pub const ALL: Self = Self {
divide_by_zero: true,
float_to_int: true,
min_max_nan: true,
saturate_nan: true,
flush_denormals: true,
};
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Provenance {
pub format: ShaderFormat,
pub target: String,
pub lifter: String,
pub lifter_version: u32,
pub source_hash: Option<String>,
pub instruction_count: Option<iridia_interface::InstructionCount>,
}
#[derive(Clone, Debug)]
pub struct Program {
pub module: Module,
pub stage: Stage,
pub entry: String,
pub interface: Interface,
pub bindings: Vec<(ResourceId, Handle<naga::GlobalVariable>)>,
pub conventions: Conventions,
pub modes: D3dModes,
pub provenance: Provenance,
pub notes: Vec<String>,
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("invalid program: {0}")]
Invalid(String),
#[error("{writer} cannot write this program: {detail}")]
Unsupported {
writer: &'static str,
detail: String,
},
#[error("the pipeline cannot take this program: {0}")]
Pipeline(String),
}
impl Program {
pub fn global(&self, id: ResourceId) -> Option<Handle<naga::GlobalVariable>> {
self.bindings.iter().find(|(r, _)| *r == id).map(|(_, g)| *g)
}
pub fn unread_resources(&self) -> Result<BTreeSet<ResourceId>, Error> {
self.validated()?;
let mut module = self.module.clone();
naga::compact::compact(&mut module, naga::compact::KeepUnused::No);
let kept = |g: &naga::GlobalVariable| {
module
.global_variables
.iter()
.any(|(_, k)| k.name == g.name && k.binding == g.binding)
};
Ok(self
.bindings
.iter()
.filter(|(_, g)| !kept(&self.module.global_variables[*g]))
.map(|(id, _)| *id)
.collect())
}
pub fn varying_name(label: &crate::Label) -> String {
io::varying_name(label)
}
pub fn validate(&self) -> Result<naga::valid::ModuleInfo, Vec<Problem>> {
validate(self)
}
pub(crate) fn validated(&self) -> Result<naga::valid::ModuleInfo, Error> {
self.validate().map_err(|problems| {
Error::Invalid(
problems
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join("; "),
)
})
}
pub fn text(&self) -> Result<String, Error> {
text::text(self)
}
}