#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