From b190d6fb1c22070abe1d5838857684fc677cdfea Mon Sep 17 00:00:00 2001 From: Rua Date: Mon, 4 Mar 2024 22:58:27 +0100 Subject: [PATCH] Rewrite `VertexDefinition` (#2487) --- examples/async-update/main.rs | 4 +- examples/buffer-allocator/main.rs | 4 +- .../deferred/frame/ambient_lighting_system.rs | 4 +- .../frame/directional_lighting_system.rs | 4 +- .../deferred/frame/point_lighting_system.rs | 4 +- examples/deferred/triangle_draw_system.rs | 4 +- examples/gl-interop/main.rs | 4 +- examples/image-self-copy-blit/main.rs | 4 +- examples/image/main.rs | 4 +- examples/immutable-sampler/main.rs | 4 +- examples/indirect/main.rs | 4 +- examples/instancing/main.rs | 2 +- examples/msaa-renderpass/main.rs | 4 +- examples/multi-window/main.rs | 4 +- examples/multiview/main.rs | 4 +- examples/occlusion-query/main.rs | 4 +- examples/offscreen/main.rs | 4 +- examples/push-descriptors/main.rs | 4 +- examples/runtime-array/main.rs | 4 +- examples/runtime-shader/main.rs | 4 +- examples/simple-particles/main.rs | 4 +- examples/teapot/main.rs | 2 +- examples/tessellation/main.rs | 4 +- examples/texture-array/main.rs | 4 +- examples/triangle-util/main.rs | 4 +- examples/triangle-v1_3/main.rs | 4 +- examples/triangle/main.rs | 4 +- vulkano-macros/src/derive_vertex.rs | 3 +- vulkano/autogen/formats.rs | 22 ++ .../pipeline/graphics/vertex_input/buffers.rs | 10 +- .../graphics/vertex_input/definition.rs | 300 ++++++++++++----- .../graphics/vertex_input/impl_vertex.rs | 3 +- .../src/pipeline/graphics/vertex_input/mod.rs | 9 +- .../pipeline/graphics/vertex_input/vertex.rs | 16 +- .../src/pipeline/shader/inout_interface.rs | 36 ++- .../src/pipeline/shader/validate_runtime.rs | 9 +- vulkano/src/shader/mod.rs | 83 ----- vulkano/src/shader/reflect.rs | 305 +----------------- 38 files changed, 325 insertions(+), 575 deletions(-) diff --git a/examples/async-update/main.rs b/examples/async-update/main.rs index 66b5be5d..265888bd 100644 --- a/examples/async-update/main.rs +++ b/examples/async-update/main.rs @@ -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), diff --git a/examples/buffer-allocator/main.rs b/examples/buffer-allocator/main.rs index 20fffe85..d60f8d44 100644 --- a/examples/buffer-allocator/main.rs +++ b/examples/buffer-allocator/main.rs @@ -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), diff --git a/examples/deferred/frame/ambient_lighting_system.rs b/examples/deferred/frame/ambient_lighting_system.rs index 4973dce4..a9966bbb 100644 --- a/examples/deferred/frame/ambient_lighting_system.rs +++ b/examples/deferred/frame/ambient_lighting_system.rs @@ -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), diff --git a/examples/deferred/frame/directional_lighting_system.rs b/examples/deferred/frame/directional_lighting_system.rs index 7b34482d..538a48de 100644 --- a/examples/deferred/frame/directional_lighting_system.rs +++ b/examples/deferred/frame/directional_lighting_system.rs @@ -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), diff --git a/examples/deferred/frame/point_lighting_system.rs b/examples/deferred/frame/point_lighting_system.rs index 238ffa15..cf8d15bd 100644 --- a/examples/deferred/frame/point_lighting_system.rs +++ b/examples/deferred/frame/point_lighting_system.rs @@ -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), diff --git a/examples/deferred/triangle_draw_system.rs b/examples/deferred/triangle_draw_system.rs index 4f38d734..7c13f19d 100644 --- a/examples/deferred/triangle_draw_system.rs +++ b/examples/deferred/triangle_draw_system.rs @@ -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), diff --git a/examples/gl-interop/main.rs b/examples/gl-interop/main.rs index 339ed937..84937758 100644 --- a/examples/gl-interop/main.rs +++ b/examples/gl-interop/main.rs @@ -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), diff --git a/examples/image-self-copy-blit/main.rs b/examples/image-self-copy-blit/main.rs index 1dcf8630..35cb9992 100644 --- a/examples/image-self-copy-blit/main.rs +++ b/examples/image-self-copy-blit/main.rs @@ -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), diff --git a/examples/image/main.rs b/examples/image/main.rs index 1fde1104..f5150de1 100644 --- a/examples/image/main.rs +++ b/examples/image/main.rs @@ -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), diff --git a/examples/immutable-sampler/main.rs b/examples/immutable-sampler/main.rs index 85f75684..0efed200 100644 --- a/examples/immutable-sampler/main.rs +++ b/examples/immutable-sampler/main.rs @@ -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), diff --git a/examples/indirect/main.rs b/examples/indirect/main.rs index fd6ebf30..4aacb2b2 100644 --- a/examples/indirect/main.rs +++ b/examples/indirect/main.rs @@ -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), diff --git a/examples/instancing/main.rs b/examples/instancing/main.rs index f6f802e3..0c076203 100644 --- a/examples/instancing/main.rs +++ b/examples/instancing/main.rs @@ -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), diff --git a/examples/msaa-renderpass/main.rs b/examples/msaa-renderpass/main.rs index 1f1b8785..cb466084 100644 --- a/examples/msaa-renderpass/main.rs +++ b/examples/msaa-renderpass/main.rs @@ -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), diff --git a/examples/multi-window/main.rs b/examples/multi-window/main.rs index d06ee166..ae726a40 100644 --- a/examples/multi-window/main.rs +++ b/examples/multi-window/main.rs @@ -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), diff --git a/examples/multiview/main.rs b/examples/multiview/main.rs index 3cb04df1..63fcdf7f 100644 --- a/examples/multiview/main.rs +++ b/examples/multiview/main.rs @@ -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), diff --git a/examples/occlusion-query/main.rs b/examples/occlusion-query/main.rs index a5e31bad..c850a602 100644 --- a/examples/occlusion-query/main.rs +++ b/examples/occlusion-query/main.rs @@ -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), diff --git a/examples/offscreen/main.rs b/examples/offscreen/main.rs index 6f471b92..cbb06220 100644 --- a/examples/offscreen/main.rs +++ b/examples/offscreen/main.rs @@ -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), diff --git a/examples/push-descriptors/main.rs b/examples/push-descriptors/main.rs index b6e509aa..d6958b16 100644 --- a/examples/push-descriptors/main.rs +++ b/examples/push-descriptors/main.rs @@ -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), diff --git a/examples/runtime-array/main.rs b/examples/runtime-array/main.rs index 86f702d6..9161202a 100644 --- a/examples/runtime-array/main.rs +++ b/examples/runtime-array/main.rs @@ -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), diff --git a/examples/runtime-shader/main.rs b/examples/runtime-shader/main.rs index 5ebb1de9..a0d5cd8f 100644 --- a/examples/runtime-shader/main.rs +++ b/examples/runtime-shader/main.rs @@ -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), diff --git a/examples/simple-particles/main.rs b/examples/simple-particles/main.rs index 09ef07d7..04bfccba 100644 --- a/examples/simple-particles/main.rs +++ b/examples/simple-particles/main.rs @@ -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), diff --git a/examples/teapot/main.rs b/examples/teapot/main.rs index b9e756b5..4a9eb547 100644 --- a/examples/teapot/main.rs +++ b/examples/teapot/main.rs @@ -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), diff --git a/examples/tessellation/main.rs b/examples/tessellation/main.rs index ed5a02a2..d5aa14bc 100644 --- a/examples/tessellation/main.rs +++ b/examples/tessellation/main.rs @@ -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), diff --git a/examples/texture-array/main.rs b/examples/texture-array/main.rs index 49738d3e..4c0b40fe 100644 --- a/examples/texture-array/main.rs +++ b/examples/texture-array/main.rs @@ -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), diff --git a/examples/triangle-util/main.rs b/examples/triangle-util/main.rs index 00b36bd6..249e3810 100644 --- a/examples/triangle-util/main.rs +++ b/examples/triangle-util/main.rs @@ -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 = [ diff --git a/examples/triangle-v1_3/main.rs b/examples/triangle-v1_3/main.rs index cee351d4..1edb5cc3 100644 --- a/examples/triangle-v1_3/main.rs +++ b/examples/triangle-v1_3/main.rs @@ -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 = [ diff --git a/examples/triangle/main.rs b/examples/triangle/main.rs index 5556c35e..54e70255 100644 --- a/examples/triangle/main.rs +++ b/examples/triangle/main.rs @@ -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 = [ diff --git a/vulkano-macros/src/derive_vertex.rs b/vulkano-macros/src/derive_vertex.rs index faf9b569..14dfe9c6 100644 --- a/vulkano-macros/src/derive_vertex.rs +++ b/vulkano-macros/src/derive_vertex.rs @@ -61,7 +61,7 @@ pub fn derive_vertex(crate_ident: &Ident, ast: syn::DeriveInput) -> Result(); 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 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 { diff --git a/vulkano/src/pipeline/graphics/vertex_input/buffers.rs b/vulkano/src/pipeline/graphics/vertex_input/buffers.rs index e18df9c5..81890ac3 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/buffers.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/buffers.rs @@ -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> { - self.0.definition(interface) + self.0.definition(entry_point) } } diff --git a/vulkano/src/pipeline/graphics/vertex_input/definition.rs b/vulkano/src/pipeline/graphics/vertex_input/definition.rs index c1ad461e..163129e5 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/definition.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/definition.rs @@ -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>; } @@ -19,89 +32,198 @@ unsafe impl VertexDefinition for &[VertexBufferDescription] { #[inline] fn definition( &self, - interface: &ShaderInterface, + entry_point: &EntryPoint, ) -> Result> { - 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 = HashMap::default(); + + for variable_id in interface.iter().copied() { + input_output_map( + spirv, + execution_model, + variable_id, + StorageClass::Input, + |key, data| -> Result<(), Box> { + 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 VertexDefinition for [VertexBufferDescription; N] { #[inline] fn definition( &self, - interface: &ShaderInterface, + entry_point: &EntryPoint, ) -> Result> { - self.as_slice().definition(interface) + self.as_slice().definition(entry_point) } } @@ -119,9 +241,9 @@ unsafe impl VertexDefinition for Vec { #[inline] fn definition( &self, - interface: &ShaderInterface, + entry_point: &EntryPoint, ) -> Result> { - 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> { - std::slice::from_ref(self).definition(interface) + std::slice::from_ref(self).definition(entry_point) } } diff --git a/vulkano/src/pipeline/graphics/vertex_input/impl_vertex.rs b/vulkano/src/pipeline/graphics/vertex_input/impl_vertex.rs index 580c6e75..9dc20cf9 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/impl_vertex.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/impl_vertex.rs @@ -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, }); } )* diff --git a/vulkano/src/pipeline/graphics/vertex_input/mod.rs b/vulkano/src/pipeline/graphics/vertex_input/mod.rs index 322cbd30..8a52cca5 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/mod.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/mod.rs @@ -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)) }) }) diff --git a/vulkano/src/pipeline/graphics/vertex_input/vertex.rs b/vulkano/src/pipeline/graphics/vertex_input/vertex.rs index 2da3db30..76e3aa33 100644 --- a/vulkano/src/pipeline/graphics/vertex_input/vertex.rs +++ b/vulkano/src/pipeline/graphics/vertex_input/vertex.rs @@ -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 { diff --git a/vulkano/src/pipeline/shader/inout_interface.rs b/vulkano/src/pipeline/shader/inout_interface.rs index a0075e7b..4477bb8a 100644 --- a/vulkano/src/pipeline/shader/inout_interface.rs +++ b/vulkano/src/pipeline/shader/inout_interface.rs @@ -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( 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(()) } } diff --git a/vulkano/src/pipeline/shader/validate_runtime.rs b/vulkano/src/pipeline/shader/validate_runtime.rs index 25b4e5a3..ea99842b 100644 --- a/vulkano/src/pipeline/shader/validate_runtime.rs +++ b/vulkano/src/pipeline/shader/validate_runtime.rs @@ -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 { diff --git a/vulkano/src/shader/mod.rs b/vulkano/src/shader/mod.rs index 2e959593..b5af2fe2 100644 --- a/vulkano/src/shader/mod.rs +++ b/vulkano/src/shader/mod.rs @@ -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, - 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, -} - -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) -> 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>, - - /// 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] diff --git a/vulkano/src/shader/reflect.rs b/vulkano/src/shader/reflect.rs index 607778f6..87743673 100644 --- a/vulkano/src/shader/reflect.rs +++ b/vulkano/src/shader/reflect.rs @@ -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 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 &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 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 { 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 { match spirv.id(id).instruction() { Instruction::Constant { value, .. } => match value.len() {