为啥在使用 OpenGL 核心配置文件时会崩溃?

Posted

技术标签:

【中文标题】为啥在使用 OpenGL 核心配置文件时会崩溃?【英文标题】:Why does this crash when using OpenGL core profile?为什么在使用 OpenGL 核心配置文件时会崩溃? 【发布时间】:2014-01-16 07:24:12 【问题描述】:

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

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

我的操作系统是 Windows 7 64 位,我的 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);

【问题讨论】:

1:您应该始终将您的代码发布在 SO 上,因为如果 pastebin 上的代码被删除,这个问题将无法帮助其他遇到同样问题的人。 2:分段错误发生在哪一行? (忽略nr 2,我可以看到你写了评论) 【参考方案1】:

在调用glewInit() 之后,您实际上从 OpenGL 获得了一个 Invalid Enum [1280],最简单的解决方法就是这样做。

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。

【讨论】:

实际上,glewExperimental 在大多数情况下并非如此。这是告诉 GLEW 不要使用glGetString (...) 来查询扩展字符串以确定支持哪些扩展的一种非常迂回的方式。在 OpenGL 3.2 core 配置文件中,使用glGetString (...) 查询GL_EXTENSIONS无效,您必须使用@987654334 为每个扩展逐一进行@。 GLEW 不知道这一点,因此当您拥有核心配置文件上下文时,您需要告诉 GLEW 尝试获取每个扩展函数的入口点以确定支持。 大多数情况下,glewExperimental 可以用来解决可能会导致的矛盾情况。 glGetStringi (...) 是在核心 OpenGL 3.2 中处理扩展查询的正确方法,但 GLEW 想要查询扩展字符串以查看系统正在运行什么样的上下文。它将使用glGetString (...) 执行此操作,但这会生成GL_INVALID_ENUM 错误并且在核心3.2 上下文中不返回任何内容。 GLEW 确实需要像所有现代 GL 框架一样进行重构,以将上下文版本作为初始化参数来处理。【参考方案2】:

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

【讨论】:

如果调用glGenVertexArrays 导致我的程序出现段错误,我无法输出glGenVertexArrays 的值。 @Chris:他并不是要打电话给它。他的意思是打印glGenVertexArrays 的值(注意:那里没有括号)。它是一个函数指针... 这对以后调试问题很有帮助。每当我在OpenGL中遇到段错误时,往往是因为函数指针没有设置。【参考方案3】:

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

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

【讨论】:

这与 GLEW 用于查询扩展字符串的函数有关。 glGetString (...) 以及对 OpenGL 3.2 核心规范所做的一些更改。在核心中,使用该函数查询扩展字符串是无效的,您必须使用glGetStringi (...) 否则它将生成GL_INVALID_ENUM 错误并且不返回任何字符串。这不是你的软件的问题,只是 glew 的一个非常愚蠢的设计。

以上是关于为啥在使用 OpenGL 核心配置文件时会崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的程序在管理这个 JSON 文件时会崩溃?

为啥在使用 OpenGL 编译顶点着色器时会出现着色器编译器错误 #143、#160 和 #216?

为啥我的应用在使用 cloudkit 时会崩溃?

为啥 CLGeocoder 在调用时会崩溃

为啥 ProcessPoolExecutor 和 Pool 在调用 super() 时会崩溃?

为啥我的 Flutter 应用在​​ iOS 上启动时会崩溃?