fallingCand/main.c
2025-11-29 01:35:51 -08:00

143 lines
4.1 KiB
C

// main.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "glad/glad.h"
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
static void glfw_error_callback(int error, const char* description) {
fprintf(stderr, "GLFW error %d: %s\n", error, description);
}
static GLuint create_compute_program(const char* source) {
GLint success = 0;
GLchar log[1024];
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, sizeof(log), NULL, log);
fprintf(stderr, "Compute shader compilation failed:\n%s\n", log);
exit(EXIT_FAILURE);
}
GLuint program = glCreateProgram();
glAttachShader(program, shader);
glLinkProgram(program);
glDeleteShader(shader);
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, sizeof(log), NULL, log);
fprintf(stderr, "Program link failed:\n%s\n", log);
exit(EXIT_FAILURE);
}
return program;
}
int main(void) {
// --- Init GLFW & create GL context ---
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit()) {
fprintf(stderr, "Failed to init GLFW\n");
return EXIT_FAILURE;
}
// Request OpenGL 4.3 core (needed for compute shaders)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// We don't actually *need* to show the window
GLFWwindow* window = glfwCreateWindow(640, 480, "GPU Hello", NULL, NULL);
if (!window) {
fprintf(stderr, "Failed to create GLFW window\n");
glfwTerminate();
return EXIT_FAILURE;
}
glfwMakeContextCurrent(window);
// --- Load GL symbols via GLAD ---
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
fprintf(stderr, "Failed to initialize GLAD\n");
glfwDestroyWindow(window);
glfwTerminate();
return EXIT_FAILURE;
}
printf("OpenGL version: %s\n", glGetString(GL_VERSION));
printf("GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
// --- Prepare data buffer on GPU (SSBO) ---
const GLuint N = 16;
GLuint initial[N];
for (GLuint i = 0; i < N; ++i) {
initial[i] = i;
}
GLuint ssbo = 0;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(initial), initial, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo); // binding = 0 in shader
// --- Compute shader source: data[i] *= 2 ---
const char* compute_src =
"#version 430 core\n"
"layout(local_size_x = 16) in;\n"
"layout(std430, binding = 0) buffer Data {\n"
" uint data[];\n"
"};\n"
"void main() {\n"
" uint idx = gl_GlobalInvocationID.x;\n"
" // N == 16 and local_size_x == 16, so we know idx < 16\n"
" data[idx] *= 2u;\n"
"}\n";
GLuint compute_program = create_compute_program(compute_src);
// --- Run the compute shader ---
glUseProgram(compute_program);
// One workgroup of 16 threads (matches local_size_x)
glDispatchCompute(1, 1, 1);
// Make sure writes to the SSBO are visible to the CPU
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
// --- Read back the result ---
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
GLuint* ptr = (GLuint*)glMapBufferRange(
GL_SHADER_STORAGE_BUFFER,
0,
sizeof(initial),
GL_MAP_READ_BIT
);
if (!ptr) {
fprintf(stderr, "Failed to map SSBO\n");
} else {
printf("GPU computed values:\n");
for (GLuint i = 0; i < N; ++i) {
printf(" %2u -> %2u\n", i, ptr[i]);
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
// --- Cleanup ---
glDeleteProgram(compute_program);
glDeleteBuffers(1, &ssbo);
glfwDestroyWindow(window);
glfwTerminate();
return EXIT_SUCCESS;
}