3

I attach a vertex and fragment shader to a program object, then attempt to link the said program. GL_LINK_STATUS returns false. I check the info log, it's a bunch of gibberish characters. I check GL_INFO_LOG_LENGTH, it's 0. How do I debug this situation?

//this is the end of my LoadBasicShaders function
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);

glLinkProgram(program);

GLint status;

glGetProgramiv(program, GL_LINK_STATUS, &status);

if (status == GL_FALSE)
{
    GLint logLength = 0;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
    std::vector<GLchar> log(logLength + 1);
    glGetProgramInfoLog(program, logLength, &logLength, &log[0]);

    fprintf(stderr, "%s\n\n", log);
    //logLength returns 0, log returns seemingly random chars

    return -3;//just my error code
}

My shaders are the simplest ones possible, since I'm just starting out. Here's the vertex shader:

#version 330

layout(location = 0) in vec4 position;
void main()
{
    gl_Position = position;
}

And here's the fragment shader:

#version 330

out vec4 outputColor;
void main()
{
    outputColor = vec4(1.0, 1.0, 1.0, 1.0);
}

I use GLFW to create the OpenGL window, and GLEW to load the functions:

if (!glfwInit())
{/*error checking*/}

    window = glfwCreateWindow(800, 600, "Swash", NULL, NULL);

if (!window)
{/*more error checking*/}

glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwSetKeyCallback(window, key_callback);

if (glewInit() != GLEW_OK)
{/*you guessed it*/}
//don't call anything that involves nonstandard OpenGL functions before this point

GLuint shaderProgram;

int shaderLoadResult = LoadBasicShaders(shaderProgram, "../res/vert.shader", "../res/frag.shader");
3
  • Post a MCVE including your shaders and context creation. Commented Feb 9, 2015 at 19:30
  • @genpfault I assume you mean OpenGL context creation, also should I include how I read from the shader files? Commented Feb 9, 2015 at 20:32
  • Yeah, window/context creation. You can inline the shader text into a string using something like this. Used in context. Commented Feb 9, 2015 at 20:33

2 Answers 2

2

All together (this is what I meant by posting a MCVE):

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <cstdlib>

struct GlDebugOutput
{
    static void Install()
    {
        if( !glewIsSupported( "GL_ARB_debug_output" ) ) 
        {
            std::cerr << "GL_ARB_debug_output not supported" << std::endl;
            return;
        }
        glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB );
        glDebugMessageCallbackARB( DebugCallback, 0 );
        glDebugMessageControlARB( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE );
    }

private:
    static const char* Source( GLenum source )
    {
        switch( source )
        {
        case GL_DEBUG_SOURCE_API_ARB                : return "API";
        case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB      : return "WINDOW_SYSTEM";
        case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB    : return "SHADER_COMPILER";
        case GL_DEBUG_SOURCE_THIRD_PARTY_ARB        : return "THIRD_PARTY";
        case GL_DEBUG_SOURCE_APPLICATION_ARB        : return "APPLICATION";
        case GL_DEBUG_SOURCE_OTHER_ARB              : return "OTHER";
        default                                     : return "Unknown source";
        }
    }

    static const char* Type( GLenum type )
    {
        switch( type )
        {
        case GL_DEBUG_TYPE_ERROR_ARB                : return "ERROR";
        case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB  : return "DEPRECATED_BEHAVIOR";
        case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB   : return "UNDEFINED_BEHAVIOR";
        case GL_DEBUG_TYPE_PORTABILITY_ARB          : return "PORTABILITY";
        case GL_DEBUG_TYPE_PERFORMANCE_ARB          : return "PERFORMANCE";
        case GL_DEBUG_TYPE_OTHER_ARB                : return "OTHER";
        default                                     : return "Unknown type";
        }
    }

    static const char* Severity( GLenum severity )
    {
        switch( severity )
        {
        case GL_DEBUG_SEVERITY_HIGH_ARB     : return "HIGH";
        case GL_DEBUG_SEVERITY_MEDIUM_ARB   : return "MEDIUM";
        case GL_DEBUG_SEVERITY_LOW_ARB      : return "LOW";
        default                             : return "Unknown severity";
        }
    }

    static void APIENTRY DebugCallback
        (
        GLenum source,
        GLenum type,
        GLuint id,
        GLenum severity,
        GLsizei length,
        const GLchar* message,
        const void* userParam
        )
    {
        std::cerr << "GL_DEBUG" 
            << ": " << Source( source ) 
            << ": " << Type( type ) 
            << ": " << Severity( severity ) 
            << ": " << message 
            << std::endl;
    }
};

