From fa1620ddc0111eee653c29b4ec1e419496e53459 Mon Sep 17 00:00:00 2001 From: mars Date: Tue, 19 Apr 2022 17:43:52 -0600 Subject: [PATCH] Add FrameData and RenderLayouts --- src/lib.rs | 140 +++++++++++++++++++++++++++++++++++++++++++++------- src/pass.rs | 10 ++-- 2 files changed, 128 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 887cd70..b4667bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,9 +2,8 @@ //! in Rust. use rayon::prelude::*; +use std::sync::Arc; use std::sync::Mutex; -use std::sync::{Arc, RwLock}; -use strum::IntoEnumIterator; pub mod mesh; pub mod pass; @@ -14,19 +13,124 @@ pub mod staging; use pass::*; use phase::*; +pub struct ViewportUniform { + pub vp: [f32; 16], +} + +impl ViewportUniform { + pub fn binding_size() -> wgpu::BufferSize { + let size = std::mem::size_of::() as u64; + size.try_into().unwrap() + } +} + +pub struct RenderLayouts { + pub device: Arc, + pub bind_viewport: wgpu::BindGroupLayout, +} + +impl RenderLayouts { + pub fn new_arc(device: Arc) -> Arc { + let bind_viewport = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("viewport"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: Some(ViewportUniform::binding_size()), + }, + count: None, + }], + }); + + Arc::new(Self { + device, + bind_viewport, + }) + } +} + +pub struct FrameData { + pub frame_index: usize, + pub bind_viewport: wgpu::BindGroup, + pub viewport_uniform: wgpu::Buffer, +} + +impl FrameData { + pub fn new(frame_index: usize, layouts: &RenderLayouts) -> Self { + let viewport_uniform = layouts.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("viewport"), + size: ViewportUniform::binding_size().into(), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let bind_viewport = layouts + .device + .create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("viewport"), + layout: &layouts.bind_viewport, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { + buffer: &viewport_uniform, + offset: 0, + size: None, + }), + }], + }); + + Self { + frame_index, + bind_viewport, + viewport_uniform, + } + } + + pub fn make_phase_data<'a>( + &'a self, + phase: Phase, + viewport_data: &'a ViewportData, + ) -> IndexedPhaseData<'a> { + IndexedPhaseData { + phase, + frame_data: self.frame_index, + viewport_data, + bind_viewport: &self.bind_viewport, + } + } +} + pub struct Renderer { device: Arc, + layouts: Arc, queue: wgpu::Queue, frames_in_flight: usize, + frame_datas: Vec, + frame_index: usize, render_passes: Vec>, } impl Renderer { pub fn new(device: Arc, queue: wgpu::Queue) -> Self { + let layouts = RenderLayouts::new_arc(device.clone()); + + let frames_in_flight = 1; + + let mut frame_datas = Vec::with_capacity(frames_in_flight); + for frame_index in 0..frames_in_flight { + frame_datas.push(FrameData::new(frame_index, &layouts)); + } + Self { device, + layouts, queue, - frames_in_flight: 2, + frames_in_flight, + frame_datas, + frame_index: 0, render_passes: Vec::new(), } } @@ -35,6 +139,10 @@ impl Renderer { &self.device } + pub fn get_layouts(&self) -> &Arc { + &self.layouts + } + pub fn add_pass(&mut self, pass: T) { let pass = Arc::new(pass); self.add_pass_arc(pass); @@ -54,7 +162,13 @@ impl Renderer { surface: &wgpu::Surface, format: wgpu::TextureFormat, ) -> Result<(), wgpu::SurfaceError> { - let frame_index = 0; + self.frame_index += 1; + if self.frame_index >= self.frame_datas.len() { + self.frame_index = 0; + } + + let frame_index = self.frame_index; + let frame_data = &self.frame_datas[frame_index]; let phase_passes = multimap::MultiMap::::new(); let phase_passes = std::sync::Mutex::new(phase_passes); @@ -88,29 +202,19 @@ impl Renderer { if let Some(upload) = phase_passes.get_vec(&Phase::Upload) { upload.iter().for_each(|pass_index| { - let frame_data = IndexedPhaseData { - phase: Phase::Upload, - frame_data: frame_index, - viewport: &viewport, - }; - + let phase_data = frame_data.make_phase_data(Phase::Upload, &viewport); let pass = &self.render_passes[*pass_index]; - pass.record_commands(frame_data, &mut encoder); + pass.record_commands(phase_data, &mut encoder); }); } let opaque_cmds = Mutex::new(Vec::new()); if let Some(opaque) = phase_passes.get_vec(&Phase::Opaque) { opaque.par_iter().for_each(|pass_index| { + let phase_data = frame_data.make_phase_data(Phase::Opaque, &viewport); let pass = &self.render_passes[*pass_index]; - let frame_data = IndexedPhaseData { - phase: Phase::Opaque, - frame_data: frame_index, - viewport: &viewport, - }; - - if let Some(cmd) = pass.record_render(frame_data) { + if let Some(cmd) = pass.record_render(phase_data) { opaque_cmds.lock().unwrap().push(cmd); } }) diff --git a/src/pass.rs b/src/pass.rs index 7ec67c2..37031e6 100644 --- a/src/pass.rs +++ b/src/pass.rs @@ -13,7 +13,8 @@ pub struct ViewportData; pub struct PhaseData<'a, T> { pub phase: Phase, pub frame_data: T, - pub viewport: &'a ViewportData, + pub viewport_data: &'a ViewportData, + pub bind_viewport: &'a wgpu::BindGroup, } pub type IndexedPhaseData<'a> = PhaseData<'a, usize>; @@ -100,7 +101,8 @@ impl RenderPassBox { let PhaseData { phase, frame_data, - viewport, + viewport_data, + bind_viewport, } = index; let frame_data = self.frame_data.get(frame_data).unwrap(); @@ -108,7 +110,8 @@ impl RenderPassBox { PhaseData { phase, frame_data, - viewport, + viewport_data, + bind_viewport, } } } @@ -131,7 +134,6 @@ impl RenderPassBoxTrait for RenderPassBox { fn record_render(&self, data: IndexedPhaseData) -> Option { let frame_data = self.get_frame_data(data); - // let render_pass = self.render_pass.read().unwrap(); self.render_pass.record_render(frame_data) } }