Search code examples
c++xcodeopenglglfwexc-bad-access

OpenGL: glGenVertexArrays() gives EXC_BAD_ACCESS


When I use OpenGL and run my code to make a triangle the function glGenVertexArrays() gives me EXE_BAD_ACCESS

Error

Code:

#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <cmath>

// Window specs
const int HEIGHT = 800;
const int WIDTH = 600;

// Shader source code
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(0.8f, 0.3f, 0.02f, 1.0f);\n"
"}\n\0";

int main(void)
{
    if (!glfwInit())
    {
        std::cout<<"GLFW failed to Initialize!"<<std::endl;
        return -1;
    }
    
    
    GLfloat vertices[] =
    {
        -0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f,
        0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f,
        0.0f, 0.5f * float(sqrt(3)) * 2 / 3, 0.0f
    };
    
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Open GL", NULL, NULL);
        
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    glfwMakeContextCurrent(window);
    
    if(!window)
    {
        std::cout<<"Something went Wrong when Creating a Window!\nShutting down ..."<<std::endl;
        glfwTerminate();
        return -1;
    }
    //
    gladLoadGL();
    glViewport(0, 0, WIDTH, HEIGHT);
    
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    
    GLuint fragmentShader  = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    //
    GLuint shaderProgram = glCreateProgram();
    
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    
    glLinkProgram(shaderProgram);
    
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    
    GLuint VAO;
    GLuint VBO;
    
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    
    glBindVertexArray(VAO);
    
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    while(!glfwWindowShouldClose(window))
    {
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glfwSwapBuffers(window);
        
        glfwPollEvents();
    }
    
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);
    
    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

I used glad to write the code. Does anybody have any idea how to fix this or what I did wrong.

To recreate it use Xcode 13.2.1 then link Glad using Opengl 4.1 and GLFW and make it look something like this

File Layout

Then paste the code into main and run.


Solution

  • A few things:

    • glfwWindowHint() only affects the next glfwCreateWindow() call so make sure to call them before you create a window. The default hint settings will generally give you a version 2.1 Compatibility context on macOS which won't be able to handle #version 330 core GLSL code.
    • GLFW_CONTEXT_VERSION_MAJOR was used twice; you need a GLFW_CONTEXT_VERSION_MINOR too.
    • macOS needs GLFW_OPENGL_FORWARD_COMPAT set to GLFW_TRUE for Core contexts.
    • Check for shader compilation/link errors.
    • Your GLAD might have been out of sync for the GL version you were targeting; see the generator link in the comments for the settings I used.
    • GLFW has a perfectly usable GLADloadproc in glfwGetProcAddress(); might as well switch from gladLoadGL() to gladLoadGLLoader().
    • Supplying a glfwSetErrorCallback() can get you some early/immediate error reporting from GLFW. It's how I discovered the missing GLFW_CONTEXT_VERSION_MINOR hint. No reason not to use it.

    All together:

    // g++ -Iinclude main.cpp src/glad.c `pkg-config --cflags --libs glfw3`
    
    // Commandline:
    //   --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --no-loader --extensions=""
    // Online:
    //   https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&api=gl%3D3.3
    #include <glad/glad.h>
    
    #include <GLFW/glfw3.h>
    #include <iostream>
    #include <cmath>
    
    void CheckStatus( GLuint obj, bool isShader )
    {
        GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
        ( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        ( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
        std::cerr << (GLchar*)log << "\n";
        std::exit( EXIT_FAILURE );
    }
    
    void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader, true );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
    
    const char* const vert = 1 + R"GLSL(
    #version 330 core
    layout (location = 0) in vec3 aPos;
    void main()
    {
       gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    };
    )GLSL";
    
    const char* const frag = 1 + R"GLSL(
    #version 330 core
    out vec4 FragColor;
    void main()
    {
       FragColor = vec4(0.8f, 0.3f, 0.02f, 1.0f);
    }
    )GLSL";
    
    int main(void)
    {
        glfwSetErrorCallback( []( int, const char* desc )
        {
            std::cerr << desc << "\n";
            std::exit( EXIT_FAILURE );
        } );
        if (!glfwInit())
        {
            std::cout<<"GLFW failed to Initialize!"<<std::endl;
            return -1;
        }
    
        GLfloat vertices[] =
        {
            -0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f,
            0.5f, -0.5f * float(sqrt(3)) / 3, 0.0f,
            0.0f, 0.5f * float(sqrt(3)) * 2 / 3, 0.0f
        };
    
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
        GLFWwindow* window = glfwCreateWindow(800, 600, "Open GL", NULL, NULL);
        if(!window)
        {
            std::cout<<"Something went Wrong when Creating a Window!\nShutting down ..."<<std::endl;
            glfwTerminate();
            return -1;
        }
    
        glfwMakeContextCurrent(window);
    
        gladLoadGLLoader( (GLADloadproc)glfwGetProcAddress );
    
        glViewport(0, 0, 800, 600);
    
        GLuint prog = glCreateProgram();
        AttachShader( prog, GL_VERTEX_SHADER, vert );
        AttachShader( prog, GL_FRAGMENT_SHADER, frag );
        glLinkProgram( prog );
        CheckStatus( prog, false );
        glUseProgram( prog );
    
        GLuint VAO;
        GLuint VBO;
    
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
    
        glBindVertexArray(VAO);
    
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(0);
    
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    
        while(!glfwWindowShouldClose(window))
        {
            glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
    
            glUseProgram(prog);
            glBindVertexArray(VAO);
    
            glDrawArrays(GL_TRIANGLES, 0, 3);
            glfwSwapBuffers(window);
    
            glfwPollEvents();
        }
    
        glDeleteVertexArrays(1, &VAO);
        glDeleteBuffers(1, &VBO);
        glDeleteProgram(prog);
    
        glfwDestroyWindow(window);
        glfwTerminate();
        return 0;
    }