Skip to main content

easy_gpu/
renderer.rs

1use std::sync::Arc;
2use wgpu::{BufferUsages, Device, Queue, ShaderModule, StoreOp, Surface, SurfaceConfiguration};
3use winit::dpi::PhysicalSize;
4use winit::window::Window;
5use crate::{frame::Frame};
6use crate::assets::buffer::Buffer;
7use crate::assets::compute::bind_group::{ComputeBindGroup, ComputeBindGroupBuilder};
8use crate::assets::compute::pipeline::{ComputePipeline, ComputePipelineBuilder};
9use crate::assets::render::material::{Material, MaterialBuilder};
10use crate::assets::render::mesh::Mesh;
11use crate::assets::render::pipeline::{RenderPipeline, RenderPipelineBuilder};
12use crate::assets::vertex_layout::GpuVertex;
13use crate::assets_manager::asset_manager::AssetManager;
14use crate::assets_manager::asset_registry::AssetRegistry;
15use crate::assets_manager::handle::Handle;
16
17pub struct Renderer {
18    device: Device,
19    queue: Queue,
20    surface: Surface<'static>,
21    surface_config: SurfaceConfiguration,
22
23    pub asset_registry: AssetRegistry,
24    pub asset_manager: AssetManager,
25
26    depth_texture: Option<wgpu::Texture>,
27    depth_view: Option<wgpu::TextureView>,
28
29    frame: Frame,
30}
31
32impl Renderer {
33    pub async fn new(window: Arc<Window>) -> Self {
34        let instance = wgpu::Instance::default();
35
36        let surface = instance.create_surface(window.clone()).unwrap();
37
38        let adapter = instance.request_adapter(
39            &wgpu::RequestAdapterOptions {
40                compatible_surface: Some(&surface),
41                ..Default::default()
42            },
43        ).await.unwrap();
44
45        let (device, queue) = adapter.request_device(
46            &wgpu::DeviceDescriptor::default(),
47        ).await.unwrap();
48
49        let caps = surface.get_capabilities(&adapter);
50
51        let surface_config = SurfaceConfiguration {
52            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
53            format: caps.formats[0],
54            width: window.inner_size().width,
55            height: window.inner_size().height,
56            present_mode: caps.present_modes[0],
57            alpha_mode: caps.alpha_modes[0],
58            view_formats: vec![],
59            desired_maximum_frame_latency: 2,
60        };
61
62        surface.configure(&device, &surface_config);
63
64        let asset_manager = AssetManager::new();
65        let asset_registry = AssetRegistry::new();
66
67        let frame = Frame::new();
68
69        Self {
70            device,
71            queue,
72            surface,
73            surface_config,
74            asset_registry,
75            asset_manager,
76            depth_texture: None,
77            depth_view: None,
78            frame,
79        }
80    }
81
82    pub fn render(&self) {
83        let output = match self.surface.get_current_texture() {
84            wgpu::CurrentSurfaceTexture::Success(frame) => frame,
85            wgpu::CurrentSurfaceTexture::Suboptimal(frame) => {
86                // still usable, but should reconfigure soon
87                frame
88            }
89
90            wgpu::CurrentSurfaceTexture::Timeout => {
91                return; // skip frame
92            }
93            wgpu::CurrentSurfaceTexture::Occluded => {
94                return; // window hidden
95            }
96            wgpu::CurrentSurfaceTexture::Outdated => {
97                // reconfigure surface
98                self.surface.configure(&self.device, &self.surface_config);
99                return;
100            }
101            wgpu::CurrentSurfaceTexture::Lost => {
102                // recreate surface ideally, but reconfigure for now
103                self.surface.configure(&self.device, &self.surface_config);
104                return;
105            }
106            wgpu::CurrentSurfaceTexture::Validation => {
107                return;
108            }
109        };
110
111        let view = output
112            .texture
113            .create_view(&wgpu::TextureViewDescriptor::default());
114
115        let mut encoder = self.device.create_command_encoder(
116            &wgpu::CommandEncoderDescriptor {
117                label: Some("Render Encoder"),
118            },
119        );
120
121        for compute_task in &self.frame.compute_tasks{
122            compute_task.execute(&mut encoder, &self.asset_manager)
123        }
124
125        {
126            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
127                label: Some("Render Pass"),
128
129                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
130                    view: &view,
131                    depth_slice: None,
132                    resolve_target: None,
133                    ops: wgpu::Operations {
134                        load: wgpu::LoadOp::Clear(wgpu::Color {
135                            r: 0.0,
136                            g: 0.0,
137                            b: 0.0,
138                            a: 1.0,
139                        }),
140                        store: wgpu::StoreOp::Store,
141                    },
142                })],
143                depth_stencil_attachment: self.depth_view.as_ref().map(|view| wgpu::RenderPassDepthStencilAttachment {
144                            view,
145                            depth_ops: Some(wgpu::Operations {
146                                load: wgpu::LoadOp::Clear(1.0),
147                                store: StoreOp::Store,
148                            }),
149                            stencil_ops: None,
150                        }) ,
151                occlusion_query_set: None,
152                timestamp_writes: None,
153                multiview_mask: None,
154            });
155
156            for item in &self.frame.render_tasks {
157                let material = self.asset_manager.materials.get(item.material).unwrap();
158                let pipeline = self.asset_manager.render_pipelines.get(material.pipeline).unwrap();
159                let mesh = self.asset_manager.meshes.get(item.mesh).unwrap();
160                let instances = self.asset_manager.buffers.get(item.instances).unwrap();
161
162                render_pass.set_pipeline(&pipeline.pipeline);
163                render_pass.set_bind_group(0, &material.bind_group, &[]);
164                render_pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
165                render_pass.set_vertex_buffer(1, instances.buffer.slice(..));
166                render_pass.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
167
168                render_pass.draw_indexed(0..mesh.index_count, 0,item.range.clone());
169            }
170        }
171
172        self.queue.submit(Some(encoder.finish()));
173
174        output.present();
175    }
176
177    pub fn resize_surface(&mut self, size: PhysicalSize<u32>) {
178        self.surface_config.width = size.width;
179        self.surface_config.height = size.height;
180        self.surface.configure(&self.device, &self.surface_config);
181        self.create_depth_texture(size.width, size.height);
182    }
183    
184    pub fn window_aspect(&self) -> f32 {
185        self.surface_config.width as f32 / self.surface_config.height as f32
186    }
187
188    pub fn begin_frame(&mut self) -> &mut Frame {
189        self.frame.clear();
190        &mut self.frame
191    }
192
193    pub fn current_frame(&mut self) -> &mut Frame {
194        &mut self.frame
195    }
196
197    pub fn create_mesh<T: GpuVertex>(&mut self, vertices: &[T],indices: &[u32]) -> Handle<Mesh>{
198        let mesh = Mesh::new(&self.device,vertices,indices);
199        self.asset_manager.meshes.insert(mesh)
200    }
201
202    pub fn create_render_pipeline(&mut self, builder: RenderPipelineBuilder) -> Handle<RenderPipeline> {
203        if builder.depth_format.is_some() && self.depth_texture.is_none() {
204            self.create_depth_texture(self.surface_config.width,self.surface_config.height);
205        }
206
207        let pipeline = builder.build(&self.device,&self.asset_manager,&self.surface_config);
208        self.asset_manager.render_pipelines.insert(pipeline)
209    }
210
211    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    pub fn create_material(&mut self,builder: MaterialBuilder) -> Handle<Material> {
234        let material = builder.build(&self.device,&self.asset_manager);
235        self.asset_manager.materials.insert(material)
236    }
237
238    pub fn create_buffer(&mut self,buffer_usages: BufferUsages,size:u64) -> Handle<Buffer> {
239        let buffer = Buffer::new(&self.device,size,buffer_usages);
240        self.asset_manager.buffers.insert(buffer)
241    }
242
243    pub fn create_buffer_with_contents(&mut self,buffer_usages: BufferUsages,contents:&[u8]) -> Handle<Buffer> {
244        let buffer = Buffer::from_contents(&self.device,contents,buffer_usages);
245        self.asset_manager.buffers.insert(buffer)
246    }
247
248    pub fn load_shader(&mut self,src: &'static str) -> Handle<ShaderModule>{
249        let shader = self.device.create_shader_module(wgpu::ShaderModuleDescriptor {
250            label: Some("Shader"),
251            source: wgpu::ShaderSource::Wgsl(src.into()),
252        });
253        self.asset_manager.shaders.insert(shader)
254    }
255
256    pub fn write_buffer<T: bytemuck::Pod>(&self,handle: Handle<Buffer>,data: T){
257        let uniform = self.asset_manager.buffers.get(handle).unwrap();
258        self.queue.write_buffer(&uniform.buffer, 0, bytemuck::cast_slice(&[data]));
259    }
260
261    pub fn create_compute_pipeline(&mut self,builder: ComputePipelineBuilder) -> Handle<ComputePipeline>{
262        let pipeline = builder.build(&self.device,&self.asset_manager);
263        self.asset_manager.compute_pipelines.insert(pipeline)
264    }
265
266    pub fn create_compute_bind_group(&mut self, builder: ComputeBindGroupBuilder) -> Handle<ComputeBindGroup>{
267        let bind_group = builder.build(&self.device,&self.asset_manager);
268        self.asset_manager.compute_bind_groups.insert(bind_group)
269    }
270
271}
272