PDA

View Full Version : Trivial SSBO implementation not working



Albatross
08-16-2015, 07:58 AM
Hello

I am trying to use a very simple Shader Storage Buffer Object inside a trivial fragment shader, however it is not working :doh:.

The vertex shader:

#version 430

layout(location = 0) in vec2 Vertex;

void main() {
gl_Position = vec4(Vertex, 0.0, 1.0);
}

The fragment shader:

#version 430

layout(std430, binding = 0) buffer ColorSSBO {
float color[];
};

out vec4 FragmentColor;

void main() {
FragmentColor = vec4(color[0], color[1], color[2], 1.0);
}

I know that (apart the color array) this shader program is correct, because if I put the white color in FragmentColor, I see a white triangle in the center of the viewport.

The host code that initialize and bind the SSBO:

glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
float color[] = {1.f, 1.f, 1.f};
glBufferData(GL_SHADER_STORAGE_BUFFER, 3*sizeof(float), color, GL_DYNAMIC_COPY);

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
assert(glGetError() == GL_NO_ERROR);

So no error is raised, but the result is a black screen. The shader program is active when I perform those calls. What's wrong with my code?

malexander
08-16-2015, 01:43 PM
gl_FragColor doesn't exist in 430. You can try #version 430 Compatibility, or replace gl_FragColor with 'out vec4 color_out;'.

Albatross
08-16-2015, 02:10 PM
I have changed it, but still it does not work.

malexander
08-16-2015, 03:00 PM
Can you post more of your code, including how you draw the triangle and bind the shader?

Albatross
08-17-2015, 07:20 AM
Sure, I post the whole code it's short.


#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <cassert>

#define WIDTH 800
#define HEIGHT 480
using namespace std;

static void init();
static void initShaderProgram();
static void allocateSSBO();
static void display();
static void reshape(int,int);

static const char *vertexShader = R"(
#version 430

layout(location = 0) in vec2 Vertex;

void main() {
gl_Position = vec4(Vertex, 0.0, 1.0);
}
)";

static const char *fragmentShader = R"(
#version 430

layout(std430, binding = 0) buffer ColorSSBO {
float color[];
};

out vec4 FragmentColor;

void main() {
FragmentColor = vec4(color[0], color[1], color[2], 1.0);
}
)";

static int window;
static GLuint shaders[3];
static GLuint vao;
static GLuint vbo;
static GLuint ssbo;

static void __stdcall DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam) {
cout << message << endl;
}

void init() {
// Init FreeGLUT
int temp = 0;
glutInit(&temp, nullptr);
glutInitContextVersion(4, 3);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInitContextFlags(GLUT_DEBUG);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(WIDTH, HEIGHT);
window = glutCreateWindow("LinkedList-OIT");
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glClearColor(0, 0, 0, 1);

// Init GLEW
glewExperimental = GL_TRUE;
GLenum outcome = glewInit();
if(outcome != GL_NO_ERROR)
exit(-1);
glGetError();

initShaderProgram();
glDebugMessageCallback((GLDEBUGPROC)DebugCallback, nullptr);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);

// Init center triangle
float triangle[] = {
+0.00, +0.67,
+0.67, -0.67,
-0.67, -0.67
};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 2*sizeof(float)*3, triangle, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

// Print debug info
cout << glGetString(GL_VERSION) << endl;
}

static void checkShader(GLuint shader) {
// Standard shader validation
}

static void checkProgram(GLuint program) {
// Standard program validation
}

void initShaderProgram() {
// Init vertex shader
shaders[0] = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shaders[0], 1, &vertexShader, nullptr);
glCompileShader(shaders[0]);
checkShader(shaders[0]);

// Init fragment shader
shaders[1] = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shaders[1], 1, &fragmentShader, nullptr);
glCompileShader(shaders[1]);
checkShader(shaders[1]);

// Link program
shaders[2] = glCreateProgram();
glAttachShader(shaders[2], shaders[0]);
glAttachShader(shaders[2], shaders[1]);
glLinkProgram(shaders[2]);
checkProgram(shaders[2]);

// Bind the compiled program
glUseProgram(shaders[2]);
}

void allocateSSBO() {
// Build and populate
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
float color[] = {1.f, 1.f, 1.f};
glBufferData(GL_SHADER_STORAGE_BUFFER, 3*sizeof(float), color, GL_DYNAMIC_COPY);

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
assert(glGetError() == GL_NO_ERROR);
}

void reshape(int width, int height) {
glViewport(0, 0, width, height);
}

void display() {
glClear(GL_COLOR_BUFFER_BIT);

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);

glutSwapBuffers();
glutPostRedisplay();
}

int main(int argc, char **argv) {
init();
allocateSSBO();
glutMainLoop();
}


Thank you for this.

malexander
08-17-2015, 02:42 PM
Perhaps you could try clearing the viewport to a different color (like red) to see if the triangle is drawing black (SSBO data upload issue?) or not at all (shader problem?). Nothing jumps out at me as obviously wrong in your code.

EmJayJay
08-18-2015, 05:24 AM
You are missing connections to the shader programs entirely. Follow this tutorial http://www.geeks3d.com/20140704/tutorial-introduction-to-opengl-4-3-shader-storage-buffers-objects-ssbo-demo/

EDIT:I was hasty and missed the part where you could use the hard coded binding index to skip the glShadeStorageBlockBinding() call.

Albatross
08-18-2015, 09:45 AM
Perhaps you could try clearing the viewport to a different color (like red) to see if the triangle is drawing black (SSBO data upload issue?) or not at all (shader problem?). Nothing jumps out at me as obviously wrong in your code.

I tried and I see a black triangle. So it seems to be a data upload issue, but I can't find anything wrong too. I'm wondering if it could be a bug with the Catalyst.

Albatross
09-04-2015, 06:58 PM
I found this, which seemed to explain why the GLSL program was not working:


The rules for std140​ layout are covered quite well in the OpenGL specification (OpenGL 4.5, Section 7.6.2.2, page 137). Among the most important is the fact that arrays of types are not necessarily tightly packed. An array of float​s in such a block will not be the equivalent to an array of floats​ in C/C++. The array stride (the bytes between array elements) is always rounded up to the size of a vec4​ (ie: 16-bytes). So arrays will only match their C/C++ definitions if the type is a multiple of 16 bytes.

However this evening the program has started to work without modifications (!!). Honestly I don't know what to think.. maybe the driver was in good spirits. Anyway, it seems that to avoid any trouble it's better to use only vec4 within uniform blocks.

Alfonse Reinheart
09-04-2015, 07:59 PM
I found this, which seemed to explain why the GLSL program was not working:

No it doesn't. That's talking about std140 layout rules. You explicitly asked for std430. And the principle difference between them is that std430 doesn't do that.

Albatross
09-05-2015, 04:31 AM
The wiki is dangerously vague on this.. it states that the std430 layout is almost identical to the std140, except for some unspecified optimizations. The 4.5 specs (https://www.opengl.org/registry/doc/glspec45.core.pdf) are more clear:



When using the std430 storage layout, shader storage blocks will be laid out in buffer storage identically to uniform and shader storage blocks using the std140 layout, except that the base alignment and stride of arrays of scalars and vectors in rule 4 and of structures in rule 9 are not rounded up a multiple of the base alignment of a vec4.

Quite a mess. I mean, I know GPU are complex devices, but I hadn't such issues with CUDA.