ddgi_probes_dbg.cpp

cross platform rendering playground

src/passes/ddgi/ddgi_probes_dbg.cpp

7.8 KB
#include "ddgi_probes_dbg.h"

#include "pipelines.h"
#include "renderer.h"
#include "shaders/renderer_types.h"

namespace ddgi_probes {
static const f32 PI = 3.14159265358979323846f;

void record(
    rhi::Device &device,
    Pipelines &pipelines,
    rhi::ShaderCompiler &sc,
    FrameGraph &fg,
    ImageHandle main,
    ImageHandle depth,
    ddgi_trace::Resources &res,
    DebugViewMode *debug_mode
) {

    rhi::RenderPipelineDesc ddgi_probe_p;
    ddgi_probe_p.device = &device;
    ddgi_probe_p.set_shaders(sc, "src/passes/ddgi/ddgi_probe.slang", "vsMain", "fsMain");
    ddgi_probe_p.set_depth_testing(true, true, rhi::PipelineCompareOp::GREATER_EQUAL);
    ddgi_probe_p.set_cull_mode(rhi::PipelineCullMode::NONE, rhi::PipelineTriangleWindingOrder::CW);
    ddgi_probe_p.set_blending();
    ddgi_probe_p.set_color_format(rhi::ImageFormat::RGBA16_FLOAT);
    ddgi_probe_p.set_depth_format(rhi::ImageFormat::D32_FLOAT);
    rhi::RenderPipeline &raw_pipeline = pipelines.add_render("DdgiProbe", ddgi_probe_p);

    rhi::RenderPipelineDesc ddgi_probe_atlas_p;
    ddgi_probe_atlas_p.device = &device;
    ddgi_probe_atlas_p.set_shaders(sc, "src/passes/ddgi/ddgi_probe.slang", "vsMain", "fsAtlasMain");
    ddgi_probe_atlas_p.set_depth_testing(true, true, rhi::PipelineCompareOp::GREATER_EQUAL);
    ddgi_probe_atlas_p.set_cull_mode(rhi::PipelineCullMode::NONE, rhi::PipelineTriangleWindingOrder::CW);
    ddgi_probe_atlas_p.set_blending();
    ddgi_probe_atlas_p.set_color_format(rhi::ImageFormat::RGBA16_FLOAT);
    ddgi_probe_atlas_p.set_depth_format(rhi::ImageFormat::D32_FLOAT);
    rhi::RenderPipeline &atlas_pipeline = pipelines.add_render("DdgiProbeAtlas", ddgi_probe_atlas_p);

    rhi::RenderPipelineDesc ddgi_probe_dist_p;
    ddgi_probe_dist_p.device = &device;
    ddgi_probe_dist_p.set_shaders(sc, "src/passes/ddgi/ddgi_probe.slang", "vsMain", "fsDistMain");
    ddgi_probe_dist_p.set_depth_testing(true, true, rhi::PipelineCompareOp::GREATER_EQUAL);
    ddgi_probe_dist_p.set_cull_mode(rhi::PipelineCullMode::NONE, rhi::PipelineTriangleWindingOrder::CW);
    ddgi_probe_dist_p.set_blending();
    ddgi_probe_dist_p.set_color_format(rhi::ImageFormat::RGBA16_FLOAT);
    ddgi_probe_dist_p.set_depth_format(rhi::ImageFormat::D32_FLOAT);
    rhi::RenderPipeline &distance_pipeline = pipelines.add_render("DdgiProbeDistance", ddgi_probe_dist_p);

    static const auto sphere_verts = []() {
        const u32 num_sides = 32;
        const u32 num_rings = 16;
        std::vector<vec4> v;
        v.reserve(num_sides * num_rings * 6);
        for (u32 r = 0; r < num_rings; r++) {
            f32 phi0 = (f32)(r) / (f32)num_rings * PI;
            f32 phi1 = (f32)(r + 1) / (f32)num_rings * PI;
            for (u32 s = 0; s < num_sides; s++) {
                f32 theta0 = (f32)(s) / (f32)num_sides * 2.0f * PI;
                f32 theta1 = (f32)(s + 1) / (f32)num_sides * 2.0f * PI;
                auto vert = [](f32 theta, f32 phi) {
                    return vec4(sinf(phi) * cosf(theta), cosf(phi), sinf(phi) * sinf(theta), 0.0f);
                };
                v.push_back(vert(theta0, phi0));
                v.push_back(vert(theta1, phi0));
                v.push_back(vert(theta0, phi1));
                v.push_back(vert(theta1, phi0));
                v.push_back(vert(theta1, phi1));
                v.push_back(vert(theta0, phi1));
            }
        }
        return v;
    }();

    u32 sphere_index_count = (u32)sphere_verts.size();
    u64 sphere_size = (u64)sphere_verts.size() * sizeof(vec4);

    auto sphere_vb = fg.add_buffer({
        .desc =
            {
                .size = sphere_size,
                .usage = rhi::BufferUsage::StorageBuffer | rhi::BufferUsage::ShaderAddr,
                .memory = rhi::BufferMemType::Upload,
            },
        .name = "fg/ddgi/probe-spheres",
    });

    fg.add_pass("DDGI Probes")
        .read(res.ray_samples, rhi::ResourceState::StorageRead)
        .read(res.probe_state, rhi::ResourceState::StorageRead)
        .read(res.irradiance_img, rhi::ResourceState::TextureSample)
        .read(res.distance_img, rhi::ResourceState::TextureSample)
        .write(main, rhi::ResourceState::ColorDraw)
        .write(depth, rhi::ResourceState::DepthDraw)
        .execute([=, &raw_pipeline, &atlas_pipeline, &distance_pipeline](PassContext &ctx) {
            // one-time upload of static sphere mesh
            {
                auto &buf = ctx.get_buffer(sphere_vb);
                if (buf.mapped) {
                    memcpy(buf.mapped, sphere_verts.data(), sphere_size);
                }
            }

            u64 sample_idx;
            rhi::RenderPipeline *p = nullptr;
            if (*debug_mode == DebugViewMode::PROBES_RAY_SAMPLES ||
                *debug_mode == DebugViewMode::PROBES_CLASSIFICATION) {
                p = &raw_pipeline;
                sample_idx = 0; // raw view reads rays via bda, no atlas sample
            } else if (*debug_mode == DebugViewMode::PROBES_IRRADIANCE) {
                p = &atlas_pipeline;
                sample_idx = (u64)ctx.view(res.irradiance_img);
            } else if (*debug_mode == DebugViewMode::PROBES_DISTANCE) {
                p = &distance_pipeline;
                sample_idx = (u64)ctx.view(res.distance_img);
            } else {
                return;
            }

            auto main_view = ctx.image_view(main, {.aspect = rhi::ImageAspect::Color, .mip_count = 1});
            auto depth_view = ctx.image_view(depth, {.aspect = rhi::ImageAspect::Depth, .mip_count = 1});

            rhi::AttachmentDesc color_att{};
            color_att.img = &main_view;
            color_att.loadOp = rhi::LoadOp::LOAD;
            color_att.storeOp = rhi::StoreOp::STORE;
            rhi::AttachmentDesc depth_att{};
            depth_att.img = &depth_view;
            depth_att.loadOp = rhi::LoadOp::LOAD;
            depth_att.storeOp = rhi::StoreOp::STORE;

            rhi::RenderingInfo ri{};
            ri.colorAttachments[0] = color_att;
            ri.colorAttachmentCount = 1;
            ri.depthAttachment = depth_att;
            ri.width = ctx.render_width;
            ri.height = ctx.render_height;

            rhi::begin_rendering(ctx.cmd, ri);
            rhi::set_pipeline(ctx.cmd, *p);

            rhi::Viewport vp{};
            vp.width = (f32)ctx.render_width;
            vp.height = (f32)ctx.render_height;
            rhi::set_viewports(ctx.cmd, &vp);
            rhi::Rect scissor{};
            scissor.width = (i32)ctx.render_width;
            scissor.height = (i32)ctx.render_height;
            rhi::set_scissors(ctx.cmd, &scissor);

            u32 probe_count = res.grid.probe_count;

            ProbeSpherePushConstants pc{};
            pc.frame = (u64)ctx.render_data->frame_ubo_view[ctx.frame_index].slot;
            pc.sphere_mesh = rhi::buffer_device_address(ctx.device, ctx.get_buffer(sphere_vb));
            pc.sphere_vertex_count = sphere_index_count;
            if (*debug_mode == DebugViewMode::PROBES_RAY_SAMPLES ||
                *debug_mode == DebugViewMode::PROBES_CLASSIFICATION) {
                pc.samples_buffer = rhi::buffer_device_address(ctx.device, ctx.get_buffer(res.ray_samples));
            } else {
                pc.samples_buffer = 0;
            }
            pc.atlas_sampled = (u32)sample_idx;
            pc.probe_state = rhi::buffer_device_address(ctx.device, ctx.get_buffer(res.probe_state));
            pc.debug_flag = *debug_mode;
            pc.rays_per_probe = RAYS_PER_PROBE;

            {
                static_assert(sizeof(pc) <= 128, "push constants exceed global 128B range");
                char pc128[128] = {};
                std::memcpy(pc128, &pc, sizeof(pc));
                rhi::set_constants(ctx.cmd, *p, rhi::ShaderStage::ALL, sizeof(pc128), pc128);
            }
            rhi::draw(ctx.cmd, sphere_index_count, probe_count, 0, 0);
            rhi::end_rendering(ctx.cmd);
        });
}

} // namespace ddgi_probes