VAO和元素数组缓冲区状态 [英] VAO and element array buffer state

查看:99
本文介绍了VAO和元素数组缓冲区状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近正在用顶点数组对象(VAO)编写一些OpenGL 3.3代码,后来在Intel图形适配器上对其进行了测试,令我失望的是,元素数组缓冲区绑定显然不是VAO状态的一部分,原因是:

I was recently writing some OpenGL 3.3 code with Vertex Array Objects (VAO) and tested it later on Intel graphics adapter where I found, to my disappointment, that element array buffer binding is evidently not part of VAO state, as calling:

glBindVertexArray(my_vao);
glDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_INTEGER, 0);

没有效果,而:

glBindVertexArray(my_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, my_index_buffer); // ?
glDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_INTEGER, 0);

渲染几何体.我认为这只是Intel OpenGL实现中的一个错误(因为GL_ARB_vertex_array_object(甚至在GL_OES_vertex_array_object中已明确指出)元素数组是保存状态的一部分,但随后它在移动设备上发生了NVIDIA Quadro4200.这没什么好玩的.

rendered the geometry. I thought it was a mere bug in Intel implementation of OpenGL (because it is clearly stated in GL_ARB_vertex_array_object (and even in GL_OES_vertex_array_object) that element array is part of the saved state), but then it occured on mobile NVIDIA Quadro 4200. That's no fun.

是驱动程序错误,规范错误还是代码中的某个错误?该代码可在GeForce 260和480上完美运行.

Is it a driver bug, a specs bug, or a bug somewhere in my code? The code works flawlessly on GeForce 260 and 480.

有人有类似的经历吗?

还奇怪的是GL_EXT_direct_state_access没有将元素数组缓冲区绑定到VAO的功能(但是它确实具有指定顶点attrib数组的功能,因此指定了数组缓冲区). GPU制造商是在规范规格并欺骗我们吗?

What is also strange is that GL_EXT_direct_state_access does not have a function to bind an element array buffer to VAO (but it does have functions to specify vertex attrib arrays, and hence array buffers). Are the GPU manufacturers screwing the specs and cheating on us, or what?

编辑:

我本来不打算显示任何源代码,因为我认为这里没有必要.但是根据要求,这是重现该问题的最小测试用例:

I originally didn't intend to show any source code because I believed it was not necessary here. But as requested, here is the minimal test case that reproduces the problem:

static GLuint n_vertex_buffer_object, p_index_buffer_object_list[3];
static GLuint p_vao[2];

bool InitGLObjects()
{
    const float p_quad_verts_colors[] = {
        1, 0, 0, -1, 1, 0,
        1, 0, 0, 1, 1, 0,
        1, 0, 0, 1, -1, 0,
        1, 0, 0, -1, -1, 0, // red quad
        0, 0, 1, -1, 1, 0,
        0, 0, 1, 1, 1, 0,
        0, 0, 1, 1, -1, 0,
        0, 0, 1, -1, -1, 0, // blue quad
        0, 0, 0, -1, 1, 0,
        0, 0, 0, 1, 1, 0,
        0, 0, 0, 1, -1, 0,
        0, 0, 0, -1, -1, 0 // black quad
    };
    const unsigned int p_quad_indices[][6] = {
        {0, 1, 2, 0, 2, 3},
        {4, 5, 6, 4, 6, 7},
        {8, 9, 10, 8, 10, 11}
    };
    glGenBuffers(1, &n_vertex_buffer_object);
    glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
    glBufferData(GL_ARRAY_BUFFER, sizeof(p_quad_verts_colors), p_quad_verts_colors, GL_STATIC_DRAW);
    glGenBuffers(3, p_index_buffer_object_list);
    for(int n = 0; n < 3; ++ n) {
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[n]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(p_quad_indices[n]), p_quad_indices[n], GL_STATIC_DRAW);
    }

    glGenVertexArrays(2, p_vao);
    glBindVertexArray(p_vao[0]);
    {
        glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(3 * sizeof(float)));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[0]); // red
    }
    glBindVertexArray(0);

    glBindVertexArray(p_vao[1]);
    {
        glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(3 * sizeof(float)));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[1]); // blue
    }
    glBindVertexArray(0);

#ifdef BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[2]);
    // bind the buffer with the black quad (not inside VAO, should NOT be seen)
#endif // BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER

    // [compile shaders here]

    return true; // success
}

上面的代码创建一个顶点缓冲区,其中包含三个四边形,一个红色,一个蓝色和一个黑色.然后,它创建三个指向各个四边形的索引缓冲区.然后,创建并设置了两个VAO,一个应该包含红色的四分之一索引,另一个应该包含蓝色的四分之一索引.黑色四边形根本不应该呈现(假设已定义BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER ).

The above code creates a vertex buffer containing three quads, red one, blue one and black one. Then it creates three index buffers that point to the individual quads. Then two VAOs are created and set up, one should contain red quad indices and the other should contain blue quad indices. The black quad should not be rendered at all (assume BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER is defined).

void onDraw()
{
    glClearColor(.5f, .5f, .5f, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);

    glUseProgram(n_program_object);

    static int n_last_color = -1;
    int n_color = (clock() / 2000) % 2;
    if(n_last_color != n_color) {
        printf("now drawing %s quad\n", (n_color)? "blue" : "red");
        n_last_color = n_color;
    }

    glBindVertexArray(p_vao[n_color]);
#ifdef VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[n_color]); // fixes the problem
#endif // VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

这会将视口清除为灰色,并以重复方式渲染蓝色或红色四边形(也将打印其中一个).虽然这在台式机GPU上有效,但在笔记本GPU上无效(除非定义了VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER宏,否则将渲染黑色四边形.取消定义BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER宏会使四边形变为蓝色,因为蓝色索引缓冲区最后绑定.无论如何都渲染红色四边形.

This clears the viewport to gray and renders either blue or red quad in repeating manner (it also prints which one). While this works on desktop GPU, it doesn't work on notebook GPU (black quad is rendered unless the VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER macro is defined. Undefining the BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER macro makes the quad blue, as the blue index buffer is bound last. But it doesn't render the red quad no matter what.

所以从我的角度来看,这可能是对VAO应该如何工作的致命误解,代码中的错误或驱动程序错误.

So the way I see it, it's either a fatal misconception in my understanding of how should VAO work, a bug in my code, or a driver bug.

完整源文件
二进制文件(Windows,32位)

推荐答案

一段时间后,我发现这实际上是我的坏处.设置了带有移动NVIDIA Quadro 4200显卡的笔记本电脑,以便即使在笔记本电脑处于性能模式时,默认情况下所有应用程序都可以在Intel显卡上运行.我不明白为什么有人要这么做,因为那时没有任何应用程序可以使用来自OpenGL的功能更强大的GPU(由于有明确的设备选择,因此仍然可以将其用于OpenCL,也许是为了DirectX-可以解释为什么某些游戏运行平稳).

After some time, I found out this was actually kind of my bad. The laptop with the mobile NVIDIA Quadro 4200 graphics card was set so that all the apps would run on the Intel graphics by default, even when the laptop was in the performance mode. I don't understand why would someone want to do that, as then there was no way for any application to use the more powerful GPU from OpenGL (it was still possible to use it for OpenCL as there is explicit device selection, also maybe for DirectX - that would explain why some games ran smoothly).

尽管如此,所描述的错误行为只是Intel驱动程序中的一个错误,仅此而已.英特尔驱动程序不保存ELEMENT_ARRAY_BUFFER_BINDING.在那里.

Nevertheless, the described errorneous behavior is just a bug in Intel drivers, that's all there's to it. Intel drivers do not save ELEMENT_ARRAY_BUFFER_BINDING. There.

我很抱歉提出这个问题,因为如果不了解上述内容,就无法给出一个很好的答案.

I'm sincerely sorry for asking the question, as there was no way to give a good answer without knowing the above.

这篇关于VAO和元素数组缓冲区状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