#include "shared.h"
#include "renderer_types.h"
[[vk::push_constant]]
HiZPushConstants pc;
[numthreads(16, 16, 1)]
void csMain(uvec3 gtid: SV_GroupThreadID, uvec3 gid: SV_GroupID) {
uvec2 src_size = uvec2(pc.src_width, pc.src_height);
uvec2 dst_size = max(uvec2(1, 1), src_size >> 1);
uvec2 px = gid.xy * 16 + gtid.xy;
if (px.x >= dst_size.x || px.y >= dst_size.y)
return;
uvec2 sx = px * 2;
uvec2 p0 = min(sx + uvec2(0, 0), src_size - 1);
uvec2 p1 = min(sx + uvec2(1, 0), src_size - 1);
uvec2 p2 = min(sx + uvec2(0, 1), src_size - 1);
uvec2 p3 = min(sx + uvec2(1, 1), src_size - 1);
f32 d0, d1, d2, d3;
if (pc.mip_level == 0) {
d0 = pc.depth[p0].r; // reverse-Z depth buffer
d1 = pc.depth[p1].r;
d2 = pc.depth[p2].r;
d3 = pc.depth[p3].r;
} else {
int src_mip = int(pc.mip_level) - 1;
d0 = pc.hiz_src.Load(ivec3(p0, src_mip)).r;
d1 = pc.hiz_src.Load(ivec3(p1, src_mip)).r;
d2 = pc.hiz_src.Load(ivec3(p2, src_mip)).r;
d3 = pc.hiz_src.Load(ivec3(p3, src_mip)).r;
}
// NOTE: I'm yet to truly wrap up hiz, and I've looked into it twice
// so the long comment stays
// MAX reduction: stores the closest depth per 2×2 block
// (reverse-Z: larger values = closer to camera)
// storage_images[pc.hiz_dst_idx][px] = max(max(d0, d1), max(d2, d3));
// MIN reduction: stores the farthest (smallest) depth per 2×2 block.
// Reverse-Z: 0.0 = far plane, 1.0 = near plane.
// Conservative occlusion testing needs the FARTHEST occluder in the region
// (= smallest value in reverse-Z) to avoid false occlusion:
// "is the entire object behind everything in this tile?"
// MIN is correct here, NOT MAX (MAX = closest, would over-occlude).
pc.hiz_dst[px] = min(min(d0, d1), min(d2, d3));
}