Search code examples
c++openglglslsubroutine

Why glGetSubroutineIndex returns the same value for different function?


I have got a fragment shader that should operate 2 colors - red and blue.

#version 460 core

layout (location = 0) out vec4 outColor;

subroutine vec4 colorRedBlue();

subroutine (colorRedBlue) 
vec4 redColor() 
{
    return vec4(1.0, 0.0, 0.0, 1.0);
} 

subroutine (colorRedBlue) 
vec4 blueColor() 
{ 
    return vec4(0.0, 0.0, 1.0, 1.0);
}

subroutine uniform colorRedBlue myRedBlueSelection;

void main()
{
    outColor = myRedBlueSelection();
}

when I cout glGetSubroutineIndex(shaderProgram, GL_FRAGMENT_SHADER, "redColor"); and glGetSubroutineIndex(shaderProgram, GL_FRAGMENT_SHADER, "blueColor");

they are the same numbers: 4294967295

Why they are the same numbers? What did I do wrong?


Solution

  • If you want to retrieve information about the subroutine indices the you have to use glGetActiveSubroutineUniformiv:

    GLint no_of_subroutines;
    glGetActiveSubroutineUniformiv(
        shaderProgram, GL_FRAGMENT_SHADER, 
        0, // Index of the subroutine uniform, but NOT the location of the uniform variable 
        GL_NUM_COMPATIBLE_SUBROUTINES, &no_of_subroutines);
    
    std::vector<GLint> sub_routines( no_of_subroutines ); 
    glGetActiveSubroutineUniformiv(
        shaderProgram, GL_FRAGMENT_SHADER, 
        0, // Index of the subroutine uniform, but NOT the location of the uniform variable 
        GL_COMPATIBLE_SUBROUTINES, sub_routines.data());
    

    The name of a subroutine which corresponds to a subroutine index can be get by glGetActiveSubroutineName.

    But I recommend to use layout qualifier to specify the subroutine indices in the shader code - see Shader Subroutine - In-shader specification:

    subroutine vec4 colorRedBlue();
    
    layout(index = 1) subroutine (colorRedBlue) 
    vec4 redColor() 
    {
        return vec4(1.0, 0.0, 0.0, 1.0);
    } 
    
    layout(index = 2) subroutine (colorRedBlue) 
    vec4 blueColor() 
    { 
        return vec4(0.0, 0.0, 1.0, 1.0);
    }  
    
    layout(location = 0) subroutine uniform colorRedBlue myRedBlueSelection;
    

    Note, all the subroutines for all the subroutine unifroms of one shader stage have to be set at once, by glUniformSubroutinesuiv. In your case, that's not a big thing, because there is only 1 subroutine uniform. This operation applies to the current shader program (glUsePrgram).
    The number of indices wich you have to pass to glUniformSubroutinesuiv has to match the number of GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS but not the number of GL_ACTIVE_SUBROUTINE_UNIFORM - see glGetProgramStageiv:

    GLint nLocationCount = 0;
    glGetProgramStageiv( 
        program, GL_FRAGMENT_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, &nLocationCount );
    
    std::vector<GLuint> sub_routines( nLocationCount, 0 );
    
    Glint redBlueSelection_location = 0;
    sub_routines[redBlueSelection_location] = 1; // index of 'redColor` or `blueColor`
    
    glUniformSubroutinesuiv(
        GL_FRAGMENT_SHADER, (GLsizei)sub_routines.size(), sub_routines.data() );