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) {
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 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, 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}