VAO et de l'élément de tableau d'état de la mémoire tampon

J'ai récemment écrit certains OpenGL 3.3 code de Vertex Array d'Objets (VAO) et testé plus tard sur carte graphique Intel où j'ai trouvé, à ma déception, que l'élément de matrice de tampon de liaison est de toute évidence pas partie de VAO état, comme l'appel:

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

a eu aucun effet, tandis que:

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

rendu de la géométrie. Je pensais que c'était un simple bug Intel de mise en œuvre de OpenGL (car il est clairement indiqué dans GL_ARB_vertex_array_object (et même dans GL_OES_vertex_array_object) que l'élément de tableau est partie de l'état sauvegardé), mais ensuite elle s'est produite sur mobile NVIDIA Quadro 4200. Ce n'est pas amusant.

Est-il un pilote bug, un specs bug, ou un bug quelque part dans mon code? Le code fonctionne parfaitement sur GeForce 260 et 480.

Quelqu'un a une expérience similaire?

Ce qui est aussi étrange, c'est que GL_EXT_direct_state_access n'a pas une fonction pour lier un élément de tableau tampon à VAO (mais il a des fonctions de spécifier vertex attrib tableaux, et donc la matrice de tampons). Sont le GPU fabricants de visser les spécifications et la tricherie sur nous, ou quoi?

MODIFIER:

A l'origine, je n'ai pas l'intention de montrer tout le code source parce que j'ai cru qu'il n'était pas nécessaire ici. Mais comme l'a demandé, voici le minimum de cas de test qui reproduit le problème:

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
}

Le code ci-dessus crée un vertex buffer contenant trois quads, rouge, bleu et noir. Puis il crée trois index buffers de ce point à l'individu quads. Puis deux VAOs sont créés et mis en place, on devrait contenir rouge quad indices, et l'autre doit contenir bleu quad indices. Le noir quad ne devrait pas être rendu à tous (à supposer BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER est défini).

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

Cela efface la fenêtre d'affichage de gris et rend en bleu ou en rouge quad en répétant de manière (il imprime aussi qui une). Alors que cela fonctionne sur l'ordinateur GPU, il ne fonctionne pas sur le portable GPU (noir quad est rendue, à moins que le VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFER macro est définie. La suppression de la BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFER macro fait du quad, de bleu, comme le bleu de l'indice de tampon est lié dernier. Mais il ne rend pas le rouge quad n'importe quoi.

La façon dont je le vois, c'est soit une mauvaise idée fatale dans ma compréhension de la façon dont devrait VAO travail, un bug dans mon code, ou un pilote de bug.

Source complet

Les binaires (windows, 32 bits).

  • Il est plus probable que votre code n'est pas de mettre l'élément de mémoire tampon dans le VAO initialement. Pourquoi ne pas nous montrer votre VAO code d'initialisation.
  • Oh viens, pas si bête. En Plus je l'ai dit, il a travaillé sur les GeForce 260 / 480. Lire les posts avant d'écrire des commentaires. Je suis entièrement capable de débogage mon code OpenGL. Cette question est au sujet des différences entre les implémentations d'OpenGL et de la compatibilité.
  • Tout simplement parce que le code fonctionne ne signifie pas qu'il est correct. Soit par une circonstance fortuite ou que ce soit, code pouvez gérer au travail. Le fait qu'il échoue et réussit sur les pilotes NVIDIA suggère erreur de l'utilisateur. Si elle a travaillé sur NVIDIA et échoué sur ATI, ou vice-versa, il pourrait être plus susceptible d'être un pilote de bug. Mais NVIDIA, en particulier, est assez auto-similaire. Donc, si il travaille parfois sur certaines cartes NVIDIA matériel et parfois ne l'est pas, cela ressemble à de l'erreur de l'utilisateur.
InformationsquelleAutor the swine | 2012-01-23