Compute shader uniform float var not getting updated after initial call to glUniform1f
I've tried everything I can think of. I'm brand new to GLSL compute shaders. I'm working with some code provided by Victor Gordan, and trying to modify it very slightly to pass a constantly changing float uniform to the compute shader. The code builds and runs fine, except that the value of the unifrom only seems to be effected by the very first call to glUniform1v; sunsequent calls, despite passing a changed value for the variable, never do anything. Rendoerdoc shows every frame , no matter when captured, as setting the uniform to the same value as the first call (first frame). I'm tearing my hair out here. I've tried every suggestion I have found online: the commented out define at the top of the code, and various calls to glUniform versions, all were attempts that failed to solve the problem. I've tried setting the uniform layout location to other values, and the returned handle from glGetUniformLocation() will always agree with that new location, and the value of the c++ variable "timer" \*is\* definitely changing. The uniform exists, and has not been compiled out of the shader. What the heck is going on? When run, the window displays, and displays the correct colour for frame 1. It never changes color over time.
//#define GL_GLEXT_PROTOTYPES
#include<iostream>
#include"glad/glad.h" #include"GLFW/glfw3.h"
#include <chrono> #include<cassert>
const unsigned int SCREEN_WIDTH = 1024; const unsigned int SCREEN_HEIGHT = 1024;
const unsigned short OPENGL_MAJOR_VERSION = 4; const unsigned short OPENGL_MINOR_VERSION = 6;
bool vSync = true;
GLfloat vertices[] = { -1.0f, -1.0f , 0.0f, 0.0f, 0.0f, -1.0f, 1.0f , 0.0f, 0.0f, 1.0f, 1.0f, 1.0f , 0.0f, 1.0f, 1.0f, 1.0f, -1.0f , 0.0f, 1.0f, 0.0f, };
GLuint indices[] = { 0, 2, 1, 0, 3, 2 };
const char* screenVertexShaderSource = R"(#version 460 core layout (location = 0) in vec3 pos; layout (location = 1) in vec2 uvs; out vec2 UVs; void main() { gl_Position = vec4(pos.x, pos.y, pos.z, 1.0); UVs = uvs; })"; const char* screenFragmentShaderSource = R"(#version 460 core out vec4 FragColor; uniform sampler2D screen; in vec2 UVs; void main() { FragColor = texture(screen, UVs); })"; const char* screenComputeShaderSource = R"(#version 460 core layout (location = 0) uniform float timer; layout(local_size_x = 8, local_size_y = 4, local_size_z = 1) in; layout(rgba32f, binding = 0) uniform image2D screen;
void main() { vec4 pixel; ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
ivec2 dims = imageSize(screen); float x = -(float(pixel_coords.x * 2 - dims.x) / dims.x); // transforms to [-1.0, 1.0] float y = -(float(pixel_coords.y * 2 - dims.y) / dims.y); // transforms to [-1.0, 1.0] pixel.r = timer/6.28318530718;//(sin(timer*x) + 1)/2; pixel.g = 0.5;//(cos(timer*y) + 1)/2; pixel.b = 0.5;//range(0, 6.28318530718, timer); pixel.a = 1.0;
imageStore(screen, pixel_coords, pixel); })";
int main() { glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, OPENGL_MAJOR_VERSION); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, OPENGL_MINOR_VERSION); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "OpenGL Compute Shaders", NULL, NULL); if (!window) { std::cout << "Failed to create the GLFW window\n"; glfwTerminate(); } glfwMakeContextCurrent(window); glfwSwapInterval(vSync);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize OpenGL context" << std::endl; } glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
GLuint VAO, VBO, EBO; glCreateVertexArrays(1, &VAO); glCreateBuffers(1, &VBO); glCreateBuffers(1, &EBO);
glNamedBufferData(VBO, sizeof(vertices), vertices, GL_STATIC_DRAW); glNamedBufferData(EBO, sizeof(indices), indices, GL_STATIC_DRAW);
glEnableVertexArrayAttrib(VAO, 0); glVertexArrayAttribBinding(VAO, 0, 0); glVertexArrayAttribFormat(VAO, 0, 3, GL_FLOAT, GL_FALSE, 0);
glEnableVertexArrayAttrib(VAO, 1); glVertexArrayAttribBinding(VAO, 1, 0); glVertexArrayAttribFormat(VAO, 1, 2, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat));
glVertexArrayVertexBuffer(VAO, 0, VBO, 0, 5 * sizeof(GLfloat)); glVertexArrayElementBuffer(VAO, EBO);
GLuint screenTex; glCreateTextures(GL_TEXTURE_2D, 1, &screenTex); glTextureParameteri(screenTex, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTextureParameteri(screenTex, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTextureParameteri(screenTex, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTextureParameteri(screenTex, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTextureStorage2D(screenTex, 1, GL_RGBA32F, SCREEN_WIDTH, SCREEN_HEIGHT); glBindImageTexture(0, screenTex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
GLuint screenVertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(screenVertexShader, 1, &screenVertexShaderSource, NULL); glCompileShader(screenVertexShader); GLuint screenFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(screenFragmentShader, 1, &screenFragmentShaderSource, NULL); glCompileShader(screenFragmentShader);
GLuint screenShaderProgram = glCreateProgram(); glAttachShader(screenShaderProgram, screenVertexShader); glAttachShader(screenShaderProgram, screenFragmentShader); glLinkProgram(screenShaderProgram);
glDeleteShader(screenVertexShader); glDeleteShader(screenFragmentShader);
GLuint computeShader = glCreateShader(GL_COMPUTE_SHADER); glShaderSource(computeShader, 1, &screenComputeShaderSource, NULL); glCompileShader(computeShader);
GLuint computeProgram = glCreateProgram(); glAttachShader(computeProgram, computeShader); glLinkProgram(computeProgram);
int work_grp_cnt[3]; glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &work_grp_cnt[0]); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &work_grp_cnt[1]); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &work_grp_cnt[2]); std::cout << "Max work groups per compute shader" << " x:" << work_grp_cnt[0] << " y:" << work_grp_cnt[1] << " z:" << work_grp_cnt[2] << "\n";
int work_grp_size[3]; glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &work_grp_size[0]); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &work_grp_size[1]); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &work_grp_size[2]); std::cout << "Max work group sizes" << " x:" << work_grp_size[0] << " y:" << work_grp_size[1] << " z:" << work_grp_size[2] << "\n";
int work_grp_inv; glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &work_grp_inv); std::cout << "Max invocations count per work group: " << work_grp_inv << "\n";
auto currentTime = std::chrono::high_resolution_clock::now(); auto previousTime = currentTime; float elapsed_time = 0; float timer = 0.333f; while (!glfwWindowShouldClose(window)) { currentTime = std::chrono::high_resolution_clock::now(); elapsed_time = std::chrono::duration_cast<std::chrono::seconds> (currentTime - previousTime).count(); previousTime = currentTime; if (elapsed_time > 0.15f) elapsed_time = 0.15f; timer += elapsed_time; if (timer > 6.28318530718f) timer -= 6.28318530718f;
glUseProgram(computeProgram);
GLint timerHandle = glGetUniformLocation(computeProgram, "timer"); assert(timerHandle != -1); glUniform1f(timerHandle, timer); //glUniform1fv(timerHandle, 1, &timer); //glUniform1f(1, timer); //glProgramUniform1f(computeProgram, timerHandle, timer);
glDispatchCompute(ceil(SCREEN_WIDTH / 8), ceil(SCREEN_HEIGHT / 4), 1); glMemoryBarrier(GL_ALL_BARRIER_BITS);
glUseProgram(screenShaderProgram); glBindTextureUnit(0, screenTex); glUniform1i(glGetUniformLocation(screenShaderProgram, "screen"), 0); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window); glfwPollEvents(); }
glfwDestroyWindow(window); glfwTerminate(); }