pontifikas's picture

GLSL Compatibility question

Is it possible to write 1.5 shaders and have <3.1 opengl context?


Comments

Comment viewing options

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

It should be, as long as the drivers are up to date. I have written 1.4 shaders on a 2.1 context and they worked fine (both Nvidia and Ati).

pontifikas's picture

Which brings me to my other question:
Having written some code that performs drawing using VBOs and glVertexPointer function,
how can I pass the vertex-normal attribute values into the shader now that gl_Vertex (or gl_Normal) is deprecated?

I have some in variables in my shader for storing vertex data. Am I supposed to use VertexAttribPointer and then bind them
to some index or is there some default index for vertex attributes which I can bind to this variables directly with BindAttribLocation?

the Fiddler's picture

Two ways: you can either bind attributes to specific indices or you can link the shader and query the indices generated by the linker.

In the first case, you could say (for example) that "in Position" is always #0, "in Normal" #1, etc. This is the simplest approach and it works great in most cases.

In the second case, you need to build a dictionary of indices once the shader is linked. You can then use this dictionary to map your vertex attributes to indices. Example code below (this is taken from the WIP OpenTK demo, slightly modified(*)):

    public struct VertexAttribute
    {
        public string Name { get; private set; }
        public int Index { get; private set; }
        public ActiveAttribType AttributeType { get; private set; }
 
        public VertexAttribute(string name, int index, ActiveAttribType type)
            : this()
        {
            Name = name;
            Index = index;
            AttributeType = type;
        }
    }
 
    public class ShaderProgram 
    {
        public int Id { get; private set; }
        public Dictionary<string, VertexAttribute> Attributes { get; private set; }
        ...
        void DetectAttributes()
        {
            // Get the attribute name -> id mapping, as generated by the driver and enable all necessary attributes.
            //// To find out all necessary attributes we query all attribute names. If a name is a non-zero string, we
            //// consider that attribute as enabled.
            int num_attributes;
            int max_attribute_length;
            GL.GetProgram(Id, ProgramParameter.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.
            GL.GetProgram(Id, ProgramParameter.ActiveAttributes, out num_attributes);
 
            for (int index = 0; index < num_attributes; index++)
            {
                int length, size;
                ActiveAttribType type;
                name.Remove(0, name.Length);
                GL.GetActiveAttrib(Id, index, name.Capacity, out length, out size, out type, name);
 
                if (length > 0)
                {
                    int location = GL.GetAttribLocation(Id, name.ToString());
                    var attr = new VertexAttribute(name.ToString(), location, type);
                    Attributes.Add(attr.Name, attr);
                    //Debug.Print("Attribute detected {0} {1} -> {2}", attr.AttributeType, attr.Name, attr.Index);
                }
            }
        }
        ...
    }

You can then use something similar to program.Attributes["Position"].Index to find out which index "in Position" is mapped to.

This approach is slightly more flexible, but accessing the dictionary to set attributes at runtime can be rather slow without vertex array objects. Still, performance should be adequate for simple applications.

pontifikas's picture

The question is if there is some default(by the driver) attribute index, so by simply binding my variable to it
using, say BindAttributeLocation(prog_id,driver_default_vertex_attribute_index,"Position"),
to create an alias and be able to access the vertex data from withing the shader via Position.

I ask because I have a general function performing draw in which I dont want to know what variables exist
at any given shader that is executed.

the Fiddler's picture

No, there is no default mapping. You either have to force a mapping beforehand (i.e. make sure all shaders use the same attribute names that are bound to well-defined indices) or you need to query the driver after shader linkage. The first approach is conceptually similar to using built-in attributes.

I know this doesn't answer your question directly, but the draw method doesn't necessarily need to be aware of the actual shader variables. For example, in the past I've used reflection to generate this information automatically, where a struct { public Vector3  Position, Normal; } can be automagically bound to a shader with in vec3 Position, Normal; attributes. This works, but tends to get complicated when using multiple VBOs for a single shader. Another, possibly better approach is to generate VAOs at load time, so you don't have to worry about binding attributes at render time (the VAO encapsulates this information, so you simply bind it and render).

I'd love to hear if anyone has a better solution to this issue.

kvark's picture

When the shader is linked in my engine, the special attribute dictionary is provided.
I call glBindAttributeLocation for each attribute in this dictionary right before linking, not caring about actual existence of the attributes in the shader code.
The dictionary is different for particle systems & regular objects, there might be more of them in the future.

pontifikas's picture
kvark wrote:

When the shader is linked in my engine, the special attribute dictionary is provided.
I call glBindAttributeLocation for each attribute in this dictionary right before linking, not caring about actual existence of the attributes in the shader code.
The dictionary is different for particle systems & regular objects, there might be more of them in the future.

What do you mean by "special attribute" dictionary?
Do you have some identifier (as is gl_ in the beggining of the uniform name) that tells you "This is for vertex-normal-color data" in your dictionary and you bind the buffer at this variable?

kvark's picture

The attribute dictionary I mentioned is just a ('id'->'name') collection. These names are usually meaningful like at_vertex, at_quat, etc.

pontifikas's picture

This is the approach I've been considering. I can't think of any other way to maintain generality in my drawing functions unless I define set of my own variables with, somehow, identifiable names.

Thank you all for your answers!