• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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