mraphics_core/render/
conveyor.rs

1use std::collections::HashMap;
2
3#[derive(Debug)]
4struct Gadget {
5    buffer: wgpu::Buffer,
6    ty: wgpu::BufferBindingType,
7}
8
9#[derive(Debug, Clone, Copy)]
10pub struct GadgetIndex {
11    pub group_index: usize,
12    pub binding_index: u32,
13}
14
15pub struct GadgetDescriptor<'a> {
16    pub label: &'a str,
17    pub index: GadgetIndex,
18    pub size: u64,
19    pub usage: wgpu::BufferUsages,
20    pub ty: wgpu::BufferBindingType,
21}
22
23#[derive(Clone, Debug)]
24pub struct GadgetData {
25    pub label: String,
26    pub index: GadgetIndex,
27    pub data: Vec<u8>,
28    pub needs_update_value: bool,
29    pub needs_update_buffer: bool,
30}
31
32#[derive(Debug)]
33pub struct Bundle {
34    bind_group: wgpu::BindGroup,
35    bind_group_layout: wgpu::BindGroupLayout,
36}
37
38#[derive(Debug)]
39pub enum ConveyorError {
40    UnknownGadgetLabel,
41}
42
43pub struct Conveyor {
44    pub needs_update: bool,
45    pub bundles: Vec<Option<Bundle>>,
46
47    gadgets: HashMap<String, Gadget>,
48    indices: Vec<Option<HashMap<u32, String>>>,
49}
50
51impl Conveyor {
52    pub fn new() -> Self {
53        Self {
54            gadgets: HashMap::new(),
55            bundles: Vec::new(),
56            indices: Vec::new(),
57            needs_update: false,
58        }
59    }
60
61    pub fn upsert_gadget(&mut self, device: &wgpu::Device, desc: &GadgetDescriptor) {
62        let buffer = device.create_buffer(&wgpu::BufferDescriptor {
63            label: Some(desc.label),
64            size: desc.size,
65            usage: desc.usage,
66            mapped_at_creation: false,
67        });
68
69        let gadget = Gadget {
70            buffer,
71            ty: desc.ty,
72        };
73
74        self.gadgets.insert(String::from(desc.label), gadget);
75
76        let group_index = desc.index.group_index;
77
78        while self.indices.len() <= group_index {
79            self.indices.push(None);
80        }
81
82        if self.indices[group_index].is_none() {
83            self.indices[group_index] = Some(HashMap::new());
84        }
85
86        // SATFTY: Checked upon
87        let group_desc = self.indices[group_index].as_mut().unwrap();
88        group_desc.insert(desc.index.binding_index, String::from(desc.label));
89
90        self.needs_update = true;
91    }
92
93    pub fn update_gadget(
94        &mut self,
95        queue: &wgpu::Queue,
96        gadget_label: &str,
97        data: &[u8],
98    ) -> Result<(), ConveyorError> {
99        let gadget = self
100            .gadgets
101            .get(gadget_label)
102            .ok_or(ConveyorError::UnknownGadgetLabel)?;
103
104        queue.write_buffer(&gadget.buffer, 0, data);
105
106        Ok(())
107    }
108
109    pub fn update_bundles(&mut self, device: &wgpu::Device) {
110        self.bundles = Vec::new();
111
112        for (group_index, group_desc) in self.indices.iter().enumerate() {
113            let mut bind_group_layout_entries: Vec<wgpu::BindGroupLayoutEntry> = Vec::new();
114            let mut bind_group_entries: Vec<wgpu::BindGroupEntry> = Vec::new();
115
116            if group_desc.is_none() {
117                self.bundles.push(None);
118                continue;
119            }
120
121            let group_desc = group_desc.as_ref().unwrap();
122
123            for (binding_index, gadget_label) in group_desc {
124                let gadget = self.gadgets.get(gadget_label).unwrap();
125
126                bind_group_layout_entries.push(wgpu::BindGroupLayoutEntry {
127                    binding: *binding_index,
128                    visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, // Hard coded currently
129                    ty: wgpu::BindingType::Buffer {
130                        ty: gadget.ty,
131                        has_dynamic_offset: false,
132                        min_binding_size: None,
133                    },
134                    count: None,
135                });
136
137                bind_group_entries.push(wgpu::BindGroupEntry {
138                    binding: *binding_index,
139                    resource: gadget.buffer.as_entire_binding(),
140                })
141            }
142
143            let bind_group_layout =
144                device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
145                    label: Some(&format!(
146                        "Mraphics bind group layout with index {}",
147                        group_index
148                    )),
149                    entries: &bind_group_layout_entries,
150                });
151
152            let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
153                label: Some(&format!("Mraphics bind group with index {}", group_index)),
154                layout: &bind_group_layout,
155                entries: &bind_group_entries,
156            });
157
158            let bundle = Bundle {
159                bind_group: bind_group,
160                bind_group_layout: bind_group_layout,
161            };
162
163            self.bundles.push(Some(bundle));
164
165            self.needs_update = false;
166        }
167    }
168
169    pub fn attach_bundles(&self, render_pass: &mut wgpu::RenderPass) {
170        for (index, maybe_bundle) in self.bundles.iter().enumerate() {
171            if let Some(bundle) = maybe_bundle {
172                render_pass.set_bind_group(index as u32, &bundle.bind_group, &[]);
173            }
174        }
175    }
176
177    pub fn collect_bind_group_layouts(
178        bundles_collection: Vec<&Vec<Option<Bundle>>>,
179    ) -> Vec<&wgpu::BindGroupLayout> {
180        let mut max_len = 0;
181        let mut bind_group_layouts = Vec::new();
182
183        for bundles in bundles_collection.iter() {
184            if bundles.len() > max_len {
185                max_len = bundles.len()
186            }
187        }
188
189        for i in 0..max_len {
190            for bundles in bundles_collection.iter() {
191                if !bundles.get(i).is_none() && !bundles[i].is_none() {
192                    bind_group_layouts.push(&bundles[i].as_ref().unwrap().bind_group_layout);
193                }
194            }
195        }
196
197        bind_group_layouts
198    }
199}