1use crate::constants::{
2 INDEX_BUFFER_LABEL, PROJECTION_MAT_INDEX, PROJECTION_MAT_LABEL, VIEW_MAT_INDEX, VIEW_MAT_LABEL,
3};
4use crate::{
5 Camera, Color, Conveyor, ConveyorManager, GadgetData, GadgetDescriptor, GeometryIndices,
6 PipelineManager, RenderInstance,
7};
8use wgpu::{Texture, TextureFormat, util::DeviceExt};
9
10pub struct Renderer {
11 pub device: wgpu::Device,
12 pub queue: wgpu::Queue,
13
14 pipeline_manager: PipelineManager,
15 mesh_conveyor_manager: ConveyorManager<usize>,
16 material_conveyor_manager: ConveyorManager<String>,
17 shared_conveyor: Conveyor,
18}
19
20impl Renderer {
21 pub fn new(device: wgpu::Device, queue: wgpu::Queue) -> Self {
22 let mut shared_conveyor = Conveyor::new();
23 shared_conveyor.upsert_gadget(
24 &device,
25 &GadgetDescriptor {
26 label: VIEW_MAT_LABEL,
27 index: VIEW_MAT_INDEX,
28 size: 4 * 4 * 4,
29 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
30 ty: wgpu::BufferBindingType::Uniform,
31 },
32 );
33 shared_conveyor.upsert_gadget(
34 &device,
35 &GadgetDescriptor {
36 label: PROJECTION_MAT_LABEL,
37 index: PROJECTION_MAT_INDEX,
38 size: 4 * 4 * 4,
39 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
40 ty: wgpu::BufferBindingType::Uniform,
41 },
42 );
43
44 Self {
45 device,
46 queue,
47 pipeline_manager: PipelineManager::new(),
48 mesh_conveyor_manager: ConveyorManager::new(),
49 material_conveyor_manager: ConveyorManager::new(),
50 shared_conveyor,
51 }
52 }
53
54 pub fn read_texture_rgbau8(&self, texture: &Texture, size: (u32, u32)) -> Vec<u8> {
63 let (width, height) = size;
64 let unpadded_bytes_per_row = width * 4; let bytes_per_row =
66 wgpu::util::align_to(unpadded_bytes_per_row, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT);
67 let buffer_size = (bytes_per_row * height) as wgpu::BufferAddress;
68 let buffer = self.device.create_buffer(&wgpu::BufferDescriptor {
69 label: Some("Mraphics Texture Mapping Buffer"),
70 size: buffer_size,
71 usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
72 mapped_at_creation: false,
73 });
74
75 let mut encoder = self
76 .device
77 .create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
78
79 encoder.copy_texture_to_buffer(
80 wgpu::TexelCopyTextureInfoBase {
81 texture,
82 mip_level: 0,
83 origin: wgpu::Origin3d::ZERO,
84 aspect: wgpu::TextureAspect::All,
85 },
86 wgpu::TexelCopyBufferInfoBase {
87 buffer: &buffer,
88 layout: wgpu::TexelCopyBufferLayout {
89 offset: 0,
90 bytes_per_row: Some(bytes_per_row),
91 rows_per_image: Some(height),
92 },
93 },
94 wgpu::Extent3d {
95 width,
96 height,
97 depth_or_array_layers: 1,
98 },
99 );
100
101 self.queue.submit(std::iter::once(encoder.finish()));
102
103 let (sender, receiver) = std::sync::mpsc::sync_channel(1);
104
105 buffer.map_async(wgpu::MapMode::Read, .., move |result| {
106 sender.send(result).unwrap();
107 });
108
109 self.device
110 .poll(wgpu::PollType::wait_indefinitely())
111 .unwrap();
112
113 receiver.recv().unwrap().unwrap();
114
115 let raw_data = buffer.get_mapped_range(..);
116 let mut data = Vec::with_capacity((unpadded_bytes_per_row * height) as usize);
117
118 for row in 0..height {
119 let row_start = (row * bytes_per_row) as usize;
120 let row_end = row_start + unpadded_bytes_per_row as usize;
121
122 data.extend_from_slice(&raw_data[row_start..row_end]);
123 }
124
125 drop(raw_data);
126
127 buffer.unmap();
128
129 data
130 }
131
132 pub fn render<C: Camera>(
142 &mut self,
143 texture: &Texture,
144 texture_format: TextureFormat,
145 instances: &mut [RenderInstance],
146 camera: &C,
147 clear_color: &Color<f64>,
148 ) {
149 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
150
151 let mut encoder = self
152 .device
153 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
154 label: Some("Mraphics Command Encoder"),
155 });
156
157 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
158 label: Some("Mraphics Render Pass"),
159 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
160 view: &view,
161 resolve_target: None,
162 ops: wgpu::Operations {
163 load: wgpu::LoadOp::Clear(wgpu::Color {
164 r: clear_color[0],
165 g: clear_color[1],
166 b: clear_color[2],
167 a: clear_color[3],
168 }),
169 store: wgpu::StoreOp::Store,
170 },
171 depth_slice: None,
172 })],
173 ..Default::default()
174 });
175
176 self.shared_conveyor
178 .update_gadget(&self.queue, VIEW_MAT_LABEL, camera.view_mat_data())
179 .unwrap();
180 self.shared_conveyor
181 .update_gadget(
182 &self.queue,
183 PROJECTION_MAT_LABEL,
184 camera.projection_mat_data(),
185 )
186 .unwrap();
187
188 fn render_recursive(
189 this: &mut Renderer,
190 texture_format: TextureFormat,
191 render_pass: &mut wgpu::RenderPass,
192 instance: &mut RenderInstance,
193 ) {
194 if instance.visible {
195 this.render_instance(texture_format, render_pass, instance);
196 }
197
198 for mut child in &mut instance.children {
199 render_recursive(this, texture_format, render_pass, &mut child);
200 }
201 }
202
203 for instance in instances {
204 render_recursive(self, texture_format, &mut render_pass, instance);
205 }
206
207 drop(render_pass);
208
209 self.queue.submit(std::iter::once(encoder.finish()));
210 }
211
212 fn render_instance(
220 &mut self,
221 texture_format: TextureFormat,
222 render_pass: &mut wgpu::RenderPass,
223 instance: &mut RenderInstance,
224 ) {
225 let mesh_conveyor = self
226 .mesh_conveyor_manager
227 .acquire_conveyor(&instance.identifier);
228
229 update_gadgets(
230 &self.device,
231 &self.queue,
232 mesh_conveyor,
233 &mut instance.geometry.attributes,
234 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
235 wgpu::BufferBindingType::Storage { read_only: true },
236 );
237
238 update_gadgets(
239 &self.device,
240 &self.queue,
241 mesh_conveyor,
242 &mut instance.geometry.uniforms,
243 wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
244 wgpu::BufferBindingType::Uniform,
245 );
246
247 let material_conveyor = self
248 .material_conveyor_manager
249 .acquire_conveyor(&(instance.identifier.to_string() + &instance.material.identifier));
250
251 update_gadgets(
252 &self.device,
253 &self.queue,
254 material_conveyor,
255 &mut instance.material.attributes,
256 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
257 wgpu::BufferBindingType::Storage { read_only: true },
258 );
259
260 update_gadgets(
261 &self.device,
262 &self.queue,
263 material_conveyor,
264 &mut instance.material.uniforms,
265 wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
266 wgpu::BufferBindingType::Uniform,
267 );
268
269 let needs_update = self.shared_conveyor.needs_update
270 || mesh_conveyor.needs_update
271 || material_conveyor.needs_update;
272 if needs_update {
273 self.shared_conveyor.update_bundles(&self.device);
274 mesh_conveyor.update_bundles(&self.device);
275 material_conveyor.update_bundles(&self.device);
276 }
277
278 let maybe_bind_group_layouts = Conveyor::collect_bind_group_layouts(vec![
279 &self.shared_conveyor.bundles,
280 &mesh_conveyor.bundles,
281 &material_conveyor.bundles,
282 ]);
283 let bind_group_placeholder = if maybe_bind_group_layouts.contains(&None) {
284 Some(
285 self.device
286 .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
287 label: Some(&format!("Mraphics bind group layout placeholder",)),
288 entries: &[],
289 }),
290 )
291 } else {
292 None
293 };
294 let bind_group_layouts = maybe_bind_group_layouts
295 .iter()
296 .map(|bind_group| {
297 bind_group.unwrap_or_else(|| bind_group_placeholder.as_ref().unwrap())
298 })
299 .collect::<Vec<_>>();
300
301 let pipeline = self.pipeline_manager.acquire_pipeline(
302 &self.device,
303 texture_format,
304 instance,
305 &bind_group_layouts,
306 needs_update,
307 );
308
309 self.shared_conveyor.attach_bundles(render_pass);
310 mesh_conveyor.attach_bundles(render_pass);
311 material_conveyor.attach_bundles(render_pass);
312
313 render_pass.set_pipeline(pipeline);
314
315 match &mut instance.geometry.indices {
316 GeometryIndices::Sequential(indices) => {
317 render_pass.draw(0..*indices, 0..1);
318 }
319 GeometryIndices::CustomU16(indices) => {
320 if indices.buffer.is_none() {
321 indices.buffer.replace(self.device.create_buffer_init(
322 &wgpu::util::BufferInitDescriptor {
323 label: Some(INDEX_BUFFER_LABEL),
324 contents: bytemuck::cast_slice(&indices.data),
325 usage: wgpu::BufferUsages::INDEX,
326 },
327 ));
328 }
329
330 let buffer = indices.buffer.as_ref().unwrap();
332 render_pass.set_index_buffer(buffer.slice(..), wgpu::IndexFormat::Uint16);
333 render_pass.draw_indexed(0..(indices.data.len() as u32), 0, 0..1);
334 }
335 GeometryIndices::CustomU32(indices) => {
336 if indices.buffer.is_none() {
337 if indices.buffer.is_none() {
338 indices.buffer.replace(self.device.create_buffer_init(
339 &wgpu::util::BufferInitDescriptor {
340 label: Some(INDEX_BUFFER_LABEL),
341 contents: bytemuck::cast_slice(&indices.data),
342 usage: wgpu::BufferUsages::INDEX,
343 },
344 ));
345 }
346 }
347
348 let buffer = indices.buffer.as_ref().unwrap();
350 render_pass.set_index_buffer(buffer.slice(..), wgpu::IndexFormat::Uint32);
351 render_pass.draw_indexed(0..(indices.data.len() as u32), 0, 0..1);
352 }
353 }
354 }
355}
356
357fn update_gadgets(
358 device: &wgpu::Device,
359 queue: &wgpu::Queue,
360 conveyor: &mut Conveyor,
361 gadget_data: &mut Vec<GadgetData>,
362 usage: wgpu::BufferUsages,
363 ty: wgpu::BufferBindingType,
364) {
365 for data in gadget_data {
366 update_gadget(device, queue, conveyor, data, usage, ty);
367 }
368}
369
370fn update_gadget(
371 device: &wgpu::Device,
372 queue: &wgpu::Queue,
373 conveyor: &mut Conveyor,
374 data: &mut GadgetData,
375 usage: wgpu::BufferUsages,
376 ty: wgpu::BufferBindingType,
377) {
378 if data.needs_update_buffer {
379 conveyor.upsert_gadget(
380 device,
381 &GadgetDescriptor {
382 label: &data.label,
383 index: data.index,
384 size: data.data.len() as u64,
385 usage,
386 ty,
387 },
388 );
389
390 data.needs_update_buffer = false;
391 }
392
393 if !data.needs_update_value {
394 return;
395 }
396
397 conveyor
399 .update_gadget(queue, &data.label, &data.data)
400 .unwrap();
401
402 data.needs_update_value = false;
403}