renderling/
debug.rs

1//! Debug overlay.
2#[cfg(cpu)]
3mod cpu;
4#[cfg(cpu)]
5pub use cpu::*;
6
7pub mod shader {
8    use crabslab::{Id, Slab};
9    use glam::{Vec2, Vec3Swizzles, Vec4, Vec4Swizzles};
10    use spirv_std::{arch::IndexUnchecked, spirv};
11
12    use crate::{
13        draw::DrawIndirectArgs, geometry::shader::GeometryDescriptor,
14        primitive::shader::PrimitiveDescriptor, sdf, transform::shader::TransformDescriptor,
15    };
16    /// Renders an implicit quad.
17    #[spirv(vertex)]
18    pub fn debug_overlay_vertex(
19        #[spirv(vertex_index)] vertex_id: u32,
20        #[spirv(position)] clip_pos: &mut Vec4,
21    ) {
22        *clip_pos = crate::math::CLIP_SPACE_COORD_QUAD_CCW[vertex_id as usize % 6];
23    }
24
25    /// Renders a debug overlay on top of the current framebuffer.
26    ///
27    /// Displays useful information in real time.
28    #[spirv(fragment)]
29    pub fn debug_overlay_fragment(
30        #[spirv(storage_buffer, descriptor_set = 0, binding = 0)] slab: &[u32],
31        #[spirv(storage_buffer, descriptor_set = 0, binding = 1)] draw_calls: &[DrawIndirectArgs],
32        #[spirv(frag_coord)] frag_coord: Vec4,
33        frag_color: &mut Vec4,
34    ) {
35        let camera_id_id = Id::from(GeometryDescriptor::OFFSET_OF_CAMERA_ID);
36        let camera_id = slab.read_unchecked(camera_id_id);
37        let camera = slab.read_unchecked(camera_id);
38        let resolution_id = Id::from(GeometryDescriptor::OFFSET_OF_RESOLUTION);
39        let viewport_size = slab.read_unchecked(resolution_id);
40
41        *frag_color = Vec4::ZERO;
42
43        for i in 0..draw_calls.len() {
44            let draw_call = unsafe { draw_calls.index_unchecked(i) };
45            let primitive_id: Id<PrimitiveDescriptor> =
46                Id::<PrimitiveDescriptor>::new(draw_call.first_instance);
47            let transform_id =
48                slab.read_unchecked(primitive_id + PrimitiveDescriptor::OFFSET_OF_TRANSFORM_ID);
49            let mut model = TransformDescriptor::IDENTITY;
50            slab.read_into_if_some::<TransformDescriptor>(transform_id, &mut model);
51            let bounds = slab.read_unchecked(primitive_id + PrimitiveDescriptor::OFFSET_OF_BOUNDS);
52
53            let (_, sphere_in_world_coords) = bounds.is_inside_camera_view(&camera, model);
54            let sphere_aabb = sphere_in_world_coords.project_onto_viewport(
55                &camera,
56                Vec2::new(viewport_size.x as f32, viewport_size.y as f32),
57            );
58
59            let sdf_circle = sdf::Box {
60                center: sphere_aabb.center().xy(),
61                half_extent: (sphere_aabb.max.xy() - sphere_aabb.min.xy()) * 0.5,
62            };
63
64            let distance = sdf_circle.distance(frag_coord.xy() + 0.5);
65
66            // Here we use `step_le`, which I have annotated with `#inline(always)`.
67            // I did this because without it, it seems to do the opposite of expected.
68            // I found this by inlining by hand.
69            let alpha = crate::math::step_le(sphere_aabb.max.z, 1.0);
70            if distance.abs() < 0.5 {
71                *frag_color = Vec4::new(0.0, 0.0, 0.0, 1.0 * alpha);
72            } else if distance.abs() <= 2.0 {
73                *frag_color = Vec4::new(1.0, 1.0, 1.0, 0.5 * alpha);
74            } else if distance.abs() <= 3.0 {
75                *frag_color = Vec4::new(0.5, 0.5, 0.5, 1.0 * alpha);
76            }
77        }
78    }
79}