#include "gfx/gl_loader.h"
#include "gfx/gpu_dispatch.h"

namespace fn::gfx {

static inline GLuint groups(int n, int local) {
    if (n <= 0 || local <= 0) return 0;
    return static_cast<GLuint>((n + local - 1) / local);
}

void dispatch_1d(int num_invocations, int local_size_x) {
    GLuint gx = groups(num_invocations, local_size_x);
    if (gx == 0) return;
    glDispatchCompute(gx, 1, 1);
}

void dispatch_2d(int width, int height, int local_size_x, int local_size_y) {
    GLuint gx = groups(width, local_size_x);
    GLuint gy = groups(height, local_size_y);
    if (gx == 0 || gy == 0) return;
    glDispatchCompute(gx, gy, 1);
}

void dispatch_3d(int x, int y, int z,
                 int local_size_x, int local_size_y, int local_size_z) {
    GLuint gx = groups(x, local_size_x);
    GLuint gy = groups(y, local_size_y);
    GLuint gz = groups(z, local_size_z);
    if (gx == 0 || gy == 0 || gz == 0) return;
    glDispatchCompute(gx, gy, gz);
}

void barrier_storage()       { glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); }
void barrier_uniform()       { glMemoryBarrier(GL_UNIFORM_BARRIER_BIT); }
void barrier_image()         { glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); }
void barrier_buffer_update() { glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); }
void barrier_all()           { glMemoryBarrier(GL_ALL_BARRIER_BITS); }

} // namespace fn::gfx
