1use std::{cell::Cell, mem, ptr};
2
3#[derive(Clone, Copy, Debug, Default)]
4pub struct DebugBlit {
5 pub input: blade_graphics::TextureView,
6 pub mip_level: u32,
7 pub target_offset: [i32; 2],
8 pub target_size: [u32; 2],
9}
10
11#[repr(C)]
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct DebugPoint {
14 pub pos: [f32; 3],
15 pub color: u32,
16}
17
18#[repr(C)]
19#[derive(Clone, Copy, Debug, PartialEq)]
20pub struct DebugLine {
21 pub a: DebugPoint,
22 pub b: DebugPoint,
23}
24
25#[derive(blade_macros::ShaderData)]
26struct DebugDrawData {
27 camera: super::CameraParams,
28 debug_lines: blade_graphics::BufferPiece,
29 depth: blade_graphics::TextureView,
30}
31
32#[repr(C)]
33#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
34struct DebugBlitParams {
35 target_offset: [f32; 2],
36 target_size: [f32; 2],
37 mip_level: f32,
38 unused: u32,
39}
40
41#[derive(blade_macros::ShaderData)]
42struct DebugBlitData {
43 input: blade_graphics::TextureView,
44 samp: blade_graphics::Sampler,
45 params: DebugBlitParams,
46}
47
48#[repr(C)]
50#[derive(Debug)]
51pub struct DebugVariance {
52 pub color_sum: [f32; 3],
53 pad: u32,
54 pub color2_sum: [f32; 3],
55 pub count: u32,
56}
57
58#[repr(C)]
60#[derive(Debug)]
61pub struct DebugEntry {
62 pub custom_index: u32,
63 pub depth: f32,
64 pub tex_coords: [f32; 2],
65 pub base_color_texture: u32,
66 pub normal_texture: u32,
67 pad: [u32; 2],
68 pub position: [f32; 3],
69 position_w: f32,
70 pub normal: [f32; 3],
71 normal_w: f32,
72}
73
74fn create_draw_pipeline(
75 shader: &blade_graphics::Shader,
76 format: blade_graphics::TextureFormat,
77 gpu: &blade_graphics::Context,
78) -> blade_graphics::RenderPipeline {
79 shader.check_struct_size::<DebugPoint>();
80 shader.check_struct_size::<DebugLine>();
81 let layout = <DebugDrawData as blade_graphics::ShaderData>::layout();
82 gpu.create_render_pipeline(blade_graphics::RenderPipelineDesc {
83 name: "debug-draw",
84 data_layouts: &[&layout],
85 vertex: shader.at("debug_vs"),
86 vertex_fetches: &[],
87 primitive: blade_graphics::PrimitiveState {
88 topology: blade_graphics::PrimitiveTopology::LineList,
89 ..Default::default()
90 },
91 depth_stencil: None,
92 fragment: Some(shader.at("debug_fs")),
93 color_targets: &[blade_graphics::ColorTargetState {
94 format,
95 blend: Some(blade_graphics::BlendState::ALPHA_BLENDING),
96 write_mask: blade_graphics::ColorWrites::all(),
97 }],
98 multisample_state: blade_graphics::MultisampleState::default(),
99 })
100}
101
102fn create_blit_pipeline(
103 shader: &blade_graphics::Shader,
104 format: blade_graphics::TextureFormat,
105 gpu: &blade_graphics::Context,
106) -> blade_graphics::RenderPipeline {
107 shader.check_struct_size::<DebugBlitParams>();
108 let layout = <DebugBlitData as blade_graphics::ShaderData>::layout();
109 gpu.create_render_pipeline(blade_graphics::RenderPipelineDesc {
110 name: "debug-blit",
111 data_layouts: &[&layout],
112 vertex: shader.at("blit_vs"),
113 vertex_fetches: &[],
114 primitive: blade_graphics::PrimitiveState {
115 topology: blade_graphics::PrimitiveTopology::TriangleStrip,
116 ..Default::default()
117 },
118 depth_stencil: None,
119 fragment: Some(shader.at("blit_fs")),
120 color_targets: &[format.into()],
121 multisample_state: blade_graphics::MultisampleState::default(),
122 })
123}
124
125pub struct DebugRender {
126 capacity: u32,
127 surface_format: blade_graphics::TextureFormat,
128 buffer: blade_graphics::Buffer,
129 variance_buffer: blade_graphics::Buffer,
130 entry_buffer: blade_graphics::Buffer,
131 cpu_lines_buffer: blade_graphics::Buffer,
132 cpu_lines_offset: Cell<u64>,
134 draw_pipeline: blade_graphics::RenderPipeline,
135 blit_pipeline: blade_graphics::RenderPipeline,
136 line_size: u32,
137 buffer_size: u32,
138}
139
140impl DebugRender {
141 pub(super) fn init(
142 encoder: &mut blade_graphics::CommandEncoder,
143 gpu: &blade_graphics::Context,
144 shader_draw: &blade_graphics::Shader,
145 shader_blit: &blade_graphics::Shader,
146 capacity: u32,
147 surface_info: blade_graphics::SurfaceInfo,
148 ) -> Self {
149 let line_size = shader_draw.get_struct_size("DebugLine");
150 let buffer_size = shader_draw.get_struct_size("DebugBuffer");
151 let this = Self {
152 capacity,
153 surface_format: surface_info.format,
154 buffer: gpu.create_buffer(blade_graphics::BufferDesc {
155 name: "debug",
156 size: (buffer_size + capacity.saturating_sub(1) * line_size) as u64,
157 memory: blade_graphics::Memory::Device,
158 }),
159 variance_buffer: gpu.create_buffer(blade_graphics::BufferDesc {
160 name: "variance",
161 size: mem::size_of::<DebugVariance>() as u64,
162 memory: blade_graphics::Memory::Shared,
163 }),
164 entry_buffer: gpu.create_buffer(blade_graphics::BufferDesc {
165 name: "debug entry",
166 size: mem::size_of::<DebugEntry>() as u64,
167 memory: blade_graphics::Memory::Shared,
168 }),
169 cpu_lines_buffer: gpu.create_buffer(blade_graphics::BufferDesc {
170 name: "CPU debug lines",
171 size: (capacity * line_size) as u64,
172 memory: blade_graphics::Memory::Shared,
173 }),
174 cpu_lines_offset: Cell::new(0),
175 draw_pipeline: create_draw_pipeline(shader_draw, surface_info.format, gpu),
176 blit_pipeline: create_blit_pipeline(shader_blit, surface_info.format, gpu),
177 line_size,
178 buffer_size,
179 };
180
181 let init_data = [2u32, 0, 0, 0, capacity];
182 let init_size = init_data.len() * mem::size_of::<u32>();
183 assert!(init_size <= mem::size_of::<DebugEntry>());
184 unsafe {
185 ptr::write_bytes(
186 this.variance_buffer.data(),
187 0,
188 mem::size_of::<DebugVariance>(),
189 );
190 ptr::write_bytes(this.entry_buffer.data(), 0, mem::size_of::<DebugEntry>());
191 ptr::copy_nonoverlapping(
193 init_data.as_ptr(),
194 this.entry_buffer.data() as *mut u32,
195 init_data.len(),
196 );
197 }
198
199 let mut transfers = encoder.transfer("upload debug");
200 transfers.copy_buffer_to_buffer(
201 this.entry_buffer.at(0),
202 this.buffer.at(0),
203 init_size as u64,
204 );
205
206 this
207 }
208
209 pub(super) fn destroy(&mut self, gpu: &blade_graphics::Context) {
210 gpu.destroy_buffer(self.buffer);
211 gpu.destroy_buffer(self.variance_buffer);
212 gpu.destroy_buffer(self.entry_buffer);
213 gpu.destroy_buffer(self.cpu_lines_buffer);
214 gpu.destroy_render_pipeline(&mut self.draw_pipeline);
215 gpu.destroy_render_pipeline(&mut self.blit_pipeline);
216 }
217
218 pub(super) fn recreate_draw_pipeline(
219 &mut self,
220 shader: &blade_graphics::Shader,
221 gpu: &blade_graphics::Context,
222 ) {
223 assert_eq!(shader.get_struct_size("DebugLine"), self.line_size);
224 assert_eq!(shader.get_struct_size("DebugBuffer"), self.buffer_size);
225 self.draw_pipeline = create_draw_pipeline(shader, self.surface_format, gpu);
226 }
227
228 pub(super) fn recreate_blit_pipeline(
229 &mut self,
230 shader: &blade_graphics::Shader,
231 gpu: &blade_graphics::Context,
232 ) {
233 self.draw_pipeline = create_blit_pipeline(shader, self.surface_format, gpu);
234 }
235
236 fn add_lines(&self, lines: &[DebugLine]) -> (blade_graphics::BufferPiece, u32) {
237 let required_size = lines.len() as u64 * self.line_size as u64;
238 let old_offset = self.cpu_lines_offset.get();
239 let (original_offset, count) =
240 if old_offset + required_size <= (self.capacity * self.line_size) as u64 {
241 (old_offset, lines.len())
242 } else {
243 let count = lines.len().min(self.capacity as usize);
244 if count < lines.len() {
245 log::warn!("Reducing the debug lines from {} to {}", lines.len(), count);
246 }
247 (0, count)
248 };
249
250 unsafe {
251 ptr::copy_nonoverlapping(
252 lines.as_ptr(),
253 self.cpu_lines_buffer.data().add(original_offset as usize) as *mut DebugLine,
254 count,
255 );
256 }
257
258 self.cpu_lines_offset
259 .set(original_offset + count as u64 * self.line_size as u64);
260 (self.cpu_lines_buffer.at(original_offset), count as u32)
261 }
262
263 pub(super) fn render_lines(
264 &self,
265 debug_lines: &[DebugLine],
266 camera: super::CameraParams,
267 depth: blade_graphics::TextureView,
268 pass: &mut blade_graphics::RenderCommandEncoder,
269 ) {
270 let mut pc = pass.with(&self.draw_pipeline);
271 let lines_offset = 32 + mem::size_of::<DebugVariance>() + mem::size_of::<DebugEntry>();
272 pc.bind(
273 0,
274 &DebugDrawData {
275 camera,
276 debug_lines: self.buffer.at(lines_offset as u64),
277 depth,
278 },
279 );
280 pc.draw_indirect(self.buffer.at(0));
281
282 if !debug_lines.is_empty() {
283 let (lines_buf, count) = self.add_lines(debug_lines);
284 pc.bind(
285 0,
286 &DebugDrawData {
287 camera,
288 debug_lines: lines_buf,
289 depth,
290 },
291 );
292 pc.draw(0, 2, 0, count);
293 }
294 }
295
296 pub(super) fn render_blits(
297 &self,
298 debug_blits: &[DebugBlit],
299 samp: blade_graphics::Sampler,
300 screen_size: blade_graphics::Extent,
301 pass: &mut blade_graphics::RenderCommandEncoder,
302 ) {
303 let mut pc = pass.with(&self.blit_pipeline);
304 for db in debug_blits {
305 pc.bind(
306 0,
307 &DebugBlitData {
308 input: db.input,
309 samp,
310 params: DebugBlitParams {
311 target_offset: [
312 db.target_offset[0] as f32 / screen_size.width as f32,
313 db.target_offset[1] as f32 / screen_size.height as f32,
314 ],
315 target_size: [
316 db.target_size[0] as f32 / screen_size.width as f32,
317 db.target_size[1] as f32 / screen_size.height as f32,
318 ],
319 mip_level: db.mip_level as f32,
320 unused: 0,
321 },
322 },
323 );
324 pc.draw(0, 4, 0, 1);
325 }
326 }
327
328 pub fn buffer_resource(&self) -> blade_graphics::BufferPiece {
329 self.buffer.into()
330 }
331
332 pub fn enable_draw(&self, transfer: &mut blade_graphics::TransferCommandEncoder, enable: bool) {
333 transfer.fill_buffer(self.buffer.at(20), 4, enable as _);
334 }
335
336 pub fn reset_lines(&self, transfer: &mut blade_graphics::TransferCommandEncoder) {
337 transfer.fill_buffer(self.buffer.at(4), 4, 0);
338 }
339
340 pub fn reset_variance(&self, transfer: &mut blade_graphics::TransferCommandEncoder) {
341 transfer.fill_buffer(
342 self.buffer.at(32),
343 mem::size_of::<DebugVariance>() as u64,
344 0,
345 );
346 }
347
348 pub fn update_variance(&self, transfer: &mut blade_graphics::TransferCommandEncoder) {
350 transfer.copy_buffer_to_buffer(
351 self.buffer.at(32),
352 self.variance_buffer.into(),
353 mem::size_of::<DebugVariance>() as u64,
354 );
355 }
356
357 pub fn update_entry(&self, transfer: &mut blade_graphics::TransferCommandEncoder) {
359 transfer.copy_buffer_to_buffer(
360 self.buffer.at(32 + mem::size_of::<DebugVariance>() as u64),
361 self.entry_buffer.into(),
362 mem::size_of::<DebugEntry>() as u64,
363 );
364 }
365
366 pub fn read_shared_data(&self) -> (&DebugVariance, &DebugEntry) {
367 let db_v = unsafe { &*(self.variance_buffer.data() as *const DebugVariance) };
368 let db_e = unsafe { &*(self.entry_buffer.data() as *const DebugEntry) };
369 (db_v, db_e)
370 }
371}