1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 //! Definition for creating a [`VertexInputState`] based on a [`ShaderInterface`]. 11 //! 12 //! # Implementing `Vertex` 13 //! 14 //! The implementations of the `VertexDefinition` trait that are provided by vulkano require you to 15 //! use a buffer whose content is `[V]` where `V` implements the `Vertex` trait. 16 //! 17 //! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!` 18 //! macro. 19 //! 20 //! # Examples 21 //! 22 //! ```ignore // TODO: 23 //! # #[macro_use] extern crate vulkano 24 //! # fn main() { 25 //! # use std::sync::Arc; 26 //! # use vulkano::device::Device; 27 //! # use vulkano::device::Queue; 28 //! use vulkano::buffer::BufferAccess; 29 //! use vulkano::buffer::BufferUsage; 30 //! use vulkano::memory::HostVisible; 31 //! use vulkano::pipeline::vertex::; 32 //! # let device: Arc<Device> = return; 33 //! # let queue: Arc<Queue> = return; 34 //! 35 //! struct Vertex { 36 //! position: [f32; 2] 37 //! } 38 //! 39 //! impl_vertex!(Vertex, position); 40 //! 41 //! let usage = BufferUsage { 42 //! vertex_buffer: true, 43 //! ..BufferUsage::empty() 44 //! }; 45 //! 46 //! let vertex_buffer = BufferAccess::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue) 47 //! .expect("failed to create buffer"); 48 //! 49 //! // TODO: finish example 50 //! # } 51 //! ``` 52 53 use super::{ 54 VertexBufferDescription, VertexInputAttributeDescription, VertexInputBindingDescription, 55 }; 56 use crate::{ 57 pipeline::graphics::vertex_input::{VertexInputState, VertexMemberInfo}, 58 shader::{ShaderInterface, ShaderInterfaceEntryType}, 59 DeviceSize, 60 }; 61 use std::{ 62 error::Error, 63 fmt::{Display, Error as FmtError, Formatter}, 64 }; 65 66 /// Trait for types that can create a [`VertexInputState`] from a [`ShaderInterface`]. 67 pub unsafe trait VertexDefinition { 68 /// Builds the vertex definition to use to link this definition to a vertex shader's input 69 /// interface. 70 // TODO: remove error return, move checks to GraphicsPipelineBuilder definition( &self, interface: &ShaderInterface, ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>71 fn definition( 72 &self, 73 interface: &ShaderInterface, 74 ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>; 75 } 76 77 unsafe impl VertexDefinition for VertexInputState { definition( &self, _interface: &ShaderInterface, ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>78 fn definition( 79 &self, 80 _interface: &ShaderInterface, 81 ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> { 82 Ok(self.clone()) 83 } 84 } 85 86 /// Error that can happen when the vertex definition doesn't match the input of the vertex shader. 87 #[derive(Clone, Debug, PartialEq, Eq)] 88 pub enum IncompatibleVertexDefinitionError { 89 /// An attribute of the vertex shader is missing in the vertex source. 90 MissingAttribute { 91 /// Name of the missing attribute. 92 attribute: String, 93 }, 94 95 /// The format of an attribute does not match. 96 FormatMismatch { 97 /// Name of the attribute. 98 attribute: String, 99 /// The format in the vertex shader. 100 shader: ShaderInterfaceEntryType, 101 /// The format in the vertex definition. 102 definition: VertexMemberInfo, 103 }, 104 } 105 106 impl Error for IncompatibleVertexDefinitionError {} 107 108 impl Display for IncompatibleVertexDefinitionError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>109 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 110 match self { 111 IncompatibleVertexDefinitionError::MissingAttribute { .. } => { 112 write!(f, "an attribute is missing") 113 } 114 IncompatibleVertexDefinitionError::FormatMismatch { .. } => { 115 write!(f, "the format of an attribute does not match") 116 } 117 } 118 } 119 } 120 121 unsafe impl VertexDefinition for &[VertexBufferDescription] { 122 #[inline] definition( &self, interface: &ShaderInterface, ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>123 fn definition( 124 &self, 125 interface: &ShaderInterface, 126 ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> { 127 let bindings = self.iter().enumerate().map(|(binding, buffer)| { 128 ( 129 binding as u32, 130 VertexInputBindingDescription { 131 stride: buffer.stride, 132 input_rate: buffer.input_rate, 133 }, 134 ) 135 }); 136 let mut attributes: Vec<(u32, VertexInputAttributeDescription)> = Vec::new(); 137 138 for element in interface.elements() { 139 let name = element.name.as_ref().unwrap().clone().into_owned(); 140 141 let (infos, binding) = self 142 .iter() 143 .enumerate() 144 .find_map(|(binding, buffer)| { 145 buffer 146 .members 147 .get(&name) 148 .map(|infos| (infos.clone(), binding as u32)) 149 }) 150 .ok_or_else(|| 151 // TODO: move this check to GraphicsPipelineBuilder 152 IncompatibleVertexDefinitionError::MissingAttribute { 153 attribute: name.clone(), 154 })?; 155 156 // TODO: ShaderInterfaceEntryType does not properly support 64bit. 157 // Once it does the below logic around num_elements and num_locations 158 // might have to be updated. 159 if infos.num_components() != element.ty.num_components 160 || infos.num_elements != element.ty.num_locations() 161 { 162 return Err(IncompatibleVertexDefinitionError::FormatMismatch { 163 attribute: name, 164 shader: element.ty, 165 definition: infos, 166 }); 167 } 168 169 let mut offset = infos.offset as DeviceSize; 170 let block_size = infos.format.block_size().unwrap(); 171 // Double precision formats can exceed a single location. 172 // R64B64G64A64_SFLOAT requires two locations, so we need to adapt how we bind 173 let location_range = if block_size > 16 { 174 (element.location..element.location + 2 * element.ty.num_locations()).step_by(2) 175 } else { 176 (element.location..element.location + element.ty.num_locations()).step_by(1) 177 }; 178 179 for location in location_range { 180 attributes.push(( 181 location, 182 VertexInputAttributeDescription { 183 binding, 184 format: infos.format, 185 offset: offset as u32, 186 }, 187 )); 188 offset += block_size; 189 } 190 } 191 192 Ok(VertexInputState::new() 193 .bindings(bindings) 194 .attributes(attributes)) 195 } 196 } 197 198 unsafe impl<const N: usize> VertexDefinition for [VertexBufferDescription; N] { 199 #[inline] definition( &self, interface: &ShaderInterface, ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>200 fn definition( 201 &self, 202 interface: &ShaderInterface, 203 ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> { 204 self.as_slice().definition(interface) 205 } 206 } 207 208 unsafe impl VertexDefinition for Vec<VertexBufferDescription> { 209 #[inline] definition( &self, interface: &ShaderInterface, ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>210 fn definition( 211 &self, 212 interface: &ShaderInterface, 213 ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> { 214 self.as_slice().definition(interface) 215 } 216 } 217 218 unsafe impl VertexDefinition for VertexBufferDescription { 219 #[inline] definition( &self, interface: &ShaderInterface, ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>220 fn definition( 221 &self, 222 interface: &ShaderInterface, 223 ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> { 224 std::slice::from_ref(self).definition(interface) 225 } 226 } 227