VAOと要素のアレイバッファの状態
-
12-11-2019 - |
質問
私は最近頂点アレイオブジェクト(VAO)を使用していくつかのOpenGL 3.3コードを作成し、私が見つけたIntel Graphicsアダプタの後にテストした。
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);
.
ジオメトリをレンダリングしました。私はそれがOpenGLのIntel実装の単なるバグだと思いました(GL_ARB_VERTEX_ARRAY_OBJECT(およびGL_OES_VERTEX_ARRAY_OBJECTでは明確に記載されているため)この要素配列は保存された状態のの一部です)ですが、それはモバイルで発生しましたNVIDIA Quadro 4200.それは楽しいことです。
ドライバのバグ、スペックのバグ、またはコードのどこかのバグですか?コードはGeForce 260および480で完璧に機能します。
だれでも同様の経験がありましたか?
GL_EXT_DIRECT_STATE_ACCESSには、要素アレイバッファをVAOにバインドする機能がないこともあります(ただし、頂点属性配列、したがって配列バッファを指定する機能はあります)。 GPU製造業者はスペックをねじ込みし、私たちに不正行為をしているか、何ですか?
編集:
私はこれが必要ではないと信じていたので、もともとソースコードを表示するつもりはなかった。しかし要求されたように、これは問題を再現する最小のテストケースです:
.
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
}
上記のコードは、3つのクワッド、赤いもの、青いもの、黒のものを含む頂点バッファを作成します。その後、個々のクワッドを指す3つのインデックスバッファを作成します。次に、2つのVAOが作成され設定されます。これは赤いクワッドインデックスを含める必要があり、もう1つは青いクワッドインデックスを含める必要があります。ブラッククワッドはまったくレンダリングされるべきではありません(bind_black_quad_element_array_buffer が定義されているの存在)。
.
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で動作しますが、Notebook GPUでは機能しません(Black QuadはVAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFERマクロが定義されていない限りレンダリングされます。BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFERマクロを未定義にすると、青いインデックスバッファは最後にバインドされます。しかし、そうではありません。何をしても赤いQuadをレンダリングします。
だから私がそれを見る方法は、VAOが仕事、私のコードのバグ、または運転者のバグを理解するのは、致命的な誤解です。
解決
しばらくした後、私はこれが実際に私の悪い人であったことを発見しました。モバイルNVIDIA Quadro 4200グラフィックスカードを搭載したラップトップは、ラップトップがパフォーマンスモードの場合でも、すべてのアプリがデフォルトでIntelグラフィック上で実行されるように設定されました。誰かがそれをやりたいのかを理解していません。DirectX - なぜいくつかのゲームがスムーズに走った理由を説明するでしょう。
は、記載されている誤った動作は、Intelドライバのほんのバグですが、それがすべてのものです。Intelドライバはelement_array_buffer_bindingを保存しません。そこに。
上記を知らずに良い答えを与える方法がなかったので、私は質問をして申し訳ありません。
他のヒント
私は実際にはARB VAOに要素アレイバッファバインディング(または他の緩衝結合)状態が欠落していると考えています。
信念は不要です。仕様は事実を語ります。
コマンド
.void GenVertexArrays(sizei n, uint *arrays);
以前の未使用の頂点配列オブジェクト名を返します。これらの名前は、GENVERTEXARRAYSのみの目的で使用されているとマークされ、表6.6(client_abled_textureセレクタ状態を除く)、6.7および6.8(Array_Buffer_Binding状態を除く)でリストされている状態で初期化されます。
私たちはそれを持っています:VAOに含まれる全状態は、注目された例外を持つ3つのテーブルの内容です。
拡張子は OpenGL Graphics Specificationバージョン2.1(pdf)。したがって、ページ番号、セクションラベル、または表番号はその仕様と比較して参照されます。
これが、IntelアダプタがOpenGL 3.3コンテキストを提供できないが、その代わりに2.1などにIntelアダプタが提供できないことです。他のものが指摘したように、以前のバージョンのOpenGLでは、要素アレイバッファ状態はVAOの一部ではありませんでした。
ELEMENT
バッファがキャッシュされていないと想像できます。あなたがするなら:
glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer_object);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), p_OffsetInVBO(0));
.
言うのが好きです:
gBoundBuffer_GL_ARRAY_BUFFER=n_vertex_buffer_object;
currentVAO->enable|=(1<<0);
currentVAO->vertexBuffer=IndexToPointer(gBoundBuffer_GL_ARRAY_BUFFER);
.
換言すれば、glBindBuffer()
は何もしません。それはあなたがVAOを修正したGL_ARRAY_BUFFER
です。
だからあなたがするとき:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, p_index_buffer_object_list[0]);
glBindVertexArray(0);
.
本当にやる:
gBoundBuffer_GL_ELEMENT_ARRAY_BUFFER=p_index_buffer_object_list[0];
currentVAO=0;
.
glVertexAttribPointer()
バインディングが何もしていないことを理解するとは意味があります。
(GL_ELEMENT_ARRAY_BUFFER
のような)要素にglVertexAttribPointer()
のようなバリアントがあるかどうかはわかりません。これは実際にはVAOに行動します。