#version 450
// @[export]
// @[internal_buffer]
layout(set = 0, binding = 0) uniform DepthPyramidConfig
{
// Size of image in pixels
uint input_width;
uint input_height;
bool odd_width;
bool odd_height;
} config;
// @[export]
layout (set = 0, binding = 1) uniform texture2D src_depth_tex;
// @[immutable_samplers([
// (
// mag_filter: Nearest,
// min_filter: Nearest,
// mip_map_mode: Nearest,
// address_mode_u: ClampToEdge,
// address_mode_v: ClampToEdge,
// address_mode_w: ClampToEdge,
// )
// ])]
layout (set = 0, binding = 2) uniform sampler smp;
// @[export]
layout (set = 0, binding = 3) writeonly uniform image2D dst_depth_tex;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
if (gl_GlobalInvocationID.x >= config.input_width / 2) {
return;
}
if (gl_GlobalInvocationID.y >= config.input_height / 2) {
return;
}
//
// Do 2x2 gather and take minimum value
//
vec2 texel_size = vec2(1.0 / config.input_width, 1.0 / config.input_height);
vec2 src_uv = (gl_GlobalInvocationID.xy * 2 + vec2(0.5, 0.5)) * texel_size;
vec4 gathered = textureGather(sampler2D(src_depth_tex, smp), src_uv);
float min_value = min(min(gathered.x, gathered.y), min(gathered.z, gathered.w));
//
// In the case where we have odd source input, we actually need to do three samples. For example, a 5x5 mip
// becomes 2x2 in the next mip, and each pixel in the 2x2 mip actually overlaps 3 pixels in the original mip.
// 0 samples [0, 2.5] which is {0,1,2} and 1 samples [2.5, 5] which is {2,3,4}
//
if (config.odd_width) {
float a = texture(sampler2D(src_depth_tex, smp), src_uv + vec2(2, 0) * texel_size).x;
float b = texture(sampler2D(src_depth_tex, smp), src_uv + vec2(2, 1) * texel_size).x;
min_value = min(min_value, min(a, b));
}
if (config.odd_height) {
float a = texture(sampler2D(src_depth_tex, smp), src_uv + vec2(0, 2) * texel_size).x;
float b = texture(sampler2D(src_depth_tex, smp), src_uv + vec2(1, 2) * texel_size).x;
min_value = min(min_value, min(a, b));
}
if (config.odd_width && config.odd_height) {
float a = texture(sampler2D(src_depth_tex, smp), src_uv + vec2(2, 2) * texel_size).x;
min_value = min(min_value, a);
}
//
// Write the minimum of all
//
imageStore(dst_depth_tex, ivec2(gl_GlobalInvocationID.xy), vec4(min_value));
}