Skip to main content

easy_gpu/
renderer.rs

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