Start doing something correct in the code generation

This commit is contained in:
Pierre Krieger 2016-02-05 15:20:14 +01:00
parent 49b460e580
commit 61d00ce9a8

View File

@ -18,74 +18,136 @@ pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
let mut output = String::new(); let mut output = String::new();
{ {
// contains the data that was passed as input to this function
let spirv_data = data.iter().map(|&byte| byte.to_string()) let spirv_data = data.iter().map(|&byte| byte.to_string())
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", "); .join(", ");
// writing the header
output.push_str(&format!(r#" output.push_str(&format!(r#"
pub struct {name}; pub struct {name} {{
shader: ::std::sync::Arc<::vulkano::ShaderModule>,
}}
impl {name} {{ impl {name} {{
pub fn load(device: &::std::sync::Arc<::vulkano::Device>) {{ /// Loads the shader in Vulkan as a `ShaderModule`.
#[inline]
pub fn load(device: &::std::sync::Arc<::vulkano::Device>) -> {name} {{
unsafe {{ unsafe {{
let data = [{spirv_data}]; let data = [{spirv_data}];
::vulkano::ShaderModule::new(device, &data) {name} {{
shader: ::vulkano::ShaderModule::new(device, &data)
}} }}
}} }}
}} }}
/// Returns the module that was created.
#[inline]
pub fn module(&self) -> &::std::sync::Arc<::vulkano::ShaderModule> {{
&self.shader
}}
"#, name = name, spirv_data = spirv_data)); "#, name = name, spirv_data = spirv_data));
}
println!("{:#?}", doc);
// writing one method for each entry point of this module
for instruction in doc.instructions.iter() { for instruction in doc.instructions.iter() {
match instruction { if let &parse::Instruction::EntryPoint { .. } = instruction {
&parse::Instruction::Variable { result_type_id, result_id, ref storage_class, .. } => { output.push_str(&write_entry_point(&doc, instruction));
match *storage_class { }
enums::StorageClass::StorageClassUniformConstant => (), }
enums::StorageClass::StorageClassUniform => (),
enums::StorageClass::StorageClassPushConstant => (),
_ => continue
};
let name = name_from_id(&doc, result_id); // footer
output.push_str(&format!("{}: {};", name, type_from_id(&doc, result_type_id))); output.push_str(&format!(r#"
}, }}
_ => () "#));
}
} }
// TODO: remove
println!("{:#?}", doc);
Ok(output) Ok(output)
} }
fn name_from_id(doc: &parse::Spirv, searched: u32) -> String { #[derive(Debug)]
doc.instructions.iter().filter_map(|i| { pub enum Error {
if let &parse::Instruction::Name { target_id, ref name } = i { IoError(IoError),
if target_id == searched { ParseError(ParseError),
Some(name.clone())
} else {
None
}
} else {
None
}
}).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
.unwrap_or("__unnamed".to_owned())
} }
fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String { impl From<IoError> for Error {
doc.instructions.iter().filter_map(|i| { #[inline]
if let &parse::Instruction::MemberName { target_id, member, ref name } = i { fn from(err: IoError) -> Error {
if target_id == searched && member == searched_member { Error::IoError(err)
Some(name.clone())
} else {
None
} }
} else { }
None
impl From<ParseError> for Error {
#[inline]
fn from(err: ParseError) -> Error {
Error::ParseError(err)
} }
}).next().and_then(|n| if !n.is_empty() { Some(n) } else { None }) }
.unwrap_or("__unnamed".to_owned())
fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
let (execution, ep_name, interface) = match instruction {
&parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
(execution, name, interface)
},
_ => unreachable!()
};
let ty = match *execution {
enums::ExecutionModel::ExecutionModelVertex => {
format!("VertexShaderEntryPoint")
},
enums::ExecutionModel::ExecutionModelTessellationControl => {
format!("TessControlShaderEntryPoint")
},
enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
format!("TessEvaluationShaderEntryPoint")
},
enums::ExecutionModel::ExecutionModelGeometry => {
format!("GeometryShaderEntryPoint")
},
enums::ExecutionModel::ExecutionModelFragment => {
let mut output_types = Vec::new();
for interface in interface.iter() {
for i in doc.instructions.iter() {
match i {
&parse::Instruction::Variable { result_type_id, result_id,
storage_class: enums::StorageClass::StorageClassOutput, .. }
if &result_id == interface =>
{
output_types.push(type_from_id(doc, result_type_id));
},
_ => ()
}
}
}
format!("FragmentShaderEntryPoint<({output})>",
output = output_types.join(", ") + ",")
},
enums::ExecutionModel::ExecutionModelGLCompute => {
format!("ComputeShaderEntryPoint")
},
enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
};
format!(r#"
/// Returns a logical struct describing the entry point named `{ep_name}`.
#[inline]
pub fn {ep_name}_entry_point(&self) -> {ty} {{
self.shader.entry_point("{ep_name}")
}}
"#, ep_name = ep_name, ty = ty)
} }
fn type_from_id(doc: &parse::Spirv, searched: u32) -> String { fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
@ -152,22 +214,32 @@ fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
panic!("Type #{} not found", searched) panic!("Type #{} not found", searched)
} }
#[derive(Debug)] fn name_from_id(doc: &parse::Spirv, searched: u32) -> String {
pub enum Error { doc.instructions.iter().filter_map(|i| {
IoError(IoError), if let &parse::Instruction::Name { target_id, ref name } = i {
ParseError(ParseError), if target_id == searched {
Some(name.clone())
} else {
None
}
} else {
None
}
}).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
.unwrap_or("__unnamed".to_owned())
} }
impl From<IoError> for Error { fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String {
#[inline] doc.instructions.iter().filter_map(|i| {
fn from(err: IoError) -> Error { if let &parse::Instruction::MemberName { target_id, member, ref name } = i {
Error::IoError(err) if target_id == searched && member == searched_member {
Some(name.clone())
} else {
None
} }
} } else {
None
impl From<ParseError> for Error {
#[inline]
fn from(err: ParseError) -> Error {
Error::ParseError(err)
} }
}).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
.unwrap_or("__unnamed".to_owned())
} }