Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 7 of 7

Thread: Compute shader and buffer format

  1. #1
    Junior Member Newbie
    Join Date
    Aug 2012
    Posts
    7

    Compute shader and buffer format

    Hello,

    I'm just trying to play with the compute shader (GL 4.3) and I'm facing some issues with the way I'm filling my shader uniform buffer.

    This is my shader code:

    Code :
    #version 430 core
     
    layout (local_size_x = 32) in;
     
    layout(binding=0) buffer inputBuffer {
        float input[];
    };
     
    // don't use std140 for this, I must understand why...
    layout(binding=1) buffer outputBuffer {
        float output[];
    };
     
    void main()
    {
        const uint offset = gl_GlobalInvocationID.x;
     
        if(offset % 2 == 0)
            output[offset] = input[offset];
        else
            output[offset] = -input[offset];
    }

    Which is really simple, it takes a buffer as input and write the same buffer as output with all odd numbers negated.

    this is my GL code:

    Code :
    // cc -Wall -Wextra -g -std=c99  -lglut -lGLEW -lGL  test_debug.c   -o test_debug
    #include <assert.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
     
    #include <GL/glew.h>
    #include <GL/gl.h>
    #include <GL/freeglut.h>
     
    struct State
    {
        GLuint buffers[2];
        GLuint shader_program;
     
    } state;
     
    void debug
    (GLenum source,
     GLenum type,
     GLuint id,
     GLenum severity,
     GLsizei length,
     const GLchar* message,
     GLvoid* userParams)
    {
        printf("DEBUG: %s\n", message);
    }
     
    char *read_file(char *filename)
    {
        FILE* fp = fopen(filename, "r");
        assert(fp);
        fseek(fp, 0, SEEK_END);
        long size = ftell(fp);
        fseek(fp, 0, SEEK_SET);
     
        char * data = malloc(sizeof(char) * size + 1);
        size_t r = fread(data, sizeof(char), size, fp);
        assert(r == size);
        data[size] = '\0';
     
        fclose(fp);
     
        return data;
    }
     
    void init2()
    {
        // Compute shader creation
        GLuint compute_shader = glCreateShader(GL_COMPUTE_SHADER);
        const GLchar * csSrc = read_file("test.cs");
        GLint size = strlen(csSrc);
        glShaderSource(compute_shader, 1, &csSrc, &size);
        glCompileShader(compute_shader);
     
        // link of program
        state.shader_program = glCreateProgram();
        glAttachShader(state.shader_program, compute_shader);
        glLinkProgram(state.shader_program);
     
        // Display errors
        char infoLog[10000];
        glGetProgramInfoLog(state.shader_program, sizeof(infoLog), NULL, infoLog);
        printf("%s\n", infoLog);
     
     
        // buffer creation (input and output)
        glGenBuffers(2, state.buffers);
     
        // fill the input buffer with numbers
        float data[32];
        for(unsigned int i = 0; i < 32; ++i)
            data[i] = i;
     
        glBindBuffer( GL_SHADER_STORAGE_BUFFER, state.buffers[0] );
        glBufferData( GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW );
     
     
        // resize the output buffer
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, state.buffers[1]);
     
        // XXX depending of the choice I use, I got right/wrong results
        //GLenum choice = GL_STATIC_DRAW; // NO
        //GLenum choice = GL_STATIC_READ; // NO
        //GLenum choice = GL_STATIC_COPY; // NO
        //GLenum choice = GL_DYNAMIC_DRAW; // NO
        //GLenum choice = GL_DYNAMIC_READ; // YES
        //GLenum choice = GL_DYNAMIC_COPY; // YES
        //GLenum choice = GL_STREAM_DRAW; // NO
        GLenum choice = GL_STREAM_READ; // YES
        //GLenum choice = GL_STREAM_COPY; // YES
     
        glBufferData( GL_SHADER_STORAGE_BUFFER, sizeof(data), NULL, choice);
        glMemoryBarrier(GL_ALL_BARRIER_BITS);
     
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
    }
     
    void renderScene2()
    {
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, state.buffers[0]);
        glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, state.buffers[1]);
     
        glUseProgram(state.shader_program);
     
        // Ugly memory sync because I don't know what I'm doing, I want to be sure that all my data are sent
        glMemoryBarrier(GL_ALL_BARRIER_BITS);
     
        glDispatchCompute(1, 1, 1);
     
        // Ugly memory sync because I don't know what I'm doing, I want to bu sure that my shader correctly modified the data
        glMemoryBarrier(GL_ALL_BARRIER_BITS);
     
        glUseProgram(0);
     
        // Get the resul0t back
        float result[32];
        // Ugly init of the result vector for debug
        for(unsigned int i = 0; i < 32; ++i)
            result[i] = -2;
     
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, state.buffers[1]);
        glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(result), result);
     
        // Get and display the results
        for(unsigned int i = 0; i < 32; ++i)
            printf("%f\n", result[i]);
     
        glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
    }
     
    int main(int argc, char **argv) {
        // init GLUT and create Window
        glutInit(&argc, argv);
     
        //glutInitContextVersion(4, 3);
        glutInitContextFlags(GLUT_CORE_PROFILE | GLUT_DEBUG);
     
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
     
        glutInitWindowSize(800, 600);
     
        glutCreateWindow("Instance Test");
     
     
        // C'est pour glew, pour recuperer toutes les extensions
        glewInit();
     
        glEnable(GL_DEBUG_OUTPUT);
     
        glDebugMessageCallback(&debug, NULL);
     
        printf("VERSION: %s\n", glGetString(GL_VERSION));
        printf("RENDERER: %s\n", glGetString(GL_RENDERER));
        printf("VENDOR: %s\n", glGetString(GL_VENDOR));
        GLint mcsms;
        glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &mcsms);
        printf("GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: %d\n", mcsms);
     
        glutDisplayFunc(renderScene2);
     
        init2();
     
        renderScene2();
        //glutMainLoop();
        return 0;
    }

    I tried to set enough comments, but the main issue comes from the fact that the result can totally change depending on the *usage* flag of the *glBufferSubData* command for the second (output) buffer. (See the GLenum choice lines, thoses with a NO does not works and thoses with the YES works).

    It appears from what I read in the spec that the usage flag may not change the behavior of the driver, so is this a driver bug ? Or is this a driver different behavior (because of the usage hint) which leads to a different result because of a bug in my code?

    Please note that I putted synchronisation everywhere because I'm not too sure of where I need to put them.

    Thank you for your help.

    Last but not least, I runned this on Arch Linux with Nvidia drivers 304.15 on a GeForce 560 Ti.

  2. #2
    Senior Member OpenGL Guru
    Join Date
    May 2009
    Posts
    4,948
    The spec is very clear: hints affect performance, not behavior. That is a driver bug, no question.

  3. #3
    Junior Member Newbie
    Join Date
    Aug 2012
    Posts
    7
    Quote Originally Posted by Alfonse Reinheart View Post
    The spec is very clear: hints affect performance, not behavior. That is a driver bug, no question.
    Thank you for your answer.

    I was asking because sometime unexcepted behavior are trigered because users (like me) are doing some ugly stuff somewhere else which triggers an undefined behavior in a place where undefined behavior are not excepcted.

    I'll try to do a nvidia bug repport if I'm finding how to do it.

  4. #4

  5. #5
    Intern Contributor
    Join Date
    Mar 2010
    Posts
    59
    Hi guiboi,

    I have reproduced the issue you report and I will investigate the problem and implement a fix. I'll let you know when you can expect to see the fix in an OpenGL 4.3 beta driver update.

    Regards,
    Piers

  6. #6
    Intern Contributor
    Join Date
    Mar 2010
    Posts
    59
    This bug has now been fixed and will be included in the next beta release. As a work-around you can modify the NULL pointer you use with glBindData to be a non-NULL pointer, for example just use "data".

  7. #7
    Junior Member Newbie
    Join Date
    Aug 2012
    Posts
    7
    Quote Originally Posted by Piers Daniell View Post
    This bug has now been fixed and will be included in the next beta release.
    Thank you! I'm really looking forward for the next release.

    As a work-around you can modify the NULL pointer you use with glBindData to be a non-NULL pointer, for example just use "data".
    Ha, sorry, I had noticed this fact, but don't though about it when I wrote the message.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •