ewgpu/
uniform.rs

1use super::binding::BindGroup;
2use super::binding::CreateBindGroupLayout;
3use super::buffer::*;
4use super::binding;
5use std::ops::{Deref, DerefMut};
6
7///
8/// A struct mutably referencing a Uniform to edit its content and update it when UniformRef is
9/// droped.
10///
11pub struct UniformRef<'ur, C: bytemuck::Pod>{
12    queue: &'ur wgpu::Queue,
13    uniform: &'ur mut Uniform<C>,
14}
15
16
17impl<C: bytemuck::Pod> Deref for UniformRef<'_, C>{
18    type Target = C;
19
20    fn deref(&self) -> &Self::Target {
21        &self.uniform.uniform_vec.content[0]
22    }
23}
24
25impl<C: bytemuck::Pod> DerefMut for UniformRef<'_, C>{
26    fn deref_mut(&mut self) -> &mut Self::Target {
27        &mut self.uniform.uniform_vec.content[0]
28    }
29}
30
31impl<C: bytemuck::Pod> Drop for UniformRef<'_, C>{
32    fn drop(&mut self) {
33        self.uniform.uniform_vec.update_int(self.queue);
34    }
35}
36
37///
38/// A struct mutably referencing a UniformVec to edit its content and update it when UniformVecRef is
39/// droped.
40///
41pub struct UniformVecRef<'ur, C: bytemuck::Pod>{
42    queue: &'ur mut wgpu::Queue,
43    uniform_vec: &'ur mut UniformVec<C>,
44}
45
46impl<C: bytemuck::Pod> Deref for UniformVecRef<'_, C>{
47    type Target = [C];
48
49    fn deref(&self) -> &Self::Target{
50        &self.uniform_vec.content
51    }
52}
53
54impl<C: bytemuck::Pod> DerefMut for UniformVecRef<'_, C>{
55    fn deref_mut(&mut self) -> &mut Self::Target {
56        &mut self.uniform_vec.content
57    }
58}
59
60impl<C: bytemuck::Pod> Drop for UniformVecRef<'_, C>{
61    fn drop(&mut self){
62        self.uniform_vec.update_int(self.queue);
63    }
64}
65
66///
67/// A Buffer with a vector that can be used as a Unform directly.
68/// It keeps a copy of the content in memory for easier updates.
69/// TODO: Remove content.
70///
71pub struct UniformVec<C: bytemuck::Pod>{
72    buffer: Buffer<C>,
73
74    content: Vec<C>,
75}
76
77impl<C: bytemuck::Pod> UniformVec<C>{
78    fn name() -> &'static str{
79        let type_name = std::any::type_name::<C>();
80        let pos = type_name.rfind(':').unwrap_or_else(||{0});
81        &type_name[(pos + 1)..]
82    }
83
84    pub fn new(src: &[C], device: &wgpu::Device) -> Self{
85        let buffer = Buffer::new_dst_uniform(
86            device, 
87            Some(&format!("UniformBuffer: {}", Self::name())),
88            src,
89        );
90        /* content would be copied twice
91         *
92        let buffer = BufferBuilder::new()
93            .uniform().copy_dst()
94            .set_label(Some(&format!("UniformBuffer: {}", Self::name())))
95            .append_slice(src)
96            .build(device);
97        */
98
99        Self{
100            buffer,
101            content: Vec::from(src),
102        }
103    }
104
105    pub fn update_int(&mut self, queue: &wgpu::Queue){
106        queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&self.content));
107    }
108
109    pub fn borrow_ref<'ur>(&'ur mut self, queue: &'ur mut wgpu::Queue) -> UniformVecRef<'ur, C>{
110        UniformVecRef{
111            queue,
112            uniform_vec: self,
113        }
114    }
115}
116
117impl<C: bytemuck::Pod> binding::BindGroupContent for UniformVec<C>{
118    fn entries(visibility: wgpu::ShaderStages) -> Vec<binding::BindGroupLayoutEntry>{
119        vec!{
120            binding::BindGroupLayoutEntry::new(visibility, binding::wgsl::uniform()),
121        }
122    }
123
124    fn resources<'br>(&'br self) -> Vec<wgpu::BindingResource<'br>> {
125        vec!{
126            self.buffer.as_entire_binding(),
127        }
128    }
129}
130
131///
132/// A UniformVec with a single element usefull for cameras etc.
133///
134pub struct Uniform<C: bytemuck::Pod>{
135    uniform_vec: UniformVec<C>,
136}
137
138impl<C: bytemuck::Pod> Uniform<C>{
139    pub fn new(src: C, device: &wgpu::Device) -> Self{
140        Self{
141            uniform_vec: UniformVec::new(&[src], device)
142        }
143    }
144
145    pub fn borrow_ref<'ur>(&'ur mut self, queue: &'ur wgpu::Queue) -> UniformRef<'ur, C>{
146        UniformRef{
147            queue,
148            uniform: self,
149        }
150    }
151}
152
153impl<C: bytemuck::Pod> binding::BindGroupContent for Uniform<C>{
154    fn entries(visibility: wgpu::ShaderStages) -> Vec<binding::BindGroupLayoutEntry>{
155        vec!{
156            binding::BindGroupLayoutEntry::new(visibility, binding::wgsl::uniform())
157        }
158    }
159
160    fn resources<'br>(&'br self) -> Vec<wgpu::BindingResource<'br>> {
161        vec!{
162            self.uniform_vec.buffer.as_entire_binding(),
163        }
164    }
165}
166
167///
168/// A uniform inside a BindGroup
169///
170pub struct UniformBindGroup<C: bytemuck::Pod>{
171    bind_group: binding::BindGroup<Uniform<C>>,
172}
173
174impl <C: bytemuck::Pod> UniformBindGroup<C>{
175    pub fn new(device: &wgpu::Device, src: C) -> Self{
176        Self{
177            bind_group: binding::BindGroup::new(Uniform::new(src, device), device)
178        }
179    }
180}
181
182impl<C: bytemuck::Pod> binding::GetBindGroup for UniformBindGroup<C>{
183    fn get_bind_group<'l>(&'l self) -> &'l wgpu::BindGroup {
184        self.bind_group.get_bind_group()
185    }
186}
187
188impl<C: bytemuck::Pod> Deref for UniformBindGroup<C>{
189    type Target = binding::BindGroup<Uniform<C>>;
190
191    fn deref(&self) -> &Self::Target {
192        &self.bind_group
193    }
194}
195
196impl<C: bytemuck::Pod> DerefMut for UniformBindGroup<C>{
197    fn deref_mut(&mut self) -> &mut Self::Target {
198        &mut self.bind_group
199    }
200}
201
202impl<C: bytemuck::Pod> CreateBindGroupLayout for UniformBindGroup<C>{
203    fn create_bind_group_layout(device: &wgpu::Device, label: Option<&str>) -> binding::BindGroupLayoutWithDesc {
204        BindGroup::<Uniform<C>>::create_bind_group_layout(device, label)
205    }
206    fn create_bind_group_layout_vis(device: &wgpu::Device, label: Option<&str>, visibility: wgpu::ShaderStages) -> crate::BindGroupLayoutWithDesc {
207        BindGroup::<Uniform<C>>::create_bind_group_layout_vis(device, label, visibility)
208    }
209}