mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 14:24:18 +00:00
Rewrite VertexDefinition
(#2487)
This commit is contained in:
parent
960e554ca0
commit
b190d6fb1c
@ -432,9 +432,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = MyVertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = MyVertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -222,9 +222,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -87,9 +87,7 @@ impl AmbientLightingSystem {
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let vertex_input_state = LightingVertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = LightingVertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -88,9 +88,7 @@ impl DirectionalLightingSystem {
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let vertex_input_state = LightingVertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = LightingVertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -87,9 +87,7 @@ impl PointLightingSystem {
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let vertex_input_state = LightingVertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = LightingVertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -77,9 +77,7 @@ impl TriangleDrawSystem {
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let vertex_input_state = TriangleVertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = TriangleVertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -694,9 +694,7 @@ mod linux {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = MyVertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = MyVertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -343,9 +343,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -290,9 +290,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -296,9 +296,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -314,9 +314,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -290,7 +290,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = [TriangleVertex::per_vertex(), InstanceData::per_instance()]
|
||||
.definition(&vs.info().input_interface)
|
||||
.definition(&vs)
|
||||
.unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
|
@ -313,9 +313,7 @@ fn main() {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -259,9 +259,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -260,9 +260,7 @@ fn main() {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -300,9 +300,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -206,9 +206,7 @@ fn main() {
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
|
@ -281,9 +281,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -400,9 +400,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -187,9 +187,7 @@ fn main() -> Result<(), impl Error> {
|
||||
module.entry_point("main").unwrap()
|
||||
};
|
||||
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -460,9 +460,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -497,7 +497,7 @@ fn window_size_dependent_setup(
|
||||
// https://computergraphics.stackexchange.com/questions/5742/vulkan-best-way-of-updating-pipeline-viewport
|
||||
let pipeline = {
|
||||
let vertex_input_state = [Position::per_vertex(), Normal::per_vertex()]
|
||||
.definition(&vs.info().input_interface)
|
||||
.definition(&vs)
|
||||
.unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
|
@ -340,9 +340,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(tcs),
|
||||
|
@ -301,9 +301,7 @@ fn main() -> Result<(), impl Error> {
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
let stages = [
|
||||
PipelineShaderStageCreateInfo::new(vs),
|
||||
PipelineShaderStageCreateInfo::new(fs),
|
||||
|
@ -197,9 +197,7 @@ fn main() -> Result<(), impl Error> {
|
||||
|
||||
// Automatically generate a vertex input state from the vertex shader's input interface,
|
||||
// that takes a single vertex buffer containing `Vertex` structs.
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
|
||||
// Make a list of the shader stages that the pipeline will have.
|
||||
let stages = [
|
||||
|
@ -385,9 +385,7 @@ fn main() -> Result<(), impl Error> {
|
||||
|
||||
// Automatically generate a vertex input state from the vertex shader's input interface,
|
||||
// that takes a single vertex buffer containing `Vertex` structs.
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
|
||||
// Make a list of the shader stages that the pipeline will have.
|
||||
let stages = [
|
||||
|
@ -390,9 +390,7 @@ fn main() -> Result<(), impl Error> {
|
||||
|
||||
// Automatically generate a vertex input state from the vertex shader's input interface,
|
||||
// that takes a single vertex buffer containing `Vertex` structs.
|
||||
let vertex_input_state = Vertex::per_vertex()
|
||||
.definition(&vs.info().input_interface)
|
||||
.unwrap();
|
||||
let vertex_input_state = Vertex::per_vertex().definition(&vs).unwrap();
|
||||
|
||||
// Make a list of the shader stages that the pipeline will have.
|
||||
let stages = [
|
||||
|
@ -61,7 +61,7 @@ pub fn derive_vertex(crate_ident: &Ident, ast: syn::DeriveInput) -> Result<Token
|
||||
|
||||
let field_size = ::std::mem::size_of::<#field_ty>();
|
||||
let format = #format;
|
||||
let format_size = format.block_size() as usize;
|
||||
let format_size = usize::try_from(format.block_size()).unwrap();
|
||||
let num_elements = field_size / format_size;
|
||||
let remainder = field_size % format_size;
|
||||
::std::assert!(
|
||||
@ -76,6 +76,7 @@ pub fn derive_vertex(crate_ident: &Ident, ast: syn::DeriveInput) -> Result<Token
|
||||
offset: offset.try_into().unwrap(),
|
||||
format,
|
||||
num_elements: num_elements.try_into().unwrap(),
|
||||
stride: format_size.try_into().unwrap(),
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -143,6 +143,19 @@ fn formats_output(members: &[FormatMember]) -> TokenStream {
|
||||
}
|
||||
},
|
||||
);
|
||||
let locations_items = members.iter().filter_map(
|
||||
|FormatMember {
|
||||
name, components, ..
|
||||
}| {
|
||||
if components.starts_with(&[64, 64, 64]) {
|
||||
Some(quote! {
|
||||
Self::#name => 2,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let compression_items = members.iter().filter_map(
|
||||
|FormatMember {
|
||||
name, compression, ..
|
||||
@ -418,6 +431,15 @@ fn formats_output(members: &[FormatMember]) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of shader input/output locations that a single element of this
|
||||
/// format takes up.
|
||||
pub fn locations(self) -> u32 {
|
||||
match self {
|
||||
#(#locations_items)*
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the block compression scheme used for this format, if any. Returns `None` if
|
||||
/// the format does not use compression.
|
||||
pub fn compression(self) -> Option<CompressionType> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::VertexBufferDescription;
|
||||
use super::{definition::VertexDefinition, VertexBufferDescription};
|
||||
use crate::{
|
||||
pipeline::graphics::vertex_input::{Vertex, VertexDefinition, VertexInputState},
|
||||
shader::ShaderInterface,
|
||||
pipeline::graphics::vertex_input::{Vertex, VertexInputState},
|
||||
shader::EntryPoint,
|
||||
ValidationError,
|
||||
};
|
||||
|
||||
@ -55,8 +55,8 @@ unsafe impl VertexDefinition for BuffersDefinition {
|
||||
#[inline]
|
||||
fn definition(
|
||||
&self,
|
||||
interface: &ShaderInterface,
|
||||
entry_point: &EntryPoint,
|
||||
) -> Result<VertexInputState, Box<ValidationError>> {
|
||||
self.0.definition(interface)
|
||||
self.0.definition(entry_point)
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,30 @@
|
||||
use super::{
|
||||
VertexBufferDescription, VertexInputAttributeDescription, VertexInputBindingDescription,
|
||||
VertexMemberInfo,
|
||||
};
|
||||
use crate::{
|
||||
pipeline::graphics::vertex_input::VertexInputState, shader::ShaderInterface, DeviceSize,
|
||||
pipeline::{
|
||||
graphics::vertex_input::VertexInputState,
|
||||
inout_interface::{
|
||||
input_output_map, InputOutputData, InputOutputKey, InputOutputUserKey,
|
||||
InputOutputVariableBlock,
|
||||
},
|
||||
},
|
||||
shader::{
|
||||
spirv::{ExecutionModel, Instruction, StorageClass},
|
||||
EntryPoint,
|
||||
},
|
||||
ValidationError,
|
||||
};
|
||||
use ahash::HashMap;
|
||||
use std::{borrow::Cow, collections::hash_map::Entry};
|
||||
|
||||
/// Trait for types that can create a [`VertexInputState`] from a [`ShaderInterface`].
|
||||
/// Trait for types that can create a [`VertexInputState`] from an [`EntryPoint`].
|
||||
pub unsafe trait VertexDefinition {
|
||||
/// Builds the `VertexInputState` for the provided `interface`.
|
||||
/// Builds the `VertexInputState` for the provided `entry_point`.
|
||||
fn definition(
|
||||
&self,
|
||||
interface: &ShaderInterface,
|
||||
entry_point: &EntryPoint,
|
||||
) -> Result<VertexInputState, Box<ValidationError>>;
|
||||
}
|
||||
|
||||
@ -19,89 +32,198 @@ unsafe impl VertexDefinition for &[VertexBufferDescription] {
|
||||
#[inline]
|
||||
fn definition(
|
||||
&self,
|
||||
interface: &ShaderInterface,
|
||||
entry_point: &EntryPoint,
|
||||
) -> Result<VertexInputState, Box<ValidationError>> {
|
||||
let bindings = self.iter().enumerate().map(|(binding, buffer)| {
|
||||
(
|
||||
binding as u32,
|
||||
VertexInputBindingDescription {
|
||||
stride: buffer.stride,
|
||||
input_rate: buffer.input_rate,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
});
|
||||
let mut attributes: Vec<(u32, VertexInputAttributeDescription)> = Vec::new();
|
||||
let spirv = entry_point.module().spirv();
|
||||
let Some(&Instruction::EntryPoint {
|
||||
execution_model,
|
||||
ref interface,
|
||||
..
|
||||
}) = spirv.function(entry_point.id()).entry_point()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
for element in interface.elements() {
|
||||
let name = element.name.as_ref().unwrap();
|
||||
|
||||
let (infos, binding) = self
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(binding, buffer)| {
|
||||
buffer
|
||||
.members
|
||||
.get(name.as_ref())
|
||||
.map(|infos| (infos.clone(), binding as u32))
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"the shader interface contains a variable named \"{}\", \
|
||||
but no such attribute exists in the vertex definition",
|
||||
name,
|
||||
)
|
||||
.into(),
|
||||
..Default::default()
|
||||
})
|
||||
})?;
|
||||
|
||||
// TODO: ShaderInterfaceEntryType does not properly support 64bit.
|
||||
// Once it does the below logic around num_elements and num_locations
|
||||
// might have to be updated.
|
||||
if infos.num_components() != element.ty.num_components
|
||||
|| infos.num_elements != element.ty.num_locations()
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"for the variable \"{}\", the number of locations and components \
|
||||
required by the shader don't match the number of locations and components \
|
||||
of the type provided in the vertex definition",
|
||||
name,
|
||||
)
|
||||
.into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
let mut offset = infos.offset as DeviceSize;
|
||||
let block_size = infos.format.block_size();
|
||||
// Double precision formats can exceed a single location.
|
||||
// R64B64G64A64_SFLOAT requires two locations, so we need to adapt how we bind
|
||||
let location_range = if block_size > 16 {
|
||||
(element.location..element.location + 2 * element.ty.num_locations()).step_by(2)
|
||||
} else {
|
||||
(element.location..element.location + element.ty.num_locations()).step_by(1)
|
||||
};
|
||||
|
||||
for location in location_range {
|
||||
attributes.push((
|
||||
location,
|
||||
VertexInputAttributeDescription {
|
||||
binding,
|
||||
format: infos.format,
|
||||
offset: offset as u32,
|
||||
..Default::default()
|
||||
},
|
||||
));
|
||||
offset += block_size;
|
||||
}
|
||||
if execution_model != ExecutionModel::Vertex {
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "entry_point".into(),
|
||||
problem: "is not a vertex shader".into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(VertexInputState::new()
|
||||
.bindings(bindings)
|
||||
.attributes(attributes))
|
||||
let bindings = self
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(binding, buffer_description)| {
|
||||
let &VertexBufferDescription {
|
||||
members: _,
|
||||
stride,
|
||||
input_rate,
|
||||
} = buffer_description;
|
||||
|
||||
(
|
||||
binding.try_into().unwrap(),
|
||||
VertexInputBindingDescription {
|
||||
stride,
|
||||
input_rate,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let mut attributes: HashMap<u32, VertexInputAttributeDescription> = HashMap::default();
|
||||
|
||||
for variable_id in interface.iter().copied() {
|
||||
input_output_map(
|
||||
spirv,
|
||||
execution_model,
|
||||
variable_id,
|
||||
StorageClass::Input,
|
||||
|key, data| -> Result<(), Box<ValidationError>> {
|
||||
let InputOutputKey::User(key) = key else {
|
||||
return Ok(());
|
||||
};
|
||||
let InputOutputUserKey {
|
||||
mut location,
|
||||
component,
|
||||
index: _,
|
||||
} = key;
|
||||
|
||||
// TODO: can we make this work somehow?
|
||||
if component != 0 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"the shader interface contains an input variable (location {}) \
|
||||
with a non-zero component decoration ({}), which is not yet \
|
||||
supported by `VertexDefinition` in Vulkano",
|
||||
location, component,
|
||||
)
|
||||
.into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
let InputOutputData {
|
||||
variable_id,
|
||||
pointer_type_id: _,
|
||||
block,
|
||||
type_id: _,
|
||||
} = data;
|
||||
|
||||
// Find the name of the variable defined in the shader,
|
||||
// or use a default placeholder.
|
||||
let names = if let Some(block) = block {
|
||||
let InputOutputVariableBlock {
|
||||
type_id,
|
||||
member_index,
|
||||
} = block;
|
||||
|
||||
spirv.id(type_id).members()[member_index].names()
|
||||
} else {
|
||||
spirv.id(variable_id).names()
|
||||
};
|
||||
let name = names
|
||||
.iter()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Name { ref name, .. }
|
||||
| Instruction::MemberName { ref name, .. } => {
|
||||
Some(Cow::Borrowed(name.as_str()))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_else(|| Cow::Owned(format!("vertex_input_{}", location)));
|
||||
|
||||
// Find a vertex member whose name matches the one in the shader.
|
||||
let (vertex_member_info, binding) = self
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(binding, buffer)| {
|
||||
buffer
|
||||
.members
|
||||
.get(name.as_ref())
|
||||
.map(|info| (info, binding.try_into().unwrap()))
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"the shader interface contains an input variable named \"{}\" \
|
||||
(location {}, component {}), but no such attribute exists in \
|
||||
the vertex definition",
|
||||
name, location, component,
|
||||
)
|
||||
.into(),
|
||||
..Default::default()
|
||||
})
|
||||
})?;
|
||||
|
||||
let &VertexMemberInfo {
|
||||
mut offset,
|
||||
format,
|
||||
num_elements,
|
||||
mut stride,
|
||||
} = vertex_member_info;
|
||||
|
||||
let locations_per_element;
|
||||
|
||||
if num_elements > 1 {
|
||||
locations_per_element = format.locations();
|
||||
|
||||
if u64::from(stride) < format.block_size() {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"in the vertex member named \"{}\" in buffer {}, the `stride` is \
|
||||
less than the block size of `format`",
|
||||
name, binding,
|
||||
)
|
||||
.into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
stride = 0;
|
||||
locations_per_element = 0;
|
||||
}
|
||||
|
||||
// Add an attribute description for every element in the member.
|
||||
for _ in 0..num_elements {
|
||||
match attributes.entry(location) {
|
||||
Entry::Occupied(_) => {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"the vertex definition specifies a variable at \
|
||||
location {}, but that location is already occupied by \
|
||||
another variable",
|
||||
location,
|
||||
)
|
||||
.into(),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(VertexInputAttributeDescription {
|
||||
binding,
|
||||
format,
|
||||
offset,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
location = location.checked_add(locations_per_element).unwrap();
|
||||
offset = offset.checked_add(stride).unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(VertexInputState {
|
||||
bindings,
|
||||
attributes,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,9 +231,9 @@ unsafe impl<const N: usize> VertexDefinition for [VertexBufferDescription; N] {
|
||||
#[inline]
|
||||
fn definition(
|
||||
&self,
|
||||
interface: &ShaderInterface,
|
||||
entry_point: &EntryPoint,
|
||||
) -> Result<VertexInputState, Box<ValidationError>> {
|
||||
self.as_slice().definition(interface)
|
||||
self.as_slice().definition(entry_point)
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,9 +241,9 @@ unsafe impl VertexDefinition for Vec<VertexBufferDescription> {
|
||||
#[inline]
|
||||
fn definition(
|
||||
&self,
|
||||
interface: &ShaderInterface,
|
||||
entry_point: &EntryPoint,
|
||||
) -> Result<VertexInputState, Box<ValidationError>> {
|
||||
self.as_slice().definition(interface)
|
||||
self.as_slice().definition(entry_point)
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,8 +251,8 @@ unsafe impl VertexDefinition for VertexBufferDescription {
|
||||
#[inline]
|
||||
fn definition(
|
||||
&self,
|
||||
interface: &ShaderInterface,
|
||||
entry_point: &EntryPoint,
|
||||
) -> Result<VertexInputState, Box<ValidationError>> {
|
||||
std::slice::from_ref(self).definition(interface)
|
||||
std::slice::from_ref(self).definition(entry_point)
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +57,10 @@ macro_rules! impl_vertex {
|
||||
let member_ptr = (&dummy.$member) as *const _;
|
||||
|
||||
members.insert(stringify!($member).to_string(), VertexMemberInfo {
|
||||
offset: member_ptr as usize - dummy_ptr as usize,
|
||||
offset: u32::try_from(member_ptr as usize - dummy_ptr as usize).unwrap(),
|
||||
format,
|
||||
num_elements,
|
||||
stride: format_size,
|
||||
});
|
||||
}
|
||||
)*
|
||||
|
@ -304,7 +304,7 @@ impl VertexInputState {
|
||||
// the location following it needs to be empty.
|
||||
let unassigned_locations = attributes
|
||||
.iter()
|
||||
.filter(|&(_, attribute_desc)| attribute_desc.format.block_size() > 16)
|
||||
.filter(|&(_, attribute_desc)| attribute_desc.format.locations() == 2)
|
||||
.map(|(location, _)| location + 1);
|
||||
|
||||
for location in unassigned_locations {
|
||||
@ -342,12 +342,7 @@ impl VertexInputState {
|
||||
location.checked_sub(1).and_then(|location| {
|
||||
self.attributes
|
||||
.get(&location)
|
||||
.filter(|attribute_desc| {
|
||||
attribute_desc
|
||||
.format
|
||||
.components()
|
||||
.starts_with(&[64, 64, 64])
|
||||
})
|
||||
.filter(|attribute_desc| attribute_desc.format.locations() == 2)
|
||||
.map(|d| (true, d))
|
||||
})
|
||||
})
|
||||
|
@ -83,13 +83,19 @@ impl VertexBufferDescription {
|
||||
/// Information about a member of a vertex struct.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct VertexMemberInfo {
|
||||
/// Offset of the member in bytes from the start of the struct.
|
||||
pub offset: usize,
|
||||
/// Attribute format of the member. Implicitly provides number of components.
|
||||
/// The offset of the member in bytes from the start of the struct.
|
||||
pub offset: u32,
|
||||
|
||||
/// The attribute format of the member. Implicitly provides the number of components.
|
||||
pub format: Format,
|
||||
/// Number of consecutive array elements or matrix columns using format. The corresponding
|
||||
/// number of locations might defer depending on the size of the format.
|
||||
|
||||
/// The number of consecutive array elements or matrix columns using `format`.
|
||||
/// The corresponding number of locations might differ depending on the size of the format.
|
||||
pub num_elements: u32,
|
||||
|
||||
/// If `num_elements` is greater than 1, the stride in bytes between the start of consecutive
|
||||
/// elements.
|
||||
pub stride: u32,
|
||||
}
|
||||
|
||||
impl VertexMemberInfo {
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
ValidationError,
|
||||
};
|
||||
use ahash::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::{collections::hash_map::Entry, convert::Infallible};
|
||||
|
||||
pub(crate) fn validate_interfaces_compatible(
|
||||
out_spirv: &Spirv,
|
||||
@ -208,7 +208,7 @@ fn get_variables_by_key<'a>(
|
||||
execution_model,
|
||||
variable_id,
|
||||
filter_storage_class,
|
||||
|key, data| {
|
||||
|key, data| -> Result<(), Infallible> {
|
||||
if let InputOutputKey::User(InputOutputUserKey {
|
||||
location,
|
||||
component,
|
||||
@ -241,8 +241,11 @@ fn get_variables_by_key<'a>(
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
variables_by_key
|
||||
@ -723,13 +726,16 @@ pub(crate) fn shader_interface_location_info(
|
||||
execution_model,
|
||||
variable_id,
|
||||
filter_storage_class,
|
||||
|key, data| {
|
||||
|key, data| -> Result<(), Infallible> {
|
||||
if let InputOutputKey::User(key) = key {
|
||||
let InputOutputData { type_id, .. } = data;
|
||||
shader_interface_analyze_type(spirv, type_id, key, &mut scalar_func);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
locations
|
||||
@ -864,13 +870,13 @@ pub(crate) struct InputOutputVariableBlock {
|
||||
pub(crate) member_index: usize,
|
||||
}
|
||||
|
||||
pub(crate) fn input_output_map(
|
||||
pub(crate) fn input_output_map<E>(
|
||||
spirv: &Spirv,
|
||||
execution_model: ExecutionModel,
|
||||
variable_id: Id,
|
||||
filter_storage_class: StorageClass,
|
||||
mut func: impl FnMut(InputOutputKey, InputOutputData),
|
||||
) {
|
||||
mut func: impl FnMut(InputOutputKey, InputOutputData) -> Result<(), E>,
|
||||
) -> Result<(), E> {
|
||||
let variable_id_info = spirv.id(variable_id);
|
||||
let (pointer_type_id, storage_class) = match *variable_id_info.instruction() {
|
||||
Instruction::Variable {
|
||||
@ -878,7 +884,7 @@ pub(crate) fn input_output_map(
|
||||
storage_class,
|
||||
..
|
||||
} if storage_class == filter_storage_class => (result_type_id, storage_class),
|
||||
_ => return,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
let pointer_type_id_info = spirv.id(pointer_type_id);
|
||||
let type_id = match *pointer_type_id_info.instruction() {
|
||||
@ -918,7 +924,7 @@ pub(crate) fn input_output_map(
|
||||
block: None,
|
||||
type_id,
|
||||
},
|
||||
);
|
||||
)
|
||||
} else if let Some(built_in) = built_in {
|
||||
func(
|
||||
InputOutputKey::BuiltIn(built_in),
|
||||
@ -928,13 +934,13 @@ pub(crate) fn input_output_map(
|
||||
block: None,
|
||||
type_id,
|
||||
},
|
||||
);
|
||||
)
|
||||
} else {
|
||||
let block_type_id = type_id;
|
||||
let block_type_id_info = spirv.id(block_type_id);
|
||||
let member_types = match block_type_id_info.instruction() {
|
||||
Instruction::TypeStruct { member_types, .. } => member_types,
|
||||
_ => return,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
for (member_index, (&type_id, member_info)) in member_types
|
||||
@ -975,7 +981,7 @@ pub(crate) fn input_output_map(
|
||||
}),
|
||||
type_id,
|
||||
},
|
||||
);
|
||||
)?;
|
||||
} else if let Some(built_in) = built_in {
|
||||
func(
|
||||
InputOutputKey::BuiltIn(built_in),
|
||||
@ -988,9 +994,11 @@ pub(crate) fn input_output_map(
|
||||
}),
|
||||
type_id,
|
||||
},
|
||||
);
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
||||
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version,
|
||||
};
|
||||
use ahash::HashMap;
|
||||
use std::cmp::max;
|
||||
use std::{cmp::max, convert::Infallible};
|
||||
|
||||
pub(crate) fn validate_runtime(
|
||||
device: &Device,
|
||||
@ -1366,7 +1366,7 @@ impl<'a> RuntimeValidator<'a> {
|
||||
self.execution_model,
|
||||
result_id,
|
||||
storage_class,
|
||||
|key, data| {
|
||||
|key, data| -> Result<(), Infallible> {
|
||||
let InputOutputData { type_id, .. } = data;
|
||||
|
||||
match key {
|
||||
@ -1386,8 +1386,11 @@ impl<'a> RuntimeValidator<'a> {
|
||||
// https://github.com/KhronosGroup/Vulkan-Docs/issues/2293
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if is_in_interface && storage_class == StorageClass::Output {
|
||||
|
@ -433,7 +433,6 @@ use half::f16;
|
||||
use smallvec::SmallVec;
|
||||
use spirv::ExecutionModel;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::hash_map::Entry,
|
||||
mem::{discriminant, size_of_val, MaybeUninit},
|
||||
num::NonZeroU64,
|
||||
@ -1150,8 +1149,6 @@ pub struct EntryPointInfo {
|
||||
pub execution_model: ExecutionModel,
|
||||
pub descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
|
||||
pub push_constant_requirements: Option<PushConstantRange>,
|
||||
pub input_interface: ShaderInterface,
|
||||
pub output_interface: ShaderInterface,
|
||||
}
|
||||
|
||||
/// Represents a shader entry point in a shader module.
|
||||
@ -1372,86 +1369,6 @@ impl DescriptorRequirements {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type that contains the definition of an interface between two shader stages, or between
|
||||
/// the outside and a shader stage.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ShaderInterface {
|
||||
elements: Vec<ShaderInterfaceEntry>,
|
||||
}
|
||||
|
||||
impl ShaderInterface {
|
||||
/// Constructs a new `ShaderInterface`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Must only provide one entry per location.
|
||||
/// - The format of each element must not be larger than 128 bits.
|
||||
// TODO: 4x64 bit formats are possible, but they require special handling.
|
||||
// TODO: could this be made safe?
|
||||
#[inline]
|
||||
pub unsafe fn new_unchecked(elements: Vec<ShaderInterfaceEntry>) -> ShaderInterface {
|
||||
ShaderInterface { elements }
|
||||
}
|
||||
|
||||
/// Creates a description of an empty shader interface.
|
||||
#[inline]
|
||||
pub const fn empty() -> ShaderInterface {
|
||||
ShaderInterface {
|
||||
elements: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a slice containing the elements of the interface.
|
||||
#[inline]
|
||||
pub fn elements(&self) -> &[ShaderInterfaceEntry] {
|
||||
self.elements.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Entry of a shader interface definition.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ShaderInterfaceEntry {
|
||||
/// The location slot that the variable starts at.
|
||||
pub location: u32,
|
||||
|
||||
/// The index within the location slot that the variable is located.
|
||||
/// Only meaningful for fragment outputs.
|
||||
pub index: u32,
|
||||
|
||||
/// The component slot that the variable starts at. Must be in the range 0..=3.
|
||||
pub component: u32,
|
||||
|
||||
/// Name of the element, or `None` if the name is unknown.
|
||||
pub name: Option<Cow<'static, str>>,
|
||||
|
||||
/// The type of the variable.
|
||||
pub ty: ShaderInterfaceEntryType,
|
||||
}
|
||||
|
||||
/// The type of a variable in a shader interface.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ShaderInterfaceEntryType {
|
||||
/// The base numeric type.
|
||||
pub base_type: NumericType,
|
||||
|
||||
/// The number of vector components. Must be in the range 1..=4.
|
||||
pub num_components: u32,
|
||||
|
||||
/// The number of array elements or matrix columns.
|
||||
pub num_elements: u32,
|
||||
|
||||
/// Whether the base type is 64 bits wide. If true, each item of the base type takes up two
|
||||
/// component slots instead of one.
|
||||
pub is_64bit: bool,
|
||||
}
|
||||
|
||||
impl ShaderInterfaceEntryType {
|
||||
pub(crate) fn num_locations(&self) -> u32 {
|
||||
assert!(!self.is_64bit); // TODO: implement
|
||||
self.num_elements
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_bitflags_enum! {
|
||||
#[non_exhaustive]
|
||||
|
||||
|
@ -6,17 +6,15 @@ use crate::{
|
||||
image::view::ImageViewType,
|
||||
pipeline::layout::PushConstantRange,
|
||||
shader::{
|
||||
spirv::{Decoration, Dim, ExecutionModel, Id, Instruction, Spirv, StorageClass},
|
||||
DescriptorIdentifier, DescriptorRequirements, EntryPointInfo, NumericType, ShaderInterface,
|
||||
ShaderInterfaceEntry, ShaderInterfaceEntryType, ShaderStage, ShaderStages,
|
||||
SpecializationConstant,
|
||||
spirv::{Decoration, Dim, Id, Instruction, Spirv, StorageClass},
|
||||
DescriptorIdentifier, DescriptorRequirements, EntryPointInfo, NumericType, ShaderStage,
|
||||
ShaderStages, SpecializationConstant,
|
||||
},
|
||||
DeviceSize, Version,
|
||||
};
|
||||
use ahash::{HashMap, HashSet};
|
||||
use half::f16;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Returns an iterator over all entry points in `spirv`, with information about the entry point.
|
||||
#[inline]
|
||||
@ -24,15 +22,14 @@ pub fn entry_points(spirv: &Spirv) -> impl Iterator<Item = (Id, EntryPointInfo)>
|
||||
let interface_variables = interface_variables(spirv);
|
||||
|
||||
spirv.entry_points().iter().filter_map(move |instruction| {
|
||||
let (execution_model, function_id, entry_point_name, interface) = match *instruction {
|
||||
Instruction::EntryPoint {
|
||||
execution_model,
|
||||
entry_point,
|
||||
ref name,
|
||||
ref interface,
|
||||
..
|
||||
} => (execution_model, entry_point, name, interface),
|
||||
_ => return None,
|
||||
let &Instruction::EntryPoint {
|
||||
execution_model,
|
||||
entry_point,
|
||||
ref name,
|
||||
..
|
||||
} = instruction
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let stage = ShaderStage::from(execution_model);
|
||||
@ -41,44 +38,22 @@ pub fn entry_points(spirv: &Spirv) -> impl Iterator<Item = (Id, EntryPointInfo)>
|
||||
&interface_variables.descriptor_binding,
|
||||
spirv,
|
||||
stage,
|
||||
function_id,
|
||||
entry_point,
|
||||
);
|
||||
let push_constant_requirements = push_constant_requirements(
|
||||
&interface_variables.push_constant,
|
||||
spirv,
|
||||
stage,
|
||||
function_id,
|
||||
);
|
||||
let input_interface = shader_interface(
|
||||
spirv,
|
||||
interface,
|
||||
StorageClass::Input,
|
||||
matches!(
|
||||
execution_model,
|
||||
ExecutionModel::TessellationControl
|
||||
| ExecutionModel::TessellationEvaluation
|
||||
| ExecutionModel::Geometry
|
||||
),
|
||||
);
|
||||
let output_interface = shader_interface(
|
||||
spirv,
|
||||
interface,
|
||||
StorageClass::Output,
|
||||
matches!(
|
||||
execution_model,
|
||||
ExecutionModel::TessellationControl | ExecutionModel::MeshEXT
|
||||
),
|
||||
entry_point,
|
||||
);
|
||||
|
||||
Some((
|
||||
function_id,
|
||||
entry_point,
|
||||
EntryPointInfo {
|
||||
name: entry_point_name.clone(),
|
||||
name: name.clone(),
|
||||
execution_model,
|
||||
descriptor_binding_requirements,
|
||||
push_constant_requirements,
|
||||
input_interface,
|
||||
output_interface,
|
||||
},
|
||||
))
|
||||
})
|
||||
@ -1066,118 +1041,6 @@ pub(super) fn specialization_constants(spirv: &Spirv) -> HashMap<u32, Specializa
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Extracts the `ShaderInterface` with the given storage class from `spirv`.
|
||||
fn shader_interface(
|
||||
spirv: &Spirv,
|
||||
interface: &[Id],
|
||||
filter_storage_class: StorageClass,
|
||||
ignore_first_array: bool,
|
||||
) -> ShaderInterface {
|
||||
let elements: Vec<_> = interface
|
||||
.iter()
|
||||
.filter_map(|&id| {
|
||||
let (result_type_id, result_id) = match *spirv.id(id).instruction() {
|
||||
Instruction::Variable {
|
||||
result_type_id,
|
||||
result_id,
|
||||
storage_class,
|
||||
..
|
||||
} if storage_class == filter_storage_class => (result_type_id, result_id),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if is_builtin(spirv, result_id) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let id_info = spirv.id(result_id);
|
||||
|
||||
let name = id_info
|
||||
.names()
|
||||
.iter()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Name { ref name, .. } => Some(Cow::Owned(name.clone())),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let location = id_info
|
||||
.decorations()
|
||||
.iter()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Decorate {
|
||||
decoration: Decoration::Location { location },
|
||||
..
|
||||
} => Some(location),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Input/output variable with id {} (name {:?}) is missing a location",
|
||||
result_id, name,
|
||||
)
|
||||
});
|
||||
let component = id_info
|
||||
.decorations()
|
||||
.iter()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Decorate {
|
||||
decoration: Decoration::Component { component },
|
||||
..
|
||||
} => Some(component),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let index = id_info
|
||||
.decorations()
|
||||
.iter()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Decorate {
|
||||
decoration: Decoration::Index { index },
|
||||
..
|
||||
} => Some(index),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(0);
|
||||
|
||||
let ty = shader_interface_type_of(spirv, result_type_id, ignore_first_array);
|
||||
assert!(ty.num_elements >= 1);
|
||||
|
||||
Some(ShaderInterfaceEntry {
|
||||
location,
|
||||
index,
|
||||
component,
|
||||
ty,
|
||||
name,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Checking for overlapping elements.
|
||||
for (offset, element1) in elements.iter().enumerate() {
|
||||
for element2 in elements.iter().skip(offset + 1) {
|
||||
if element1.index == element2.index
|
||||
&& (element1.location == element2.location
|
||||
|| (element1.location < element2.location
|
||||
&& element1.location + element1.ty.num_locations() > element2.location)
|
||||
|| (element2.location < element1.location
|
||||
&& element2.location + element2.ty.num_locations() > element1.location))
|
||||
{
|
||||
panic!(
|
||||
"The locations of attributes `{:?}` ({}..{}) and `{:?}` ({}..{}) overlap",
|
||||
element1.name,
|
||||
element1.location,
|
||||
element1.location + element1.ty.num_locations(),
|
||||
element2.name,
|
||||
element2.location,
|
||||
element2.location + element2.ty.num_locations(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderInterface { elements }
|
||||
}
|
||||
|
||||
/// Returns the size of a type, or `None` if its size cannot be determined.
|
||||
pub(crate) fn size_of_type(spirv: &Spirv, id: Id) -> Option<DeviceSize> {
|
||||
let id_info = spirv.id(id);
|
||||
@ -1302,144 +1165,6 @@ fn offset_of_struct(spirv: &Spirv, id: Id) -> u32 {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// If `ignore_first_array` is true, the function expects the outermost instruction to be
|
||||
/// `OpTypeArray`. If it's the case, the OpTypeArray will be ignored. If not, the function will
|
||||
/// panic.
|
||||
fn shader_interface_type_of(
|
||||
spirv: &Spirv,
|
||||
id: Id,
|
||||
ignore_first_array: bool,
|
||||
) -> ShaderInterfaceEntryType {
|
||||
match *spirv.id(id).instruction() {
|
||||
Instruction::TypeInt {
|
||||
width, signedness, ..
|
||||
} => {
|
||||
assert!(!ignore_first_array);
|
||||
ShaderInterfaceEntryType {
|
||||
base_type: match signedness {
|
||||
0 => NumericType::Uint,
|
||||
1 => NumericType::Int,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
num_components: 1,
|
||||
num_elements: 1,
|
||||
is_64bit: match width {
|
||||
8 | 16 | 32 => false,
|
||||
64 => true,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
Instruction::TypeFloat { width, .. } => {
|
||||
assert!(!ignore_first_array);
|
||||
ShaderInterfaceEntryType {
|
||||
base_type: NumericType::Float,
|
||||
num_components: 1,
|
||||
num_elements: 1,
|
||||
is_64bit: match width {
|
||||
16 | 32 => false,
|
||||
64 => true,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
Instruction::TypeVector {
|
||||
component_type,
|
||||
component_count,
|
||||
..
|
||||
} => {
|
||||
assert!(!ignore_first_array);
|
||||
ShaderInterfaceEntryType {
|
||||
num_components: component_count,
|
||||
..shader_interface_type_of(spirv, component_type, false)
|
||||
}
|
||||
}
|
||||
Instruction::TypeMatrix {
|
||||
column_type,
|
||||
column_count,
|
||||
..
|
||||
} => {
|
||||
assert!(!ignore_first_array);
|
||||
ShaderInterfaceEntryType {
|
||||
num_elements: column_count,
|
||||
..shader_interface_type_of(spirv, column_type, false)
|
||||
}
|
||||
}
|
||||
Instruction::TypeArray {
|
||||
element_type,
|
||||
length,
|
||||
..
|
||||
} => {
|
||||
if ignore_first_array {
|
||||
shader_interface_type_of(spirv, element_type, false)
|
||||
} else {
|
||||
let mut ty = shader_interface_type_of(spirv, element_type, false);
|
||||
let length = get_constant(spirv, length).expect("failed to find array length");
|
||||
ty.num_elements *= length as u32;
|
||||
ty
|
||||
}
|
||||
}
|
||||
Instruction::TypePointer { ty, .. } => {
|
||||
shader_interface_type_of(spirv, ty, ignore_first_array)
|
||||
}
|
||||
Instruction::TypeStruct { .. } => {
|
||||
panic!("Structs are not yet supported in shader in/out interface!");
|
||||
}
|
||||
_ => panic!("Type {} not found or invalid", id),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if a `BuiltIn` decorator is applied on an id.
|
||||
fn is_builtin(spirv: &Spirv, id: Id) -> bool {
|
||||
let id_info = spirv.id(id);
|
||||
|
||||
if id_info.decorations().iter().any(|instruction| {
|
||||
matches!(
|
||||
instruction,
|
||||
Instruction::Decorate {
|
||||
decoration: Decoration::BuiltIn { .. },
|
||||
..
|
||||
}
|
||||
)
|
||||
}) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if id_info
|
||||
.members()
|
||||
.iter()
|
||||
.flat_map(|member_info| member_info.decorations())
|
||||
.any(|instruction| {
|
||||
matches!(
|
||||
instruction,
|
||||
Instruction::MemberDecorate {
|
||||
decoration: Decoration::BuiltIn { .. },
|
||||
..
|
||||
}
|
||||
)
|
||||
})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
match id_info.instruction() {
|
||||
Instruction::Variable {
|
||||
result_type_id: ty, ..
|
||||
}
|
||||
| Instruction::TypeArray {
|
||||
element_type: ty, ..
|
||||
}
|
||||
| Instruction::TypeRuntimeArray {
|
||||
element_type: ty, ..
|
||||
}
|
||||
| Instruction::TypePointer { ty, .. } => is_builtin(spirv, *ty),
|
||||
Instruction::TypeStruct { member_types, .. } => {
|
||||
member_types.iter().any(|ty| is_builtin(spirv, *ty))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_constant(spirv: &Spirv, id: Id) -> Option<u64> {
|
||||
match spirv.id(id).instruction() {
|
||||
Instruction::Constant { value, .. } => match value.len() {
|
||||
|
Loading…
Reference in New Issue
Block a user