gloss_renderer/forward_renderer/render_passes/
line_pipeline.rs1use std::collections::HashMap;
2
3use crate::{
4 components::{EdgesV1GPU, EdgesV2GPU, ModelMatrix, Name, Renderable, VisLines},
5 config::RenderConfig,
6 forward_renderer::{bind_group_collection::BindGroupCollection, locals::LocalEntData},
7 scene::Scene,
8};
9
10use easy_wgpu::{
11 bind_group::{BindGroupBuilder, BindGroupWrapper},
12 bind_group_layout::{BindGroupLayoutBuilder, BindGroupLayoutDesc},
13 buffer::Buffer,
14 gpu::Gpu,
15 pipeline::RenderPipelineDescBuilder,
16 utils::create_empty_group,
17};
18
19use gloss_hecs::Entity;
20
21use super::{pipeline_runner::PipelineRunner, upload_pass::PerFrameUniforms};
22
23use encase;
24use gloss_utils::numerical::align;
25
26#[include_wgsl_oil::include_wgsl_oil("../../../shaders/line_instanced.wgsl")]
28mod shader_code {}
29
30pub struct LinePipeline {
32 render_pipeline: wgpu::RenderPipeline,
33 _empty_group: wgpu::BindGroup,
34 locals_uniform: Buffer, locals_bind_groups: LocalsBindGroups,
36}
37
38impl LinePipeline {
39 pub fn new(gpu: &Gpu, params: &RenderConfig, color_target_format: wgpu::TextureFormat, depth_target_format: wgpu::TextureFormat) -> Self {
43 const_assert!(std::mem::size_of::<Locals>() % 16 == 0);
45
46 let render_pipeline = RenderPipelineDescBuilder::new()
48 .label("line_pipeline")
49 .shader_code(shader_code::SOURCE)
50 .shader_label("line_shader")
51 .add_bind_group_layout_desc(PerFrameUniforms::build_layout_desc())
52 .add_bind_group_layout_desc(LocalsBindGroups::build_layout_desc())
54 .add_vertex_buffer_layout(EdgesV1GPU::vertex_buffer_layout_instanced::<0>())
57 .add_vertex_buffer_layout(EdgesV2GPU::vertex_buffer_layout_instanced::<1>())
58 .add_render_target(wgpu::ColorTargetState {
59 format: color_target_format,
60 blend: None,
61 write_mask: wgpu::ColorWrites::ALL,
62 })
63 .depth_state(Some(wgpu::DepthStencilState {
64 format: depth_target_format,
65 depth_write_enabled: true,
66 depth_compare: wgpu::CompareFunction::Greater, stencil: wgpu::StencilState::default(), bias: wgpu::DepthBiasState::default(),
69 }))
70 .multisample(wgpu::MultisampleState {
71 count: params.msaa_nr_samples,
72 ..Default::default()
73 })
74 .build_pipeline(gpu.device());
75
76 let empty_group = create_empty_group(gpu.device());
77
78 let size_bytes = 0x10000;
79 let usage = wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM;
80 let locals_uniform = Buffer::new_empty(gpu.device(), usage, Some("local_buffer"), size_bytes);
81
82 let locals_bind_groups = LocalsBindGroups::new(gpu);
83
84 Self {
85 render_pipeline,
86 _empty_group: empty_group,
87 locals_uniform,
88 locals_bind_groups,
89 }
90 }
91}
92
93impl PipelineRunner for LinePipeline {
94 type QueryItems<'a> = (&'a EdgesV1GPU, &'a EdgesV2GPU, &'a VisLines, &'a Name);
95 type QueryState<'a> = gloss_hecs::QueryBorrow<'a, gloss_hecs::With<Self::QueryItems<'a>, &'a Renderable>>;
96
97 fn query_state(scene: &Scene) -> Self::QueryState<'_> {
98 scene.world.query::<Self::QueryItems<'_>>().with::<&Renderable>()
99 }
100 fn prepare<'a>(&mut self, gpu: &Gpu, _per_frame_uniforms: &PerFrameUniforms, scene: &'a Scene) -> Self::QueryState<'a> {
101 self.begin_pass();
102 self.update_locals(gpu, scene);
103 Self::query_state(scene)
104 }
105 fn run<'r>(
106 &'r mut self,
107 render_pass: &mut wgpu::RenderPass<'r>,
108 per_frame_uniforms: &'r PerFrameUniforms,
109 _render_params: &RenderConfig,
110 query_state: &'r mut Self::QueryState<'_>,
111 _scene: &Scene,
112 ) {
113 if query_state.iter().count() == 0 {
115 return;
116 }
117 render_pass.set_pipeline(&self.render_pipeline);
118
119 render_pass.set_bind_group(0, &per_frame_uniforms.bind_group, &[]);
121
122 for (_id, (ev1, ev2, vis_lines, name)) in query_state.iter() {
125 if !vis_lines.show_lines {
126 continue;
127 }
128 let (local_bg, offset) = &self.locals_bind_groups.mesh2local_bind[&name.0.clone()];
130 render_pass.set_bind_group(1, local_bg.bg(), &[*offset]);
131 render_pass.set_vertex_buffer(0, ev1.buf.slice(..));
132 render_pass.set_vertex_buffer(1, ev2.buf.slice(..));
133 render_pass.draw(0..6, 0..ev1.nr_vertices);
134 }
135 }
136
137 fn begin_pass(&mut self) {}
138
139 fn update_locals(&mut self, gpu: &Gpu, scene: &Scene) {
140 Self::update_locals_inner::<Locals, _>(
141 gpu,
142 scene,
143 &mut self.locals_uniform,
144 &mut self.locals_bind_groups,
145 &mut Self::query_state(scene),
146 );
147 }
148}
149
150#[repr(C)]
152#[derive(Clone, Copy, encase::ShaderType)]
153struct Locals {
154 model_matrix: nalgebra::Matrix4<f32>,
155 color_type: i32,
156 line_color: nalgebra::Vector4<f32>,
157 line_width: f32,
158 zbuffer: u32,
159 antialias_edges: u32,
160 is_floor: u32,
161 pad_b: f32,
163 pad_c: f32,
164 pad_d: f32,
165}
166impl LocalEntData for Locals {
167 fn new(entity: Entity, scene: &Scene) -> Self {
168 let model_matrix = scene.get_comp::<&ModelMatrix>(&entity).unwrap().0.to_homogeneous();
169 let vis_lines = scene.get_comp::<&VisLines>(&entity).unwrap();
170 let color_type = vis_lines.color_type as i32;
171 let is_floor = if let Some(floor) = scene.get_floor() {
172 floor.entity == entity
173 } else {
174 false
175 };
176 let is_floor = u32::from(is_floor);
177 Locals {
178 model_matrix,
179 color_type,
180 line_color: vis_lines.line_color,
181 line_width: vis_lines.line_width,
182 zbuffer: u32::from(vis_lines.zbuffer),
183 antialias_edges: u32::from(vis_lines.antialias_edges),
184 is_floor,
185 pad_b: 0.0,
186 pad_c: 0.0,
187 pad_d: 0.0,
188 }
189 }
190}
191
192struct LocalsBindGroups {
193 layout: wgpu::BindGroupLayout,
194 pub mesh2local_bind: HashMap<String, (BindGroupWrapper, u32)>,
195}
196impl BindGroupCollection for LocalsBindGroups {
197 fn new(gpu: &Gpu) -> Self {
198 Self {
199 layout: Self::build_layout_desc().into_bind_group_layout(gpu.device()),
200 mesh2local_bind: HashMap::default(),
201 }
202 }
203
204 fn build_layout_desc() -> BindGroupLayoutDesc {
205 BindGroupLayoutBuilder::new()
206 .label("gbuffer_pass_locals_layout")
207 .add_entry_uniform(
209 wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
210 true,
211 wgpu::BufferSize::new(u64::from(align(u32::try_from(std::mem::size_of::<Locals>()).unwrap(), 256))),
212 )
213 .build()
214 }
215
216 fn update_bind_group(&mut self, _entity: Entity, gpu: &Gpu, mesh_name: &str, ubo: &Buffer, offset_in_ubo: u32, _scene: &Scene) {
217 let entries = BindGroupBuilder::new().add_entry_buf_chunk::<Locals>(&ubo.buffer).build_entries();
218
219 self.update_if_stale(mesh_name, entries, offset_in_ubo, gpu);
220 }
221
222 fn get_layout(&self) -> &wgpu::BindGroupLayout {
223 &self.layout
224 }
225 fn get_mut_entity2binds(&mut self) -> &mut HashMap<String, (BindGroupWrapper, u32)> {
226 &mut self.mesh2local_bind
227 }
228}