1use std::sync::Arc;
2use image::GenericImageView;
3use wgpu::{BufferUsages, Color, Device, Extent3d, Queue, ShaderModule, StoreOp, Surface, SurfaceConfiguration, TextureDimension};
4use winit::dpi::PhysicalSize;
5use winit::window::Window;
6use crate::{frame::Frame};
7use crate::assets::buffer::Buffer;
8use crate::assets::render::mesh::Mesh;
9use crate::assets::Texture;
10use crate::assets::vertex_layout::GpuVertex;
11use crate::assets_manager::asset_manager::AssetManager;
12use crate::assets_manager::handle::Handle;
13use crate::wgpu::TextureFormat;
14
15pub struct Renderer {
16 pub(crate) device: Device,
17 queue: Queue,
18 surface: Surface<'static>,
19 pub(crate)surface_config: SurfaceConfiguration,
20
21 pub asset_manager: AssetManager,
22
23 pub(crate)depth_texture: Option<wgpu::Texture>,
24 depth_view: Option<wgpu::TextureView>,
25
26 frame: Frame,
27
28 clear_colour: Color,
29}
30
31impl Renderer {
32 pub async fn new(window: Arc<Window>) -> Self {
33 let instance = wgpu::Instance::default();
34
35 let surface = instance.create_surface(window.clone()).unwrap();
36
37 let adapter = instance.request_adapter(
38 &wgpu::RequestAdapterOptions {
39 compatible_surface: Some(&surface),
40 ..Default::default()
41 },
42 ).await.unwrap();
43
44 let (device, queue) = adapter.request_device(
45 &wgpu::DeviceDescriptor::default(),
46 ).await.unwrap();
47
48 let caps = surface.get_capabilities(&adapter);
49
50 let surface_format = caps.formats
51 .iter()
52 .copied()
53 .find(|f| f.is_srgb())
54 .unwrap_or(caps.formats[0]);
55
56 let surface_config = SurfaceConfiguration {
57 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
58 format: surface_format,
59 width: window.inner_size().width,
60 height: window.inner_size().height,
61 present_mode: if caps.present_modes.contains(&wgpu::PresentMode::Mailbox) {
62 wgpu::PresentMode::Mailbox
63 } else {
64 wgpu::PresentMode::Fifo
65 },
66 alpha_mode: caps.alpha_modes[0],
67 view_formats: vec![],
68 desired_maximum_frame_latency: 2,
69 };
70
71 surface.configure(&device, &surface_config);
72
73 let asset_manager = AssetManager::new();
74
75 let frame = Frame::new();
76
77 Self {
78 device,
79 queue,
80 surface,
81 surface_config,
82 asset_manager,
83 depth_texture: None,
84 depth_view: None,
85 frame,
86 clear_colour: wgpu::Color::BLACK,
87 }
88 }
89
90 pub fn clear_colour(mut self,r: f64,g: f64,b: f64,a: f64) -> Self{
91 self.clear_colour = Color{
92 r,
93 g,
94 b,
95 a,
96 };
97 self
98 }
99
100 pub fn render(&mut self) {
101 let output = match self.surface.get_current_texture() {
102 wgpu::CurrentSurfaceTexture::Success(frame) => frame,
103 wgpu::CurrentSurfaceTexture::Suboptimal(frame) => {
104 frame
106 }
107 wgpu::CurrentSurfaceTexture::Timeout => {
108 return; }
110 wgpu::CurrentSurfaceTexture::Occluded => {
111 return; }
113 wgpu::CurrentSurfaceTexture::Outdated => {
114 self.surface.configure(&self.device, &self.surface_config);
116 return;
117 }
118 wgpu::CurrentSurfaceTexture::Lost => {
119 self.surface.configure(&self.device, &self.surface_config);
121 return;
122 }
123 wgpu::CurrentSurfaceTexture::Validation => {
124 return;
125 }
126 };
127
128 let view = output
129 .texture
130 .create_view(&wgpu::TextureViewDescriptor::default());
131
132 let mut encoder = self.device.create_command_encoder(
133 &wgpu::CommandEncoderDescriptor {
134 label: Some("Render Encoder"),
135 },
136 );
137
138 for texture in self.frame.textures_to_clear.drain(..){
139 let view = &self.asset_manager.textures.get(texture).unwrap().view;
140
141 let _rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
142 label: Some("Clear Texture Pass"),
143 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
144 view,
145 depth_slice: None,
146 resolve_target: None,
147 ops: wgpu::Operations {
148 load: wgpu::LoadOp::Clear(wgpu::Color {
149 r: 0.0,
150 g: 0.0,
151 b: 0.0,
152 a: 1.0,
153 }),
154 store: Default::default(),
155 },
156 })],
157 depth_stencil_attachment: None,
158 timestamp_writes: None,
159 occlusion_query_set: None,
160 multiview_mask: None,
161 });
162 }
163
164 for compute_task in &self.frame.compute_tasks{
165 compute_task.execute(&mut encoder, &self.asset_manager)
166 }
167
168 {
169 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
170 label: Some("Render Pass"),
171
172 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
173 view: &view,
174 depth_slice: None,
175 resolve_target: None,
176 ops: wgpu::Operations {
177 load: wgpu::LoadOp::Clear(self.clear_colour),
178 store: StoreOp::Store,
179 },
180 })],
181 depth_stencil_attachment: self.depth_view.as_ref().map(|view| wgpu::RenderPassDepthStencilAttachment {
182 view,
183 depth_ops: Some(wgpu::Operations {
184 load: wgpu::LoadOp::Clear(1.0),
185 store: StoreOp::Store,
186 }),
187 stencil_ops: None,
188 }) ,
189 occlusion_query_set: None,
190 timestamp_writes: None,
191 multiview_mask: None,
192 });
193
194 let mut current_material = None;
195 let mut current_mesh = None;
196
197 for item in &self.frame.render_tasks {
198 if Some(item.material) != current_material{
199 current_material = Some(item.material);
200 let material = self.asset_manager.materials.get(item.material).unwrap();
201 let pipeline = self.asset_manager.render_pipelines.get(material.pipeline).unwrap();
202
203 render_pass.set_pipeline(&pipeline.pipeline);
204 render_pass.set_bind_group(0, &material.bind_group, &[]);
205 }
206
207 let mesh = self.asset_manager.meshes.get(item.mesh).unwrap();
208 if Some(item.mesh) != current_mesh{
209 current_mesh = Some(item.mesh);
210 render_pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
211 render_pass.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
212 }
213
214 if let Some(instances) = item.instances{
215 let instances = self.asset_manager.buffers.get(instances).unwrap();
216 render_pass.set_vertex_buffer(1, instances.buffer.slice(..));
217 render_pass.draw_indexed(0..mesh.index_count, 0,item.range.clone().unwrap());
218 }
219 else{
220 render_pass.draw_indexed(0..mesh.index_count, 0,0..1);
221 }
222
223
224 }
225 }
226
227 self.queue.submit(Some(encoder.finish()));
228
229 output.present();
230 }
231
232 pub fn resize_surface(&mut self, size: PhysicalSize<u32>) {
233 self.surface_config.width = size.width;
234 self.surface_config.height = size.height;
235 self.surface.configure(&self.device, &self.surface_config);
236 self.create_depth_texture(size.width, size.height);
237 }
238
239 pub fn window_aspect(&self) -> f32 {
240 self.surface_config.width as f32 / self.surface_config.height as f32
241 }
242
243 pub fn width(&self) -> u32{
244 self.surface_config.width
245 }
246 pub fn height(&self) -> u32{
247 self.surface_config.height
248 }
249
250 pub fn begin_frame(&mut self) -> &mut Frame {
251 self.frame.clear();
252 &mut self.frame
253 }
254
255 pub fn current_frame(&mut self) -> &mut Frame {
256 &mut self.frame
257 }
258
259 pub fn create_mesh<T: GpuVertex>(&mut self, vertices: &[T],indices: &[u16]) -> Handle<Mesh>{
260 let mesh = Mesh::new(&self.device,vertices,indices);
261 self.asset_manager.meshes.insert(mesh)
262 }
263
264 pub(crate) fn create_depth_texture(&mut self, width: u32, height: u32){
265 let texture = self.device.create_texture(&wgpu::TextureDescriptor {
266 size: wgpu::Extent3d {
267 width,
268 height,
269 depth_or_array_layers: 1,
270 },
271 mip_level_count: 1,
272 sample_count: 1,
273 dimension: wgpu::TextureDimension::D2,
274 format: wgpu::TextureFormat::Depth24Plus,
275 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
276 label: Some("depth_texture"),
277 view_formats: &[],
278 });
279
280 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
281
282 self.depth_view = Some(view);
283 self.depth_texture = Some(texture);
284 }
285
286 pub fn create_buffer(&mut self,buffer_usages: BufferUsages,size:u64) -> Handle<Buffer> {
287 let buffer = Buffer::new(&self.device,size,buffer_usages);
288 self.asset_manager.buffers.insert(buffer)
289 }
290
291 pub fn create_buffer_with_contents(&mut self,buffer_usages: BufferUsages,contents:&[u8]) -> Handle<Buffer> {
292 let buffer = Buffer::from_contents(&self.device,contents,buffer_usages);
293 self.asset_manager.buffers.insert(buffer)
294 }
295
296 pub fn load_shader(&mut self,src: &'static str) -> Handle<ShaderModule>{
297 let shader = self.device.create_shader_module(wgpu::ShaderModuleDescriptor {
298 label: Some("Shader"),
299 source: wgpu::ShaderSource::Wgsl(src.into()),
300 });
301 self.asset_manager.shaders.insert(shader)
302 }
303
304 pub fn write_buffer<T: bytemuck::Pod>(&self,handle: Handle<Buffer>,data: T){
305 let uniform = self.asset_manager.buffers.get(handle).unwrap();
306 self.queue.write_buffer(&uniform.buffer, 0, bytemuck::cast_slice(&[data]));
307 }
308 pub fn load_texture_from_file(&mut self,texture_bytes: Vec<u8>) -> Handle<Texture> {
309 let image = image::load_from_memory(texture_bytes.as_slice()).unwrap();
310 let rgba = image.to_rgba8();
311
312 let dims = image.dimensions();
313
314 let texture_size = wgpu::Extent3d{
315 width: dims.0,
316 height: dims.1,
317 depth_or_array_layers: 1,
318 };
319
320 let texture = self.device.create_texture(&wgpu::TextureDescriptor{
321 label: None,
322 size: texture_size,
323 mip_level_count: 1,
324 sample_count: 1,
325 dimension: TextureDimension::D2,
326 format: TextureFormat::Rgba8UnormSrgb,
327 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
328 view_formats: &[],
329 });
330
331 self.queue.write_texture(
332 wgpu::TexelCopyTextureInfo{
333 texture: &texture,
334 mip_level: 0,
335 origin: wgpu::Origin3d::ZERO,
336 aspect: wgpu::TextureAspect::All,
337 },
338 &rgba,
339 wgpu::TexelCopyBufferLayout{
340 offset: 0,
341 bytes_per_row: Some(4 * dims.0),
342 rows_per_image: Some(dims.1),
343 },
344 texture_size
345 );
346
347 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
348
349 self.asset_manager.textures.insert(Texture::new(texture,view))
350 }
351
352 pub fn write_texture(&self,texture: Handle<Texture>,bytes: &[u8],byte_per_pixel: u32, texture_size: Extent3d){
353 let texture = &self.asset_manager.textures.get(texture).unwrap().texture;
354
355 self.queue.write_texture(
356 wgpu::TexelCopyTextureInfo{
357 texture,
358 mip_level: 0,
359 origin: wgpu::Origin3d::ZERO,
360 aspect: wgpu::TextureAspect::All,
361 },
362 bytes,
363 wgpu::TexelCopyBufferLayout{
364 offset: 0,
365 bytes_per_row: Some(byte_per_pixel * texture_size.width),
366 rows_per_image: Some(texture_size.height),
367 },
368 texture_size
369 );
370 }
371}
372