struct Program
{
    static GLuint Load( const char* vert, const char* geom, const char* frag )
    {
        GLuint prog = glCreateProgram();
        if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
        if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
        if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE;
        if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        GLchar log[ 1 << 15 ] = { 0 };
        if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
        if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
        std::cerr << log << std::endl;
        exit( EXIT_FAILURE );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};

#define GLSL(version, shader) "#version " #version "\n" #shader

const char* vert = GLSL
( 
    330,
    layout( location = 0 ) in vec4 position;
    void main()
    {
        gl_Position = position;
    }
);

const char* frag = GLSL
( 
    330,
    out vec4 outputColor;
    void main()
    {
        outputColor = vec4( 1.0, 1.0, 1.0, 1.0 );
    }
);

GLuint VAO;
GLuint VBO;
GLuint prog;
void init()
{
    glGenVertexArrays( 1, &VAO );
    glBindVertexArray( VAO );

    glGenBuffers( 1,&VBO );
    glBindBuffer( GL_ARRAY_BUFFER, VBO );
    float verts[] =
    {
        -1.0, -1.0,
         1.0, -1.0,
         0.0,  1.0,
    };
    glBufferData( GL_ARRAY_BUFFER, sizeof( verts ), verts, GL_STATIC_DRAW );

    prog = Program::Load( vert, NULL, frag );
    glUseProgram( prog );

    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, 0 );
}

void display()
{
    glClearColor( 0, 0, 0, 1 );
    glClear( GL_COLOR_BUFFER_BIT );

    glUseProgram( prog );
    glBindVertexArray( VAO );
    glDrawArrays( GL_TRIANGLES, 0, 3 );
}

void glfwErrorCallback( int error, const char* description )
{
    std::cerr << "GLFW error: " << description << std::endl;
}

int main( int argc, char** argv )
{
    glfwSetErrorCallback( glfwErrorCallback );

    if( GL_FALSE == glfwInit() )
    {
        return EXIT_FAILURE;
    }
    std::cout << "GLFW version : " << glfwGetVersionString() << std::endl;

    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE );
    glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE );
    GLFWwindow* window = glfwCreateWindow( 640, 480, "Test", NULL, NULL );
    if( NULL == window )
    {
        glfwTerminate();
        return EXIT_FAILURE;
    }
    glfwMakeContextCurrent( window );

    glfwSwapInterval( 1 );

    glewExperimental = GL_TRUE;
    const GLenum glewErr = glewInit();
    if( GLEW_OK != glewErr )
    {
        std::cerr << "glewInit() failed: " << glewGetErrorString( glewErr ) << std::endl;
        glfwTerminate();
        return EXIT_FAILURE;
    }
    // consume spurious GL error from GLEW init
    glGetError();

    GlDebugOutput::Install();

    init();

    while( !glfwWindowShouldClose( window ) )
    {
        glfwPollEvents();

        int w, h;
        glfwGetFramebufferSize( window, &w, &h );
        glViewport( 0, 0, w, h );

        display();

        glfwSwapBuffers( window );
    }

    return EXIT_SUCCESS;
}

If anything is even just a little bit off with your OpenGL implementation and/or shaders that program should scream bloody murder to stderr and exit.

Sign up to request clarification or add additional context in comments.

2 Comments

Your code didn't work until I made the userParams parameter const. But it helped a lot, so thanks
@Yago: Sorry about that, I was using an outdated GLEW that had the wrong function signature for GLDEBUGPROCARB.
1

Sorry for the very slow update, I've been busy with other things.

Anyways, the problem was that while writing the code, I had included the line

program = glCreateProgram();

but at some point, while tidying up, I accidentally deleted it. That's why the shaders were compiling but weren't linking, they weren't being linked to a program object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.