Generate attributes description struct for all shader stages

This commit is contained in:
Pierre Krieger 2016-05-04 09:06:53 +02:00
parent ad27205f7b
commit e2fc113711
6 changed files with 130 additions and 60 deletions

View File

@ -12,7 +12,7 @@
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
in vec2 tex_coords;
layout(location = 0) in vec2 tex_coords;
layout(location = 0) out vec4 f_color;
layout(set = 0, binding = 0) uniform sampler2D tex;

View File

@ -13,7 +13,7 @@
#extension GL_ARB_shading_language_420pack : enable
layout(location = 0) in vec2 position;
out vec2 tex_coords;
layout(location = 0) out vec2 tex_coords;
void main() {
gl_Position = vec4(position, 0.0, 1.0);

View File

@ -12,7 +12,7 @@
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
in vec3 v_normal;
layout(location = 0) in vec3 v_normal;
layout(location = 0) out vec4 f_color;
const vec3 LIGHT = vec3(0.0, 0.0, 1.0);

View File

@ -15,7 +15,7 @@
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
out vec3 v_normal;
layout(location = 0) out vec3 v_normal;
layout(set = 0, binding = 0) uniform Data {
mat4 worldview;

View File

@ -16,7 +16,7 @@ use location_decoration;
use type_from_id;
use format_from_id;
pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> (String, String) {
let (execution, ep_name, interface) = match instruction {
&parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
(execution, name, interface)
@ -24,57 +24,15 @@ pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -
_ => unreachable!()
};
let capitalized_ep_name: String = ep_name.chars().take(1).flat_map(|c| c.to_uppercase())
.chain(ep_name.chars().skip(1)).collect();
let interface_structs = write_interface_structs(doc, &capitalized_ep_name, interface);
let (ty, f_call) = match *execution {
enums::ExecutionModel::ExecutionModelVertex => {
let mut attributes = 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::StorageClassInput, .. }
if &result_id == interface =>
{
if is_builtin(doc, result_id) {
continue;
}
let name = name_from_id(doc, result_id);
let loc = match location_decoration(doc, result_id) {
Some(l) => l,
None => panic!("vertex attribute `{}` is missing a location", name)
};
attributes.push((loc, name, format_from_id(doc, result_type_id)));
},
_ => ()
}
}
}
// Checking for overlapping attributes.
for (offset, &(loc, ref name, (_, loc_len))) in attributes.iter().enumerate() {
for &(loc2, ref name2, (_, loc_len2)) in attributes.iter().skip(offset + 1) {
if loc == loc2 || (loc < loc2 && loc + loc_len as u32 > loc2) ||
(loc2 < loc && loc2 + loc_len2 as u32 > loc)
{
panic!("The locations of vertex attributes `{}` and `{}` overlap",
name, name2);
}
}
}
let attributes = attributes.iter().map(|&(loc, ref name, (ref ty, num_locs))| {
assert!(num_locs >= 1);
format!("::vulkano::pipeline::shader::ShaderInterfaceDefEntry {{
location: {} .. {},
format: ::vulkano::format::Format::{},
name: Some(::std::borrow::Cow::Borrowed(\"{}\"))
}}", loc, loc as usize + num_locs, ty, name)
}).collect::<Vec<_>>().join(", ");
let t = "::vulkano::pipeline::shader::VertexShaderEntryPoint<(), Vec<::vulkano::pipeline::shader::ShaderInterfaceDefEntry>, Layout>".to_owned();
let f = format!("vertex_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _), Layout, vec![{}])", attributes);
let t = format!("::vulkano::pipeline::shader::VertexShaderEntryPoint<(), {}Input, Layout>", capitalized_ep_name);
let f = format!("vertex_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _), Layout, {}Input)", capitalized_ep_name);
(t, f)
},
@ -96,9 +54,8 @@ pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -
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 =>
&parse::Instruction::Variable { result_type_id, result_id, ref storage_class,
.. } if &result_id == interface =>
{
output_types.push(type_from_id(doc, result_type_id));
},
@ -125,7 +82,7 @@ pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -
enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
};
format!(r#"
let entry_point = format!(r#"
/// Returns a logical struct describing the entry point named `{ep_name}`.
#[inline]
pub fn {ep_name}_entry_point(&self) -> {ty} {{
@ -138,5 +95,113 @@ pub fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -
"#, ep_name = ep_name, ep_name_lenp1 = ep_name.chars().count() + 1, ty = ty,
encoded_ep_name = ep_name.chars().map(|c| (c as u32).to_string())
.collect::<Vec<String>>().join(", "),
f_call = f_call)
f_call = f_call);
(interface_structs, entry_point)
}
fn write_interface_structs(doc: &parse::Spirv, capitalized_ep_name: &str, interface: &[u32])
-> String
{
let mut input_elements = Vec::new();
let mut output_elements = Vec::new();
// Filling `input_elements` and `output_elements`.
for interface in interface.iter() {
for i in doc.instructions.iter() {
match i {
&parse::Instruction::Variable { result_type_id, result_id, ref storage_class, .. }
if &result_id == interface =>
{
if is_builtin(doc, result_id) {
continue;
}
if is_builtin(doc, result_type_id) {
continue;
}
let to_write = match storage_class {
&enums::StorageClass::StorageClassInput => &mut input_elements,
&enums::StorageClass::StorageClassOutput => &mut output_elements,
_ => continue
};
let name = name_from_id(doc, result_id);
if name == "__unnamed" { continue; } // FIXME: hack
let loc = match location_decoration(doc, result_id) {
Some(l) => l,
None => panic!("Attribute `{}` (id {}) is missing a location", name, result_id)
};
to_write.push((loc, name, format_from_id(doc, result_type_id)));
},
_ => ()
}
}
}
write_interface_struct(&format!("{}Input", capitalized_ep_name), &input_elements) +
&write_interface_struct(&format!("{}Output", capitalized_ep_name), &output_elements)
}
fn write_interface_struct(struct_name: &str, attributes: &[(u32, String, (String, usize))]) -> String {
// Checking for overlapping elements.
for (offset, &(loc, ref name, (_, loc_len))) in attributes.iter().enumerate() {
for &(loc2, ref name2, (_, loc_len2)) in attributes.iter().skip(offset + 1) {
if loc == loc2 || (loc < loc2 && loc + loc_len as u32 > loc2) ||
(loc2 < loc && loc2 + loc_len2 as u32 > loc)
{
panic!("The locations of attributes `{}` and `{}` overlap",
name, name2);
}
}
}
let body = attributes.iter().enumerate().map(|(num, &(loc, ref name, (ref ty, num_locs)))| {
assert!(num_locs >= 1);
format!("if self.num == {} {{
self.num += 1;
return Some(::vulkano::pipeline::shader::ShaderInterfaceDefEntry {{
location: {} .. {},
format: ::vulkano::format::Format::{},
name: Some(::std::borrow::Cow::Borrowed(\"{}\"))
}});
}}", num, loc, loc as usize + num_locs, ty, name)
}).collect::<Vec<_>>().join("");
format!("
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct {name};
unsafe impl ::vulkano::pipeline::shader::ShaderInterfaceDef for {name} {{
type Iter = {name}Iter;
fn elements(&self) -> {name}Iter {{
{name}Iter {{ num: 0 }}
}}
}}
#[derive(Debug, Copy, Clone)]
pub struct {name}Iter {{ num: u16 }}
impl Iterator for {name}Iter {{
type Item = ::vulkano::pipeline::shader::ShaderInterfaceDefEntry;
#[inline]
fn next(&mut self) -> Option<Self::Item> {{
{body}
None
}}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {{
let len = ({len} - self.num) as usize;
(len, Some(len))
}}
}}
impl ExactSizeIterator for {name}Iter {{}}
", name = struct_name, body = body, len = attributes.len())
}

View File

@ -136,9 +136,12 @@ impl {name} {{
"#, name = name, spirv_data = spirv_data));
// writing one method for each entry point of this module
let mut outside_impl = String::new();
for instruction in doc.instructions.iter() {
if let &parse::Instruction::EntryPoint { .. } = instruction {
output.push_str(&entry_point::write_entry_point(&doc, instruction));
let (outside, entry_point) = entry_point::write_entry_point(&doc, instruction);
output.push_str(&entry_point);
outside_impl.push_str(&outside);
}
}
@ -147,6 +150,8 @@ impl {name} {{
}}
"#));
output.push_str(&outside_impl);
// struct definitions
output.push_str("pub mod ty {");
output.push_str(&structs::write_structs(&doc));