0
\$\begingroup\$

In my code-base I need to link the vertex declarations from a mesh to the attributes of a shader. To do this I retrieve all the attribute names after linking the shader. I use the following code (with some added debug info since it's not really working):

int shaders[] = { m_ps, m_vs };
if(linkProgram(shaders, 2))
{
    ASSERT(glIsProgram(m_program) == GL_TRUE, "program is invalid");

    int attrCount = 0;
    GL_CHECKED(glGetProgramiv(m_program, GL_ACTIVE_ATTRIBUTES, &attrCount));

    int maxAttrLength = 0;
    GL_CHECKED(glGetProgramiv(m_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttrLength));

    LOG_INFO("shader", "got %d attributes for '%s' (%d) (maxlen: %d)", attrCount, name, m_program, maxAttrLength);

    m_attrs.reserve(attrCount);

    GLsizei attrLength = -1;
    GLint attrSize = -1;
    GLenum attrType = 0;

    char tmp[256];
    for(int i = 0; i < attrCount; i++)
    {
        tmp[0] = 0;
        GL_CHECKED(glGetActiveAttrib(m_program, GLuint(i), sizeof(tmp), &attrLength, &attrSize, &attrType, tmp));
        LOG_INFO("shader", "%d: %d %d '%s'", i, attrLength, attrSize, tmp);
        m_attrs.append(String(tmp, attrLength));
    }
}

GL_CHECKED is a macro that calls the function and calls glGetError() to see if something went wrong. This code works perfectly on Windows 7 using ANGLE and gives this this output:

info:shader: got 2 attributes for 'static/simplecolor.glsl' (3) (maxlen: 11)
info:shader: 0: 7 1 'a_Color'
info:shader: 1: 10 1 'a_Position'

But on my Nexus 7 (1st gen) I get the following (the errors are the output from the GL_CHECKED macro):

I/testgame:shader(30865): got 2 attributes for 'static/simplecolor.glsl' (3) (maxlen: 11)
E/testgame:gl(30865): 'glGetActiveAttrib(m_program, GLuint(i), sizeof(tmp), &attrLength, &attrSize, &attrType, tmp)' failed: INVALID_VALUE [jni/src/../../../../src/Game/Asset/ShaderAsset.cpp:50]
I/testgame:shader(30865): 0: -1 -1 ''
E/testgame:gl(30865): 'glGetActiveAttrib(m_program, GLuint(i), sizeof(tmp), &attrLength, &attrSize, &attrType, tmp)' failed: INVALID_VALUE [jni/src/../../../../src/Game/Asset/ShaderAsset.cpp:50]
I/testgame:shader(30865): 1: -1 -1 ''

I.e. the call to glGetActiveAttrib gives me an INVALID_VALUE. The opengl docs says this about the possible errors:

GL_INVALID_VALUE is generated if program is not a value generated by OpenGL.

This is not the case, I added an ASSERT to make sure glIsProgram(m_program) == GL_TRUE, and it doesn't trigger.

GL_INVALID_OPERATION is generated if program is not a program object.

Different error.

GL_INVALID_VALUE is generated if index is greater than or equal to the number of active attribute variables in program.

i is 0 and 1, and the number of active attribute variables are 2, so this isn't the case.

GL_INVALID_VALUE is generated if bufSize is less than 0.

Well, it's not zero, it's 256.

Does anyone have an idea what's causing this? Am I just lucky that it works in ANGLE, or is the nvidia tegra driver wrong?

\$\endgroup\$
0
\$\begingroup\$

After lots of trial and error I found that calling glDetachShader(...) on the vertex shader before glGetActiveAttrib(...) will lead to the results I saw. I can't find anything about this in the docs, so I assume it's implementation specific.

The solution is to get all the data you need before detaching the individual shaders.

\$\endgroup\$
  • \$\begingroup\$ Why are you calling glDetachShader? You do not need to detach the shader from the program until/if you release your gl resources. \$\endgroup\$ – ashleysmithgpu May 31 '14 at 13:00
  • \$\begingroup\$ The following question contains argument for why it's a good idea: gamedev.stackexchange.com/questions/47910/… \$\endgroup\$ – user408952 May 31 '14 at 13:16
  • \$\begingroup\$ @user408952: You have taken that question out of context. What you want to do is delete your shader after you compile and attach it. This ensures that after all of the GLSL programs that use the shader have been destroyed, the shader itself also is. Otherwise, shader objects tend to leak in OpenGL. But if you detach the shader and then delete it, you have first invalidated your GLSL program and then if the reference count for your shader is 0 at that point, you also deleted your shader. \$\endgroup\$ – Andon M. Coleman Jun 1 '14 at 21:55
  • \$\begingroup\$ @user408952: Deleting a shader does not actually do anything until the shader's reference count reaches 0. That happens once it has been detached from all GLSL programs, until that point the shader is basically put onto a list of objects to be deleted. Detaching is very different from deleting, and it will break your GLSL program if you try to continue using the program while one of its linked shaders is detached. \$\endgroup\$ – Andon M. Coleman Jun 1 '14 at 21:56
  • \$\begingroup\$ This is the link I meant to post: stackoverflow.com/questions/9113154/… which says that "Yes -- in fact it is highly desireable to detach and delete your shader objects as soon as possible. That way the driver can free up all the memory it is using to hold a copy of the shader source and unlinked object code, which can be quite substantial." \$\endgroup\$ – user408952 Jun 3 '14 at 9:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.