Skip to main content

mew/
buffer.rs

1/// Define a storage buffer, with an optional internal type/struct to align its
2/// length with.
3///
4/// For example, if the buffer stores an array of `f32` matrices, you could set
5/// the internal type to `[f32; 16]`, and the buffer descriptor will initialize
6/// a multiple of the internal type's size. This doesn't validate the data
7/// written in any way.  
8/// If omitted, the internal type will default to `u8`, so you can initialize
9/// the buffer using a number of bytes manually.
10///
11/// Not all buffers need to be used in bind groups, for example vertex/index
12/// buffers. If you don't specify either `STORAGE` or `UNIFORM` as one of the
13/// [`wgpu::BufferUsages`](https://docs.rs/wgpu/latest/wgpu/struct.BufferUsages.html),
14/// you won't be able to put it in a bind group. Also note only one of those is
15/// allowed at a time, can't have a uniform that's also a storage.
16///
17/// ```
18/// buffer! { MatrixBuffer <SomeMatrixStructYouDefinedBefore> as VERTEX | COPY_DST }
19///
20/// let buffer: MatrixBuffer = render_context.new_buffer(16);
21///
22/// queue.write_buffer(&buffer, 0, &[1, 2, 3, ..]);
23/// ```
24#[macro_export]
25macro_rules! buffer {
26    { @searchbinding $struct:ident ; } => {};
27    { @searchbinding $struct:ident ; $first:ident $( $rest:ident )* } => {
28        $crate::buffer! { @trybinding $struct ; $first }
29        $crate::buffer! { @searchbinding $struct ; $( $rest )* }
30    };
31    { @trybinding $struct:ident ; STORAGE } => {
32        impl $crate::buffer::MewBufferBinding for $struct {
33            fn binding_type() -> $crate::wgpu::BindingType {
34                $crate::wgpu::BindingType::Buffer {
35                    ty: $crate::wgpu::BufferBindingType::Storage { read_only: true, },
36                    has_dynamic_offset: false,
37                    min_binding_size: None,
38                }
39            }
40
41            fn as_binding<'a>(&'a self) -> $crate::wgpu::BindingResource<'a> {
42                self.buffer.as_entire_binding()
43            }
44        }
45    };
46    { @trybinding $struct:ident ; UNIFORM } => {
47        impl $crate::buffer::MewBufferBinding for $struct {
48            fn binding_type() -> $crate::wgpu::BindingType {
49                $crate::wgpu::BindingType::Buffer {
50                    ty: $crate::wgpu::BufferBindingType::Uniform,
51                    has_dynamic_offset: false,
52                    min_binding_size: None,
53                }
54            }
55
56            fn as_binding<'a>(&'a self) -> $crate::wgpu::BindingResource<'a> {
57                self.buffer.as_entire_binding()
58            }
59        }
60    };
61    { @trybinding $struct:ident ; $other:ident } => {};
62
63    { $struct:ident as $( $usage:ident )|+ } => {
64        $crate::buffer! { $struct <u8> as $( $usage )|+ }
65    };
66    { $struct:ident < $inner:ty > as $( $usage:ident )|+ } => {
67        #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
68        pub struct $struct {
69            buffer: $crate::wgpu::Buffer,
70        }
71
72        impl ::std::ops::Deref for $struct {
73            type Target = $crate::wgpu::Buffer;
74            fn deref(&self) -> &Self::Target {
75                &self.buffer
76            }
77        }
78
79        impl $crate::buffer::MewBuffer for $struct {
80            type Inner = $inner;
81
82            fn new(buffer: $crate::wgpu::Buffer) -> Self {
83                Self {
84                    buffer,
85                }
86            }
87
88            fn buffer_desc(inner_size: u64) -> $crate::wgpu::BufferDescriptor<'static> {
89                $crate::wgpu::BufferDescriptor {
90                    label: Some(concat!(stringify!($struct), "<", stringify!($inner), "> Buffer")),
91                    size: inner_size * ::std::mem::size_of::<Self::Inner>() as u64,
92                    usage: $( $crate::wgpu::BufferUsages::$usage )|+,
93                    mapped_at_creation: false,
94                }
95            }
96        }
97
98        $crate::buffer! { @searchbinding $struct ; $( $usage )+ }
99    }
100}
101pub use buffer;
102
103
104/// Trait for internal use to work with buffers.
105pub trait MewBuffer {
106    /// The "inner" type - what the buffer is supposed to hold. When creating buffers
107    /// their capacity in bytes will be the input size times the size of this struct.
108    type Inner;
109    /// Build this buffer type from a
110    /// [`wgpu::Buffer`](https://docs.rs/wgpu/latest/wgpu/struct.Buffer.html).
111    fn new(buffer: wgpu::Buffer) -> Self;
112    /// Get a [`wgpu::BufferDescriptor`](https://docs.rs/wgpu/latest/wgpu/type.BufferDescriptor.html)
113    /// to build this type of buffer, with the capacity to fit some number of [`Self::Inner`]s.
114    fn buffer_desc(inner_size: u64) -> wgpu::BufferDescriptor<'static>;
115}
116
117/// Trait for internal use to work specifically with buffers that can be put in
118/// a bind group.
119pub trait MewBufferBinding: MewBuffer {
120    /// Get a [`wgpu::BindingType`](https://docs.rs/wgpu/latest/wgpu/enum.BindingType.html)
121    /// to use for this type of buffer.
122    fn binding_type() -> wgpu::BindingType;
123    /// Get this buffer's [`wgpu::BindingResource`](https://docs.rs/wgpu/latest/wgpu/enum.BindingResource.html)
124    /// to bind it in a bind group.
125    fn as_binding<'a>(&'a self) -> wgpu::BindingResource<'a>;
126}