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(&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 compute_task in &self.frame.compute_tasks{
117            compute_task.execute(&mut encoder, &self.asset_manager)
118        }
119
120        {
121            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
122                label: Some("Render Pass"),
123
124                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
125                    view: &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: wgpu::StoreOp::Store,
136                    },
137                })],
138                depth_stencil_attachment: self.depth_view.as_ref().map(|view| wgpu::RenderPassDepthStencilAttachment {
139                            view,
140                            depth_ops: Some(wgpu::Operations {
141                                load: wgpu::LoadOp::Clear(1.0),
142                                store: StoreOp::Store,
143                            }),
144                            stencil_ops: None,
145                        }) ,
146                occlusion_query_set: None,
147                timestamp_writes: None,
148                multiview_mask: None,
149            });
150
151            for item in &self.frame.render_tasks {
152                let material = self.asset_manager.materials.get(item.material).unwrap();
153                let pipeline = self.asset_manager.render_pipelines.get(material.pipeline).unwrap();
154                let mesh = self.asset_manager.meshes.get(item.mesh).unwrap();
155
156                render_pass.set_pipeline(&pipeline.pipeline);
157                render_pass.set_bind_group(0, &material.bind_group, &[]);
158                render_pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
159                render_pass.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
160
161                if let Some(instances) = item.instances{
162                    let instances = self.asset_manager.buffers.get(instances).unwrap();
163                    render_pass.set_vertex_buffer(1, instances.buffer.slice(..));
164                    render_pass.draw_indexed(0..mesh.index_count, 0,item.range.clone().unwrap());
165                }
166                else{
167                    render_pass.draw_indexed(0..mesh.index_count, 0,0..1);
168                }
169
170
171            }
172        }
173
174        self.queue.submit(Some(encoder.finish()));
175
176        output.present();
177    }
178
179    pub fn resize_surface(&mut self, size: PhysicalSize<u32>) {
180        self.surface_config.width = size.width;
181        self.surface_config.height = size.height;
182        self.surface.configure(&self.device, &self.surface_config);
183        self.create_depth_texture(size.width, size.height);
184    }
185    
186    pub fn window_aspect(&self) -> f32 {
187        self.surface_config.width as f32 / self.surface_config.height as f32
188    }
189
190    pub fn width(&self) -> u32{
191        self.surface_config.width
192    }
193    pub fn height(&self) -> u32{
194        self.surface_config.height
195    }
196
197    pub fn begin_frame(&mut self) -> &mut Frame {
198        self.frame.clear();
199        &mut self.frame
200    }
201
202    pub fn current_frame(&mut self) -> &mut Frame {
203        &mut self.frame
204    }
205
206    pub fn create_mesh<T: GpuVertex>(&mut self, vertices: &[T],indices: &[u16]) -> Handle<Mesh>{
207        let mesh = Mesh::new(&self.device,vertices,indices);
208        self.asset_manager.meshes.insert(mesh)
209    }
210
211    pub(crate) fn create_depth_texture(&mut self, width: u32, height: u32){
212        let texture = self.device.create_texture(&wgpu::TextureDescriptor {
213            size: wgpu::Extent3d {
214                width,
215                height,
216                depth_or_array_layers: 1,
217            },
218            mip_level_count: 1,
219            sample_count: 1,
220            dimension: wgpu::TextureDimension::D2,
221            format: wgpu::TextureFormat::Depth24Plus,
222            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
223            label: Some("depth_texture"),
224            view_formats: &[],
225        });
226
227        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
228
229        self.depth_view = Some(view);
230        self.depth_texture = Some(texture);
231    }
232
233
234    pub fn create_buffer(&mut self,buffer_usages: BufferUsages,size:u64) -> Handle<Buffer> {
235        let buffer = Buffer::new(&self.device,size,buffer_usages);
236        self.asset_manager.buffers.insert(buffer)
237    }
238
239    pub fn create_buffer_with_contents(&mut self,buffer_usages: BufferUsages,contents:&[u8]) -> Handle<Buffer> {
240        let buffer = Buffer::from_contents(&self.device,contents,buffer_usages);
241        self.asset_manager.buffers.insert(buffer)
242    }
243
244    pub fn load_shader(&mut self,src: &'static str) -> Handle<ShaderModule>{
245        let shader = self.device.create_shader_module(wgpu::ShaderModuleDescriptor {
246            label: Some("Shader"),
247            source: wgpu::ShaderSource::Wgsl(src.into()),
248        });
249        self.asset_manager.shaders.insert(shader)
250    }
251
252    pub fn write_buffer<T: bytemuck::Pod>(&self,handle: Handle<Buffer>,data: T){
253        let uniform = self.asset_manager.buffers.get(handle).unwrap();
254        self.queue.write_buffer(&uniform.buffer, 0, bytemuck::cast_slice(&[data]));
255    }
256    pub fn load_texture_from_file(&mut self,texture_bytes: Vec<u8>) -> Handle<Texture> {
257        let image = image::load_from_memory(texture_bytes.as_slice()).unwrap();
258        let rgba = image.to_rgba8();
259
260        let dims = image.dimensions();
261
262        let texture_size = wgpu::Extent3d{
263            width: dims.0,
264            height: dims.1,
265            depth_or_array_layers: 1,
266        };
267
268        let texture = self.device.create_texture(&wgpu::TextureDescriptor{
269            label: None,
270            size: texture_size,
271            mip_level_count: 1,
272            sample_count: 1,
273            dimension: TextureDimension::D2,
274            format: TextureFormat::Rgba8UnormSrgb,
275            usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
276            view_formats: &[],
277        });
278
279        self.queue.write_texture(
280            wgpu::TexelCopyTextureInfo{
281                texture: &texture,
282                mip_level: 0,
283                origin: wgpu::Origin3d::ZERO,
284                aspect: wgpu::TextureAspect::All,
285            },
286            &rgba,
287            wgpu::TexelCopyBufferLayout{
288                offset: 0,
289                bytes_per_row: Some(4 * dims.0),
290                rows_per_image: Some(dims.1),
291            },
292            texture_size
293        );
294
295        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
296
297        self.asset_manager.textures.insert(Texture::new(texture,view))
298    }
299
300    pub fn write_texture(&self,texture: Handle<Texture>,bytes: &[u8],byte_per_pixel: u32, texture_size: Extent3d){
301        let texture = &self.asset_manager.textures.get(texture).unwrap().texture;
302
303        self.queue.write_texture(
304            wgpu::TexelCopyTextureInfo{
305                texture,
306                mip_level: 0,
307                origin: wgpu::Origin3d::ZERO,
308                aspect: wgpu::TextureAspect::All,
309            },
310            bytes,
311            wgpu::TexelCopyBufferLayout{
312                offset: 0,
313                bytes_per_row: Some(byte_per_pixel * texture_size.width),
314                rows_per_image: Some(texture_size.height),
315            },
316            texture_size
317        );
318    }
319}
320