mraphics_core/render/
conveyor.rs1use 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) {
63 let buffer = device.create_buffer(&wgpu::BufferDescriptor {
64 label: Some(desc.label),
65 size: desc.size,
66 usage: desc.usage,
67 mapped_at_creation: false,
68 });
69
70 let gadget = Gadget {
71 buffer,
72 ty: desc.ty,
73 };
74
75 self.gadgets.insert(String::from(desc.label), gadget);
76
77 let group_index = desc.index.group_index;
78
79 while self.indices.len() <= group_index {
80 self.indices.push(None);
81 }
82
83 if self.indices[group_index].is_none() {
84 self.indices[group_index] = Some(HashMap::new());
85 }
86
87 let group_desc = self.indices[group_index].as_mut().unwrap();
89 group_desc.insert(desc.index.binding_index, String::from(desc.label));
90
91 self.needs_update = true;
92 }
93
94 pub fn update_gadget(
95 &mut self,
96 queue: &wgpu::Queue,
97 gadget_label: &str,
98 data: &[u8],
99 ) -> Result<(), ConveyorError> {
100 let gadget = self
101 .gadgets
102 .get(gadget_label)
103 .ok_or(ConveyorError::UnknownGadgetLabel)?;
104
105 queue.write_buffer(&gadget.buffer, 0, data);
106
107 Ok(())
108 }
109
110 pub fn update_bundles(&mut self, device: &wgpu::Device) {
111 self.bundles = Vec::new();
112
113 for (group_index, group_desc) in self.indices.iter().enumerate() {
114 if group_desc.is_none() {
115 self.bundles.push(None);
116 continue;
117 }
118
119 let group_desc = group_desc.as_ref().unwrap();
120
121 let mut bind_group_layout_entries: Vec<wgpu::BindGroupLayoutEntry> = Vec::new();
122 let mut bind_group_entries: Vec<wgpu::BindGroupEntry> = Vec::new();
123
124 for (binding_index, gadget_label) in group_desc {
125 let gadget = self.gadgets.get(gadget_label).unwrap();
126
127 bind_group_layout_entries.push(wgpu::BindGroupLayoutEntry {
128 binding: *binding_index,
129 visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, ty: wgpu::BindingType::Buffer {
131 ty: gadget.ty,
132 has_dynamic_offset: false,
133 min_binding_size: None,
134 },
135 count: None,
136 });
137
138 bind_group_entries.push(wgpu::BindGroupEntry {
139 binding: *binding_index,
140 resource: gadget.buffer.as_entire_binding(),
141 })
142 }
143
144 let bind_group_layout =
145 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
146 label: Some(&format!(
147 "Mraphics bind group layout with index {}",
148 group_index
149 )),
150 entries: &bind_group_layout_entries,
151 });
152
153 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
154 label: Some(&format!("Mraphics bind group with index {}", group_index)),
155 layout: &bind_group_layout,
156 entries: &bind_group_entries,
157 });
158
159 let bundle = Bundle {
160 bind_group: bind_group,
161 bind_group_layout: bind_group_layout,
162 };
163
164 self.bundles.push(Some(bundle));
165
166 self.needs_update = false;
167 }
168 }
169
170 pub fn attach_bundles(&self, render_pass: &mut wgpu::RenderPass) {
171 for (index, maybe_bundle) in self.bundles.iter().enumerate() {
172 if let Some(bundle) = maybe_bundle {
173 render_pass.set_bind_group(index as u32, &bundle.bind_group, &[]);
174 }
175 }
176 }
177
178 pub fn collect_bind_group_layouts(
187 bundles_collection: Vec<&Vec<Option<Bundle>>>,
188 ) -> Vec<Option<&wgpu::BindGroupLayout>> {
189 let mut max_len = 0;
190 let mut bind_group_layouts = Vec::new();
191
192 for bundles in bundles_collection.iter() {
193 if bundles.len() > max_len {
194 max_len = bundles.len()
195 }
196 }
197
198 'outer: for i in 0..max_len {
199 for bundles in bundles_collection.iter() {
200 if !bundles.get(i).is_none() && !bundles[i].is_none() {
201 bind_group_layouts.push(Some(&bundles[i].as_ref().unwrap().bind_group_layout));
202 continue 'outer;
203 }
204 }
205
206 bind_group_layouts.push(None);
207 }
208
209 bind_group_layouts
210 }
211}