opengl intel nvidia opengl-3 vertex-array
Binarios (ventanas, 32 bits)

opengl - VAO y estado del búfer de matriz de elementos



intel nvidia (4)

De hecho, creo que a ARB VAO le falta el estado del enlace de matriz de elementos (o cualquier otro enlace de búfer).

La creencia no es requerida; la especificación dice los hechos.

De la especificación ARB_vertex_array_object :

El comando

void GenVertexArrays(sizei n, uint *arrays);

devuelve nombres de objetos de matriz de vértices anteriores no utilizados en. Estos nombres están marcados como utilizados, solo para fines de GenVertexArrays, y se inicializan con el estado enumerado en las tablas 6.6 (excepto para el estado del selector CLIENT_ACTIVE_TEXTURE), 6.7 y 6.8 (excepto para el estado ARRAY_BUFFER_BINDING).

Entonces ahí lo tenemos: todo el estado abarcado por los VAO son los contenidos de esas tres tablas, con las excepciones señaladas.

La extensión está escrita contra la especificación de gráficos OpenGL versión 2.1 (PDF) . Por lo tanto, se hace referencia a cualquier número de página, etiqueta de sección o número de tabla en relación con esa especificación.

No voy a copiar esas tres tablas aquí. Pero si mira en la página 273 (según el recuento de páginas de la especificación) / página 287 (por el número de páginas físicas), encontrará la tabla 6.8. Y en esa mesa está lo siguiente:

  • ELEMENT_ARRAY_BUFFER_BINDING

No hay ambigüedad aquí. La información no puede ser claramente declarada. Pero está ahí , incuestionablemente. ELEMENT_ARRAY_BUFFER_BINDING es parte del estado VAO.

Por lo tanto, su problema puede provenir de una de dos fuentes:

  1. Error del controlador. Como dije en un comentario, un error del controlador parece improbable. No es imposible, solo poco probable. Los controladores de NVIDIA son bastante similares a sí mismos para hardware diferente, y los VAO apenas se reflejan en el hardware. A menos que esté usando versiones diferentes de los controladores, hay pocas razones para esperar que un error se deba a una falla del controlador.

  2. Error de usuario. Sé que afirmas que tu código funciona, y por lo tanto está bien. Todos hacen esa afirmación sobre algún código. Y ha habido muchas veces en las que juraría que algún código funcionaba bien. Sin embargo, estaba roto; simplemente sucedió para salir adelante. Sucede. Si publica su código, al menos podremos descontar esta posibilidad. De lo contrario, no tenemos nada más que tu palabra. Y teniendo en cuenta la frecuencia con la que los seres humanos están equivocados al respecto, eso no vale mucho.

Hace poco escribí código OpenGL 3.3 con Vertex Array Objects (VAO) y lo probé más tarde en el adaptador de gráficos Intel, donde encontré, para mi decepción, que el enlace de matriz de elementos no es parte del estado VAO, como llamar:

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

no tuvo ningún efecto, mientras:

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

representa la geometría Pensé que era un mero error en la implementación Intel de OpenGL (porque está claramente indicado en GL_ARB_vertex_array_object (e incluso en GL_OES_vertex_array_object) ese conjunto de elementos es parte del estado guardado), pero luego ocurrió en el dispositivo móvil NVIDIA Quadro 4200. Eso no es divertido .

¿Es un error del controlador, un error de especificación o un error en algún lugar de mi código? El código funciona sin problemas en GeForce 260 y 480.

¿Alguien tuvo una experiencia similar?

Lo que también es extraño es que GL_EXT_direct_state_access no tiene una función para vincular un elemento de matriz de búfer a VAO (pero sí tiene funciones para especificar matrices attrib de vértices y, por lo tanto, búferes de matriz). ¿Los fabricantes de la GPU están atornillando las especificaciones y engañándonos, o qué?

EDITAR :

Originalmente no tenía la intención de mostrar ningún código fuente porque creía que no era necesario aquí. Pero según lo solicitado, aquí está el caso de prueba mínima que reproduce el problema:

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 }

El código anterior crea un búfer de vértices que contiene tres quads, rojo, azul y negro. Luego crea tres búferes de índice que apuntan a los quads individuales. Luego se crean y configuran dos VAO, uno debe contener índices cuadriculados rojos y el otro debe contener índices cuádruples azules. El quad negro no se debe representar en absoluto (supongamos que BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER está definido).

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

Esto borra la ventana gráfica en gris y representa cuádruple azul o rojo en forma repetida (también imprime cuál). Si bien esto funciona en la GPU de escritorio, no funciona en la GPU portátil (el cuadrante negro se representa a menos que se defina la macro VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER. Al definir la macro BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER, el cuadrángulo se vuelve azul, ya que el índice azul está enlazado al final. renderizar el cuadrante rojo sin importar qué.

Entonces, de la forma en que lo veo, es una idea falsamente fatal en mi comprensión de cómo debería funcionar VAO, un error en mi código o un error en el controlador.

Fuente completa
Binarios (ventanas, 32 bits)


Después de un tiempo, descubrí que esto era realmente malo. La computadora portátil con la tarjeta gráfica NVIDIA Quadro 4200 se configuró para que todas las aplicaciones se ejecutaran en los gráficos Intel por defecto, incluso cuando la computadora portátil estaba en el modo de rendimiento. No entiendo por qué alguien querría hacer eso, ya que entonces no había forma de que ninguna aplicación utilizara la GPU más poderosa de OpenGL (aún era posible usarla para OpenCL ya que hay una selección de dispositivos explícita, también tal vez para DirectX: eso explicaría por qué algunos juegos funcionaron sin problemas).

Sin embargo, el comportamiento erróneo descrito es solo un error en los controladores de Intel, eso es todo. Los controladores de Intel no guardan ELEMENT_ARRAY_BUFFER_BINDING. Ahí.

Lamento sinceramente haber hecho la pregunta, ya que no había forma de dar una buena respuesta sin saber lo anterior.


Me imagino que el búfer ELEMENT no se almacena en caché; si lo haces:

glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));

Es como decir:

gBoundBuffer_GL_ARRAY_BUFFER=n_vertex_buffer_object; currentVAO->enable|=(1<<0); currentVAO->vertexBuffer=IndexToPointer(gBoundBuffer_GL_ARRAY_BUFFER);

En otras palabras, glBindBuffer() no hace nada más que establecer el valor de GL_ARRAY_BUFFER . Está en glVertexAttribPointer() donde modifica el VAO.

Entonces cuando lo haces:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[0]); glBindVertexArray(0);

Realmente lo haces:

gBoundBuffer_GL_ELEMENT_ARRAY_BUFFER=p_index_buffer_object_list[0]; currentVAO=0;

Donde tiene sentido que el enlace GL_ELEMENT_ARRAY_BUFFER no esté haciendo nada. No estoy seguro de si existe una variante similar a glVertexAttribPointer() para los elementos (como glElementPointer() ), que en realidad actuaría sobre el VAO.


Una causa probable para esto es que su adaptador Intel no puede proporcionar un contexto OpenGL 3.3, sino que se configura de manera predeterminada en 2.1 o similar. Como han señalado otros, en versiones anteriores de OpenGL, el estado del búfer de elementos no formaba parte de un VAO.