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.
Vous devez vous connecter pour publier un commentaire.
Après un certain temps, j'ai trouvé que c'était assez de mon mauvais. L'ordinateur portable avec les mobiles NVIDIA Quadro 4200 carte graphique a été définie de sorte que toutes les applications irait sur le graphique Intel par défaut, même lorsque le portable est en mode performance. Je ne comprends pas pourquoi quelqu'un voudrait-il faire, comme à l'époque il n'y avait aucun moyen de l'application à utiliser le plus puissant GPU d'OpenGL (il était encore possible de l'utiliser pour OpenCL explicite de la sélection de l'appareil, aussi peut-être pour DirectX qui pourrait expliquer pourquoi certains jeux se sont déroulées sans problème).
Néanmoins, le décrit errorneous comportement est juste un bug dans les drivers Intel, c'est tout là est à lui. Pilotes Intel ne pas enregistrer ELEMENT_ARRAY_BUFFER_BINDING. Il n'.
Je suis sincèrement désolé de poser la question, comme il n'y avait pas moyen de donner une bonne réponse sans la connaissance de la ci-dessus.
La croyance n'est pas nécessaire; la spec dit les faits.
De la ARB_vertex_array_object spécifications:
Donc là, nous avons: l'ensemble de l'état visées par VAOs sont le contenu de ces trois tableaux, avec les exceptions indiquées.
L'extension est écrit contre Le Graphique OpenGL Spécification de la version 2.1 (PDF). Par conséquent, tous les numéros de page de la section des étiquettes, ou les numéros de table sont référencés par rapport à cette spécification.
Je ne suis pas sur pour copier ces trois tables. Mais si vous regardez à la page 273 (par la spécification du nombre de pages)/page 287 (par le nombre de pages physiques), vous trouverez le tableau 6.8. Et sur cette table est la suivante:
Il n'y a pas d'ambiguïté ici. Les informations ne peuvent pas être clairement indiqué. Mais il est il, incontestablement. Le ELEMENT_ARRAY_BUFFER_BINDING fait partie de VAO état.
Par conséquent, votre problème peut venir de deux sources:
Pilote de bug. Comme je l'ai dit dans un commentaire, un pilote de bug semble peu probable. Pas impossible, juste improbable. NVIDIA pilotes sont assez similaires pour les différents matériels, et VAOs sont à peine en miroir dans le matériel. Sauf si vous utilisez différentes versions des pilotes, il y a peu de raison de s'attendre à une erreur due à un pilote de bug.
Erreur de l'utilisateur. Je sais que vous le prétendez que votre code fonctionne, et par conséquent, il est très bien. Tout le monde fait que la revendication sur une partie du code. Et il y a eu beaucoup de fois quand j'avouerais qu'un code a été fonctionne correctement. Pourtant, il a été cassé, il est arrivé à s'en sortir. Il se passe. Si vous postez votre code, puis au moins on serait en mesure d'escompte de cette possibilité. Sinon, nous n'avons rien de plus que votre parole. Et compte tenu de la façon dont souvent les êtres humains sont mauvais sujet, qui ne vaut pas beaucoup.
Une cause probable pour ceci est que votre carte Intel ne peut pas fournir un OpenGL 3.3 contexte, mais plutôt par défaut 2.1 ou similaires. Comme d'autres l'ont souligné, dans les versions antérieures d'OpenGL l'élément de tableau d'état de la mémoire tampon ne fait pas partie d'un VAO.
glGetString(GL_VERSION)
mais cela ne signifie pas que l'un bug (élément de la matrice de ne pas être mis en cache) a été causé par une bien pire bug (création d'un vieux 2.1 contexte au lieu d'un avant-compatible).Je peux imaginer le
ELEMENT
tampon de ne pas être mis en cache; si vous n':C'est comme de dire:
En d'autres termes,
glBindBuffer()
ne rien faire, mais de définir la valeur deGL_ARRAY_BUFFER
. C'est àglVertexAttribPointer()
où vous modifiez le VAO.Ainsi, lorsque vous vous:
Vous vraiment faire:
Où il est logique que le
GL_ELEMENT_ARRAY_BUFFER
la liaison n'est pas de faire quoi que ce soit.Je ne sais pas si il y a un
glVertexAttribPointer()
-comme variante pour les éléments si, commeglElementPointer()
), qui serait en fait la loi sur le VAO.