cvkg_render_gpu/passes/
geometry.rs1use crate::kvasir::node::{ExecutionContext, KvasirNode};
2use crate::kvasir::nodes::{PassId, RES_SCENE};
3use crate::kvasir::resource::ResourceId;
4
5pub struct GeometryNode {
6 pub inputs: Vec<ResourceId>,
7 pub outputs: Vec<ResourceId>,
8}
9
10impl GeometryNode {
11 pub fn new() -> Self {
12 Self {
13 inputs: vec![],
14 outputs: vec![RES_SCENE],
15 }
16 }
17}
18
19impl Default for GeometryNode {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl KvasirNode for GeometryNode {
26 fn label(&self) -> &'static str {
27 "Geometry"
28 }
29
30 fn inputs(&self) -> &[ResourceId] {
31 &self.inputs
32 }
33
34 fn outputs(&self) -> &[ResourceId] {
35 &self.outputs
36 }
37
38 fn pass_id(&self) -> PassId {
39 PassId::Geometry
40 }
41
42 fn execute(&self, ctx: &mut ExecutionContext) {
43 let scale = ctx.renderer.current_scale_factor();
44 let rt_w = ctx.renderer.current_width() as i32;
45 let rt_h = ctx.renderer.current_height() as i32;
46
47 let scene_view = match ctx.registry.get_texture_view(RES_SCENE) {
48 Some(v) => v,
49 None => {
50 log::error!("Missing texture view for {}", stringify!(RES_SCENE));
51 return;
52 }
53 };
54 let msaa_view = match ctx
55 .registry
56 .get_texture_view(crate::kvasir::nodes::RES_SCENE_MSAA)
57 {
58 Some(v) => v,
59 None => {
60 log::error!(
61 "Missing texture view for {}",
62 stringify!(crate::kvasir::nodes::RES_SCENE_MSAA)
63 );
64 return;
65 }
66 };
67 let depth_view = ctx.depth_view;
68
69 let bg = ctx.renderer.default_background_color;
70 let mut p = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
71 label: Some("Surtr P1 Opaque Background"),
72 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
73 view: &msaa_view,
74 resolve_target: Some(&scene_view),
75 ops: wgpu::Operations {
76 load: wgpu::LoadOp::Clear(wgpu::Color {
77 r: bg[0] as f64,
78 g: bg[1] as f64,
79 b: bg[2] as f64,
80 a: bg[3] as f64,
81 }),
82 store: wgpu::StoreOp::Store,
83 },
84 depth_slice: None,
85 })],
86 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
87 view: depth_view,
88 depth_ops: Some(wgpu::Operations {
89 load: wgpu::LoadOp::Clear(1.0),
90 store: wgpu::StoreOp::Store,
91 }),
92 stencil_ops: None,
93 }),
94 timestamp_writes: ctx.renderer.skuld_queries.as_ref().map(|q| {
95 wgpu::RenderPassTimestampWrites {
96 query_set: q,
97 beginning_of_pass_write_index: Some(0),
98 end_of_pass_write_index: None,
99 }
100 }),
101 occlusion_query_set: None,
102 multiview_mask: None,
103 });
104
105 if ctx.renderer.current_scene.scene_type == cvkg_core::SCENE_AURORA {
106 p.set_pipeline(&ctx.renderer.background_pipeline);
107 p.set_bind_group(0, &ctx.renderer.dummy_texture_bind_group, &[]);
108 p.set_bind_group(1, &ctx.renderer.dummy_env_bind_group, &[]);
109 p.set_bind_group(2, &ctx.renderer.berserker_bind_group, &[]);
110 p.set_bind_group(3, &ctx.renderer.gradient_bind_group, &[]);
111 p.draw(0..3, 0..1);
112 }
113
114 if !ctx.renderer.draw_calls.is_empty() {
115 log::trace!(
116 "[Kvasir] GeometryNode: draw_calls={}",
117 ctx.renderer.draw_calls.len()
118 );
119 for (i, call) in ctx.renderer.draw_calls.iter().enumerate() {
120 log::trace!(
121 "[Kvasir] call[{}]: material={:?}, target_id={:?}, index_start={}, index_count={}",
122 i,
123 call.material,
124 call.target_id,
125 call.index_start,
126 call.index_count
127 );
128 }
129 p.set_vertex_buffer(0, ctx.renderer.geometry_buffers.vertex_buffer.slice(..));
130 p.set_vertex_buffer(1, ctx.renderer.geometry_buffers.instance_buffer.slice(..));
131 p.set_index_buffer(
132 ctx.renderer.geometry_buffers.index_buffer.slice(..),
133 wgpu::IndexFormat::Uint32,
134 );
135 p.set_bind_group(1, &ctx.renderer.dummy_env_bind_group, &[]);
136 p.set_bind_group(2, &ctx.renderer.berserker_bind_group, &[]);
137 p.set_bind_group(3, &ctx.renderer.gradient_bind_group, &[]);
138
139 let mut opaque_calls_count = 0;
147 for call in ctx.renderer.draw_calls.iter().filter(|c| {
148 (matches!(c.material, cvkg_core::DrawMaterial::Opaque)
149 || matches!(c.material, cvkg_core::DrawMaterial::Blend { .. }))
150 && c.target_id.is_none()
151 }) {
152 opaque_calls_count += 1;
153 p.set_pipeline(&ctx.renderer.opaque_pipeline);
154
155 if let Some(rect) = call.scissor_rect
159 && rt_w > 0
160 && rt_h > 0
161 {
162 let x1 = (rect.x * scale).round() as i32;
163 let y1 = (rect.y * scale).round() as i32;
164 let x2 = ((rect.x + rect.width) * scale).round() as i32;
165 let y2 = ((rect.y + rect.height) * scale).round() as i32;
166 let w = (x2 - x1).clamp(0, rt_w);
167 let h = (y2 - y1).clamp(0, rt_h);
168 if w > 0 && h > 0 {
169 p.set_scissor_rect(x1 as u32, y1 as u32, w as u32, h as u32);
170 } else {
171 p.set_scissor_rect(0, 0, 0, 0);
177 }
178 } else {
179 p.set_scissor_rect(0, 0, rt_w as u32, rt_h as u32);
180 }
181
182 let bg = if let Some(id) = call.texture_id {
183 if id == 0 {
184 &ctx.renderer.mega_heim_bind_group
185 } else {
186 ctx.renderer
187 .texture_bind_groups
188 .get(id as usize)
189 .unwrap_or(&ctx.renderer.dummy_texture_bind_group)
190 }
191 } else {
192 &ctx.renderer.dummy_texture_bind_group
193 };
194 p.set_bind_group(0, bg, &[]);
195 p.draw_indexed(
196 call.index_start..call.index_start + call.index_count,
197 0,
198 call.instance_start..call.instance_start + call.instance_count,
199 );
200 }
201 log::trace!(
202 "[Kvasir] GeometryNode: opaque_calls drawn={}",
203 opaque_calls_count
204 );
205 }
206 }
207}