0

I have begun learning GLSL and OpenGL. RIght now I am trying to see how GLSL subroutines work, so I have my fragment shader here:

#version 330 core

out vec4 color;

subroutine vec4 ColorFunc();

subroutine (ColorFunc) vec4 colorBlue() {
    return vec4(0.0, 0.0, 1.0, 1.0);
}

subroutine (ColorFunc) vec4 colorGreen() {
    return vec4(0.0, 1.0, 0.0, 1.0);
}

subroutine uniform ColorFunc ColorSelector;

void main() {
    color = ColorSelector();
}

In the application's source I load, compile link the shader and start the program at the beginning. A triangle is created and the vertex shader doesn't do anything special. The display function (the one sent to glutDisplayFunc) looks like this:

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(TriangleVAO);
    glDrawArrays(GL_TRIANGLES, 0, NumVertices);

    GLint ColorSelectorLoc;
    GLuint colorBlueIndex;
    GLuint colorGreenIndex;

    ColorSelectorLoc = glGetSubroutineUniformLocation(program, GL_FRAGMENT_SHADER, "ColorSelector");
    if (ColorSelectorLoc < 0)
    {
        fprintf(stderr, "Error: ColorSelector is not an active subroutine uniform in the shader\n");
        exit(EXIT_FAILURE);
    }

    colorBlueIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorBlue");
    colorGreenIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorGreen");

    GLsizei n;
    glGetProgramStageiv(program, GL_FRAGMENT_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, &n);
    GLuint *indices = new GLuint[n];
    cout << "colorGreen: " << colorBlueIndex;
    indices[ColorSelectorLoc] = colorGreenIndex;
    glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, n, indices);
    delete [] indices;

    glFlush();
}

What I expect is the triangles to be green yet they are always blue, no matter the value of ColorSelector, which is correctly retrieved (its value is 0). colorBlueIndex is 0 and colorGreenIndex is 1. I don't know what am I missing.

ali
  • 10,927
  • 20
  • 89
  • 138
  • replace `GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS` with `GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS​` – ratchet freak Apr 30 '14 at 15:19
  • I did but nothing. With `GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS` n is 4096 but with `GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS​` it is some weird number (31498976) which looks like some pointer to something. – ali Apr 30 '14 at 15:27

2 Answers2

1

the glUniformSubroutinesuiv call expects n to be equal to the number of active subroutine locations

you can get this with:

glGetProgramStage(program, GL_FRAGMENT_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, &n);

see the wiki

ratchet freak
  • 47,288
  • 5
  • 68
  • 106
  • glGetProgramStage returns 1 active subroutine (is that correct?). The triangle is still blue. The index is not changed – ali Apr 30 '14 at 15:42
  • you never actually seem to set `color2Index` – ratchet freak Apr 30 '14 at 15:48
  • Sooy, was a typo. It is `ColorGreenIndex`. I don't understand why the first subroutine is called. If in the shader I move `colorGreen()` before `colorBlue()` then it becomes green. So, it always calls the first subroutine. – ali Apr 30 '14 at 15:54
  • @ali any glErrors? while doing this – ratchet freak Apr 30 '14 at 15:55
  • I get OpenGL error: 1280, but I get it before doing the subroutine stuff. – ali Apr 30 '14 at 16:01
  • that is error 0x500: invalid enum ([see here](http://www.opengl.org/wiki/OpenGL_Error)) see where it get activated first (follow each call with such a check) – ratchet freak Apr 30 '14 at 16:03
  • This is weird. It happens after this code: `if (glewInit()) { cerr << "Unable to initialize GLEW ... exiting" << endl; exit(EXIT_FAILURE); }`. GLEW doesn't throw any error – ali Apr 30 '14 at 16:10
  • GLEW initializes correctly but after that I get the `GL_INVALID_ENUM` error. Yet, the triangle is drawn – ali Apr 30 '14 at 16:23
  • OK. The glew error has been fixed (http://stackoverflow.com/questions/19453439/solved-opengl-error-gl-invalid-enum-0x0500-while-glewinit) but I still don't manage to call the correct subroutine – ali Apr 30 '14 at 17:03
0

I found the problem. The subroutine's code must go before glDrawArrays:

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    GLint ColorSelectorLoc;
    GLuint colorBlueIndex;
    GLuint colorGreenIndex;

    ColorSelectorLoc = glGetSubroutineUniformLocation(program, GL_FRAGMENT_SHADER, "ColorSelector");
    if (ColorSelectorLoc < 0)
    {
        fprintf(stderr, "Error: ColorSelector is not an active subroutine uniform in the shader\n");
        exit(EXIT_FAILURE);
    }

    colorBlueIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorBlue");
    colorGreenIndex = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "colorGreen");

    GLsizei n;
    glGetProgramStageiv(program, GL_FRAGMENT_SHADER, GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS, &n);
    GLuint *indices = new GLuint[n];
    cout << "colorGreen: " << colorBlueIndex;
    indices[ColorSelectorLoc] = colorGreenIndex;
    glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, n, indices);
    delete [] indices;

    glBindVertexArray(TriangleVAO);
    glDrawArrays(GL_TRIANGLES, 0, NumVertices);

    glFlush();
}
ali
  • 10,927
  • 20
  • 89
  • 138