use super::*; use crate::scene::{DebugDrawList, DebugIndex as Index, DebugVertex as Vertex}; use crate::storage::GpuVec; use crate::viewport::ViewportInfo; use crate::RenderLayouts; use parking_lot::RwLock; pub struct FrameData { vertices: GpuVec, indices: GpuVec, } pub struct DebugPass { device: Arc, pipeline: wgpu::RenderPipeline, target_info: ViewportInfo, draw_list: RwLock, } impl DebugPass { pub fn new( device: Arc, layouts: Arc, target_info: ViewportInfo, ) -> Self { // TODO hook into ShaderStore system let shader = device.create_shader_module(wgpu::include_wgsl!("debug_shader.wgsl")); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("DebugPass Pipeline Layout"), bind_group_layouts: &[&layouts.bind_viewport], push_constant_ranges: &[], }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("DebugPass Pipeline"), layout: Some(&pipeline_layout), vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", buffers: &[Vertex::desc()], }, fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { format: target_info.output_format, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, })], }), primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::LineList, strip_index_format: None, front_face: wgpu::FrontFace::Ccw, cull_mode: None, polygon_mode: wgpu::PolygonMode::Fill, unclipped_depth: false, conservative: false, }, depth_stencil: Some(wgpu::DepthStencilState { format: target_info.depth_format, depth_write_enabled: false, depth_compare: wgpu::CompareFunction::Less, stencil: Default::default(), bias: Default::default(), }), multisample: wgpu::MultisampleState { count: 1, mask: !0, alpha_to_coverage_enabled: false, }, multiview: None, }); Self { device, pipeline, target_info, draw_list: Default::default(), } } pub fn add_draw_list(&self, draw_list: &DebugDrawList) { self.draw_list.write().merge(draw_list); } } impl RenderPass for DebugPass { type FrameData = FrameData; fn create_frame_data(&self) -> FrameData { FrameData { vertices: GpuVec::new( self.device.clone(), wgpu::BufferUsages::VERTEX, 1024 * 1024, Some("Debug Vertex Buffer".to_string()), false, ), indices: GpuVec::new( self.device.clone(), wgpu::BufferUsages::INDEX, 1024 * 1024, Some("Debug Index Buffer".to_string()), false, ), } } fn begin_frame(&self, data: &mut FrameData, phases: &mut Vec, queue: &wgpu::Queue) { phases.push(Phase::Overlay); use std::mem::replace; use std::ops::DerefMut; let mut draw_list_lock = self.draw_list.write(); let vertices = replace(&mut draw_list_lock.vertices, Default::default()); let indices = replace(&mut draw_list_lock.indices, Default::default()); let _ = replace(data.vertices.deref_mut(), vertices); let _ = replace(data.indices.deref_mut(), indices); data.vertices.write(queue); data.indices.write(queue); } fn record_render(&self, data: PhaseData<&FrameData>) -> Option { let mut cmds = self.device .create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor { label: Some("DebugPass Render Bundle"), color_formats: &[Some(self.target_info.output_format)], depth_stencil: Some(wgpu::RenderBundleDepthStencil { format: self.target_info.depth_format, depth_read_only: false, // TODO optimize? stencil_read_only: true, }), sample_count: 1, multiview: None, }); let vertices = &data.frame_data.vertices; let indices = &data.frame_data.indices; cmds.set_pipeline(&self.pipeline); cmds.set_bind_group(0, data.bind_viewport, &[]); cmds.set_vertex_buffer(0, vertices.as_ref().slice(..)); cmds.set_index_buffer(indices.as_ref().slice(..), wgpu::IndexFormat::Uint32); let index_range = 0..(indices.len() as u32); cmds.draw_indexed(index_range, 0, 0..1); Some(cmds.finish(&wgpu::RenderBundleDescriptor::default())) } }