1use wgpu::util::DeviceExt;
2
3use crate::constants::{
4 INDEX_BUFFER_LABEL, PROJECTION_MAT_INDEX, PROJECTION_MAT_LABEL, VIEW_MAT_INDEX, VIEW_MAT_LABEL,
5};
6use crate::{
7 Camera, Color, Conveyor, ConveyorManager, GadgetData, GadgetDescriptor, GeometryIndices,
8 PipelineManager, RenderInstance, Scene,
9};
10
11pub struct Renderer<'window> {
12 pub surface: wgpu::Surface<'window>,
13 pub surface_config: wgpu::SurfaceConfiguration,
14 pub device: wgpu::Device,
15 pub queue: wgpu::Queue,
16
17 pipeline_manager: PipelineManager,
18 attr_conveyor_manager: ConveyorManager,
19 material_conveyor_manager: ConveyorManager,
20 shared_conveyor: Conveyor,
21}
22
23impl<'window> Renderer<'window> {
24 pub fn new(
25 surface: wgpu::Surface<'window>,
26 device: wgpu::Device,
27 queue: wgpu::Queue,
28 adapter: &wgpu::Adapter,
29 ) -> Self {
30 let surface_caps = surface.get_capabilities(adapter);
31 let surface_config = wgpu::SurfaceConfiguration {
32 width: 100,
33 height: 100,
34 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
35 format: wgpu::TextureFormat::Rgba8Unorm,
36 present_mode: surface_caps.present_modes[0],
37 alpha_mode: surface_caps.alpha_modes[0],
38 view_formats: vec![],
39 desired_maximum_frame_latency: 2,
40 };
41
42 surface.configure(&device, &surface_config);
43
44 let mut shared_conveyor = Conveyor::new();
45 shared_conveyor.upsert_gadget(
46 &device,
47 &GadgetDescriptor {
48 label: VIEW_MAT_LABEL,
49 index: VIEW_MAT_INDEX,
50 size: 4 * 4 * 4,
51 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
52 ty: wgpu::BufferBindingType::Uniform,
53 },
54 );
55 shared_conveyor.upsert_gadget(
56 &device,
57 &GadgetDescriptor {
58 label: PROJECTION_MAT_LABEL,
59 index: PROJECTION_MAT_INDEX,
60 size: 4 * 4 * 4,
61 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
62 ty: wgpu::BufferBindingType::Uniform,
63 },
64 );
65
66 Self {
67 surface,
68 surface_config,
69 device,
70 queue,
71 pipeline_manager: PipelineManager::new(),
72 attr_conveyor_manager: ConveyorManager::new(),
73 material_conveyor_manager: ConveyorManager::new(),
74 shared_conveyor,
75 }
76 }
77
78 pub fn render<C: Camera>(
79 &mut self,
80 scene: &mut Scene,
81 camera: &C,
82 clear_color: &Color<f64>,
83 ) -> Result<(), wgpu::SurfaceError> {
84 let output = self.surface.get_current_texture()?;
85 let view = output
86 .texture
87 .create_view(&wgpu::TextureViewDescriptor::default());
88
89 let mut encoder = self
90 .device
91 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
92 label: Some("Mraphics Command Encoder"),
93 });
94
95 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
96 label: Some("Mraphics Render Pass"),
97 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
98 view: &view,
99 resolve_target: None,
100 ops: wgpu::Operations {
101 load: wgpu::LoadOp::Clear(wgpu::Color {
102 r: clear_color[0],
103 g: clear_color[1],
104 b: clear_color[2],
105 a: clear_color[3],
106 }),
107 store: wgpu::StoreOp::Store,
108 },
109 depth_slice: None,
110 })],
111 ..Default::default()
112 });
113
114 self.shared_conveyor
116 .update_gadget(&self.queue, VIEW_MAT_LABEL, camera.view_mat_data())
117 .unwrap();
118 self.shared_conveyor
119 .update_gadget(
120 &self.queue,
121 PROJECTION_MAT_LABEL,
122 camera.projection_mat_data(),
123 )
124 .unwrap();
125
126 for instance in &mut scene.instances {
127 self.render_instance(&mut render_pass, instance);
128 }
129
130 drop(render_pass);
131
132 self.queue.submit(std::iter::once(encoder.finish()));
133
134 output.present();
135
136 Ok(())
137 }
138
139 pub fn render_instance(
140 &mut self,
141 render_pass: &mut wgpu::RenderPass,
142 instance: &mut RenderInstance,
143 ) {
144 let attr_conveyor = self
145 .attr_conveyor_manager
146 .acquire_attr_conveyor(&instance.identifier);
147
148 update_gadgets(
149 &self.device,
150 &self.queue,
151 attr_conveyor,
152 &mut instance.geometry.attributes,
153 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
154 wgpu::BufferBindingType::Storage { read_only: true },
155 );
156
157 update_gadgets(
158 &self.device,
159 &self.queue,
160 attr_conveyor,
161 &mut instance.geometry.uniforms,
162 wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
163 wgpu::BufferBindingType::Uniform,
164 );
165
166 let material_conveyor = self.material_conveyor_manager.acquire_attr_conveyor(
167 &(instance.material.identifier.to_string() + &instance.identifier),
168 );
169
170 update_gadgets(
171 &self.device,
172 &self.queue,
173 material_conveyor,
174 &mut instance.material.attributes,
175 wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
176 wgpu::BufferBindingType::Storage { read_only: true },
177 );
178
179 update_gadgets(
180 &self.device,
181 &self.queue,
182 material_conveyor,
183 &mut instance.material.uniforms,
184 wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
185 wgpu::BufferBindingType::Uniform,
186 );
187
188 let needs_update = self.shared_conveyor.needs_update
189 || attr_conveyor.needs_update
190 || material_conveyor.needs_update;
191 if needs_update {
192 self.shared_conveyor.update_bundles(&self.device);
193 attr_conveyor.update_bundles(&self.device);
194 material_conveyor.update_bundles(&self.device);
195 }
196
197 let pipeline = self.pipeline_manager.acquire_pipeline(
198 &self.device,
199 self.surface_config.format,
200 &instance.material,
201 &Conveyor::collect_bind_group_layouts(vec![
202 &self.shared_conveyor.bundles,
203 &attr_conveyor.bundles,
204 &material_conveyor.bundles,
205 ]),
206 needs_update,
207 );
208
209 self.shared_conveyor.attach_bundles(render_pass);
210 attr_conveyor.attach_bundles(render_pass);
211 material_conveyor.attach_bundles(render_pass);
212
213 render_pass.set_pipeline(pipeline);
214
215 match &mut instance.geometry.indices {
216 GeometryIndices::Sequential(indices) => {
217 render_pass.draw(0..*indices, 0..1);
218 }
219 GeometryIndices::CustomU16(indices) => {
220 if indices.buffer.is_none() {
221 indices.buffer.replace(self.device.create_buffer_init(
222 &wgpu::util::BufferInitDescriptor {
223 label: Some(INDEX_BUFFER_LABEL),
224 contents: bytemuck::cast_slice(&indices.data),
225 usage: wgpu::BufferUsages::INDEX,
226 },
227 ));
228 }
229
230 let buffer = indices.buffer.as_ref().unwrap();
232 render_pass.set_index_buffer(buffer.slice(..), wgpu::IndexFormat::Uint16);
233 render_pass.draw_indexed(0..(indices.data.len() as u32), 0, 0..1);
234 }
235 GeometryIndices::CustomU32(indices) => {
236 if indices.buffer.is_none() {
237 if indices.buffer.is_none() {
238 indices.buffer.replace(self.device.create_buffer_init(
239 &wgpu::util::BufferInitDescriptor {
240 label: Some(INDEX_BUFFER_LABEL),
241 contents: bytemuck::cast_slice(&indices.data),
242 usage: wgpu::BufferUsages::INDEX,
243 },
244 ));
245 }
246 }
247
248 let buffer = indices.buffer.as_ref().unwrap();
250 render_pass.set_index_buffer(buffer.slice(..), wgpu::IndexFormat::Uint32);
251 render_pass.draw_indexed(0..(indices.data.len() as u32), 0, 0..1);
252 }
253 }
254 }
255
256 pub fn resize(&mut self, width: u32, height: u32) {
257 self.surface_config.width = width;
258 self.surface_config.height = height;
259
260 self.surface.configure(&self.device, &self.surface_config);
261 }
262}
263
264fn update_gadgets(
265 device: &wgpu::Device,
266 queue: &wgpu::Queue,
267 conveyor: &mut Conveyor,
268 gadget_data: &mut Vec<GadgetData>,
269 usage: wgpu::BufferUsages,
270 ty: wgpu::BufferBindingType,
271) {
272 for data in gadget_data {
273 update_gadget(device, queue, conveyor, data, usage, ty);
274 }
275}
276
277fn update_gadget(
278 device: &wgpu::Device,
279 queue: &wgpu::Queue,
280 conveyor: &mut Conveyor,
281 data: &mut GadgetData,
282 usage: wgpu::BufferUsages,
283 ty: wgpu::BufferBindingType,
284) {
285 if data.needs_update_buffer {
286 conveyor.upsert_gadget(
287 device,
288 &GadgetDescriptor {
289 label: &data.label,
290 index: data.index,
291 size: data.data.len() as u64,
292 usage,
293 ty,
294 },
295 );
296
297 data.needs_update_buffer = false;
298 }
299
300 if !data.needs_update_value {
301 return;
302 }
303
304 conveyor
306 .update_gadget(queue, &data.label, &data.data)
307 .unwrap();
308
309 data.needs_update_value = false;
310}