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

时间:2013-12-29 04:14:46

标签: 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);
}

3 个答案:

答案 0 :(得分:7)

在您致电Invalid Enum [1280]之后,您实际上是从OpenGL获得了glewInit()

glewExperimental = GL_TRUE;

在此之前致电glewInit()

glewExperimental = GL_TRUE;

GLenum glewError = glewInit();

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

为什么呢?好吧,它与GLEW如何加载扩展,函数等有关。默认情况下,GLEW会将某些功能设置为不支持,从而绕过你需要设置glewExperimental = GL_TRUE;或者否则它会产生一个像你一样的错误。

  

实验动力

     

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

Source

附加

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

GLenum error = glGetError();

if (error != GL_NO_ERROR)
{
    std::cout << "OpenGL Error: " << error << std::endl;
}

您可以阅读有关不同错误here的信息。

答案 1 :(得分:0)

输出glGenVertexArrays的值。现在可能是0null。我发现即使在核心配置文件中我也必须首先设置某些功能。

答案 2 :(得分:0)

如果您创建核心配置文件,我遇到了类似的问题,即glew没有正确初始化所有函数指针。我打算研究一下glew实现,看看为什么会出现这种情况,但是还没有解决它,因为兼容性上下文为我提供了帮助。

但是,您可以尝试的一种可能性是使用GLFW创建兼容性上下文,初始化GLEW,销毁GLFW窗口并使用核心上下文创建一个新窗口。