Vaernus's picture

[solved] Crashing During GetActiveAttrib/GetActiveUniform

We are building a visual material editor that grabs all inputs within the shader and allows our artists to then assign the inputs through other portions of our toolkit. However, we are getting a consistent crash when trying to get the inputs using GetActiveAttrib and GetActiveUniform (to which a try/catch will not stop the crash).

The current process is to grab the vertex/fragment source strings from where they are stored, load in the shader, grab the inputs, and then delete the shader. The shader loads fine (and has been tested to properly compile the shaders), but we get unstable results as it tries to grab all the inputs. Occasionally it seems to get through the inputs, but then will randomly crash a few seconds later, and sometimes it crashes as we attempt to delete the shader.

This is what we're doing for grabbing the inputs:

var variablesList = new List<ShaderData>();
 
            int attributes;
            GL.GetProgram(currentShader.ShaderId, GetProgramParameterName.ActiveAttributes, out attributes);
 
            for (var i = 0; i < attributes; i++)
            {
                var newShaderData = new ShaderData();
                GL.GetActiveAttrib(currentShader.ShaderId, i, 255, out newShaderData.Length, out newShaderData.Size, out newShaderData.AttribType, newShaderData.Name);
                newShaderData.Location = GL.GetAttribLocation(currentShader.ShaderId, newShaderData.Name.ToString());
                variablesList.Add(newShaderData);
            }
 
            int uniforms;
            GL.GetProgram(currentShader.ShaderId, GetProgramParameterName.ActiveUniforms, out uniforms);
 
            for (var i = 0; i < uniforms; i++)
            {
                var newShaderData = new ShaderData();
                GL.GetActiveUniform(currentShader.ShaderId, i, 255, out newShaderData.Length, out newShaderData.Size, out newShaderData.UniformType, newShaderData.Name);
                newShaderData.Location = GL.GetUniformLocation(currentShader.ShaderId, newShaderData.Name.ToString());
                variablesList.Add(newShaderData);
            }
 
            return variablesList;

Any help would be greatly appreciated!


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Your code appears correct, indeed it is remarkably similar to what I am using in my own projects.

For comparison, below is the code I am using to detect attributes (uniforms are very similar). This is working with OpenTK 1.1 stable on Win7 64bit (.Net 4.0) and Mac OS X 10.9.1 32bit (mono 3.2.5).

        // Get the attribute name -> id mappings
        IEnumerable<VertexAttribute> DetectAttributes()
        {
            int max_attribute_length;
            GL.GetProgram((this as IGraphicsResource).Id, GetProgramParameterName.ActiveAttributeMaxLength, out max_attribute_length);
            StringBuilder name = new StringBuilder(2 * max_attribute_length); // Multiply by 2 because of truncated strings on Mono 1.9.1.
 
            int num_attributes;
            GL.GetProgram((this as IGraphicsResource).Id, GetProgramParameterName.ActiveAttributes, out num_attributes);
 
            for (int index = 0; index < num_attributes; index++)
            {
                int length, size;
                ActiveAttribType type;
                name.Remove(0, name.Length);
                GL.GetActiveAttrib((this as IGraphicsResource).Id, index, name.Capacity, out length, out size, out type, name);
 
                if (length > 0)
                {
                    int location = GL.GetAttribLocation((this as IGraphicsResource).Id, name.ToString());
                    var attr = new VertexAttribute(name.ToString(), location, type);
                    Debug.Print("Attribute detected {0} {1} -> {2}", attr.AttributeType, attr.Name, attr.Index);                  
                    yield return attr;
                }
            }
        }

Edit: the main difference I can see is that I am checking whether the name of the attribute has a non-zero length. The reason is that some drivers return a zero-length name for disabled attributes.

If this doesn't help, can you please file a bug report at https://github.com/opentk/opentk/issues? Please include the version of OpenTK and operating system you are using.

Edit 2: Crashes that cannot be caught by a try-catch block indicate memory corruption. This are usually an application error (e.g. when passing buffers with an incorrect size to OpenGL), but it can sometimes be a bug in OpenTK or in the OpenGL drivers.

Vaernus's picture

Working fine now. Must have been the zero-length name because as soon as I added a check for that from your example, everything runs flawless. Thank you very much for the help!

On a side note, is there a simple way to determine whether an attribute/uniform is something built-in versus something that is directly in the shader? I notice we get inputs like {gl_vertex}. Would we simply have to parse them out?

the Fiddler's picture

IIRC, built-in attributes always start with "gl_". It is an error for a user-defined attribute to start with "gl_", so you can use this as a distinguishing characteristic.