diff --git a/src/8.guest/2022/5.computeshader_helloworld/computeShader.comp b/src/8.guest/2022/5.computeshader_helloworld/computeShader.comp new file mode 100644 index 0000000..f614624 --- /dev/null +++ b/src/8.guest/2022/5.computeshader_helloworld/computeShader.comp @@ -0,0 +1,28 @@ +#version 430 core + +layout (local_size_x = 10, local_size_y = 10, local_size_z = 1) in; + +// ---------------------------------------------------------------------------- +// +// uniforms +// +// ---------------------------------------------------------------------------- + +layout(rgba32f, binding = 0) uniform image2D imgOutput; + +layout (location = 0) uniform float t; /**< Time */ + +// ---------------------------------------------------------------------------- +// +// functions +// +// ---------------------------------------------------------------------------- + +void main() { + vec4 pixel = vec4(0.0, 0.0, 0.0, 1.0); + ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy); + float speed = 0.5; + pixel.x = float(int((float(pixelCoord.x)/(gl_NumWorkGroups.x*gl_WorkGroupSize.x)+t*speed)*100)%100)/100; + pixel.y = float(pixelCoord.y)/(gl_NumWorkGroups.y*gl_WorkGroupSize.y); + imageStore(imgOutput, pixelCoord, pixel); +} \ No newline at end of file diff --git a/src/8.guest/2022/5.computeshader_helloworld/computeShader.h b/src/8.guest/2022/5.computeshader_helloworld/computeShader.h new file mode 100644 index 0000000..ebe5c85 --- /dev/null +++ b/src/8.guest/2022/5.computeshader_helloworld/computeShader.h @@ -0,0 +1,49 @@ +#include + + +class ComputeShader : public Shader +{ + public: + ComputeShader(const char* computePath) + { + // 1. retrieve the vertex/fragment source code from filePath + std::string computeCode; + std::ifstream cShaderFile; + // ensure ifstream objects can throw exceptions: + cShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + // open files + cShaderFile.open(computePath); + + std::stringstream cShaderStream; + // read file's buffer contents into streams + cShaderStream << cShaderFile.rdbuf(); + // close file handlers + cShaderFile.close(); + // convert stream into string + computeCode = cShaderStream.str(); + } + catch (std::ifstream::failure& e) + { + std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: " << e.what() << std::endl; + } + const char* cShaderCode = computeCode.c_str(); + // 2. compile shaders + unsigned int compute; + // compute shader + compute = glCreateShader(GL_COMPUTE_SHADER); + glShaderSource(compute, 1, &cShaderCode, NULL); + glCompileShader(compute); + checkCompileErrors(compute, "COMPUTE"); + + // shader Program + ID = glCreateProgram(); + glAttachShader(ID, compute); + glLinkProgram(ID); + checkCompileErrors(ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessery + glDeleteShader(compute); + + } +}; \ No newline at end of file diff --git a/src/8.guest/2022/5.computeshader_helloworld/computer_shader_hello_world.cpp b/src/8.guest/2022/5.computeshader_helloworld/computer_shader_hello_world.cpp new file mode 100644 index 0000000..369f5df --- /dev/null +++ b/src/8.guest/2022/5.computeshader_helloworld/computer_shader_hello_world.cpp @@ -0,0 +1,196 @@ +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "computeShader.h" + +void framebuffer_size_callback(GLFWwindow* window, int width, int height); +void renderQuad(); + +// settings +const unsigned int SCR_WIDTH = 800; +const unsigned int SCR_HEIGHT = 600; + +// texture size +const unsigned int TEXTURE_WIDTH = 1000, TEXTURE_HEIGHT = 1000; + +// timing +float deltaTime = 0.0f; // time between current frame and last frame +float lastFrame = 0.0f; // time of last frame + +int main(int argc, char* argv[]) +{ + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + #ifdef __APPLE__ + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + #endif + + // glfw window creation + // -------------------- + GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + glfwMakeContextCurrent(window); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSwapInterval(0); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + // query limitations + // ----------------- + int max_compute_work_group_count[3]; + int max_compute_work_group_size[3]; + int max_compute_work_group_invocations; + + for (int idx = 0; idx < 3; idx++) { + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, idx, &max_compute_work_group_count[idx]); + glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, idx, &max_compute_work_group_size[idx]); + } + glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &max_compute_work_group_invocations); + + std::cout << "OpenGL Limitations: " << std::endl; + std::cout << "maxmimum number of work groups in X dimension " << max_compute_work_group_count[0] << std::endl; + std::cout << "maxmimum number of work groups in Y dimension " << max_compute_work_group_count[1] << std::endl; + std::cout << "maxmimum number of work groups in Z dimension " << max_compute_work_group_count[2] << std::endl; + + std::cout << "maxmimum size of a work group in X dimension " << max_compute_work_group_size[0] << std::endl; + std::cout << "maxmimum size of a work group in Y dimension " << max_compute_work_group_size[1] << std::endl; + std::cout << "maxmimum size of a work group in Z dimension " << max_compute_work_group_size[2] << std::endl; + + std::cout << "Number of invocations in a single local work group that may be dispatched to a compute shader " << max_compute_work_group_invocations << std::endl; + + // build and compile shaders + // ------------------------- + Shader screenQuad("screenQuad.vs", "screenQuad.fs"); + ComputeShader computeShader("computeShader.comp"); + + screenQuad.use(); + screenQuad.setInt("tex", 0); + + // Create texture for opengl operation + // ----------------------------------- + GLuint texture; + + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL); + + glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + + // render loop + // ----------- + int fCounter = 0; + while (!glfwWindowShouldClose(window)) + { + // Set frame time + GLfloat currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; + if(fCounter > 500) { + std::cout << "FPS: " << 1 / deltaTime << std::endl; + fCounter = 0; + } else { + fCounter++; + } + + computeShader.use(); + computeShader.setFloat("t", currentFrame); + glDispatchCompute((GLuint)TEXTURE_WIDTH/10, (GLuint)TEXTURE_HEIGHT/10, 1); + + // make sure writing to image has finished before read + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + + // render image to quad + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + screenQuad.use(); + + renderQuad(); + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + } + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteTextures(1, &texture); + glDeleteProgram(screenQuad.ID); + glDeleteProgram(computeShader.ID); + + glfwTerminate(); + + return EXIT_SUCCESS; +} + +// renderQuad() renders a 1x1 XY quad in NDC +// ----------------------------------------- +unsigned int quadVAO = 0; +unsigned int quadVBO; +void renderQuad() +{ + if (quadVAO == 0) + { + float quadVertices[] = { + // positions // texture Coords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + }; + // setup plane VAO + glGenVertexArrays(1, &quadVAO); + glGenBuffers(1, &quadVBO); + glBindVertexArray(quadVAO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + } + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + glViewport(0, 0, width, height); +} \ No newline at end of file diff --git a/src/8.guest/2022/5.computeshader_helloworld/screenQuad.fs b/src/8.guest/2022/5.computeshader_helloworld/screenQuad.fs new file mode 100644 index 0000000..bcfde96 --- /dev/null +++ b/src/8.guest/2022/5.computeshader_helloworld/screenQuad.fs @@ -0,0 +1,12 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +uniform sampler2D tex; + +void main() +{ + vec3 texCol = texture(tex, TexCoords).rgb; + FragColor = vec4(texCol, 1.0); +} \ No newline at end of file diff --git a/src/8.guest/2022/5.computeshader_helloworld/screenQuad.vs b/src/8.guest/2022/5.computeshader_helloworld/screenQuad.vs new file mode 100644 index 0000000..9f93e29 --- /dev/null +++ b/src/8.guest/2022/5.computeshader_helloworld/screenQuad.vs @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoords; + +out vec2 TexCoords; + +void main() +{ + TexCoords = aTexCoords; + gl_Position = vec4(aPos, 1.0); +} \ No newline at end of file