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);

// ...

}