forked from itycodes/shaderc
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
7.6 KiB
197 lines
7.6 KiB
#[cfg(test)]
|
|
mod tests;
|
|
|
|
use crate::compiler::Module;
|
|
use std::fmt::Write;
|
|
use std::fmt;
|
|
|
|
use super::StorageClass;
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Type {
|
|
Pointer(Box<Type>, StorageClass),
|
|
Vector(Box<Type>, u32),
|
|
Float(u32),
|
|
Int(u32),
|
|
Unsigned(u32),
|
|
}
|
|
|
|
impl fmt::Display for Type {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
match self {
|
|
Type::Pointer(typ, storage_class) => {
|
|
match storage_class {
|
|
StorageClass::Input => write!(f, "*{}i", typ),
|
|
StorageClass::Output => write!(f, "*{}o", typ),
|
|
StorageClass::Undefined => panic!("Bound a non-declared variable"),
|
|
}
|
|
},
|
|
Type::Vector(typ, size) => write!(f, "v{}{}", size, typ),
|
|
Type::Float(size) => write!(f, "f{}", size),
|
|
Type::Int(size) => write!(f, "s{}", size),
|
|
Type::Unsigned(size) => write!(f, "u{}", size),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn parse_type(typ: String) -> Type {
|
|
// pointers have the format *<t>i or *<t>o, for the storage class
|
|
// floats have the format f<size>, so f32, f64...
|
|
// ints have the format s<size>, so s32, s64...
|
|
// unsigned ints have the format u<size>, so u32, u64...
|
|
// So, *v4f32i is a pointer to a vector of 4 floats, with the storage class Input.
|
|
// *v4f32o is a pointer to a vector of 4 floats, with the storage class Output.
|
|
|
|
let c = typ.chars().next().unwrap();
|
|
match c {
|
|
'*' => {
|
|
let mut chars = typ.chars();
|
|
chars.next();
|
|
let typ = chars.collect::<String>();
|
|
let storage_class = match typ.chars().last().unwrap() {
|
|
'i' => StorageClass::Input,
|
|
'o' => StorageClass::Output,
|
|
_ => panic!("Invalid storage class"),
|
|
};
|
|
let typ = typ.chars().take(typ.len() - 1).collect::<String>();
|
|
Type::Pointer(Box::new(parse_type(typ)), storage_class)
|
|
},
|
|
'v' => {
|
|
let mut chars = typ.chars();
|
|
chars.next();
|
|
let size = chars.next().unwrap().to_digit(10).unwrap();
|
|
let typ = chars.collect::<String>();
|
|
Type::Vector(Box::new(parse_type(typ)), size)
|
|
},
|
|
'f' => {
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
Type::Float(size)
|
|
},
|
|
's' => {
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
Type::Int(size)
|
|
},
|
|
'u' => {
|
|
let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
|
|
Type::Unsigned(size)
|
|
},
|
|
_ => panic!("Invalid type"),
|
|
}
|
|
|
|
}
|
|
|
|
fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
|
|
match typ {
|
|
Type::Unsigned(size) => {
|
|
ops.push((format!("%u{}", size).to_string(), format!("OpTypeInt {}", size)));
|
|
},
|
|
Type::Int(size) => {
|
|
ops.push((format!("%s{}", size).to_string(), format!("OpTypeInt {}", size)));
|
|
},
|
|
Type::Float(size) => {
|
|
ops.push((format!("%f{}", size).to_string(), format!("OpTypeFloat {}", size)));
|
|
},
|
|
Type::Vector(typ, size) => {
|
|
emit_type(*typ.clone(), ops);
|
|
let typ_id = format!("%{}", *typ.clone());
|
|
ops.push((format!("%v{}{}", typ_id, size).to_string(), format!("OpTypeVector {} {}", typ_id, size)))
|
|
},
|
|
Type::Pointer(typ, storage_class) => {
|
|
emit_type(*typ.clone(), ops);
|
|
let typ_id = format!("%{}", *typ.clone());
|
|
let storage_class = match storage_class {
|
|
StorageClass::Input => "Input",
|
|
StorageClass::Output => "Output",
|
|
StorageClass::Undefined => panic!("Bound a non-declared variable"),
|
|
};
|
|
ops.push((format!("%{}{}", typ_id, storage_class).to_string(), format!("OpTypePointer {} {}", storage_class, typ_id)))
|
|
},
|
|
}
|
|
}
|
|
|
|
fn fix_name(name: &String) -> String {
|
|
format!("%{}", name.clone().replace("-", "_"))
|
|
}
|
|
|
|
pub fn spirv_meta(module: Module) -> String {
|
|
let mut spirv_asm = String::new();
|
|
let mut ops: Vec<(Option<String>, Vec<String>)> = Vec::new();
|
|
|
|
let capabilities: Vec<String> = module.capabilities.iter()
|
|
.map(|c| format!("{:?}", c))
|
|
.collect();
|
|
for cap in capabilities {
|
|
ops.push((None, vec!["OpCapability".to_string(), cap]));
|
|
}
|
|
|
|
let memory_model_address = match module.memory_model.addressing_model {
|
|
crate::compiler::AddressingModel::Logical => "Logical",
|
|
crate::compiler::AddressingModel::Physical32 => "Physical32",
|
|
crate::compiler::AddressingModel::Physical64 => "Physical64",
|
|
crate::compiler::AddressingModel::PhysicalStorageBuffer64 => "PhysicalStorageBuffer64",
|
|
};
|
|
let memory_model_model = match module.memory_model.memory_model {
|
|
crate::compiler::MemoryModel::Simple => "Simple",
|
|
crate::compiler::MemoryModel::GLSL450 => "GLSL450",
|
|
crate::compiler::MemoryModel::OpenCL => "OpenCL",
|
|
_ => todo!(),
|
|
};
|
|
ops.push((None, vec!["OpMemoryModel".to_string(), memory_model_address.to_string(), memory_model_model.to_string()]));
|
|
|
|
for entry in module.entry_points {
|
|
let exec_model = match entry.execution_model {
|
|
crate::compiler::ExecutionModel::Fragment => "Fragment",
|
|
crate::compiler::ExecutionModel::Vertex => "Vertex",
|
|
};
|
|
let name = entry.name;
|
|
let interface: Vec<String> = entry.interface.iter()
|
|
.map(|i| fix_name(&i.to_string()))
|
|
.collect();
|
|
let exec_mode = match entry.execution_mode {
|
|
crate::compiler::ExecutionMode::OriginUpperLeft => "OriginUpperLeft",
|
|
};
|
|
ops.push((None, vec!["OpEntryPoint".to_string(), exec_model.to_string(), fix_name(&name), format!("\"{}\"", name), interface.join(" ")]));
|
|
ops.push((None, vec!["OpExecutionMode".to_string(), fix_name(&name), exec_mode.to_string()]));
|
|
}
|
|
|
|
for global in module.globals {
|
|
let name = fix_name(&global.name);
|
|
let _typ = global.typ;
|
|
let storage_class = match global.storage_class {
|
|
crate::compiler::StorageClass::Input => "Input",
|
|
crate::compiler::StorageClass::Output => "Output",
|
|
crate::compiler::StorageClass::Undefined => panic!("Bound a non-declared variable"),
|
|
};
|
|
let typ_id = format!("%{}", _typ);
|
|
let mut type_ops = Vec::new();
|
|
emit_type(parse_type(_typ), &mut type_ops);
|
|
for op in type_ops {
|
|
ops.push((Some(op.0), vec![op.1]));
|
|
}
|
|
ops.push((Some(name.clone()), vec!["OpVariable".to_string(), typ_id.to_string(), storage_class.to_string()]));
|
|
for dec in global.decorations {
|
|
// Decorations have the format Location 0, or Builtin FragCoord
|
|
let dec = match dec {
|
|
crate::compiler::Decoration::Location(loc) => format!("Location {}", loc),
|
|
crate::compiler::Decoration::BuiltIn(builtin) => {
|
|
let builtin = match builtin {
|
|
crate::compiler::BuiltinDecoration::FragCoord => "FragCoord",
|
|
};
|
|
format!("BuiltIn {}", builtin)
|
|
},
|
|
};
|
|
ops.push((None, vec!["OpDecorate".to_string(), name.clone(), dec]));
|
|
}
|
|
}
|
|
|
|
for op in ops {
|
|
if op.0.is_some() {
|
|
write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap();
|
|
}
|
|
for arg in op.1 {
|
|
write!(spirv_asm, "{} ", arg).unwrap();
|
|
}
|
|
writeln!(spirv_asm).unwrap();
|
|
}
|
|
spirv_asm
|
|
} |