Skip to main content

easy_gpu/
renderer.rs

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