From b81dbd1569d71076b60f06fa6cb957afd8d08310 Mon Sep 17 00:00:00 2001 From: mars Date: Mon, 18 Apr 2022 17:40:51 -0600 Subject: [PATCH] Begin wgpu render passes --- src/lib.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 55 +++++++++++++++++++++++++++++++++++----- 2 files changed, 117 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0c336f6..0bcfe45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ //! in Rust. use rayon::prelude::*; +use std::sync::Mutex; use std::sync::{Arc, RwLock}; use strum::IntoEnumIterator; @@ -21,9 +22,9 @@ pub struct Renderer { } impl Renderer { - pub fn new(device: wgpu::Device, queue: wgpu::Queue) -> Self { + pub fn new(device: Arc, queue: wgpu::Queue) -> Self { Self { - device: Arc::new(device), + device, queue, frames_in_flight: 2, render_passes: Vec::new(), @@ -48,7 +49,11 @@ impl Renderer { self.render_passes.push(pass); } - pub fn render(&mut self) { + pub fn render( + &mut self, + surface: &wgpu::Surface, + format: wgpu::TextureFormat, + ) -> Result<(), wgpu::SurfaceError> { let frame_index = 0; let phase_passes = multimap::MultiMap::::new(); @@ -71,6 +76,66 @@ impl Renderer { let phase_passes = phase_passes.into_inner().unwrap(); let viewport = ViewportData; - // Up next is actual rendering to a surface! + let output = surface.get_current_texture()?; + let view = output + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encoder"), + }); + + { + let mut opaque_cmds = Vec::new(); + if let Some(opaque) = phase_passes.get_vec(&Phase::Opaque) { + opaque.iter().for_each(|pass_index| { + let frame_data = IndexedPhaseData { + phase: Phase::Opaque, + frame_data: frame_index, + viewport: &viewport, + }; + + let pass = &self.render_passes[*pass_index]; + let mut cmds = self.device.create_render_bundle_encoder( + &wgpu::RenderBundleEncoderDescriptor { + label: Some("Opaque Pass Render Bundle"), + color_formats: &[format], + depth_stencil: None, + sample_count: 1, + multiview: None, + }, + ); + + pass.record_render(frame_data, &mut cmds); + opaque_cmds.push(cmds.finish(&wgpu::RenderBundleDescriptor::default())); + }) + } + + let mut rp = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }), + store: true, + }, + }], + depth_stencil_attachment: None, + }); + + rp.execute_bundles(opaque_cmds.iter()); + } + + self.queue.submit(std::iter::once(encoder.finish())); + output.present(); + + Ok(()) } } diff --git a/src/main.rs b/src/main.rs index 8ed7e99..7b8113a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,30 @@ use cyborg::{pass, Renderer}; -use winit::{event::*, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder}; +use std::sync::Arc; +use winit::{ + event::*, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; -async fn make_window_renderer(window: &winit::window::Window) -> Renderer { +struct SurfaceViewport { + device: Arc, + size: winit::dpi::PhysicalSize, + surface: wgpu::Surface, + config: wgpu::SurfaceConfiguration, +} + +impl SurfaceViewport { + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { + if new_size.width > 0 && new_size.height > 0 { + self.size = new_size; + self.config.width = new_size.width; + self.config.height = new_size.height; + self.surface.configure(&self.device, &self.config); + } + } +} + +async fn make_window_renderer(window: &winit::window::Window) -> (Renderer, SurfaceViewport) { let size = window.inner_size(); let instance = wgpu::Instance::new(wgpu::Backends::all()); let surface = unsafe { instance.create_surface(window) }; @@ -33,13 +56,21 @@ async fn make_window_renderer(window: &winit::window::Window) -> Renderer { }; surface.configure(&device, &config); - Renderer::new(device, queue) + let device = Arc::new(device); + let renderer = Renderer::new(device.clone(), queue); + let viewport = SurfaceViewport { + device, + size, + surface, + config, + }; + (renderer, viewport) } fn main() { let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); - let mut renderer = pollster::block_on(make_window_renderer(&window)); + let (mut renderer, mut viewport) = pollster::block_on(make_window_renderer(&window)); let device = renderer.get_device(); let mesh_pass = pass::mesh::MeshPass::new(device.to_owned()); @@ -47,10 +78,14 @@ fn main() { event_loop.run(move |event, _, control_flow| match event { Event::RedrawRequested(_) => { - renderer.render(); + match renderer.render(&viewport.surface, viewport.config.format) { + Ok(_) => {} + Err(wgpu::SurfaceError::Lost) => viewport.resize(viewport.size), + Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit, + Err(e) => eprintln!("error: {:?}", e), + }; } Event::MainEventsCleared => { - std::thread::sleep(std::time::Duration::from_secs_f32( 1.0 / 60.0 )); window.request_redraw(); } Event::WindowEvent { @@ -58,8 +93,14 @@ fn main() { window_id, } if window_id == window.id() => match event { WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::Resized(physical_size) => { + viewport.resize(*physical_size); + } + WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { + viewport.resize(**new_inner_size); + } _ => {} - } + }, _ => {} }); }