3
votes

I'm making a crossplatform OpenGL program. However, I've encountered a problem, where glGetUniformLocation, which should return the location of a uniform variable in my shader program, returns -1, and it only occurs on Linux (Raspbian distro, ran on Raspberry PI), and on Windows the same code works perfectly! Here's my code:

Load Shader program function:

int shader, status;

programID = glCreateProgram();

// Load vertex shader
shader = LoadShaderFromString(GL_VERTEX_SHADER, Tools::GetFileAsString("VertexShader.glsl"), "Unable to compile vertex shader.\n");
glAttachShader(programID, shader);

// Load pixel shader
shader = LoadShaderFromString(GL_FRAGMENT_SHADER, Tools::GetFileAsString("FilterPixelShader.glsl"), "Unable to compile pixel shader.\n");
glAttachShader(programID, shader);

// Link the program
glLinkProgram(programID);
glGetProgramiv(programID, GL_LINK_STATUS, &status);

if (status == 0)
{
    Log("Unable to link filter shader program.\n");
    PrintProgramLog(programID);
    Fail();     // Quits program
}   

// returns -1 here!
frameTextureLocation = glGetUniformLocation(programID, "FrameTextureUnit");
if (frameTextureLocation == -1)
{
    int errorCode = glGetError();
    Log(string("Error retrieving variable frameTextureLocation from shader program: "));
    Log((const char*)glewGetErrorString(errorCode))
    Log("!\n");
    Fail();
}

LoadShaderFromString:

int Shader::LoadShaderFromString(int type, const string& shaderSource, const string& errorMessage)
{
    int shader, status;
    const char* programSource;

    shader = glCreateShader(type);
    programSource = shaderSource.c_str();
    glShaderSource(shader, 1, &programSource, nullptr);
    glCompileShader(shader);
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);

    if (status == 0)
    {
        Log(errorMessage);
        PrintShaderLog(shader);
        Fail();
    }

    return shader;
}

Lastly, the shader itself:

uniform sampler2D FrameTextureUnit; 
uniform sampler2D BackgroundTextureUnit;

#if __VERSION__ >= 130 
    // Texture coordinate 
    in vec2 texCoord; 

    // Final color 
    out vec4 gl_FragColor; 
#else
    // Texture coordinate 
    varying vec2 texCoord; 
#endif

uniform float Tolerance;                    // Tolerance for color difference
uniform vec4 FilterColor;                   // Color of the filter

void main()
{
    vec4 pixel = texture2D(FrameTextureUnit, texCoord);
    vec4 background = texture2D(BackgroundTextureUnit, texCoord);

    float difference = abs(background.x - pixel.x)
                   + abs(background.y - pixel.y)
                   + abs(background.z - pixel.z);

    if (difference > Tolerance)
    {
        gl_FragColor = FilterColor;
    }
    else
    {
        // Y = 0.2126 R + 0.7152 G + 0.0722 B 
        float gray = pixel.x * 0.2126 + pixel.y * 0.7152 + pixel.z * 0.0722;
        gl_FragColor = vec4(gray, gray, gray, 1);
    }
}

Does anyone know why this might be happening? :( It's worth adding that the error handling code:

    int errorCode = glGetError();
    Log(string("Error retrieving variable frameTextureLocation from shader program: "));
    Log((const char*)glewGetErrorString(errorCode));

Prints "Error retrieving variable frameTextureLocation from shader program: No error".

1
For some reason genpfault edited my message tags so they say it's an opengl-es problem, however, it's not - it's an OpenGL 2.1 program.Sunius
And I edited it back, if you don't mind.Sunius
Mostly when glGetUniformLocation() returns -1, no errors is thrown and you have declared the uniform in the shader it is because the uniform has been optimized out. But I can't see why this should happen here. Does the glGetUniformLocation(BackgroundTextureUnit) also return -1?Dirk
Strangely, glGetUniformLocation(BackgroundTextureUnit) returns proper value, so does for Tolerance and FilterColor. I'm totally puzzled.Sunius
I don't know if it helps, but can you also post your vertex shader?Dirk

1 Answers

0
votes

Always specify GLSL version at the top of your shaders, otherwise it defaults to a very old version. It must be the first line. It will also eliminate the need for version checking inline.

#version 150
// rest of shader here