rafx_framework/resources/
vertex_data.rs

1use fnv::FnvHashMap;
2use rafx_api::{RafxFormat, RafxPrimitiveTopology, RafxVertexAttributeRate};
3use std::collections::BTreeMap;
4use std::sync::Arc;
5
6// Hash of a GPU resource
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub struct VertexDataLayoutHash(u64);
9
10impl VertexDataLayoutHash {
11    fn new(
12        vertex_stride: usize,
13        members: &FnvHashMap<String, VertexDataMemberMeta>,
14    ) -> VertexDataLayoutHash {
15        // Put everything in the BTree so that we get a deterministic sort
16        let mut sorted = BTreeMap::<&String, &VertexDataMemberMeta>::default();
17        for (key, value) in members {
18            sorted.insert(key, value);
19        }
20
21        // Hash the vertex size/btree
22        use fnv::FnvHasher;
23        use std::hash::Hash;
24        use std::hash::Hasher;
25        let mut hasher = FnvHasher::default();
26        vertex_stride.hash(&mut hasher);
27        sorted.hash(&mut hasher);
28        VertexDataLayoutHash(hasher.finish())
29    }
30}
31
32// Hash of a GPU resource
33#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
34pub struct VertexDataSetLayoutHash(u64);
35
36impl VertexDataSetLayoutHash {
37    fn new(
38        layouts: &[VertexDataLayout],
39        primitive_topology: RafxPrimitiveTopology,
40    ) -> VertexDataSetLayoutHash {
41        // Hash the hashes
42        use fnv::FnvHasher;
43        use std::hash::Hash;
44        use std::hash::Hasher;
45        let mut hasher = FnvHasher::default();
46        for layout in layouts {
47            layout.hash().0.hash(&mut hasher);
48        }
49        primitive_topology.hash(&mut hasher);
50        VertexDataSetLayoutHash(hasher.finish())
51    }
52}
53
54#[derive(Debug, Copy, Clone, PartialEq)]
55pub enum VertexCopyError {
56    VertexCountDoesNotMatch,
57    MemberFormatDoesNotMatch,
58    SizeOfSliceTypeDoesNotMatchLayout,
59    CantReinitializeFrom,
60}
61
62#[derive(Debug, Clone, PartialEq)]
63pub struct VertexMember {
64    pub semantic: String,
65    pub format: RafxFormat,
66    pub byte_offset: usize,
67}
68
69// Copy/'static constraints ensure we only pass simple value types. Anything else is almost certainly a mistake
70impl VertexMember {
71    pub fn new<VertexT: Copy + 'static, MemberT: Copy + 'static>(
72        vertex: &VertexT,
73        member: &MemberT,
74        semantic: String,
75        format: RafxFormat,
76    ) -> VertexMember {
77        // Get ptrs as usize to do some math
78        let vertex_addr = vertex as *const _ as usize;
79        let member_addr = member as *const _ as usize;
80
81        // Verify that MemberT is actually a member of the vertex. Check that the member pointer
82        // is at or after the vertex pointer. Also check that the member pointer + member size is
83        // less than the vertex pointer + vertex size
84        let rust_member_size = std::mem::size_of::<MemberT>();
85        assert!(member_addr >= vertex_addr);
86        assert!((member_addr + rust_member_size) <= (vertex_addr + std::mem::size_of::<VertexT>()));
87
88        // Check that the provided format is size-compatible with the rust type
89        let format_size = format.block_or_pixel_size_in_bytes();
90        assert_eq!(
91            rust_member_size as u32,
92            format_size,
93            "The provided format {:?} is {} bytes but the rust type {} is {} bytes",
94            format,
95            format_size,
96            std::any::type_name::<MemberT>(),
97            rust_member_size
98        );
99
100        let offset = member_addr - vertex_addr;
101        VertexMember {
102            semantic,
103            format,
104            byte_offset: offset,
105        }
106    }
107}
108
109pub struct VertexMemberAccumulator<'a, VertexT> {
110    members: Vec<VertexMember>,
111    vertex: &'a VertexT,
112}
113
114// Copy/'static constraints ensure we only pass simple value types. Anything else is almost certainly a mistake
115impl<'a, VertexT: Copy + 'static> VertexMemberAccumulator<'a, VertexT> {
116    pub fn add_member<MemberT: Copy + 'static, StrT: Into<String>>(
117        &mut self,
118        member: &MemberT,
119        semantic: StrT,
120        format: RafxFormat,
121    ) {
122        self.members.push(VertexMember::new(
123            self.vertex,
124            member,
125            semantic.into(),
126            format,
127        ));
128    }
129}
130
131#[derive(Debug, Clone, PartialEq, Hash)]
132pub struct VertexDataMemberMeta {
133    pub format: RafxFormat,
134    pub byte_offset: usize,
135    pub size: usize,
136}
137
138#[derive(Debug, PartialEq)]
139pub struct VertexDataLayoutInner {
140    //TODO: Change strings to hashes
141    //TODO: Not clear if hashmap is better than linear or binary search on few elements
142    members: FnvHashMap<String, VertexDataMemberMeta>,
143    vertex_stride: usize,
144    vertex_rate: RafxVertexAttributeRate,
145    hash: VertexDataLayoutHash,
146}
147
148#[derive(Debug, PartialEq, Clone)]
149pub struct VertexDataLayout {
150    //TODO: Change strings to hashes
151    //TODO: Not clear if hashmap is better than linear or binary search on few elements
152    inner: Arc<VertexDataLayoutInner>,
153}
154
155impl VertexDataLayout {
156    pub fn new(
157        vertex_stride: usize,
158        vertex_rate: RafxVertexAttributeRate,
159        members: &[VertexMember],
160    ) -> Self {
161        let mut map = Default::default();
162        for member in members {
163            Self::add_member_to_map(vertex_stride, &mut map, member);
164        }
165
166        let hash = VertexDataLayoutHash::new(vertex_stride, &map);
167
168        let inner = VertexDataLayoutInner {
169            members: map,
170            vertex_stride,
171            vertex_rate,
172            hash,
173        };
174
175        VertexDataLayout {
176            inner: Arc::new(inner),
177        }
178    }
179
180    /// Example usage to define a vertex data layout and convert it into a VertexDataSetLayout
181    /// (`VertexDataLayout::build_vertex_layout` creates a VertexDataLayout and the `.into_set()`
182    /// call makes it a single-buffer set
183    ///
184    /// ```
185    /// use rafx_framework::VertexDataLayout;
186    /// use rafx_api::{RafxFormat, RafxPrimitiveTopology, RafxVertexAttributeRate};
187    ///
188    /// #[derive(Default, Copy, Clone)]
189    /// #[repr(C)]
190    /// pub struct ExampleVertex {
191    ///     pub position: [f32; 3],
192    ///     pub normal: [f32; 3],
193    ///     pub tex_coord: [f32; 2],
194    /// }
195    ///
196    /// VertexDataLayout::build_vertex_layout(&ExampleVertex::default(), RafxVertexAttributeRate::Vertex, |builder, vertex| {
197    ///     builder.add_member(&vertex.position, "POSITION", RafxFormat::R32G32B32_SFLOAT);
198    ///     builder.add_member(&vertex.normal, "NORMAL", RafxFormat::R32G32B32_SFLOAT);
199    ///     builder.add_member(&vertex.tex_coord, "TEXCOORD", RafxFormat::R32G32_SFLOAT);
200    /// }).into_set(RafxPrimitiveTopology::TriangleList);
201    /// ```
202    pub fn build_vertex_layout<
203        VertexT,
204        F: FnOnce(&mut VertexMemberAccumulator<VertexT>, &VertexT),
205    >(
206        vertex: &VertexT,
207        vertex_rate: RafxVertexAttributeRate,
208        f: F,
209    ) -> VertexDataLayout {
210        let mut accumulator = VertexMemberAccumulator {
211            members: Default::default(),
212            vertex,
213        };
214
215        (f)(&mut accumulator, vertex);
216        VertexDataLayout::new(
217            std::mem::size_of::<VertexT>(),
218            vertex_rate,
219            &accumulator.members,
220        )
221    }
222
223    fn add_member_to_map(
224        vertex_stride: usize,
225        map: &mut FnvHashMap<String, VertexDataMemberMeta>,
226        member: &VertexMember,
227    ) {
228        let size = member.format.block_or_pixel_size_in_bytes() as usize;
229        assert!(member.byte_offset + size <= vertex_stride);
230        let old = map.insert(
231            member.semantic.clone(),
232            VertexDataMemberMeta {
233                format: member.format,
234                byte_offset: member.byte_offset,
235                size,
236            },
237        );
238        assert!(old.is_none());
239    }
240
241    pub fn member(
242        &self,
243        name: &str,
244    ) -> Option<&VertexDataMemberMeta> {
245        self.inner.members.get(name)
246    }
247
248    pub fn members(&self) -> &FnvHashMap<String, VertexDataMemberMeta> {
249        &self.inner.members
250    }
251
252    pub fn hash(&self) -> VertexDataLayoutHash {
253        self.inner.hash
254    }
255
256    pub fn vertex_rate(&self) -> RafxVertexAttributeRate {
257        self.inner.vertex_rate
258    }
259
260    pub fn vertex_stride(&self) -> usize {
261        self.inner.vertex_stride
262    }
263
264    pub fn into_set(
265        self,
266        primitive_topology: RafxPrimitiveTopology,
267    ) -> VertexDataSetLayout {
268        VertexDataSetLayout::new(vec![self], primitive_topology)
269    }
270
271    pub fn intersects_with(
272        &self,
273        other: &Self,
274    ) -> bool {
275        for member_name in self.inner.members.keys() {
276            if other.inner.members.contains_key(member_name) {
277                return true;
278            }
279        }
280
281        false
282    }
283
284    pub fn is_subset_of(
285        &self,
286        other: &Self,
287    ) -> bool {
288        for member_name in self.inner.members.keys() {
289            if !other.inner.members.contains_key(member_name) {
290                return false;
291            }
292        }
293
294        true
295    }
296
297    pub fn is_subset_of_multi(
298        subsets: &[Self],
299        others: &[Self],
300    ) -> bool {
301        for subset in subsets {
302            for member_name in subset.inner.members.keys() {
303                let mut found_in_other = false;
304                for other in others {
305                    if other.inner.members.contains_key(member_name) {
306                        found_in_other = true;
307                        break;
308                    }
309                }
310
311                if !found_in_other {
312                    return false;
313                }
314            }
315        }
316
317        true
318    }
319}
320
321#[derive(Debug, Clone, PartialEq)]
322pub struct VertexDataSetMemberMeta {
323    pub format: RafxFormat,
324    pub byte_offset: usize,
325    pub size: usize,
326    pub binding: usize,
327}
328
329#[derive(Debug, PartialEq)]
330pub struct VertexDataSetLayoutInner {
331    //TODO: Change strings to hashes
332    //TODO: Not clear if hashmap is better than linear or binary search on few elements
333    members: Arc<FnvHashMap<String, VertexDataSetMemberMeta>>,
334    layouts: Vec<VertexDataLayout>,
335    hash: VertexDataSetLayoutHash,
336    primitive_topology: RafxPrimitiveTopology,
337}
338
339#[derive(Debug, PartialEq, Clone)]
340pub struct VertexDataSetLayout {
341    inner: Arc<VertexDataSetLayoutInner>,
342}
343
344impl VertexDataSetLayout {
345    pub fn new(
346        layouts: Vec<VertexDataLayout>,
347        primitive_topology: RafxPrimitiveTopology,
348    ) -> Self {
349        let mut members = FnvHashMap::default();
350        for (binding, layout) in layouts.iter().enumerate() {
351            for (member_name, meta) in &layout.inner.members {
352                let old = members.insert(
353                    member_name.clone(),
354                    VertexDataSetMemberMeta {
355                        format: meta.format,
356                        size: meta.size,
357                        byte_offset: meta.byte_offset,
358                        binding,
359                    },
360                );
361                assert!(old.is_none());
362            }
363        }
364
365        let hash = VertexDataSetLayoutHash::new(&layouts, primitive_topology);
366
367        let inner = VertexDataSetLayoutInner {
368            members: Arc::new(members),
369            layouts,
370            hash,
371            primitive_topology,
372        };
373
374        VertexDataSetLayout {
375            inner: Arc::new(inner),
376        }
377    }
378
379    pub fn binding(
380        &self,
381        binding: usize,
382    ) -> Option<&VertexDataLayout> {
383        self.inner.layouts.get(binding)
384    }
385
386    pub fn bindings(&self) -> &Vec<VertexDataLayout> {
387        &self.inner.layouts
388    }
389
390    pub fn member(
391        &self,
392        name: &str,
393    ) -> Option<&VertexDataSetMemberMeta> {
394        self.inner.members.get(name)
395    }
396
397    pub fn members(&self) -> &FnvHashMap<String, VertexDataSetMemberMeta> {
398        &self.inner.members
399    }
400
401    pub fn hash(&self) -> VertexDataSetLayoutHash {
402        self.inner.hash
403    }
404
405    pub fn primitive_topology(&self) -> RafxPrimitiveTopology {
406        self.inner.primitive_topology
407    }
408}
409
410#[derive(Clone)]
411pub struct VertexData {
412    layout: VertexDataLayout,
413    // Align to 16 bytes to try to stay clear of alignment issues
414    data: Vec<u128>,
415    vertex_count: usize,
416}
417
418impl VertexData {
419    pub fn new_memzero(
420        layout: VertexDataLayout,
421        vertex_count: usize,
422    ) -> Self {
423        let total_size = layout.vertex_stride() * vertex_count;
424
425        // Allocate 16-byte aligned blob of memory that is large enough to contain the data
426        let data = vec![0_u128; (total_size + 15) / 16];
427
428        VertexData {
429            layout,
430            data,
431            vertex_count,
432        }
433    }
434
435    pub fn new_from_slice<T: Copy>(
436        src_layout: &VertexDataLayout,
437        src_data: &[T],
438    ) -> Self {
439        let mut data = Self::new_memzero(src_layout.clone(), src_data.len());
440        data.copy_from_slice(src_layout, src_data).unwrap();
441        data
442    }
443
444    pub fn reinitialize_from(
445        &mut self,
446        other: &Self,
447    ) -> Result<(), VertexCopyError> {
448        if !self.layout.is_subset_of(&other.layout) {
449            return Err(VertexCopyError::CantReinitializeFrom);
450        }
451
452        self.copy_from(other)
453    }
454
455    pub fn reinitialize_from_slice<T: Copy>(
456        &mut self,
457        src_layout: &VertexDataLayout,
458        src_data: &[T],
459    ) -> Result<(), VertexCopyError> {
460        if !self.layout.is_subset_of(&src_layout) {
461            return Err(VertexCopyError::CantReinitializeFrom);
462        }
463
464        self.copy_from_slice(src_layout, src_data)
465    }
466
467    pub fn copy_from(
468        &mut self,
469        other: &Self,
470    ) -> Result<(), VertexCopyError> {
471        Self::copy_between_vertex_data(other, self)
472    }
473
474    pub fn copy_to(
475        &self,
476        other: &mut Self,
477    ) -> Result<(), VertexCopyError> {
478        Self::copy_between_vertex_data(self, other)
479    }
480
481    pub fn copy_between_vertex_data(
482        src: &VertexData,
483        dst: &mut VertexData,
484    ) -> Result<(), VertexCopyError> {
485        if src.vertex_count != dst.vertex_count {
486            return Err(VertexCopyError::VertexCountDoesNotMatch);
487        }
488
489        unsafe {
490            let src_ptr = src.ptr();
491            let dst_ptr = dst.ptr_mut();
492            Self::copy_between_layouts(&src.layout, src_ptr, &dst.layout, dst_ptr, dst.vertex_count)
493        }
494    }
495
496    pub fn copy_from_slice<T: Copy>(
497        &mut self,
498        src_layout: &VertexDataLayout,
499        src_data: &[T],
500    ) -> Result<(), VertexCopyError> {
501        if src_data.len() != self.vertex_count {
502            return Err(VertexCopyError::VertexCountDoesNotMatch);
503        }
504
505        if std::mem::size_of::<T>() != src_layout.vertex_stride() {
506            return Err(VertexCopyError::SizeOfSliceTypeDoesNotMatchLayout);
507        }
508
509        unsafe {
510            let dst_data = self.ptr_mut();
511            Self::copy_between_layouts(
512                src_layout,
513                src_data.as_ptr() as *const u8,
514                &self.layout,
515                dst_data,
516                src_data.len(),
517            )
518        }
519    }
520
521    pub fn copy_to_slice<T: Copy>(
522        &self,
523        dst_layout: &VertexDataLayout,
524        dst_data: &mut [T],
525    ) -> Result<(), VertexCopyError> {
526        if dst_data.len() != self.vertex_count {
527            return Err(VertexCopyError::VertexCountDoesNotMatch);
528        }
529
530        if std::mem::size_of::<T>() != dst_layout.vertex_stride() {
531            return Err(VertexCopyError::SizeOfSliceTypeDoesNotMatchLayout);
532        }
533
534        unsafe {
535            let src_data = self.ptr();
536            Self::copy_between_layouts(
537                &self.layout,
538                src_data,
539                dst_layout,
540                dst_data.as_mut_ptr() as *mut u8,
541                dst_data.len(),
542            )
543        }
544    }
545
546    pub fn copy_between_slices<T: Copy, U: Copy>(
547        src_layout: &VertexDataLayout,
548        src_data: &[T],
549        dst_layout: &VertexDataLayout,
550        dst_data: &mut [U],
551    ) -> Result<(), VertexCopyError> {
552        if src_data.len() != dst_data.len() {
553            return Err(VertexCopyError::VertexCountDoesNotMatch);
554        }
555
556        if std::mem::size_of::<T>() != src_layout.vertex_stride() {
557            return Err(VertexCopyError::SizeOfSliceTypeDoesNotMatchLayout);
558        }
559
560        if std::mem::size_of::<U>() != dst_layout.vertex_stride() {
561            return Err(VertexCopyError::SizeOfSliceTypeDoesNotMatchLayout);
562        }
563
564        unsafe {
565            Self::copy_between_layouts(
566                src_layout,
567                src_data.as_ptr() as *const u8,
568                dst_layout,
569                dst_data.as_mut_ptr() as *mut u8,
570                dst_data.len(),
571            )
572        }
573    }
574
575    pub fn can_copy_between_layouts(
576        src_layout: &VertexDataLayout,
577        dst_layout: &VertexDataLayout,
578    ) -> Result<(), VertexCopyError> {
579        // Verify the copies will succeed before starting
580        for (member_name, src_member) in src_layout.members() {
581            if let Some(dst_member) = dst_layout.members().get(member_name) {
582                if src_member.format != dst_member.format {
583                    return Err(VertexCopyError::MemberFormatDoesNotMatch);
584                }
585
586                // Should always pass because we check that the formats are identical
587                assert_eq!(src_member.size, dst_member.size);
588            }
589        }
590
591        Ok(())
592    }
593
594    pub unsafe fn copy_between_layouts(
595        src_layout: &VertexDataLayout,
596        src_data: *const u8,
597        dst_layout: &VertexDataLayout,
598        dst_data: *mut u8,
599        vertex_count: usize,
600    ) -> Result<(), VertexCopyError> {
601        if src_layout == dst_layout {
602            std::ptr::copy_nonoverlapping(
603                src_data,
604                dst_data,
605                vertex_count * src_layout.vertex_stride(),
606            );
607            return Ok(());
608        }
609
610        if !src_layout.intersects_with(dst_layout) {
611            return Ok(());
612        }
613
614        // Verify the copies will succeed before starting
615        Self::can_copy_between_layouts(src_layout, dst_layout)?;
616
617        //TODO: Would it be faster to do per-vertex instead of per-member?
618        for (member_name, src_member) in src_layout.members() {
619            if let Some(dst_member) = dst_layout.members().get(member_name) {
620                for i in 0..vertex_count {
621                    let src_ptr =
622                        src_data.add((src_layout.vertex_stride() * i) + src_member.byte_offset);
623                    let dst_ptr =
624                        dst_data.add((dst_layout.vertex_stride() * i) + dst_member.byte_offset);
625
626                    std::ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_member.size);
627                }
628            }
629        }
630
631        Ok(())
632    }
633
634    pub unsafe fn ptr(&self) -> *const u8 {
635        self.data.as_ptr() as *const u8
636    }
637
638    pub unsafe fn ptr_mut(&mut self) -> *mut u8 {
639        self.data.as_mut_ptr() as *mut u8
640    }
641}
642
643pub struct VertexDataSet {
644    layouts: Vec<VertexDataLayout>,
645    data: Vec<VertexData>,
646    vertex_count: usize,
647}
648
649impl VertexDataSet {
650    pub fn new(data: Vec<VertexData>) -> Result<Self, &'static str> {
651        if data.is_empty() {
652            Ok(VertexDataSet {
653                data: Default::default(),
654                vertex_count: 0,
655                layouts: Default::default(),
656            })
657        } else {
658            let vertex_count = data[0].vertex_count;
659            for d in &data {
660                if vertex_count != d.vertex_count {
661                    return Err("vertex data does not have same number of vertices");
662                }
663            }
664
665            let layouts = data.iter().map(|x| x.layout.clone()).collect();
666
667            Ok(VertexDataSet {
668                data,
669                vertex_count,
670                layouts,
671            })
672        }
673    }
674
675    pub fn new_memzero(
676        layouts: &[VertexDataLayout],
677        vertex_count: usize,
678    ) -> Self {
679        let data = layouts
680            .iter()
681            .map(|layout| VertexData::new_memzero(layout.clone(), vertex_count))
682            .collect();
683
684        VertexDataSet {
685            data,
686            vertex_count,
687            layouts: layouts.to_vec(),
688        }
689    }
690
691    pub fn new_from_slice<T: Copy>(
692        src_layout: &VertexDataLayout,
693        src_data: &[T],
694    ) -> Self {
695        let mut data = vec![VertexData::new_memzero(src_layout.clone(), src_data.len())];
696        data[0].copy_from_slice(src_layout, src_data).unwrap();
697
698        VertexDataSet {
699            data,
700            vertex_count: src_data.len(),
701            layouts: vec![src_layout.clone()],
702        }
703    }
704
705    pub fn reinitialize_from(
706        &mut self,
707        other: &Self,
708    ) -> Result<(), VertexCopyError> {
709        if !VertexDataLayout::is_subset_of_multi(&self.layouts, &other.layouts) {
710            return Err(VertexCopyError::CantReinitializeFrom);
711        }
712
713        self.copy_from(other)
714    }
715
716    pub fn reinitialize_from_slice<T: Copy>(
717        &mut self,
718        src_layout: &VertexDataLayout,
719        src_data: &[T],
720    ) -> Result<(), VertexCopyError> {
721        for layout in &self.layouts {
722            if !layout.is_subset_of(src_layout) {
723                return Err(VertexCopyError::CantReinitializeFrom);
724            }
725        }
726
727        self.copy_from_slice(src_layout, src_data)
728    }
729
730    pub fn copy_from(
731        &mut self,
732        other: &Self,
733    ) -> Result<(), VertexCopyError> {
734        Self::copy_between_vertex_data(
735            other.vertex_count,
736            &other.data,
737            self.vertex_count,
738            &mut self.data,
739        )
740    }
741
742    pub fn copy_to(
743        &self,
744        other: &mut Self,
745    ) -> Result<(), VertexCopyError> {
746        Self::copy_between_vertex_data(
747            self.vertex_count,
748            &self.data,
749            other.vertex_count,
750            &mut other.data,
751        )
752    }
753
754    pub fn copy_from_single(
755        &mut self,
756        other: &VertexData,
757    ) -> Result<(), VertexCopyError> {
758        Self::copy_between_vertex_data(
759            other.vertex_count,
760            std::slice::from_ref(other),
761            self.vertex_count,
762            &mut self.data,
763        )
764    }
765
766    pub fn copy_to_single(
767        &self,
768        other: &mut VertexData,
769    ) -> Result<(), VertexCopyError> {
770        Self::copy_between_vertex_data(
771            self.vertex_count,
772            &self.data,
773            other.vertex_count,
774            std::slice::from_mut(other),
775        )
776    }
777
778    pub fn copy_between_vertex_data(
779        src_vertex_count: usize,
780        src_data: &[VertexData],
781        dst_vertex_count: usize,
782        dst_data: &mut [VertexData],
783    ) -> Result<(), VertexCopyError> {
784        if src_vertex_count != dst_vertex_count {
785            return Err(VertexCopyError::VertexCountDoesNotMatch);
786        }
787
788        for src in src_data {
789            for dst in &mut *dst_data {
790                VertexData::can_copy_between_layouts(&src.layout, &dst.layout)?;
791            }
792        }
793
794        for src in src_data {
795            for dst in &mut *dst_data {
796                dst.copy_from(src)?;
797            }
798        }
799
800        Ok(())
801    }
802
803    pub fn copy_from_slice<T: Copy>(
804        &mut self,
805        src_layout: &VertexDataLayout,
806        src_data: &[T],
807    ) -> Result<(), VertexCopyError> {
808        if src_data.len() != self.vertex_count {
809            return Err(VertexCopyError::VertexCountDoesNotMatch);
810        }
811
812        if std::mem::size_of::<T>() != src_layout.vertex_stride() {
813            return Err(VertexCopyError::SizeOfSliceTypeDoesNotMatchLayout);
814        }
815
816        for layout in &self.layouts {
817            VertexData::can_copy_between_layouts(src_layout, layout)?;
818        }
819
820        for data in &mut self.data {
821            data.copy_from_slice(src_layout, src_data)?;
822        }
823
824        Ok(())
825    }
826
827    pub fn copy_to_slice<T: Copy>(
828        &self,
829        dst_layout: &VertexDataLayout,
830        dst_data: &mut [T],
831    ) -> Result<(), VertexCopyError> {
832        if dst_data.len() != self.vertex_count {
833            return Err(VertexCopyError::VertexCountDoesNotMatch);
834        }
835
836        if std::mem::size_of::<T>() != dst_layout.vertex_stride() {
837            return Err(VertexCopyError::SizeOfSliceTypeDoesNotMatchLayout);
838        }
839
840        for layout in &self.layouts {
841            VertexData::can_copy_between_layouts(layout, dst_layout)?;
842        }
843
844        for data in &self.data {
845            data.copy_to_slice(dst_layout, dst_data)?;
846        }
847
848        Ok(())
849    }
850
851    pub unsafe fn data(&self) -> &[VertexData] {
852        &self.data
853    }
854
855    pub unsafe fn data_mut(&mut self) -> &mut [VertexData] {
856        &mut self.data
857    }
858}
859
860#[cfg(test)]
861mod test {
862    use super::*;
863    use rafx_api::RafxFormat;
864
865    #[derive(Default, Clone, Copy, Debug)]
866    #[repr(C)]
867    pub struct MediumVertex {
868        pub position: [f32; 3],
869        pub normal: [f32; 3],
870        pub color: [f32; 4],
871        pub tangent: [f32; 3],
872        pub tex_coord: [f32; 2],
873    }
874
875    impl MediumVertex {
876        fn get_layout() -> VertexDataLayout {
877            VertexDataLayout::build_vertex_layout(
878                &Self::default(),
879                RafxVertexAttributeRate::Vertex,
880                |builder, vertex| {
881                    builder.add_member(&vertex.position, "POSITION", RafxFormat::R32G32B32_SFLOAT);
882                    builder.add_member(&vertex.normal, "NORMAL", RafxFormat::R32G32B32_SFLOAT);
883                    builder.add_member(&vertex.color, "COLOR", RafxFormat::R32G32B32A32_SFLOAT);
884                    builder.add_member(&vertex.tangent, "TANGENT", RafxFormat::R32G32B32_SFLOAT);
885                    builder.add_member(&vertex.tex_coord, "TEXCOORD", RafxFormat::R32G32_SFLOAT);
886                },
887            )
888        }
889
890        fn create_empty_data() -> Vec<MediumVertex> {
891            (0..100).map(|_| MediumVertex::default()).collect()
892        }
893
894        fn create_test_data() -> Vec<MediumVertex> {
895            (0..100)
896                .map(|x| {
897                    let x = x as f32;
898                    MediumVertex {
899                        position: [1.0, x, x],
900                        normal: [2.0, x, x],
901                        color: [3.0, x, x, x],
902                        tangent: [4.0, x, x],
903                        tex_coord: [5.0, x],
904                    }
905                })
906                .collect()
907        }
908    }
909
910    #[derive(Default, Clone, Copy, Debug)]
911    #[repr(C)]
912    pub struct SmallVertex {
913        pub normal: [f32; 3],
914        pub position: [f32; 3],
915    }
916
917    impl SmallVertex {
918        fn get_layout() -> VertexDataLayout {
919            VertexDataLayout::build_vertex_layout(
920                &Self::default(),
921                RafxVertexAttributeRate::Vertex,
922                |builder, vertex| {
923                    builder.add_member(&vertex.position, "POSITION", RafxFormat::R32G32B32_SFLOAT);
924                    builder.add_member(&vertex.normal, "NORMAL", RafxFormat::R32G32B32_SFLOAT);
925                },
926            )
927        }
928
929        fn create_empty_data() -> Vec<SmallVertex> {
930            (0..100).map(|_| SmallVertex::default()).collect()
931        }
932
933        fn create_test_data() -> Vec<SmallVertex> {
934            (0..100)
935                .map(|x| {
936                    let x = x as f32;
937                    SmallVertex {
938                        position: [1.0, x, x],
939                        normal: [2.0, x, x],
940                    }
941                })
942                .collect()
943        }
944    }
945
946    #[derive(Default, Clone, Copy, Debug)]
947    #[repr(C)]
948    pub struct TinyVertex {
949        pub color: [f32; 4],
950    }
951
952    impl TinyVertex {
953        fn get_layout() -> VertexDataLayout {
954            VertexDataLayout::build_vertex_layout(
955                &Self::default(),
956                RafxVertexAttributeRate::Vertex,
957                |builder, vertex| {
958                    builder.add_member(&vertex.color, "COLOR", RafxFormat::R32G32B32A32_SFLOAT);
959                },
960            )
961        }
962    }
963
964    #[test]
965    fn test_to_smaller() {
966        let from_layout = MediumVertex::get_layout();
967        let from_data = MediumVertex::create_test_data();
968
969        let to_layout = SmallVertex::get_layout();
970        let mut to_data = SmallVertex::create_empty_data();
971
972        let data = VertexData::new_from_slice(&from_layout, &from_data);
973        data.copy_to_slice(&to_layout, &mut to_data).unwrap();
974
975        assert!((from_data[4].position[1] - 4.0).abs() < 0.1);
976        assert!((to_data[4].position[1] - 4.0).abs() < 0.1);
977
978        assert!((from_data[4].position[0] - 1.0).abs() < 0.1);
979        assert!((to_data[4].position[0] - 1.0).abs() < 0.1);
980
981        assert!((from_data[4].normal[0] - 2.0).abs() < 0.1);
982        assert!((to_data[4].normal[0] - 2.0).abs() < 0.1);
983    }
984
985    #[test]
986    fn test_to_larger() {
987        let from_layout = SmallVertex::get_layout();
988        let from_data = SmallVertex::create_test_data();
989
990        let to_layout = MediumVertex::get_layout();
991        let mut to_data = MediumVertex::create_empty_data();
992
993        let data = VertexData::new_from_slice(&from_layout, &from_data);
994        data.copy_to_slice(&to_layout, &mut to_data).unwrap();
995
996        assert!((from_data[4].position[1] - 4.0).abs() < 0.1);
997        assert!((to_data[4].position[1] - 4.0).abs() < 0.1);
998
999        assert!((from_data[4].position[0] - 1.0).abs() < 0.1);
1000        assert!((to_data[4].position[0] - 1.0).abs() < 0.1);
1001
1002        assert!((from_data[4].normal[0] - 2.0).abs() < 0.1);
1003        assert!((to_data[4].normal[0] - 2.0).abs() < 0.1);
1004    }
1005
1006    #[test]
1007    fn test_copy_from() {
1008        let from_layout = MediumVertex::get_layout();
1009        let from_data = MediumVertex::create_test_data();
1010        let from = VertexData::new_from_slice(&from_layout, &from_data);
1011
1012        let to_layout = SmallVertex::get_layout();
1013        let to_data = SmallVertex::create_empty_data();
1014        let mut to = VertexData::new_from_slice(&to_layout, &to_data);
1015
1016        to.copy_from(&from).unwrap();
1017
1018        let mut to_data = SmallVertex::create_empty_data();
1019        to.copy_to_slice(&to_layout, &mut to_data).unwrap();
1020
1021        assert!((from_data[4].position[1] - 4.0).abs() < 0.1);
1022        assert!((to_data[4].position[1] - 4.0).abs() < 0.1);
1023
1024        assert!((from_data[4].position[0] - 1.0).abs() < 0.1);
1025        assert!((to_data[4].position[0] - 1.0).abs() < 0.1);
1026
1027        assert!((from_data[4].normal[0] - 2.0).abs() < 0.1);
1028        assert!((to_data[4].normal[0] - 2.0).abs() < 0.1);
1029    }
1030
1031    #[test]
1032    fn test_into_data_set() {
1033        let from_layout = MediumVertex::get_layout();
1034        let from_data = MediumVertex::create_test_data();
1035        let from = VertexData::new_from_slice(&from_layout, &from_data);
1036
1037        let mut data_set = VertexDataSet::new(vec![
1038            VertexData::new_memzero(SmallVertex::get_layout(), 100),
1039            VertexData::new_memzero(TinyVertex::get_layout(), 100),
1040        ])
1041        .unwrap();
1042
1043        data_set.copy_from_single(&from).unwrap();
1044
1045        let mut to_data = SmallVertex::create_empty_data();
1046        data_set
1047            .copy_to_slice(&SmallVertex::get_layout(), &mut to_data)
1048            .unwrap();
1049
1050        assert!((from_data[4].position[1] - 4.0).abs() < 0.1);
1051        assert!((to_data[4].position[1] - 4.0).abs() < 0.1);
1052
1053        assert!((from_data[4].position[0] - 1.0).abs() < 0.1);
1054        assert!((to_data[4].position[0] - 1.0).abs() < 0.1);
1055
1056        assert!((from_data[4].normal[0] - 2.0).abs() < 0.1);
1057        assert!((to_data[4].normal[0] - 2.0).abs() < 0.1);
1058    }
1059}