1

I've found a strange behavior of the drivers I can't figure out while using OpenGL 4.3.

I'm drawing some triangles with glDrawArraysIndirect() on the default FBO.

    glBindBuffer(GL_DRAW_INDIRECT_BUFFER, command);
    glBindVertexArray(VAO);
        glDrawArraysIndirect(GL_TRIANGLES, nullptr);
    glBindVertexArray(0);
    glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);

The command is defined like this:

struct DrawArraysIndirectCommand 
{
    GLuint count;
    GLuint primCount;
    GLuint first;
    GLuint baseInstance;
};

It's updated in the fragment shader of a previous draw call made on an offscreen FBO, where it's bound as an atomic counter:

glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, command);

In the fragment shader it's updated in this way:

layout(binding = 0, offset = 0) uniform atomic_uint vertex_count;
main() { 
    ...
    if(some condition) { atomicCounterIncrement(vertex_count); }
    ...
}

The problem arises from a different behavior between nvidia drivers and intel drivers. At first I bound the command as an atomic counter at the beginning of the program, before any draw call and I never unbound it until the end of the program:

init() {
     // Generation of the buffer
     glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, command); // <--- FIX
}
draw() {
    glBindFramebuffer(GL_FRAMEBUFFER, offscreen_FBO);
        // Clear indirect draw command buffer
        glBindBuffer(GL_DRAW_INDIRECT_BUFFER, command);
            glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(DrawArraysIndirectCommand), 
                            &clearedCommand);
        glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);

        glBindVertexArray(VAO2);
             // Draw call in which the command is updated from the fragment shader
             glDrawArrays(GL_TRIANGLES, 0, another_vertex_count);
        glBindVertexArray(0);

        //use of the updated command in another draw call...
}

In this way it worked fine with nvidia drivers. But when I tested the application with intel drivers it worked only for a few minutes and then crashed (the crash originated in the graphic driver, but no error was produced). I solved this problem by binding the atomic counter every time before the draw call:

draw() {
    glBindFramebuffer(GL_FRAMEBUFFER, offscreen_FBO);
        // Clear indirect draw command buffer
        glBindBuffer(GL_DRAW_INDIRECT_BUFFER, command);
            glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(DrawArraysIndirectCommand), 
                            &clearedCommand);
        glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);

        glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, command); // <--- FIX
        glBindVertexArray(VAO2);
             // Draw call in which the command is updated from the fragment shader
             glDrawArrays(GL_TRIANGLES, 0, another_vertex_count);
        glBindVertexArray(0);

        //use of the updated command in another draw call...
 }

In this way it works fine also on the intel drivers. But why? Why do I need to rebind it every time? It's like if the driver sometimes lose the binding, but there isn't any other glBindBufferBase() that bind at the same index. I think the problem is related with the fact that command is used both as an atomic counter and as an indirect command buffer, but I can't understand the link.

Tarquiscani
  • 649
  • 7
  • 20

0 Answers0