cluster_bounds.cpp

cross platform rendering playground

src/passes/cluster/cluster_bounds.cpp

2.76 KB
#include "cluster_bounds.h"

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

namespace cluster_bounds {

static u64 cluster_total(u32 w, u32 h) {
    return (u64)((w + TILE_SIZE_X - 1) / TILE_SIZE_X) * ((h + TILE_SIZE_Y - 1) / TILE_SIZE_Y) * CLUSTER_COUNT_Z;
}
static u64 cluster_bounds_size(u32 w, u32 h) {
    return cluster_total(w, h) * sizeof(ClusterBounds);
}
static u64 cluster_records_size(u32 w, u32 h) {
    return cluster_total(w, h) * sizeof(ClusterRecord);
}

Resources
record(rhi::Device &device, Pipelines &pipelines, rhi::ShaderCompiler &sc, FrameGraph &fg, u32 width, u32 height) {

    rhi::ComputePipelineDesc pd;
    pd.device = &device;
    pd.set_shader(sc, "src/passes/cluster/cluster_bounds.slang", "csMain");
    rhi::ComputePipeline &pipeline = pipelines.add_compute("ClusterBounds", pd);

    Resources out;
    out.cluster_bounds = fg.add_buffer({
        .desc = {.usage = rhi::BufferUsage::StorageBuffer | rhi::BufferUsage::ShaderAddr},
        .name = "fg/cluster/bounds",
        .size_fn = cluster_bounds_size,
    });
    out.cluster_records = fg.add_buffer({
        .desc = {.usage = rhi::BufferUsage::StorageBuffer | rhi::BufferUsage::ShaderAddr},
        .name = "fg/cluster/records",
        .size_fn = cluster_records_size,
    });

    auto &builder = fg.add_pass("ClusterBounds");
    builder.write(out.cluster_bounds, rhi::ResourceState::StorageReadWrite);

    builder.execute([=, &pipeline](PassContext &ctx) {
        auto &frame = ctx.frame_data[ctx.frame_index];

        u32 cx = (ctx.render_width + TILE_SIZE_X - 1) / TILE_SIZE_X;
        u32 cy = (ctx.render_height + TILE_SIZE_Y - 1) / TILE_SIZE_Y;
        u32 cz = CLUSTER_COUNT_Z;
        u32 total_clusters = cx * cy * cz;

        rhi::set_pipeline(ctx.cmd, pipeline);

        ClusterGrid cb{
            .cluster_count_x = cx,
            .cluster_count_y = cy,
            .cluster_count_z = cz,
            .cluster_total = total_clusters,
            .clusters_bounds = rhi::buffer_device_address(ctx.device, ctx.get_buffer(out.cluster_bounds)),
        };
        memcpy((u8 *)frame.frame_ubo.mapped + offsetof(FrameUBO, cluster), &cb, sizeof(ClusterGrid));

        ClusterBoundsPushConstants pc{};
        pc.frame = (u64)ctx.render_data->frame_ubo_view[ctx.frame_index].slot;
        {
            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, pipeline, rhi::ShaderStage::ALL, sizeof(pc128), pc128);
        }

        u32 total = cx * cy * cz;
        u32 groups = (total + 63u) / 64u;
        if (groups > 0) {
            rhi::dispatch(ctx.cmd, groups);
        }
    });
    return out;
}

} // namespace cluster_bounds