rendy_mesh/
mesh.rs

1//!
2//! Manage vertex and index buffers of single objects with ease.
3//!
4
5use crate::{
6    command::{EncoderCommon, Graphics, QueueId, RenderPassEncoder, Supports},
7    core::cast_cow,
8    factory::{BufferState, Factory, UploadError},
9    memory::{Data, Upload, Write},
10    resource::{Buffer, BufferInfo, Escape},
11    AsVertex, VertexFormat,
12};
13use rendy_core::hal::adapter::PhysicalDevice;
14use std::{borrow::Cow, mem::size_of};
15
16/// Vertex buffer with it's format
17#[derive(Debug)]
18pub struct VertexBufferLayout {
19    offset: u64,
20    format: VertexFormat,
21}
22
23/// Index buffer with it's type
24#[derive(Debug)]
25pub struct IndexBuffer<B: rendy_core::hal::Backend> {
26    buffer: Escape<Buffer<B>>,
27    index_type: rendy_core::hal::IndexType,
28}
29
30/// Abstracts over two types of indices and their absence.
31#[derive(Debug)]
32pub enum Indices<'a> {
33    /// No indices.
34    None,
35
36    /// `u16` per index.
37    U16(Cow<'a, [u16]>),
38
39    /// `u32` per index.
40    U32(Cow<'a, [u32]>),
41}
42
43impl From<Vec<u16>> for Indices<'static> {
44    fn from(vec: Vec<u16>) -> Self {
45        Indices::U16(vec.into())
46    }
47}
48
49impl<'a> From<&'a [u16]> for Indices<'a> {
50    fn from(slice: &'a [u16]) -> Self {
51        Indices::U16(slice.into())
52    }
53}
54
55impl<'a> From<Cow<'a, [u16]>> for Indices<'a> {
56    fn from(cow: Cow<'a, [u16]>) -> Self {
57        Indices::U16(cow)
58    }
59}
60
61impl From<Vec<u32>> for Indices<'static> {
62    fn from(vec: Vec<u32>) -> Self {
63        Indices::U32(vec.into())
64    }
65}
66
67impl<'a> From<&'a [u32]> for Indices<'a> {
68    fn from(slice: &'a [u32]) -> Self {
69        Indices::U32(slice.into())
70    }
71}
72
73impl<'a> From<Cow<'a, [u32]>> for Indices<'a> {
74    fn from(cow: Cow<'a, [u32]>) -> Self {
75        Indices::U32(cow)
76    }
77}
78
79/// Generics-free mesh builder.
80#[derive(Clone, Debug)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub struct MeshBuilder<'a> {
83    #[cfg_attr(feature = "serde", serde(borrow))]
84    vertices: smallvec::SmallVec<[RawVertices<'a>; 16]>,
85    #[cfg_attr(feature = "serde", serde(borrow))]
86    indices: Option<RawIndices<'a>>,
87    prim: rendy_core::hal::pso::Primitive,
88}
89
90#[derive(Clone, Debug)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92struct RawVertices<'a> {
93    #[cfg_attr(feature = "serde", serde(with = "serde_bytes", borrow))]
94    vertices: Cow<'a, [u8]>,
95    format: VertexFormat,
96}
97
98#[derive(Clone, Debug)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100struct RawIndices<'a> {
101    #[cfg_attr(feature = "serde", serde(with = "serde_bytes", borrow))]
102    indices: Cow<'a, [u8]>,
103    index_type: rendy_core::hal::IndexType,
104}
105
106fn index_stride(index_type: rendy_core::hal::IndexType) -> usize {
107    match index_type {
108        rendy_core::hal::IndexType::U16 => size_of::<u16>(),
109        rendy_core::hal::IndexType::U32 => size_of::<u32>(),
110    }
111}
112
113impl<'a> MeshBuilder<'a> {
114    /// Create empty builder.
115    pub fn new() -> Self {
116        MeshBuilder {
117            vertices: smallvec::SmallVec::new(),
118            indices: None,
119            prim: rendy_core::hal::pso::Primitive::TriangleList,
120        }
121    }
122
123    /// Convert builder into fully owned type. This forces internal vertex and index buffers
124    /// to be cloned, which allows borrowed source buffers to be released.
125    pub fn into_owned(self) -> MeshBuilder<'static> {
126        MeshBuilder {
127            vertices: self
128                .vertices
129                .into_iter()
130                .map(|v| RawVertices {
131                    vertices: Cow::Owned(v.vertices.into_owned()),
132                    format: v.format,
133                })
134                .collect(),
135            indices: self.indices.map(|i| RawIndices {
136                indices: Cow::Owned(i.indices.into_owned()),
137                index_type: i.index_type,
138            }),
139            prim: self.prim,
140        }
141    }
142
143    /// Set indices buffer to the `MeshBuilder`
144    pub fn with_indices<I>(mut self, indices: I) -> Self
145    where
146        I: Into<Indices<'a>>,
147    {
148        self.set_indices(indices);
149        self
150    }
151
152    /// Set indices buffer to the `MeshBuilder`
153    pub fn set_indices<I>(&mut self, indices: I) -> &mut Self
154    where
155        I: Into<Indices<'a>>,
156    {
157        self.indices = match indices.into() {
158            Indices::None => None,
159            Indices::U16(i) => Some(RawIndices {
160                indices: cast_cow(i),
161                index_type: rendy_core::hal::IndexType::U16,
162            }),
163            Indices::U32(i) => Some(RawIndices {
164                indices: cast_cow(i),
165                index_type: rendy_core::hal::IndexType::U32,
166            }),
167        };
168        self
169    }
170
171    /// Add another vertices to the `MeshBuilder`
172    pub fn with_vertices<V, D>(mut self, vertices: D) -> Self
173    where
174        V: AsVertex + 'a,
175        D: Into<Cow<'a, [V]>>,
176    {
177        self.add_vertices(vertices);
178        self
179    }
180
181    /// Add another vertices to the `MeshBuilder`
182    pub fn add_vertices<V, D>(&mut self, vertices: D) -> &mut Self
183    where
184        V: AsVertex + 'a,
185        D: Into<Cow<'a, [V]>>,
186    {
187        self.vertices.push(RawVertices {
188            vertices: cast_cow(vertices.into()),
189            format: V::vertex(),
190        });
191        self
192    }
193
194    /// Sets the primitive type of the mesh.
195    ///
196    /// By default, meshes are constructed as triangle lists.
197    pub fn with_prim_type(mut self, prim: rendy_core::hal::pso::Primitive) -> Self {
198        self.prim = prim;
199        self
200    }
201
202    /// Sets the primitive type of the mesh.
203    ///
204    /// By default, meshes are constructed as triangle lists.
205    pub fn set_prim_type(&mut self, prim: rendy_core::hal::pso::Primitive) -> &mut Self {
206        self.prim = prim;
207        self
208    }
209
210    /// Builds and returns the new mesh.
211    ///
212    /// A mesh expects all vertex buffers to have the same number of elements.
213    /// If those are not equal, the length of smallest vertex buffer is selected,
214    /// effectively discaring extra data from larger buffers.
215    ///
216    /// Note that contents of index buffer is not validated.
217    pub fn build<B>(&self, queue: QueueId, factory: &Factory<B>) -> Result<Mesh<B>, UploadError>
218    where
219        B: rendy_core::hal::Backend,
220    {
221        let align = factory.physical().limits().non_coherent_atom_size;
222        let mut len = self
223            .vertices
224            .iter()
225            .map(|v| v.vertices.len() as u32 / v.format.stride)
226            .min()
227            .unwrap_or(0);
228
229        let buffer_size = self
230            .vertices
231            .iter()
232            .map(|v| (v.format.stride * len) as usize)
233            .sum();
234
235        let aligned_size = align_by(align, buffer_size) as u64;
236
237        let mut staging = factory
238            .create_buffer(
239                BufferInfo {
240                    size: aligned_size,
241                    usage: rendy_core::hal::buffer::Usage::TRANSFER_SRC,
242                },
243                Upload,
244            )
245            .map_err(UploadError::Create)?;
246
247        let mut buffer = factory
248            .create_buffer(
249                BufferInfo {
250                    size: buffer_size as _,
251                    usage: rendy_core::hal::buffer::Usage::VERTEX
252                        | rendy_core::hal::buffer::Usage::TRANSFER_DST,
253                },
254                Data,
255            )
256            .map_err(UploadError::Create)?;
257
258        let mut mapped = staging
259            .map(factory, 0..aligned_size)
260            .map_err(UploadError::Map)?;
261        let mut writer =
262            unsafe { mapped.write(factory, 0..aligned_size) }.map_err(UploadError::Map)?;
263        let staging_slice = unsafe { writer.slice() };
264
265        let mut offset = 0usize;
266        let mut vertex_layouts: Vec<_> = self
267            .vertices
268            .iter()
269            .map(|RawVertices { vertices, format }| {
270                let size = (format.stride * len) as usize;
271                staging_slice[offset..offset + size].copy_from_slice(&vertices[0..size]);
272                let this_offset = offset as u64;
273                offset += size;
274                VertexBufferLayout {
275                    offset: this_offset,
276                    format: format.clone(),
277                }
278            })
279            .collect();
280
281        drop(staging_slice);
282        drop(writer);
283        drop(mapped);
284
285        vertex_layouts.sort_unstable_by(|a, b| a.format.cmp(&b.format));
286
287        let index_buffer = match self.indices {
288            None => None,
289            Some(RawIndices {
290                ref indices,
291                index_type,
292            }) => {
293                len = (indices.len() / index_stride(index_type)) as u32;
294                let mut buffer = factory
295                    .create_buffer(
296                        BufferInfo {
297                            size: indices.len() as _,
298                            usage: rendy_core::hal::buffer::Usage::INDEX
299                                | rendy_core::hal::buffer::Usage::TRANSFER_DST,
300                        },
301                        Data,
302                    )
303                    .map_err(UploadError::Create)?;
304                unsafe {
305                    // New buffer can't be touched by device yet.
306                    factory.upload_buffer(
307                        &mut buffer,
308                        0,
309                        &indices,
310                        None,
311                        BufferState::new(queue)
312                            .with_access(rendy_core::hal::buffer::Access::INDEX_BUFFER_READ)
313                            .with_stage(rendy_core::hal::pso::PipelineStage::VERTEX_INPUT),
314                    )?;
315                }
316
317                Some(IndexBuffer { buffer, index_type })
318            }
319        };
320
321        unsafe {
322            factory
323                .upload_from_staging_buffer(
324                    &mut buffer,
325                    0,
326                    staging,
327                    None,
328                    BufferState::new(queue)
329                        .with_access(rendy_core::hal::buffer::Access::VERTEX_BUFFER_READ)
330                        .with_stage(rendy_core::hal::pso::PipelineStage::VERTEX_INPUT),
331                )
332                .map_err(UploadError::Upload)?;
333        }
334
335        Ok(Mesh {
336            vertex_layouts,
337            index_buffer,
338            vertex_buffer: buffer,
339            prim: self.prim,
340            len,
341        })
342    }
343}
344
345fn align_by(align: usize, value: usize) -> usize {
346    ((value + align - 1) / align) * align
347}
348
349/// Single mesh is a collection of buffer ranges that provides available attributes.
350/// Usually exactly one mesh is used per draw call.
351#[derive(Debug)]
352pub struct Mesh<B: rendy_core::hal::Backend> {
353    vertex_buffer: Escape<Buffer<B>>,
354    vertex_layouts: Vec<VertexBufferLayout>,
355    index_buffer: Option<IndexBuffer<B>>,
356    prim: rendy_core::hal::pso::Primitive,
357    len: u32,
358}
359
360impl<B> Mesh<B>
361where
362    B: rendy_core::hal::Backend,
363{
364    /// Build new mesh with `MeshBuilder`
365    pub fn builder<'a>() -> MeshBuilder<'a> {
366        MeshBuilder::new()
367    }
368
369    /// rendy_core::hal::pso::Primitive type of the `Mesh`
370    pub fn primitive(&self) -> rendy_core::hal::pso::Primitive {
371        self.prim
372    }
373
374    /// Returns the number of vertices that will be drawn
375    /// in the mesh.  For a mesh with no index buffer,
376    /// this is the same as the number of vertices, or for
377    /// a mesh with indices, this is the same as the number
378    /// of indices.
379    pub fn len(&self) -> u32 {
380        self.len
381    }
382
383    fn get_vertex_iter<'a>(
384        &'a self,
385        formats: &[VertexFormat],
386    ) -> Result<impl IntoIterator<Item = (&'a B::Buffer, u64)>, Incompatible> {
387        debug_assert!(is_slice_sorted(formats), "Formats: {:#?}", formats);
388        debug_assert!(is_slice_sorted_by_key(&self.vertex_layouts, |l| &l.format));
389
390        let mut vertex = smallvec::SmallVec::<[_; 16]>::new();
391
392        let mut next = 0;
393        for format in formats {
394            if let Some(index) = find_compatible_buffer(&self.vertex_layouts[next..], format) {
395                next += index;
396                vertex.push(self.vertex_layouts[next].offset);
397            } else {
398                // Can't bind
399                return Err(Incompatible {
400                    not_found: format.clone(),
401                    in_formats: self
402                        .vertex_layouts
403                        .iter()
404                        .map(|l| l.format.clone())
405                        .collect(),
406                });
407            }
408        }
409
410        let buffer = self.vertex_buffer.raw();
411        Ok(vertex.into_iter().map(move |offset| (buffer, offset)))
412    }
413
414    /// Bind buffers to specified attribute locations.
415    pub fn bind<C>(
416        &self,
417        first_binding: u32,
418        formats: &[VertexFormat],
419        encoder: &mut EncoderCommon<'_, B, C>,
420    ) -> Result<u32, Incompatible>
421    where
422        C: Supports<Graphics>,
423    {
424        let vertex_iter = self.get_vertex_iter(formats)?;
425        match self.index_buffer.as_ref() {
426            Some(index_buffer) => unsafe {
427                encoder.bind_index_buffer(index_buffer.buffer.raw(), 0, index_buffer.index_type);
428                encoder.bind_vertex_buffers(first_binding, vertex_iter);
429            },
430            None => unsafe {
431                encoder.bind_vertex_buffers(first_binding, vertex_iter);
432            },
433        }
434
435        Ok(self.len)
436    }
437
438    /// Bind buffers to specified attribute locations and issue draw calls with given instance range.
439    pub fn bind_and_draw(
440        &self,
441        first_binding: u32,
442        formats: &[VertexFormat],
443        instance_range: std::ops::Range<u32>,
444        encoder: &mut RenderPassEncoder<'_, B>,
445    ) -> Result<u32, Incompatible> {
446        let vertex_iter = self.get_vertex_iter(formats)?;
447        unsafe {
448            match self.index_buffer.as_ref() {
449                Some(index_buffer) => {
450                    encoder.bind_index_buffer(
451                        index_buffer.buffer.raw(),
452                        0,
453                        index_buffer.index_type,
454                    );
455                    encoder.bind_vertex_buffers(first_binding, vertex_iter);
456                    encoder.draw_indexed(0..self.len, 0, instance_range);
457                }
458                None => {
459                    encoder.bind_vertex_buffers(first_binding, vertex_iter);
460                    encoder.draw(0..self.len, instance_range);
461                }
462            }
463        }
464
465        Ok(self.len)
466    }
467}
468
469/// Error type returned by `Mesh::bind` in case of mesh's vertex buffers are incompatible with requested vertex formats.
470#[derive(Clone, Debug, PartialEq, Eq)]
471pub struct Incompatible {
472    /// Format that was queried but was not found
473    pub not_found: VertexFormat,
474    /// List of formats that were available at query time
475    pub in_formats: Vec<VertexFormat>,
476}
477
478impl std::fmt::Display for Incompatible {
479    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
480        write!(
481            f,
482            "Vertex format {:?} is not compatible with any of {:?}.",
483            self.not_found, self.in_formats
484        )
485    }
486}
487impl std::error::Error for Incompatible {}
488
489/// Helper function to find buffer with compatible format.
490fn find_compatible_buffer(
491    vertex_layouts: &[VertexBufferLayout],
492    format: &VertexFormat,
493) -> Option<usize> {
494    debug_assert!(is_slice_sorted(&*format.attributes));
495    for (i, layout) in vertex_layouts.iter().enumerate() {
496        debug_assert!(is_slice_sorted(&*layout.format.attributes));
497        if is_compatible(&layout.format, format) {
498            return Some(i);
499        }
500    }
501    None
502}
503
504/// Check is vertex format `left` is compatible with `right`.
505/// `left` must have same `stride` and contain all attributes from `right`.
506fn is_compatible(left: &VertexFormat, right: &VertexFormat) -> bool {
507    if left.stride != right.stride {
508        return false;
509    }
510
511    // Don't start searching from index 0 because attributes are sorted
512    let mut skip = 0;
513    right.attributes.iter().all(|r| {
514        left.attributes[skip..]
515            .iter()
516            .position(|l| l == r)
517            .map_or(false, |p| {
518                skip += p;
519                true
520            })
521    })
522}
523
524/// Chech if slice o f ordered values is sorted.
525fn is_slice_sorted<T: Ord>(slice: &[T]) -> bool {
526    is_slice_sorted_by_key(slice, |i| i)
527}
528
529/// Check if slice is sorted using ordered key and key extractor
530fn is_slice_sorted_by_key<'a, T, K: Ord>(slice: &'a [T], f: impl Fn(&'a T) -> K) -> bool {
531    if let Some((first, slice)) = slice.split_first() {
532        let mut cmp = f(first);
533        for item in slice {
534            let item = f(item);
535            if cmp > item {
536                return false;
537            }
538            cmp = item;
539        }
540    }
541    true
542}
543
544impl<'a, A> From<Vec<A>> for MeshBuilder<'a>
545where
546    A: AsVertex + 'a,
547{
548    fn from(vertices: Vec<A>) -> Self {
549        MeshBuilder::new().with_vertices(vertices)
550    }
551}
552
553macro_rules! impl_builder_from_vec {
554    ($($from:ident),*) => {
555        impl<'a, $($from,)*> From<($(Vec<$from>,)*)> for MeshBuilder<'a>
556        where
557            $($from: AsVertex + 'a,)*
558        {
559            fn from(vertices: ($(Vec<$from>,)*)) -> Self {
560                #[allow(unused_mut)]
561                let mut builder = MeshBuilder::new();
562                #[allow(non_snake_case)]
563                let ($($from,)*) = vertices;
564                $(builder.add_vertices($from);)*
565                builder
566            }
567        }
568
569        impl_builder_from_vec!(@ $($from),*);
570    };
571    (@) => {};
572    (@ $head:ident $(,$tail:ident)*) => {
573        impl_builder_from_vec!($($tail),*);
574    };
575}
576
577impl_builder_from_vec!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);