c - OpenGL+GLFW glGenVertexArrays 返回 GL_INVALID_OPERATION

标签 c macos opengl glfw

在尝试使用“现代”OpenGL(基本上是 3.2+)时,我在使用 GLFW、GLEW 和 OpenGL 运行基本代码(源自 herehere)时遇到了一些麻烦。

我的第一个问题是使用以下代码:

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

const GLchar* vertexSource =
    "#version 150 core\n"
    "in vec2 position;"
    "void main()"
    "{"
    "    gl_Position = vec4(position, 0.0, 1.0);"
    "}";
const GLchar* fragmentSource =
    "#version 150 core\n"
    "out vec4 outColor;"
    "void main()"
    "{"
    "    outColor = vec4(1.0, 1.0, 1.0, 1.0);"
    "}";

void checkErr(const char* msg) {
    GLenum err = glGetError();

    if (err != 0) {
        printf("@ \"%s\": %d\n", msg, err);
        exit(EXIT_FAILURE);
    } else {
        printf("@ \"%s\": successful\n", msg);
    }
}

int main(int argc, char* argv[]) {
    GLFWwindow* window;

    // Initialize GLFW
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Create a windowed mode window and its OpenGL context
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    // Make the window's context current
    glfwMakeContextCurrent(window);

    // Initialize GLEW
    glewExperimental = GL_TRUE;
    glewInit();

    // get version info
    const GLubyte* renderer = glGetString(GL_RENDERER);
    const GLubyte* version = glGetString(GL_VERSION);
    const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);
    printf ("Renderer:       %s\n", renderer);
    printf ("OpenGL version: %s\n", version);
    printf ("GLSL version:   %s\n", glslVersion);

    // Create Vertex Array Object
    GLuint vao;
    glGenVertexArrays(1, &vao);
    checkErr("Gen VAO");
    glBindVertexArray(vao);
    checkErr("Bind VAO");

    // Create a Vertex Buffer Object and copy the vertex data to it
    GLuint vbo;
    glGenBuffers(1, &vbo);
    checkErr("Gen VBO");

    GLfloat vertices[] = {
         0.0f,  0.5f,
         0.5f, -0.5f,
        -0.5f, -0.5f
    };

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    checkErr("Bind VBO");
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    checkErr("VBO data");

    // Create and compile the vertex shader
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSource, NULL);
    glCompileShader(vertexShader);
    checkErr("Compile vert shader");

    // Create and compile the fragment shader
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
    glCompileShader(fragmentShader);
    checkErr("Compile frag shader");

    // Link the vertex and fragment shader into a shader program
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glBindFragDataLocation(shaderProgram, 0, "outColor");
    glLinkProgram(shaderProgram);
    checkErr("Link program");
    glUseProgram(shaderProgram);
    checkErr("Use program");

    // Specify the layout of the vertex data
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    checkErr("Enable vertex attrib");
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
    checkErr("Describe vert data");

    // Loop until the user closes the window
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClearColor(0.0, 0.0, 0.0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    exit(EXIT_SUCCESS);
}

我在设置顶点数组对象的第一步就立即遇到了 GL_INVALID_OPERATION 错误。

我已经对 OS X 脆弱的 OpenGL 支持做了相当多的研究,但到目前为止,我在这段代码中修改的大部分内容都没有做更多的事情,只是产生了一个完全黑屏(也就是说,当我删除checkError 辅助函数的崩溃行为)。

作为引用,我在 2015 年初的 MacBook Pro w/Retina、OS X v10.11.3 上运行,上面程序列表的版本信息输出如下:

Renderer:       Intel(R) Iris(TM) Graphics 6100
OpenGL version: 4.1 INTEL-10.12.13
GLSL version:   4.10

非常感谢任何帮助!

最佳答案

您只是假设您的错误是由 glGenVertexArrays 生成的。但事实并非如此。它由 glewInit 生成。这是因为 GLEW 刚刚在核心配置文件 opengl 上被破坏:它使用 glGetString(GL_EXTENSIONS) 查询扩展字符串,这在核心配置文件中不可用并生成 GL_INVALID_ENUM错误 (1280)。

通常,glewInit 将中止并返回代码 GL_FALSE。但是,设置 glewExperimental=GL_TRUE 的“解决方法”将使它继续进行,忽略错误,并无论如何查询所有扩展指针。现在至少在 3 个不同方面被打破了:

  1. 即使在扩展可用时,用于查询特定扩展可用性的所有 GLEW 变量都返回 false。
  2. 它将检索扩展函数的函数指针,这些函数的可用性尚未被实现公布。不能保证这些指针将为 NULL,但调用它们将是未定义的行为。与 1 一起,这意味着您无法检查任何扩展的可用性,除非手动执行 glew 实际上为您做的事情。
  3. 它将使 GL 上下文处于错误状态。

作为一种快速而肮脏的 hack,您可以在 glewInit 之后添加一个 glGetError(),以读取错误。在我这样做之后,您的代码在我的实现 (NVIDIA/Linux) 上生成了预期的白色三角形。

更好的解决方法可能是切换到另一个可以正确处理核心配置文件的 GL 加载器,例如 glad .切换并不难,因为只需要替换 init 函数。请注意,glad 不是一个加载程序库,而是一个 python 脚本,它会根据您的需要生成一个加载程序 source 文件,因此您不需要链接另一个库,而只需添加另一个源文件到你的项目。

关于c - OpenGL+GLFW glGenVertexArrays 返回 GL_INVALID_OPERATION,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36326333/

相关文章:

c - 一个函数的多个定义,首先在这里定义

objective-c - NSTextField 内的 NSButton subview ,为什么我的按钮没有出现?

python - 在 mac 雪豹 macports 上 boost python 导入错误

javascript - 当我已经安装了 Node 10 时,如何安装 NodeJS 的 LTS 版本?

opengl - glm::perspective 与 gluPerspective

c++ - 使用比制服可以存储的更多的值来实例化

c - 如何在 C 中构造并返回字符串?

c - 使用 linux 功能是否禁用 LD_PRELOAD

c - 在 libcoap coap 服务器 GET 响应处理程序中如何访问 URI 的查询添加项?

opengl - 使用 GLUT 和不使用 GLUT 的 OpenGL 编程有什么区别