I am building a 3d renderer in C++ using Vulkan.hpp. I am trying to generate Spherical Harmonics (SH) coefficients for diffuse radiance. I have the below compute shader code, but I'm not sure how to set up the inputs and call the compute shader command properly. Can you firstly review the shader code and ensure it is correct and then provide examples of how I should be setting up the inputs and calling the command? As a note, the SH coefficient calculation tries to incorporate both an environmental irradiance cubemap and a depth cubemap, both generated from the probe's position.

Shader Code:

#version 450
#extension GL_EXT_scalar_block_layout : enable

#define PI 3.1415926535897932384626433832795
#define SH_ORDER 2  // For second-order SH (9 coefficients)
#define NUM_SAMPLES 64  // Number of samples per direction

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

layout(scalar, set = 0, binding = 0) buffer SHBuffer {
    vec3 shCoeffs[];
} shBuffer;

layout(set = 0, binding = 1) uniform samplerCube irradianceMap;
//layout(set = 0, binding = 2) uniform sampler2D depthMap;
layout(set = 0, binding = 2) uniform samplerCube depthMap;
layout(set = 0, binding = 3) uniform ProbePosition {
    vec3 probePos;
};

uint h1 = uint(gl_GlobalInvocationID.x);
uint h2 = uint(gl_GlobalInvocationID.y);
uint h3 = uint(gl_GlobalInvocationID.z);

// Hash function inspired by MurmurHash3
uint hash(uint h) {
    h ^= h >> 16;
    h *= 0x85ebca6b;
    h ^= h >> 13;
    h *= 0xc2b2ae35;
    h ^= h >> 16;
    return h;
}

float rand(uint seed) {
    uint hashValue = hash(seed);
    return float(hashValue) / 4294967295.0;  // Normalize to [0, 1]
}

vec3 randomCosineWeightedHemisphereDirection(uint seed) {
    float r1 = rand(seed++);
    float r2 = rand(seed++);
    
    float theta = 2.0 * PI * r1;
    float cosTheta = sqrt(1.0 - r2);
    float sinTheta = sqrt(r2);
    
    float x = cos(theta) * sinTheta;
    float y = sin(theta) * sinTheta;
    float z = cosTheta;
    
    return vec3(x, y, z);
}


vec3 sphericalHarmonicBasis(uint idx, vec3 dir) {
    // Precompute the SH basis functions for order 2
    float x = dir.x;
    float y = dir.y;
    float z = dir.z;

    vec3 shBasis[9] = vec3[](
        vec3(PI, 0.0, 0.0),  // Y_0^0
        vec3(0.4886025119029199 * x, 0.4886025119029199 * y, 0.4886025119029199 * z),  // Y_1^-1
        vec3(0.4886025119029199 * z, 0.4886025119029199 * y, 0.4886025119029199 * x),  // Y_1^0
        vec3(0.4886025119029199 * x, 0.4886025119029199 * y, 0.4886025119029199 * z),  // Y_1^1
        vec3(1.0925484305920792 * y * z, 1.0925484305920792 * (z * x - y * x), 0.31539156525252005 * (x * x - y * y)),  // Y_2^-2
        vec3(0.5462742152960396 * (x * x - 3.0 * z * z), 1.0925484305920792 * x * y, 1.0925484305920792 * y * z),  // Y_2^-1
        vec3(1.0925484305920792 * z * x, 1.0925484305920792 * z * y, 0.5462742152960396 * (y * y - 3.0 * x * x)),  // Y_2^0
        vec3(0.5462742152960396 * (3.0 * z * z - x * x), 1.0925484305920792 * x * y, 1.0925484305920792 * y * z),  // Y_2^1
        vec3(1.0925484305920792 * (y * z - z * x), 0.31539156525252005 * (x * x - y * y), 1.0925484305920792 * (z * z - 3.0 * x * x))  // Y_2^2
    );

    return shBasis[idx];
}

vec2 projectToScreen(vec3 worldPos, vec3 cameraPos) {
    // Project world position to screen space coordinates
    vec3 viewDir = worldPos - cameraPos;
    vec4 clipSpace = vec4(viewDir, 1.0);
    clipSpace.xyz /= clipSpace.w;
    clipSpace.xy = clipSpace.xy * 0.5 + 0.5;
    return clipSpace.xy;
}

void main() {
    uint idx = gl_GlobalInvocationID.x;
    if (idx >= SH_ORDER * SH_ORDER + 1) return;

    vec3 shCoeff = vec3(0.0);
    for (int i = 0; i < NUM_SAMPLES; ++i) {
        vec3 sampleDir = randomCosineWeightedHemisphereDirection(uint(gl_GlobalInvocationID.x * 1000 + i));
        float weight = 0.25 * PI;  // Cosine-weighted hemisphere sampling

        // Convert sample direction to screen space coordinates
        vec3 samplePos = probePos + sampleDir;
        //vec2 screenCoord = projectToScreen(samplePos, probePos);
        
        // Perform depth test
        //float depth = texture(depthMap, screenCoord).r;
        float depth = texture(depthMap, sampleDir).r;
        //if (length(samplePos - probePos) > depth) continue;

        vec3 irradiance = texture(irradianceMap, sampleDir).rgb;
        shCoeff += irradiance * sphericalHarmonicBasis(idx, sampleDir) * weight;
    }

    shCoeff *= 1.0 / float(NUM_SAMPLES);

    shBuffer.shCoeffs[idx] = shCoeff;
}