From 152277cd775f6a36004f99048bb6879eb913ef5e Mon Sep 17 00:00:00 2001 From: k Date: Sat, 3 May 2025 19:35:24 -0400 Subject: [PATCH] Basic compute shader --- main.cc | 127 +++++++++++++++++++++++++++++++++++++++++++++++++--- shaders.hpp | 68 ++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 shaders.hpp diff --git a/main.cc b/main.cc index 3158739..29a9a0b 100644 --- a/main.cc +++ b/main.cc @@ -1,12 +1,46 @@ #include #include +#include +#include +#include +#include -#define X 16 -#define Y 16 -#define GRID_SIZE X*Y +#include "shaders.hpp" -#define STR_EXPAND(tok) #tok -#define STR(tok) STR_EXPAND(tok) +#define X 10 +#define Y 10 +#define GRID_SIZE X *Y + +GLuint compileShader(GLenum type, const char *src) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src, nullptr); + glCompileShader(shader); + int success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetShaderInfoLog(shader, 512, nullptr, infoLog); + std::cerr << "ERROR::SHADER_COMPILATION_ERROR\n" << infoLog << std::endl; + } + return shader; +} + +GLuint linkProgram(std::vector shaders) { + GLuint program = glCreateProgram(); + for (auto s : shaders) + glAttachShader(program, s); + glLinkProgram(program); + int success; + glGetProgramiv(program, GL_LINK_STATUS, &success); + if (!success) { + char infoLog[512]; + glGetProgramInfoLog(program, 512, nullptr, infoLog); + std::cerr << "ERROR::PROGRAM_LINK_ERROR\n" << infoLog << std::endl; + } + for (auto s : shaders) + glDeleteShader(s); + return program; +} int main() { if (!glfwInit()) @@ -16,7 +50,7 @@ int main() { glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - GLFWwindow *w = glfwCreateWindow(800, 800, "game of life", NULL, NULL); + GLFWwindow *w = glfwCreateWindow(800, 600, "game of life", NULL, NULL); if (!w) return -2; @@ -26,12 +60,91 @@ int main() { return -3; glfwShowWindow(w); - glViewport(0, 0, 800, 800); + glViewport(0, 0, 800, 637); + /*gen tex*/ + GLuint tex[2]; + glGenTextures(2, tex); + for (int i = 0; i < 2; ++i) { + glBindTexture(GL_TEXTURE_2D, tex[i]); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, X, Y); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + /*rnd noise*/ + std::vector data(GRID_SIZE*4); + std::mt19937 rng; + std::uniform_int_distribution dist(0, 1); + for (int i = 0; i < GRID_SIZE; ++i) { + GLubyte v = dist(rng) * 255; + data[i * 4 + 0] = v; // R channel + data[i * 4 + 1] = v; // G channel + data[i * 4 + 2] = v; // B channel + data[i * 4 + 3] = 255; // A channel + } + + glBindTexture(GL_TEXTURE_2D, tex[0]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, X, Y, GL_RGBA, GL_UNSIGNED_BYTE, + data.data()); + + GLuint cmp, rnd, vs, fs; + cmp = linkProgram({compileShader(GL_COMPUTE_SHADER, computeShaderSrc)}); + + vs = compileShader(GL_VERTEX_SHADER, vertexShaderSrc); + fs = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSrc); + rnd = linkProgram({vs, fs}); + + /*vtex*/ + GLuint VAO, VBO, EBO; + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, + GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadIndices), quadIndices, + GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + glEnableVertexAttribArray(0); + + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); + glEnableVertexAttribArray(1); + + /**/ + int ri, wi; + ri = 0; + wi = 1; while (!glfwWindowShouldClose(w)) { glfwPollEvents(); + glClearColor(1.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); + + /*compute*/ + glUseProgram(cmp); + glBindImageTexture(0, tex[wi], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8); + glUniform1i(glGetUniformLocation(cmp, "srcTex"), 0); + glUniform1i(glGetUniformLocation(cmp, "X"), X); + glUniform1i(glGetUniformLocation(cmp, "Y"), Y); + glDispatchCompute(X, Y, 1); + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + + /*draw*/ + glUseProgram(rnd); + glActiveTexture(GL_TEXTURE0); + glUniform1i(glGetUniformLocation(rnd, "tex0"), 0); + + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void *)0); + glfwSwapBuffers(w); + std::swap(ri, wi); } glfwTerminate(); diff --git a/shaders.hpp b/shaders.hpp new file mode 100644 index 0000000..6c93406 --- /dev/null +++ b/shaders.hpp @@ -0,0 +1,68 @@ +const char *computeShaderSrc = R"glsl( +#version 430 core +layout (local_size_x = 1, local_size_y = 1) in; + +layout (rgba8) uniform writeonly image2D destTex; +uniform sampler2D srcTex; +uniform int X; +uniform int Y; + +ivec2 wrapuv (ivec2 uv){ + int wrapped_u = (uv.x % X + X) % X; + int wrapped_v = (uv.y % Y + Y) % Y; + return ivec2(wrapped_u, wrapped_v); +} + +int alive(ivec2 uv){ + uv = wrapuv(uv); + vec4 px = texelFetch(srcTex,uv,0); + return int(px.r > 0.5); +} + +void main() { + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + + vec4 c = texelFetch(srcTex,uv,0); + int newState = alive(uv-ivec2(1,1)); + imageStore(destTex, uv, vec4(newState, newState, newState, 1.0)); +} +)glsl"; + +const char *vertexShaderSrc = R"glsl( +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; +out vec2 TexCoord; + +void main() +{ + gl_Position = vec4(aPos, 1.0); + TexCoord = aTexCoord; +} + +)glsl"; + +const char *fragmentShaderSrc = R"glsl( +#version 330 core +out vec4 FragColor; + +in vec2 TexCoord; +uniform sampler2D tex0; + +void main() +{ + FragColor = texture(tex0, TexCoord); +} +)glsl"; + +float quadVertices[] = { + 1.0f, 1.0f, 0.0f, /*top R*/ + 1.0f, -1.0f, 0.0f, /*bottom R*/ + -1.0f, -1.0f, 0.0f, /*bottom L*/ + -1.0f, 1.0f, 0.0f /*top R*/ +}; + +unsigned int quadIndices[] = { + 0, 1, 3, /*tl triangle*/ + 1, 2, 3 /*br triangle*/ +};