// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. use super::VertexMemberInfo; use crate::buffer::BufferAccess; use crate::pipeline::shader::ShaderInterface; use crate::pipeline::vertex::IncompatibleVertexDefinitionError; use crate::pipeline::vertex::Vertex; use crate::pipeline::vertex::VertexDefinition; use crate::pipeline::vertex::VertexInput; use crate::pipeline::vertex::VertexInputAttribute; use crate::pipeline::vertex::VertexInputBinding; use crate::pipeline::vertex::VertexInputRate; use crate::pipeline::vertex::VertexSource; use crate::DeviceSize; use std::mem; use std::sync::Arc; /// A vertex definition for any number of vertex and instance buffers. #[derive(Clone, Default)] pub struct BuffersDefinition(Vec); #[derive(Clone, Copy)] struct VertexBuffer { info_fn: fn(&str) -> Option, stride: u32, input_rate: VertexInputRate, } impl From for VertexInputBinding { #[inline] fn from(val: VertexBuffer) -> Self { Self { stride: val.stride, input_rate: val.input_rate, } } } impl BuffersDefinition { /// Constructs a new definition. pub fn new() -> Self { BuffersDefinition(Vec::new()) } /// Adds a new vertex buffer containing elements of type `V` to the definition. pub fn vertex(mut self) -> Self { self.0.push(VertexBuffer { info_fn: V::member, stride: mem::size_of::() as u32, input_rate: VertexInputRate::Vertex, }); self } /// Adds a new instance buffer containing elements of type `V` to the definition. pub fn instance(mut self) -> Self { self.0.push(VertexBuffer { info_fn: V::member, stride: mem::size_of::() as u32, input_rate: VertexInputRate::Instance { divisor: 1 }, }); self } /// Adds a new instance buffer containing elements of type `V` to the definition, with the /// specified input rate divisor. /// /// This requires the /// [`vertex_attribute_instance_rate_divisor`](crate::device::Features::vertex_attribute_instance_rate_divisor) /// feature has been enabled on the device, unless `divisor` is 1. /// /// `divisor` can be 0 if the /// [`vertex_attribute_instance_rate_zero_divisor`](crate::device::Features::vertex_attribute_instance_rate_zero_divisor) /// feature is also enabled. This means that every vertex will use the same vertex and instance /// data. pub fn instance_with_divisor(mut self, divisor: u32) -> Self { self.0.push(VertexBuffer { info_fn: V::member, stride: mem::size_of::() as u32, input_rate: VertexInputRate::Instance { divisor }, }); self } } unsafe impl VertexDefinition for BuffersDefinition { fn definition( &self, interface: &ShaderInterface, ) -> Result { let bindings = self .0 .iter() .enumerate() .map(|(binding, &buffer)| (binding as u32, buffer.into())); let mut attributes: Vec<(u32, VertexInputAttribute)> = Vec::new(); for element in interface.elements() { let name = element.name.as_ref().unwrap(); let (infos, binding) = self .0 .iter() .enumerate() .find_map(|(binding, buffer)| { (buffer.info_fn)(name).map(|infos| (infos, binding as u32)) }) .ok_or_else(|| // TODO: move this check to GraphicsPipelineBuilder IncompatibleVertexDefinitionError::MissingAttribute { attribute: name.clone().into_owned(), })?; if !infos.ty.matches( infos.array_size, element.format, element.location.end - element.location.start, ) { // TODO: move this check to GraphicsPipelineBuilder return Err(IncompatibleVertexDefinitionError::FormatMismatch { attribute: name.clone().into_owned(), shader: ( element.format, (element.location.end - element.location.start) as usize, ), definition: (infos.ty, infos.array_size), }); } let mut offset = infos.offset as DeviceSize; for location in element.location.clone() { attributes.push(( location, VertexInputAttribute { binding, format: element.format, offset: offset as u32, }, )); offset += element.format.size().unwrap(); } } Ok(VertexInput::new(bindings, attributes)) } } unsafe impl VertexSource>> for BuffersDefinition { #[inline] fn decode( &self, source: Vec>, ) -> (Vec>, usize, usize) { let result = source .into_iter() .map(|source| Box::new(source) as Box<_>) .collect::>(); let (vertices, instances) = self.vertices_instances(&result); (result, vertices, instances) } } unsafe impl VertexSource for BuffersDefinition where B: BufferAccess + Send + Sync + 'static, { #[inline] fn decode(&self, source: B) -> (Vec>, usize, usize) { let result = vec![Box::new(source) as Box<_>]; let (vertices, instances) = self.vertices_instances(&result); (result, vertices, instances) } } unsafe impl VertexSource<(B1, B2)> for BuffersDefinition where B1: BufferAccess + Send + Sync + 'static, B2: BufferAccess + Send + Sync + 'static, { #[inline] fn decode(&self, source: (B1, B2)) -> (Vec>, usize, usize) { let result = vec![Box::new(source.0) as Box<_>, Box::new(source.1) as Box<_>]; let (vertices, instances) = self.vertices_instances(&result); (result, vertices, instances) } } impl BuffersDefinition { fn vertices_instances(&self, source: &[Box]) -> (usize, usize) { assert_eq!(source.len(), self.0.len()); let mut vertices = None; let mut instances = None; for (buffer, source) in self.0.iter().zip(source) { let items = (source.size() / buffer.stride as DeviceSize) as usize; let (items, count) = match buffer.input_rate { VertexInputRate::Vertex => (items, &mut vertices), VertexInputRate::Instance { divisor } => ( if divisor == 0 { // A divisor of 0 means the same instance data is used for all instances, // so we can draw any number of instances from a single element. // The buffer must contain at least one element though. if items == 0 { 0 } else { usize::MAX } } else { // If divisor is 2, we use only half the amount of data from the source buffer, // so the number of instances that can be drawn is twice as large. items * divisor as usize }, &mut instances, ), }; if let Some(count) = count { *count = std::cmp::min(*count, items); } else { *count = Some(items); } } // TODO: find some way to let the user specify these when drawing (vertices.unwrap_or(1), instances.unwrap_or(1)) } }