From 8885e6a7c3017f42bf1b7da39c7b0f0847839972 Mon Sep 17 00:00:00 2001 From: Andrew Cohn Date: Sat, 29 Nov 2025 12:29:08 -0800 Subject: [PATCH] babies first gpu code --- Makefile | 3 +- fallingCand | Bin 76912 -> 81768 bytes gl_utils.c | 152 ++++++++++++++++++++++++++++++++++++ gl_utils.h | 27 +++++++ main.c | 169 +++++++++++++--------------------------- sand_hello | Bin 0 -> 81768 bytes shaders/double.comp | 12 +++ shaders/fullscreen.vert | 8 ++ shaders/gradient.frag | 11 +++ 9 files changed, 265 insertions(+), 117 deletions(-) create mode 100644 gl_utils.c create mode 100644 gl_utils.h create mode 100755 sand_hello create mode 100644 shaders/double.comp create mode 100644 shaders/fullscreen.vert create mode 100644 shaders/gradient.frag diff --git a/Makefile b/Makefile index 28076d9..03be6bb 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ -# Makefile CC = gcc CFLAGS = -Wall -Wextra -O2 $(shell pkg-config --cflags glfw3) LDFLAGS = $(shell pkg-config --libs glfw3) -ldl -SRC = main.c glad.c +SRC = glad.c gl_utils.c main.c OBJ = $(SRC:.c=.o) BIN = fallingCand diff --git a/fallingCand b/fallingCand index a2ffcfd79e24c51b3b88e9d38e8704cc2e1105ee..250e73b8e07fea4c9df409576b0db9bce2b585d5 100755 GIT binary patch literal 81768 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 literal 76912 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%0Ax&zd_mIN8tNaf4wBUiUWTJU!eMBENuXo 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 +#include +#include +#include + +void glfw_error_callback(int error, const char* description) { + fprintf(stderr, "GLFW error %d: %s\n", error, description); +} + +char* load_text_file(const char* path) { + FILE* f = fopen(path, "rb"); + if (!f) { + fprintf(stderr, "Failed to open '%s': %s\n", path, strerror(errno)); + return NULL; + } + + if (fseek(f, 0, SEEK_END) != 0) { + fprintf(stderr, "fseek failed on '%s'\n", path); + fclose(f); + return NULL; + } + + long size = ftell(f); + if (size < 0) { + fprintf(stderr, "ftell failed on '%s'\n", path); + fclose(f); + return NULL; + } + + rewind(f); + + char* buffer = malloc((size_t)size + 1); + if (!buffer) { + fprintf(stderr, "Out of memory reading '%s'\n", path); + fclose(f); + return NULL; + } + + size_t read = fread(buffer, 1, (size_t)size, f); + fclose(f); + + if (read != (size_t)size) { + fprintf(stderr, "Short read on '%s'\n", path); + free(buffer); + return NULL; + } + + buffer[size] = '\0'; + return buffer; +} + +GLuint compile_shader(GLenum type, const char* source, const char* debugName) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + + GLint success = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char log[1024]; + glGetShaderInfoLog(shader, sizeof(log), NULL, log); + fprintf(stderr, "Shader compile failed (%s):\n%s\n", debugName ? debugName : "unknown", log); + glDeleteShader(shader); + exit(EXIT_FAILURE); + } + + return shader; +} + +GLuint create_program_from_files(const char* vsPath, const char* fsPath) { + char* vsSource = load_text_file(vsPath); + if (!vsSource) { + fprintf(stderr, "Could not load vertex shader from '%s'\n", vsPath); + exit(EXIT_FAILURE); + } + + char* fsSource = load_text_file(fsPath); + if (!fsSource) { + fprintf(stderr, "Could not load fragment shader from '%s'\n", fsPath); + free(vsSource); + exit(EXIT_FAILURE); + } + + GLuint vs = compile_shader(GL_VERTEX_SHADER, vsSource, vsPath); + GLuint fs = compile_shader(GL_FRAGMENT_SHADER, fsSource, fsPath); + + free(vsSource); + free(fsSource); + + GLuint prog = glCreateProgram(); + glAttachShader(prog, vs); + glAttachShader(prog, fs); + glLinkProgram(prog); + + glDeleteShader(vs); + glDeleteShader(fs); + + GLint linked = 0; + glGetProgramiv(prog, GL_LINK_STATUS, &linked); + if (!linked) { + char log[1024]; + glGetProgramInfoLog(prog, sizeof(log), NULL, log); + fprintf(stderr, "Program link failed:\n%s\n", log); + glDeleteProgram(prog); + exit(EXIT_FAILURE); + } + + return prog; +} + +GLFWwindow* init_glfw_glad(const char* title, int width, int height) { + glfwSetErrorCallback(glfw_error_callback); + + // Prefer Wayland if this GLFW build supports it + if (glfwPlatformSupported(GLFW_PLATFORM_WAYLAND)) { + glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); + fprintf(stderr, "[info] Requesting Wayland platform via glfwInitHint\n"); + } else { + fprintf(stderr, "[warn] Wayland platform not supported by this GLFW build, using default\n"); + } + + if (!glfwInit()) { + fprintf(stderr, "[fatal] glfwInit failed\n"); + return NULL; + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); + + GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL); + if (!window) { + fprintf(stderr, "[fatal] glfwCreateWindow failed\n"); + glfwTerminate(); + return NULL; + } + + glfwMakeContextCurrent(window); + + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { + fprintf(stderr, "[fatal] Failed to initialize GLAD\n"); + glfwDestroyWindow(window); + glfwTerminate(); + return NULL; + } + + return window; +} diff --git a/gl_utils.h b/gl_utils.h new file mode 100644 index 0000000..7de4523 --- /dev/null +++ b/gl_utils.h @@ -0,0 +1,27 @@ +// gl_utils.h +#ifndef GL_UTILS_H +#define GL_UTILS_H + + +#include "glad/glad.h" +#define GLFW_INCLUDE_NONE +#include +// Error callback for GLFW +void glfw_error_callback(int error, const char* description); + +// Read an entire text file into a null-terminated buffer. +// Caller must free() the returned pointer. +char* load_text_file(const char* path); + +// Compile a single shader from source. +GLuint compile_shader(GLenum type, const char* source, const char* debugName); + +// Compile & link a vertex+fragment program from files. +GLuint create_program_from_files(const char* vsPath, const char* fsPath); + +// Minimal GLFW+GLAD init: sets error callback, (optionally) hints Wayland, +// calls glfwInit, creates window, makes context current, loads GLAD. +// Returns the created window or NULL on fatal error. +GLFWwindow* init_glfw_glad(const char* title, int width, int height); + +#endif // GL_UTILS_H diff --git a/main.c b/main.c index a1ebd39..cf693c6 100644 --- a/main.c +++ b/main.c @@ -1,142 +1,81 @@ // main.c #include #include -#include -#include "glad/glad.h" -#define GLFW_INCLUDE_NONE -#include - -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; -} +#include "gl_utils.h" int main(void) { - // --- Init GLFW & create GL context --- - glfwSetErrorCallback(glfw_error_callback); + int winW = 800; + int winH = 600; - 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); + GLFWwindow* window = init_glfw_glad("Falling Sand - Fullscreen Quad", winW, winH); if (!window) { - fprintf(stderr, "Failed to create GLFW window\n"); - glfwTerminate(); return EXIT_FAILURE; } - glfwMakeContextCurrent(window); + printf("Renderer: %s\n", (const char*)glGetString(GL_RENDERER)); + printf("OpenGL: %s\n", (const char*)glGetString(GL_VERSION)); + printf("GLSL: %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); - // --- Load GL symbols via GLAD --- - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { - fprintf(stderr, "Failed to initialize GLAD\n"); - glfwDestroyWindow(window); - glfwTerminate(); - return EXIT_FAILURE; - } + // --- Create fullscreen triangle geometry (VAO + VBO) --- + float vertices[] = { + // x, y + -1.0f, -1.0f, + 3.0f, -1.0f, + -1.0f, 3.0f + }; - printf("OpenGL version: %s\n", glGetString(GL_VERSION)); - printf("GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + GLuint vao = 0, vbo = 0; + glGenVertexArrays(1, &vao); + glGenBuffers(1, &vbo); - // --- Prepare data buffer on GPU (SSBO) --- - const GLuint N = 16; - GLuint initial[N]; - for (GLuint i = 0; i < N; ++i) { - initial[i] = i; - } + glBindVertexArray(vao); - 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 + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - // --- 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, + // layout(location = 0) in vec2 aPos; + glEnableVertexAttribArray(0); + glVertexAttribPointer( 0, - sizeof(initial), - GL_MAP_READ_BIT + 2, + GL_FLOAT, + GL_FALSE, + 2 * sizeof(float), + (void*)0 ); - 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); + glBindVertexArray(0); + + // --- Create shader program --- + GLuint program = create_program_from_files( + "shaders/fullscreen.vert", + "shaders/gradient.frag" + ); + + glUseProgram(program); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + // --- Main loop --- + while (!glfwWindowShouldClose(window)) { + glfwPollEvents(); + + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(program); + glBindVertexArray(vao); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glfwSwapBuffers(window); } // --- Cleanup --- - glDeleteProgram(compute_program); - glDeleteBuffers(1, &ssbo); + glDeleteProgram(program); + glDeleteBuffers(1, &vbo); + glDeleteVertexArrays(1, &vao); glfwDestroyWindow(window); glfwTerminate(); - return EXIT_SUCCESS; } diff --git a/sand_hello b/sand_hello new file mode 100755 index 0000000000000000000000000000000000000000..250e73b8e07fea4c9df409576b0db9bce2b585d5 GIT binary patch literal 81768 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 literal 0 HcmV?d00001 diff --git a/shaders/double.comp b/shaders/double.comp new file mode 100644 index 0000000..6c506e8 --- /dev/null +++ b/shaders/double.comp @@ -0,0 +1,12 @@ +#version 460 core + +layout(local_size_x = 16) in; + +layout(std430, binding = 0) buffer Data { + uint data[]; +}; + +void main() { + uint idx = gl_GlobalInvocationID.x; + data[idx] *= 2u; +} diff --git a/shaders/fullscreen.vert b/shaders/fullscreen.vert new file mode 100644 index 0000000..c0d22c3 --- /dev/null +++ b/shaders/fullscreen.vert @@ -0,0 +1,8 @@ +#version 430 core + +layout(location = 0) in vec2 aPos; + +void main() +{ + gl_Position = vec4(aPos, 0.0, 1.0); +} diff --git a/shaders/gradient.frag b/shaders/gradient.frag new file mode 100644 index 0000000..6f8726d --- /dev/null +++ b/shaders/gradient.frag @@ -0,0 +1,11 @@ +#version 430 core + +out vec4 FragColor; + +void main() +{ + // Normalized coordinates in [0,1] + vec2 uv = gl_FragCoord.xy / vec2(800.0, 600.0); // we’ll fix this later with a uniform + vec3 color = vec3(uv.x, uv.y, 0.2); + FragColor = vec4(color, 1.0); +}