2

I'm attempting to retrieve the binary from a program that has been validly compiled and linked. I've received the length of it with GL_PROGRAM_BINARY_LENGTH. The documentation says there's two instances in which the GL_INVALID_OPERATION can occur - a failed link and bufSize being less than the size of the program. I've read that some have gotten this error when failing to give GL_PROGRAM_BINARY_RETRIEVABLE_HINT prior to linking, which is not the case for me. I've also validated the program, to be certain...and verified that GL_ARB_get_program_binary is supported.

We have a glDebugMessageCallbackARB hooked up, which gives this for some extra info: "GL_INVALID_OPERATION error generated. Object is not a program or shader object." I found nothing by searching for that extra bit in the error message.

OGL version 4.2, glsl 1.5. This is on an nVidia GeForce GTX 660 with latest drivers. Windows 7.

Here's the relevant code:

GLuint compileShaderBlock(GLenum type, const char* shaderCode, const int shaderSize) 
{
    GLuint shaderId = 0;

    if (shaderCode != NULL)
    {
        shaderId= glCreateShader(type);
        glShaderSource(shaderId, 1, &shaderCode, &shaderSize);
        glCompileShader(shaderId);
    }

    return shaderId;
};

static GLchar errBuff[4096];
bool validateShader(GLuint shaderID)
{
    GLint compiled;
    glGetShaderiv(shaderID, GL_COMPILE_STATUS, &compiled);

    GLsizei length = 0;

    glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &length);

    char* buffer = new char[length];

    if (!compiled && length > 0)
    {
        GLsizei outputlen;    
        glGetShaderInfoLog(shaderID, length, &outputlen, buffer);
        GLsizei size = 0;
        glGetShaderSource(shaderID, 4096, &size, errBuff);
    }

    assert(compiled == GL_TRUE, "Shader compile error: \n%s", buffer);
    delete[] buffer;

    return compiled == GL_TRUE;
}

bool validateLink(GLuint programID)
{
    GLint linkResult = GL_TRUE;
    glGetProgramiv(programID, GL_LINK_STATUS, &linkResult);

    if (linkResult == GL_FALSE)
    {
        GLsizei outputlen, length = 0;
        glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &length);

        char* buffer = new char[length];
        glGetProgramInfoLog(programID, length, &outputlen, buffer);

        assert(linkResult == GL_TRUE, "Program %d link error %s", programID, buffer);
        delete[] buffer;
        return GL_FALSE;
    }

    return GL_TRUE;
}

....

shader->vertexShaderId = compileShaderBlock(GL_VERTEX_SHADER, vsDataString.ToChar(), vsDataString.Length());
shader->fragmentShaderId = compileShaderBlock(GL_FRAGMENT_SHADER, fsDataString.ToChar(), fsDataString.Length());

validateShader(shader->vertexShaderId, "");
validateShader(shader->fragmentShaderId, "");

shader->programId = glCreateProgram();
glAttachShader(shader->programId, shader->vertexShaderId);
glAttachShader(shader->programId, shader->fragmentShaderId);

//Care about outputs
glBindFragDataLocation(shader->programId, 0, "outColor0");
glBindFragDataLocation(shader->programId, 1, "outColor1");
glBindFragDataLocation(shader->programId, 2, "outColor2");
glBindFragDataLocation(shader->programId, 3, "outColor3");

// let it know we plan on retrieving a binary
glProgramParameteri(shader->programId, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);

glLinkProgram(shader->programId);

... set attributes and uniforms (removing this doesn't change anything)
... do mock render (removing this doesn't change anything)

validateLink(shader->programId);

glValidateProgram((shader->programID);
GLint validateStatus;
glGetProgramiv((shader->programID, GL_VALIDATE_STATUS, &validateStatus);

glUseProgram(shader->programId);

GLint len = 0;
glGetProgramiv(shader->programId, GL_PROGRAM_BINARY_LENGTH, &len);

if (len > 0)
{
    uint8* binary = new uint8[len];
    GLenum binaryFormat;
    **ERROR** --> glGetProgramBinary(shader->programId, len, NULL, &binaryFormat, binary);
}

I feel like this doesn't make any sense, is there something I'm missing???

  • This is a longshot, but the spec. suggests "using" the GLSL program. Naturally you would think that `glUseProgram (...)` does just that, but from experience with embedded implementations, sometimes you have to make a draw call using the GLSL program one time to do what some implementations call "prewarming" the program. It seems rather unlikely in a desktop implementation, but you never know... – Andon M. Coleman Dec 13 '14 at 22:47
  • Thanks for the suggestion. Unfortunately I actually do that already, hard to see in the posted code, but "... do mock render" is where that occurs. – Ramon Johannessen Dec 14 '14 at 02:24

1 Answers1

1

So it was a really stupid copy/paste mistake, but there's a tiny chance it may be useful to someone in the future...

glGetProgramBinary was set to another gl function...