webdevqa.jp.net

VAOと要素配列のバッファ状態

私は最近、Vertex Array Objects(VAO)を使用してOpenGL 3.3コードを作成し、後でIntelグラフィックスアダプターでテストしました。残念ながら、要素配列のバッファーバインディングは、次のようにVAO状態の一部ではないことがわかりました。

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 Quadro4200で発生しました。それは面白くありません。

ドライバーのバグ、仕様のバグ、またはコードのどこかにあるバグですか?コードはGeForce260および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つには赤いクワッドインデックスが含まれ、もう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では機能しますが、ノートブックGPUでは機能しません(VAO_DOESNT_STORE_ELEMENT_ARRAY_BUFFERマクロが定義されていない限り、黒いクワッドがレンダリングされます。BIND_BLACK_QUAD_ELEMENT_ARRAY_BUFFERマクロを定義解除すると、青いインデックスバッファーが最後にバインドされるため、クワッドが青になります。ただし、そうではありません。何があっても赤いクワッドをレンダリングします。

ですから、私の見方では、VAOがどのように機能するかについての私の理解における致命的な誤解、コードのバグ、またはドライバーのバグのいずれかです。

完全なソース
バイナリ(ウィンドウ、32ビット)

23
the swine

しばらくして、これは実際には私の悪いことだとわかりました。モバイルNVIDIAQuadro 4200グラフィックカードを搭載したラップトップは、ラップトップがパフォーマンスモードの場合でも、すべてのアプリがデフォルトでIntelグラフィックスで実行されるように設定されています。なぜ誰かがそれをしたいのか理解できません。その場合、アプリケーションがOpenGLのより強力なGPUを使用する方法がありませんでした(明示的なデバイス選択があるため、OpenCLに使用することは可能でした。 DirectX-それはいくつかのゲームがスムーズに実行された理由を説明します)。

それにもかかわらず、説明されている誤った動作はIntelドライバーの単なるバグであり、それだけです。 IntelドライバーはELEMENT_ARRAY_BUFFER_BINDINGを保存しません。そこ。

上記を知らずに良い答えを出す方法がなかったので、質問をして誠に申し訳ありません。

25
the swine

私は実際、ARB VAOに要素配列のバッファー結合(または他のバッファー結合)状態が欠落していると信じています。

信念は必要ありません。仕様は事実を示しています。

ARB_vertex_array_object 仕様から:

コマンド

void GenVertexArrays(sizei n, uint *arrays);

以前の未使用の頂点配列オブジェクト名をで返します。これらの名前は、GenVertexArrayの目的でのみ使用済みとしてマークされ、表6.6(CLIENT_ACTIVE_TEXTUREセレクター状態を除く)、6.7および6.8(ARRAY_BUFFER_BINDING状態を除く)にリストされている状態で初期化されます。

これで、VAOに含まれる状態全体が、上記の例外を除いて、これら3つのテーブルの内容になります。

拡張機能は OpenGLグラフィック仕様バージョン2.1(PDF) に対して書かれています。したがって、ページ番号、セクションラベル、またはテーブル番号は、その仕様に関連して参照されます。

これらの3つのテーブルをここにコピーするつもりはありません。しかし、273ページ(仕様のページ数による)/ 287ページ(物理ページ数による)を見ると、表6.8が見つかります。そして、そのテーブルには次のものがあります。

  • ELEMENT_ARRAY_BUFFER_BINDING

ここにあいまいさはありません。情報が明確に記載されていない場合があります。しかし、それは間違いなくそこです。 ELEMENT_ARRAY_BUFFER_BINDINGはVAO状態の一部です。

したがって、問題は次の2つの原因のいずれかから発生する可能性があります。

  1. ドライバーのバグ。コメントで述べたように、ドライバーのバグはありそうにないようです。不可能ではありません。 NVIDIAのドライバーは、さまざまなハードウェアでかなり自己相似であり、VAOはハードウェアにほとんどミラーリングされていません。異なるバージョンのドライバーを使用している場合を除いて、ドライバーのバグが原因でエラーが発生すると予想する理由はほとんどありません。

  2. ユーザーエラー。コードが機能すると主張しているので、問題ありません。 Everyoneは、あるコードについてその主張をします。そして、いくつかのコードがうまく機能していることを上下に誓うことが何度もありました。それでもそれは壊れていました。たまたま通りかかった。それは起こります。コードを投稿すれば、少なくともこの可能性を無視することができます。そうでなければ、私たちはあなたの言葉しかありません。そして、人間がそれについて間違っている頻度を考えると、それはあまり価値がありません。

18
Nicol Bolas

これの考えられる原因は、IntelアダプタがOpenGL 3.3コンテキストを提供できず、代わりにデフォルトで2.1などになっていることです。他の人が指摘しているように、OpenGLの以前のバージョンでは、要素配列のバッファ状態はVAOの一部ではありませんでした。

0
bduc