In OpenGL is there a way to get a list of all uniforms & attribs used by a shader program?

后端 未结 4 1332
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-12 11:01

I\'d like to get a list of all the uniforms & attribs used by a shader program object. glGetAttribLocation() & glGetUniformLocation() can

4条回答
  •  心在旅途
    2020-12-12 11:14

    There has been a change in how this sort of thing is done in OpenGL. So let's present the old way and the new way.

    Old Way

    Linked shaders have the concept of a number of active uniforms and active attributes (vertex shader stage inputs). These are the uniforms/attributes that are in use by that shader. The number of these (as well as quite a few other things) can be queried with glGetProgramiv:

    GLint numActiveAttribs = 0;
    GLint numActiveUniforms = 0;
    glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTES, &numActiveAttribs);
    glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
    

    You can query active uniform blocks, transform feedback varyings, atomic counters, and similar things in this way.

    Once you have the number of active attributes/uniforms, you can start querying information about them. To get info about an attribute, you use glGetActiveAttrib; to get info about a uniform, you use glGetActiveUniform. As an example, extended from the above:

    GLint maxAttribNameLength = 0;
    glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH​, &maxAttribNameLength);
    std::vector nameData(maxAttribNameLength)
    for(int attrib = 0; attrib < numActiveAttribs; ++attrib)
    {
      GLint arraySize = 0;
      GLenum type = 0;
      GLsizei actualLength = 0;
      glGetActiveAttrib(prog, attrib, nameData.size(), &actualLength, &arraySize, &type, &nameData[0]);
      std::string name((char*)&nameData[0], actualLength - 1);
    }
    

    Something similar can be done for uniforms. However, the GL_ACTIVE_UNIFORM_MAX_LENGTH​ trick can be buggy on some drivers. So I would suggest this:

    std::vector nameData(256);
    for(int unif = 0; unif < numActiveUniforms; ++unif)
    {
      GLint arraySize = 0;
      GLenum type = 0;
      GLsizei actualLength = 0;
      glGetActiveUniform(prog, unif, nameData.size(), &actualLength, &arraySize, &type, &nameData[0]);
      std::string name((char*)&nameData[0], actualLength - 1);
    }
    

    Also, for uniforms, there's glGetActiveUniforms, which can query all of the name lengths for every uniform all at once (as well as all of the types, array sizes, strides, and other parameters).

    New Way

    This way lets you access pretty much everything about active variables in a successfully linked program (except for regular globals). The ARB_program_interface_query extension is not widely available yet, but it'll get there.

    It starts with a call to glGetProgramInterfaceiv, to query the number of active attributes/uniforms. Or whatever else you may want.

    GLint numActiveAttribs = 0;
    GLint numActiveUniforms = 0;
    glGetProgramInterfaceiv(prog, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &numActiveAttribs);
    glGetProgramInterfaceiv(prog, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numActiveUniforms);
    

    Attributes are just vertex shader inputs; GL_PROGRAM_INPUT means the inputs to the first program in the program object.

    You can then loop over the number of active resources, asking for info on each one in turn, from glGetProgramResourceiv and glGetProgramResourceName:

    std::vector nameData(256);
    std::vector properties;
    properties.push_back(GL_NAME_LENGTH​);
    properties.push_back(GL_TYPE​);
    properties.push_back(GL_ARRAY_SIZE​);
    std::vector values(properties.size());
    for(int attrib = 0; attrib < numActiveAttribs; ++attrib)
    {
      glGetProgramResourceiv(prog, GL_PROGRAM_INPUT, attrib, properties.size(),
        &properties[0], values.size(), NULL, &values[0]);
    
      nameData.resize(values[0]); //The length of the name.
      glGetProgramResourceName(prog, GL_PROGRAM_INPUT, attrib, nameData.size(), NULL, &nameData[0]);
      std::string name((char*)&nameData[0], nameData.size() - 1);
    }
    

    The exact same code would work for GL_UNIFORM; just swap numActiveAttribs with numActiveUniforms.

提交回复
热议问题