From e2fc11371163b48a2e7dc47d3835a33078db9a24 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 4 May 2016 09:06:53 +0200 Subject: [PATCH] Generate attributes description struct for all shader stages --- examples/src/bin/image_fs.glsl | 2 +- examples/src/bin/image_vs.glsl | 2 +- examples/src/bin/teapot_fs.glsl | 2 +- examples/src/bin/teapot_vs.glsl | 2 +- vulkano-shaders/src/entry_point.rs | 175 ++++++++++++++++++++--------- vulkano-shaders/src/lib.rs | 7 +- 6 files changed, 130 insertions(+), 60 deletions(-) diff --git a/examples/src/bin/image_fs.glsl b/examples/src/bin/image_fs.glsl index e33a7e95a..a7e662ab1 100644 --- a/examples/src/bin/image_fs.glsl +++ b/examples/src/bin/image_fs.glsl @@ -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; diff --git a/examples/src/bin/image_vs.glsl b/examples/src/bin/image_vs.glsl index a5e08e5d6..15ba00821 100644 --- a/examples/src/bin/image_vs.glsl +++ b/examples/src/bin/image_vs.glsl @@ -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); diff --git a/examples/src/bin/teapot_fs.glsl b/examples/src/bin/teapot_fs.glsl index 76d32c483..7fa98538d 100644 --- a/examples/src/bin/teapot_fs.glsl +++ b/examples/src/bin/teapot_fs.glsl @@ -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); diff --git a/examples/src/bin/teapot_vs.glsl b/examples/src/bin/teapot_vs.glsl index 6c1b58340..2a3bf2c2f 100644 --- a/examples/src/bin/teapot_vs.glsl +++ b/examples/src/bin/teapot_vs.glsl @@ -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; diff --git a/vulkano-shaders/src/entry_point.rs b/vulkano-shaders/src/entry_point.rs index cf3d9fbe3..a7f2b7a51 100644 --- a/vulkano-shaders/src/entry_point.rs +++ b/vulkano-shaders/src/entry_point.rs @@ -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::>().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::>().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::>().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 {{ + {body} + None + }} + + #[inline] + fn size_hint(&self) -> (usize, Option) {{ + let len = ({len} - self.num) as usize; + (len, Some(len)) + }} + }} + + impl ExactSizeIterator for {name}Iter {{}} + ", name = struct_name, body = body, len = attributes.len()) } diff --git a/vulkano-shaders/src/lib.rs b/vulkano-shaders/src/lib.rs index 2cce05da5..36e176c6a 100644 --- a/vulkano-shaders/src/lib.rs +++ b/vulkano-shaders/src/lib.rs @@ -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));