简体   繁体   English

OpenGL + GLFW glGenVertexArrays返回GL_INVALID_OPERATION

[英]OpenGL+GLFW glGenVertexArrays returns GL_INVALID_OPERATION

In trying to move into using "modern" OpenGL (basically 3.2+), I've run into some troubles running basic code (derived from both here and here ) using GLFW, GLEW, and OpenGL. 在尝试使用“现代”OpenGL(基本上是3.2+)时,我遇到了使用GLFW,GLEW和OpenGL运行基本代码(从这里这里派生)的一些麻烦。

My first problem is that with the below code: 我的第一个问题是使用以下代码:

#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);
}

I'm immediately running into GL_INVALID_OPERATION errors on the very first step of setting up the vertex array object. 我在设置顶点数组对象的第一步中立即GL_INVALID_OPERATION错误。

I've done a fair bit of research regarding OS X's flimsy OpenGL support, but so far most of the things I've modified in this code has done nothing more but produce a completely black screen (that is, when I removed the crashing behavior of the checkError helper function). 我已经对OS X的脆弱的OpenGL支持进行了一些研究,但到目前为止,我在这段代码中修改过的大部分内容都没有做更多的事情,只产生一个完全黑屏(也就是说,当我删除崩溃的行为时) checkError辅助函数)。

For reference, I'm running on an early 2015 MacBook Pro w/Retina, OS X v10.11.3, and the output of the version info from my above program lists as follows: 作为参考,我使用的是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

Any help is greatly appreciated! 任何帮助是极大的赞赏!

You just assumed that your error was generated by glGenVertexArrays . 您只是假设您的错误是由glGenVertexArrays生成的。 But that is not the case. 但事实并非如此。 It is generated by glewInit . 它由glewInit生成。 And this is because GLEW is just broken on core profile opengl: it uses glGetString(GL_EXTENSIONS) to query the extension string, which is not available in core prodiles and generates a GL_INVALID_ENUM error (1280). 这是因为GLEW刚刚在核心配置文件opengl上被打破:它使用glGetString(GL_EXTENSIONS)来查询扩展字符串,这在核心产品中不可用并生成GL_INVALID_ENUM错误(1280)。

Normally, glewInit will then abort with return code GL_FALSE . 通常, glewInit将以返回码GL_FALSE中止。 However, the "workaround" of setting glewExperimental=GL_TRUE will make it going on, ignoring the error, and querying all the extension pointers anyway. 但是,设置glewExperimental=GL_TRUE的“解决方法”将使其继续,忽略错误,并且无论如何都要查询所有扩展指针。 This is now broken in at least 3 different regards: 现在至少在3个不同方面打破了这个问题:

  1. All the GLEW variables for querying the avialibility of specific extensions return false even when the extension is available. 用于查询特定扩展的可用性的所有GLEW变量即使在扩展可用时也返回false。
  2. It will retrieve function pointers for extension functions whose availibility hasn't been advertised by the implementation. 它将检索扩展函数的函数指针,这些扩展函数的可用性尚未被实现公布。 It is not guaranteed that those pointers will be NULL , but calling these would be undefined behavior. 不保证这些指针将为NULL ,但调用这些指针将是未定义的行为。 Together with 1, this means you have no way of checking the availibility of any extension, except by manually doing the stuff glew is actually there for to do for you. 与1一起,这意味着您无法检查任何扩展的可用性,除非通过手动执行glew实际上为您执行的操作。
  3. It will leave the GL context in an error state. 它将使GL上下文处于错误状态。

As a quick & dirty hack, you can just add a glGetError() right after glewInit , to read the error away. 作为一个快速和肮脏的黑客,你可以再补充一个glGetError()之后glewInit ,读取错误了。 After I did that, your code produced the expected white triangle on my implementation (NVIDIA/Linux). 在我这样做之后,你的代码在我的实现(NVIDIA / Linux)上产生了预期的白色三角形。

A better fix is probably to switch over to another GL loader which does properly work with core profiles, for example glad . 一个更好的修复可能是切换到另一个GL加载器,它正确地与核心配置文件一起工作,例如很高兴 Switching over will not be really hard, as only that init function has to be replaced. 切换不会很难,因为只需要替换init函数。 Note that glad is not a loader library, but a python script which generates a loader source file for your needs, so you don't need to link another library, but just have to add another source file to your project. 请注意,很高兴不是一个加载器库,而是一个python脚本,它根据您的需要生成一个加载器文件,因此您不需要链接另一个库,只需要将另一个源文件添加到您的项目中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM