使用OpenGL核心配置文件时为什么会崩溃?

Chr*_*s_F 3 c++ opengl nvidia

当我尝试运行这个简单的OpenGL测试程序时,我遇到了分段错误.只有在使用核心配置文件标志创建上下文时才会发生这种情况.如果我使用兼容性配置文件标志,程序运行没有问题.

编辑:我检查了函数的指针glGenVertexArrays,然后返回NULL.如果glfwCreateWindow没有返回NULL,并glGetString(GL_VERSION)确认上下文是版本4.3并glewInit返回GLEW_OK那么为什么glGenVertexArrays == NULL

我的操作系统是64位Windows 7,而我的GPU是带有331.82 WHQL驱动程序的Nvidia GTX 760.

码:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>

#define GLSL(src) "#version 430 core\n" #src

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

GLuint create_program(const char* vertex_source, const char* fragment_source)
{
    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vertex_source, NULL);
    glCompileShader(vs);
    unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fragment_source, NULL);
    glCompileShader(fs);

    GLuint shader_program = glCreateProgram();
    glAttachShader(shader_program, fs);
    glAttachShader(shader_program, vs);
    glLinkProgram(shader_program);

    return shader_program;
}

const char* vertex_shader = GLSL(
    layout(location = 0) in vec3 vertex_position;

    void main()
    {
        gl_Position = vec4(vertex_position, 1.0);
    }
);

const char* fragment_shader = GLSL(
    out vec4 frag_color;

    void main()
    {
        frag_color = vec4(1.0, 0.0, 0.0, 1.0);
    }
);

int main(int argc, char* argv[])
{
    if(!glfwInit())
        exit(EXIT_FAILURE);

    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    //if we set GLFW_OPENGL_PROFILE to GLFW_OPENGL_CORE_PROFILE 
    //instead of GLFW_OPENGL_COMPAT_PROFILE the program will 
    //segfault at line 98, call to glGenVertexArrays
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(512, 512, "OpenGL", NULL, NULL);

    if(!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

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

    GLenum glewError = glewInit();

    if(glewError != GLEW_OK)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    printf("OpenGL Version: %s\n\n", glGetString(GL_VERSION));

    float position[] = 
    {
        1.0f, 1.0f, 0.0f,
        -1.0f, 1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f
    };

    unsigned short indices[] = 
    {
        1, 0, 2,
        3, 1, 2
    };

    GLuint vao = 0;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    GLuint index_buffer = 0;
    GLuint vertex_buffer = 0;

    glGenBuffers(1, &index_buffer);
    glGenBuffers(1, &vertex_buffer);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(position), &position, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    GLuint shader_program = create_program(vertex_shader, fragment_shader);
    glUseProgram(shader_program);

    while(!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
}
Run Code Online (Sandbox Code Playgroud)

Val*_*tin 7

Invalid Enum [1280]在你打电话glewInit()给最简单的修复之后,你实际上是从OpenGL 获得的.

glewExperimental = GL_TRUE;
Run Code Online (Sandbox Code Playgroud)

在你打电话之前glewInit().

glewExperimental = GL_TRUE;

GLenum glewError = glewInit();

if (glewError != GLEW_OK)
{
    glfwTerminate();
    exit(EXIT_FAILURE);
}
Run Code Online (Sandbox Code Playgroud)

为什么?好吧它与GLEW如何加载扩展,函数等有关.默认情况下,GLEW会将某些函数等设置为不受支持,从而绕过你需要设置的内容glewExperimental = GL_TRUE;,否则它会产生类似于你获取的错误.

实验动力

GLEW从图形驱动程序获取有关受支持的扩展的信息.但是,实验或预发布驱动程序可能不会通过标准机制报告每个可用的扩展,在这种情况下,GLEW将报告它不受支持.为了避免这种情况,可以通过在调用glewInit()之前将其设置为GL_TRUE来打开glewExperimental全局开关,这将确保将公开具有有效入口点的所有扩展.

资源

额外

永远记住要检查OpenGL错误,它们通常会告诉您错误和/或帮助您找到问题.

GLenum error = glGetError();

if (error != GL_NO_ERROR)
{
    std::cout << "OpenGL Error: " << error << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读有关不同错误的信息.

  • 实际上,在大多数情况下,这不是"glewExperimental"的用途.这是一种非常圆润的方式告诉GLEW不要使用`glGetString(...)`来查询扩展字符串以确定支持哪些扩展.在一个OpenGL 3.2**核心**配置文件中,使用`glGetString(...)`查询`GL_EXTENSIONS`是**无效**,你必须使用`glGetStringi(每个扩展)逐个地执行它. ...)`.GLEW不知道这一点,所以当您拥有核心配置文件上下文时,您需要告诉GLEW尝试获取每个扩展功能的入口点以确定支持. (3认同)
  • 大多数时候,"glewExperimental"可以解决一个自相矛盾的情况.`glGetStringi(...)`是在核心OpenGL 3.2中处理扩展查询的正确方法,但是GLEW想查询扩展字符串以查看系统正在运行什么样的上下文.它将使用`glGetString(...)`来做到这一点,但是会产生一个`GL_INVALID_ENUM`错误并且在核心3.2上下文中不返回任何内容.GLEW确实需要像所有现代GL框架一样重新考虑,以将上下文版本作为初始化参数来处理. (2认同)