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