OpenGL ES 3 Instance Rendering

I am working on implementing a basic example program that uses instance rendering with the “glDrawElementsInstaced” call. I have created working examples on desktop OpenGL (330 core) but I have encountered an issue porting this to OpenGL ES 3. Specifically, I am using the Android NDK and SDL2. I have worked with these libraries before with OpenGL ES 3 and have created other OpenGL ES 3 programs (namely ones that use Vertex Array Objects and FrameBuffers).

The error that I get in logcat looks like this:

0-18 15:49:57.274 20996-21026/package I/SDL/APP: Program link failed: --From Vertex Shader:
10-18 15:49:57.274 20996-21026/packageI/SDL/APP: linker error: multiple attribute attempt to bind at same location 
10-18 15:49:57.274 20996-21026/packageI/SDL/APP: --From Fragment Shader:
10-18 15:49:57.274 20996-21026/package I/SDL/APP: linker error: multiple attribute attempt to bind at same location

My vertex and indices are created like so (buffers have already been generated):


    glBindVertexArray(mVAO_Handle);

    glBindBuffer(GL_ARRAY_BUFFER, mVBO_Array[VBO_INDEX]);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW);

    // vertex position
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid*>(offsetof(Vertex, position)));

    // vertex texture coordinate
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid*>(offsetof(Vertex, texCoord)));

    // vertex normal
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid*>(offsetof(Vertex, normal)));

    // indices data
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVBO_Array[VBO_INDEX]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, mVBO_InstanceData);
    glBufferData(GL_ARRAY_BUFFER, instanceData.size() * sizeof(glm::mat4), instanceData.data(), GL_STATIC_DRAW);
    
    // instance data
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), reinterpret_cast<GLvoid*>(0));
    glVertexAttribDivisor(3, 1); // increment instance data by 1 each iteration

    glEnableVertexAttribArray(4);
    glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), reinterpret_cast<GLvoid*>(sizeof(glm::vec4)));
    glVertexAttribDivisor(4, 1);

    glEnableVertexAttribArray(5);
    glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), reinterpret_cast<GLvoid*>(2 * sizeof(glm::vec4)));
    glVertexAttribDivisor(5, 1);

    glEnableVertexAttribArray(6);
    glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), reinterpret_cast<GLvoid*>(3 * sizeof(glm::vec4)));
    glVertexAttribDivisor(6, 1);

And the vertex shader is simply:

#version 300 es
precision mediump float;

// attribute data
layout (location = 0) in vec3 aVertexPosition;
layout (location = 1) in vec2 aVertexTexCoord;
layout (location = 2) in vec3 aVertexNormal;
layout (location = 3) in mat4 aInstanceTransform;

// varying data
out vec3 vPosition;
out vec2 vTexCoord;
out vec3 vNormal;

// uniform data
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat3 uNormalMatrix;

void main(void)
{
    vec4 mvTransform = uModelViewMatrix * aInstanceTransform * vec4(aVertexPosition, 1.0);
    vTexCoord = aVertexTexCoord;
    vPosition = mvTransform.xyz;
    vNormal = normalize(uNormalMatrix * aVertexNormal);
    gl_Position = uProjectionMatrix * mvTransform;
}

I don’t know what’s causing the issue as of yet. I think it might have something to do with the “aInstanceTransform” attribute. If I comment it out in the main function then the program runs. I wonder if I need to use 2 vec4s instead?

It’s possible that the implementation has a bug regarding attributes which are matrices.

Have you tried omitting the “layout (location = 3)” qualifier and using glGetAttribLocation() instead?

A matrix is attribute is treated as multiple attributes, one for each column. It’s possible that the implementation is trying to assign location 3 to all of the columns (rather than assigning consecutive locations), which would cause the linking error.

Also, you’re not assigning locations with glBindAttribLocation(), right?

[QUOTE=GClements;1280059]

Also, you’re not assigning locations with glBindAttribLocation(), right?[/QUOTE]

I got it fixed! I was not using glBindAttribLocation since I was using layout qualifiers. But, if I removed the layout qualifiers as you suggested and used glBindAttribLocation (with the same numbering scheme as the layout qualifiers) the program runs with beautiful instance rendering.
I suppose the mat4 threw off the numbering scheme in the GPU buffers as you suggested. I probably could’ve just used glGetAttribLocation as well. Or possibly use 4 vec4’s for my instance data. I suppose it’s a hardware thing since I’ve never run into this before on desktop with instance rendering.

I’m fairly sure it’s a driver bug, specifically in the GLSL compiler.

Certainly, it isn’t a hardware issue. Matrix attributes are just syntactic sugar for multiple consecutive vector attributes; they don’t require any specific support from the hardware.

There shouldn’t be any difference between using layout(location=) qualifiers and glBindAttribLocation(). It seems that the compiler forgets to increment the location between columns, giving all of the columns the same location, then the linker generates an error because multiple attributes have the same location.

[QUOTE=GClements;1280067]I’m fairly sure it’s a driver bug, specifically in the GLSL compiler.

Certainly, it isn’t a hardware issue. Matrix attributes are just syntactic sugar for multiple consecutive vector attributes; they don’t require any specific support from the hardware.

There shouldn’t be any difference between using layout(location=) qualifiers and glBindAttribLocation(). It seems that the compiler forgets to increment the location between columns, giving all of the columns the same location, then the linker generates an error because multiple attributes have the same location.[/QUOTE]

Ah that actually makes a lot of sense. Thanks for that insight I wasn’t sure if I would ever have figured out that the layout qualifiers were not working as intended (especially since they had been working for all the vec’s that I had been using).