mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 08:14:20 +00:00
Extract entry point generation to own module
This commit is contained in:
parent
d182fcba49
commit
ad27205f7b
142
vulkano-shaders/src/entry_point.rs
Normal file
142
vulkano-shaders/src/entry_point.rs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// Copyright (c) 2016 The vulkano developers
|
||||||
|
// Licensed under the Apache License, Version 2.0
|
||||||
|
// <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||||
|
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
||||||
|
// at your option. All files in the project carrying such
|
||||||
|
// notice may not be copied, modified, or distributed except
|
||||||
|
// according to those terms.
|
||||||
|
|
||||||
|
use enums;
|
||||||
|
use parse;
|
||||||
|
|
||||||
|
use is_builtin;
|
||||||
|
use name_from_id;
|
||||||
|
use location_decoration;
|
||||||
|
use type_from_id;
|
||||||
|
use format_from_id;
|
||||||
|
|
||||||
|
pub 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, 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);
|
||||||
|
(t, f)
|
||||||
|
},
|
||||||
|
|
||||||
|
enums::ExecutionModel::ExecutionModelTessellationControl => {
|
||||||
|
(format!("::vulkano::pipeline::shader::TessControlShaderEntryPoint"), String::new())
|
||||||
|
},
|
||||||
|
|
||||||
|
enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
|
||||||
|
(format!("::vulkano::pipeline::shader::TessEvaluationShaderEntryPoint"), String::new())
|
||||||
|
},
|
||||||
|
|
||||||
|
enums::ExecutionModel::ExecutionModelGeometry => {
|
||||||
|
(format!("::vulkano::pipeline::shader::GeometryShaderEntryPoint"), String::new())
|
||||||
|
},
|
||||||
|
|
||||||
|
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));
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = {
|
||||||
|
let output = output_types.join(", ");
|
||||||
|
if output.is_empty() { output } else { output + "," }
|
||||||
|
};
|
||||||
|
|
||||||
|
let t = format!("::vulkano::pipeline::shader::FragmentShaderEntryPoint<(), ({output}), Layout>",
|
||||||
|
output = output);
|
||||||
|
(t, format!("fragment_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _), Layout)"))
|
||||||
|
},
|
||||||
|
|
||||||
|
enums::ExecutionModel::ExecutionModelGLCompute => {
|
||||||
|
(format!("::vulkano::pipeline::shader::ComputeShaderEntryPoint<(), Layout>"),
|
||||||
|
format!("compute_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _), Layout)"))
|
||||||
|
},
|
||||||
|
|
||||||
|
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} {{
|
||||||
|
unsafe {{
|
||||||
|
#[allow(dead_code)]
|
||||||
|
static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0]; // "{ep_name}"
|
||||||
|
self.shader.{f_call}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"#, 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)
|
||||||
|
}
|
@ -21,6 +21,7 @@ pub use parse::ParseError;
|
|||||||
pub use glsl_to_spirv::ShaderType;
|
pub use glsl_to_spirv::ShaderType;
|
||||||
|
|
||||||
mod descriptor_sets;
|
mod descriptor_sets;
|
||||||
|
mod entry_point;
|
||||||
mod enums;
|
mod enums;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod structs;
|
mod structs;
|
||||||
@ -137,7 +138,7 @@ impl {name} {{
|
|||||||
// writing one method for each entry point of this module
|
// writing one method for each entry point of this module
|
||||||
for instruction in doc.instructions.iter() {
|
for instruction in doc.instructions.iter() {
|
||||||
if let &parse::Instruction::EntryPoint { .. } = instruction {
|
if let &parse::Instruction::EntryPoint { .. } = instruction {
|
||||||
output.push_str(&write_entry_point(&doc, instruction));
|
output.push_str(&entry_point::write_entry_point(&doc, instruction));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,131 +179,6 @@ impl From<ParseError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, 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);
|
|
||||||
(t, f)
|
|
||||||
},
|
|
||||||
|
|
||||||
enums::ExecutionModel::ExecutionModelTessellationControl => {
|
|
||||||
(format!("::vulkano::pipeline::shader::TessControlShaderEntryPoint"), String::new())
|
|
||||||
},
|
|
||||||
|
|
||||||
enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
|
|
||||||
(format!("::vulkano::pipeline::shader::TessEvaluationShaderEntryPoint"), String::new())
|
|
||||||
},
|
|
||||||
|
|
||||||
enums::ExecutionModel::ExecutionModelGeometry => {
|
|
||||||
(format!("::vulkano::pipeline::shader::GeometryShaderEntryPoint"), String::new())
|
|
||||||
},
|
|
||||||
|
|
||||||
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));
|
|
||||||
},
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = {
|
|
||||||
let output = output_types.join(", ");
|
|
||||||
if output.is_empty() { output } else { output + "," }
|
|
||||||
};
|
|
||||||
|
|
||||||
let t = format!("::vulkano::pipeline::shader::FragmentShaderEntryPoint<(), ({output}), Layout>",
|
|
||||||
output = output);
|
|
||||||
(t, format!("fragment_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _), Layout)"))
|
|
||||||
},
|
|
||||||
|
|
||||||
enums::ExecutionModel::ExecutionModelGLCompute => {
|
|
||||||
(format!("::vulkano::pipeline::shader::ComputeShaderEntryPoint<(), Layout>"),
|
|
||||||
format!("compute_shader_entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _), Layout)"))
|
|
||||||
},
|
|
||||||
|
|
||||||
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} {{
|
|
||||||
unsafe {{
|
|
||||||
#[allow(dead_code)]
|
|
||||||
static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0]; // "{ep_name}"
|
|
||||||
self.shader.{f_call}
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
"#, 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the vulkano `Format` and number of occupied locations from an id.
|
/// Returns the vulkano `Format` and number of occupied locations from an id.
|
||||||
fn format_from_id(doc: &parse::Spirv, searched: u32) -> (String, usize) {
|
fn format_from_id(doc: &parse::Spirv, searched: u32) -> (String, usize) {
|
||||||
for instruction in doc.instructions.iter() {
|
for instruction in doc.instructions.iter() {
|
||||||
|
Loading…
Reference in New Issue
Block a user