Oscar
Oscar

Reputation: 2112

Error using glMultiDrawArraysIndirect and indirect buffer

I have two objects (A and B) to be rendered using glMultiDrawArraysIndirect(). Each object has a setupBuffers() method for creating, binding a vao, then creating and binding the indirect buffer, instanced ID buffer, vertices buffer and texture coords buffer. (using JOGL)

Here is the problem: if I call setupBuffers() of the object A before calling setupBuffers() in B, then only B will be drawn; if I call setupBuffers() of the object B before calling setupBuffers() in A, then only A will be drawn. (No exception is found.) The data stored should be all correct since I've tested both of them.

Object A:

protected void setupBuffers()
{
    gl.glGenVertexArrays(1, vaoBuff);
    gl.glBindVertexArray(vaoBuff.get(0));

    gl.glGenBuffers(4, vboBuff);

    //bind indirect buffer object
    gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
    gl.glBufferData(GL4.GL_DRAW_INDIRECT_BUFFER, instanceCount * 4 * Integer.SIZE / 8, null, GL4.GL_STATIC_DRAW);
    gl.glBufferSubData(...);

    //bind draw instance ID in the shader with a buffer object
    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(1));
    gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount * Integer.SIZE / 8, drawIndexBuff, GL4.GL_STATIC_DRAW);
    gl.glVertexAttribIPointer(d_idLoc, 1, GL4.GL_UNSIGNED_INT, 0, 0);
    gl.glVertexAttribDivisor(d_idLoc, 1);
    gl.glEnableVertexAttribArray(d_idLoc);

    //bind vertex data buffer object
    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(2));
    gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount / column_subdivision * vertBuffSize * Float.SIZE / 8, null, GL4.GL_STATIC_DRAW);
    gl.glBufferSubData(...);
    gl.glVertexAttribPointer(verPosLoc, 3, GL4.GL_FLOAT, false, 0, 0);
    gl.glEnableVertexAttribArray(verPosLoc);

    //bind texture coordinate data buffer object
    gl.glBindBuffer(GL4.GL_ARRAY_BUFFER, vboBuff.get(3));
    gl.glBufferData(GL4.GL_ARRAY_BUFFER, instanceCount / column_subdivision * texBuffSize * Float.SIZE / 8, null, GL4.GL_STATIC_DRAW);
    gl.glBufferSubData(...);
    gl.glVertexAttribPointer(tc_inLoc, 2, GL4.GL_FLOAT, false, 0, 0);
    gl.glEnableVertexAttribArray(tc_inLoc);
}

drawing method:

gl.glBindVertexArray(vaoBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_TRIANGLE_STRIP, 0, instanceCount, 0);

Object B:

(the method 'setupBuffers()' is very similar to the one in A)

drawing method:

gl.glBindVertexArray(vaoBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_PATCHES, 0, instanceCount, 0);

Any ideas?

Added: Now I have found the line causing that problem:

gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));

This method used to bind a indirect buffer is called once both in Object A & B, resulting in that problem, yet I have no idea why. Why is that? Is that the same using OpenGL (I'm using JOGL)? Or is that a bug of JOGL?

Upvotes: 1

Views: 1499

Answers (2)

Oscar
Oscar

Reputation: 2112

Fixed it finally. The GL_DRAW_INDIRECT_BUFFER binding point is not part of vertex array object state. It's global context state. So I'll have to set this to the buffer I want to pull from before performing indirect operations from that buffer (change the above code to):

gl.glBindVertexArray(vaoBuff.get(0)); 
gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_PATCHES, 0, instanceCount, 0); 

then it worked just fine.

Upvotes: 2

Reto Koradi
Reto Koradi

Reputation: 54642

The part of your own answer that describes the root cause of the problem makes a lot of sense. The GL_DRAW_INDIRECT_BUFFER binding is indeed not part of the VAO state. This is confirmed by the spec. The corresponding state (DRAW_INDIRECT_BUFFER_BINDING) is listed in table 23.5 captioned "Vertex Array Data (not in Vertex Array objects)".

Your proposed solution does not look ideal to me, though. Calling glBufferData() on the indirect buffer before each draw call would defeat the purpose of storing the data in the buffer in the first place. The idea is that you can use the data repeatedly, while it stays in memory that the GPU can access efficiently.

All you should need to do is bind the buffer again before each draw call. The call sequence for drawing then looks like this:

gl.glBindVertexArray(vaoBuff.get(0)); 
gl.glBindBuffer(GL4.GL_DRAW_INDIRECT_BUFFER, vboBuff.get(0));
gl.glMultiDrawArraysIndirect(GL4.GL_PATCHES, 0, instanceCount, 0);

Upvotes: 3

Related Questions