1. Input, Output
#version 450 core
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout (std430, binding = 1) buffer InputBlock
{
float in_data[];
};
void main() {
uint index = gl_GlobalInvocationID.x;
in_data[index] += 100;
}
This compute shader just increments the content of an input float array by 100.
in_data[index] += 100;
The compute shader will be invoked 10 times, each invocation has its unique "uvec3 gl_GlobalInvocationID".
glDispatchCompute(10, 1, 1);
The x component of gl_GlobalInvocationID will be 0 ... 9, we use that ID to access the input array:
void main() {
uint index = gl_GlobalInvocationID.x;
in_data[index] += 100;
}
The input array has to be bound to the "shader storage buffer binding point" 1.
layout (std430, binding = 1) buffer InputBlock
{
float in_data[];
};
We do that by calling:
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer);
Complete Source Code:
Main.cpp
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <string>
#include "Shader.h"
// main functions
void Initialize();
void Render();
void CleanUp();
GLFWwindow* window = nullptr;
unsigned int program = 0;
unsigned int buffer = 0;
std::string computeshader_source = {
"#version 450 core\n"
"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;"
"layout (std430, binding = 1) buffer InputBlock { float in_data[]; };"
"void main() {"
"uint index = gl_GlobalInvocationID.x;"
"in_data[index] += 100;"
"}"
};
int main(void)
{
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
// init glew
if (glewInit() != GLEW_OK)
{
glfwTerminate();
return -1;
}
Initialize();
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
Render();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
CleanUp();
glfwTerminate();
return 0;
}
void Initialize()
{
// setup input buffer
//------------------------------------------------------------------------------------------------------------------------
// initial input data
float input[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
glGenBuffers(1, &buffer);
// bind buffer to binding point 1:
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, buffer);
// allocate buffer memory:
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(input), input, GL_STATIC_DRAW);
// finished, unbind buffer
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
// the buffer is still bound at binding point 1, but not at the generic target "GL_SHADER_STORAGE_BUFFER"
//------------------------------------------------------------------------------------------------------------------------
// setup program
//------------------------------------------------------------------------------------------------------------------------
program = glCreateProgram();
unsigned int computeshader = glCreateShader(GL_COMPUTE_SHADER);
CompileShader(computeshader, computeshader_source);
LinkProgram(program, { computeshader });
// the shader object will be deleted when it is no longer attached to any program
glDeleteShader(computeshader);
//------------------------------------------------------------------------------------------------------------------------
// invoke compute shader
//------------------------------------------------------------------------------------------------------------------------
glUseProgram(program);
glDispatchCompute(10, 1, 1);
glUseProgram(0);
// invokes the compute shader 10 x 1 x 1 = 10 times
// each invocation can be identified by its "uvec3 gl_GlobalInvocationID"
// in this case:
// gl_GlobalInvocationID.x will be 0 ... 9
// gl_GlobalInvocationID.y will be 0
// gl_GlobalInvocationID.z will be 0
//------------------------------------------------------------------------------------------------------------------------
// show buffer data
//------------------------------------------------------------------------------------------------------------------------
float returned_data[10] = { 0 };
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(returned_data), returned_data);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
for (unsigned int i = 0; i < 10; i++)
std::cout << "returned_data[" << i << "] = " << returned_data[i] << std::endl;
//------------------------------------------------------------------------------------------------------------------------
// ...
}
void Render()
{
glClearColor(0, 1, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
// ...
}
void CleanUp()
{
glDeleteProgram(program);
glDeleteBuffers(1, &buffer);
// ...
}