4

最近、現在のプロジェクトの図面を、メモリアレイからVBOへの標準図面から変更しました。驚いたことに、フレームレートは60fpsから30fpsに大幅に低下し、1200vertsのモデルを8回描画しました。さらにプロファイリングを行うと、メモリから描画する場合と比較して、VBOを使用する場合はglDrawElementsに10倍の時間がかかることがわかりました。

なぜこれが起こっているのか、私は本当に困惑しています。パフォーマンス低下の原因が何であるかを誰かが知っていますか?

iOS6.1.2を実行しているiPhone5でテストしています。

VBO処理を単一の関数に分離し、関数の先頭に頂点/インデックスバッファーを静的に作成しました。#ifdefUSE_VBOを使用して通常のレンダリングとVBOレンダリングを切り替えることができます

- (void)drawDuck:(Toy*)toy reflection:(BOOL)reflection
{
    ModelOBJ* model = _duck[0].model;
    int stride = sizeof(ModelOBJ::Vertex);

#define USE_VBO
#ifdef USE_VBO
    static bool vboInitialized = false;
    static unsigned int vbo, ibo;
    if (!vboInitialized) {
        vboInitialized = true;

        // Generate VBO
        glGenBuffers(1, &vbo);
        int numVertices = model->getNumberOfVertices();
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, stride*numVertices, model->getVertexBuffer(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        // Generate index buffer
        glGenBuffers(1, &ibo);
        int numIndices = model->getNumberOfIndices();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*numIndices, model->getIndexBuffer(), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }
#endif

    [self setupDuck:toy reflection:reflection];


#ifdef USE_VBO
    // Draw with VBO
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

    glEnableVertexAttribArray(GC_SHADER_ATTRIB_POSITION);
    glEnableVertexAttribArray(GC_SHADER_ATTRIB_NORMAL);
    glEnableVertexAttribArray(GC_SHADER_ATTRIB_TEX_COORD);

    glVertexAttribPointer(GC_SHADER_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, stride, (void*)offsetof(ModelOBJ::Vertex, position));
    glVertexAttribPointer(GC_SHADER_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, stride, (void*)offsetof(ModelOBJ::Vertex, texCoord));
    glVertexAttribPointer(GC_SHADER_ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, stride, (void*)offsetof(ModelOBJ::Vertex, normal));
    glDrawElements(GL_TRIANGLES, model->getNumberOfIndices(), GL_UNSIGNED_SHORT, 0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#else
    // Draw with array
    glEnableVertexAttribArray(GC_SHADER_ATTRIB_POSITION);
    glEnableVertexAttribArray(GC_SHADER_ATTRIB_NORMAL);
    glEnableVertexAttribArray(GC_SHADER_ATTRIB_TEX_COORD);

    glVertexAttribPointer(GC_SHADER_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, stride, model->getVertexBuffer()->position);
    glVertexAttribPointer(GC_SHADER_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, stride, model->getVertexBuffer()->texCoord);
    glVertexAttribPointer(GC_SHADER_ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, stride, model->getVertexBuffer()->normal);
    glDrawElements(GL_TRIANGLES, model->getNumberOfIndices(), GL_UNSIGNED_SHORT, model->getIndexBuffer());
#endif
}

ModelOBJ :: Vertexは、pos、texcoord、normalの場合は3,2,3フロートです。インデックスはushortです。

更新:描画設定(つまり、属性バインディング呼び出し)をVAOにラップしました。パフォーマンスは問題なく、メインメモリから描画するよりもわずかに優れています。したがって、私の結論は、VAOなしのVBOサポートはiOSでは壊れているということです。その仮定は正しいですか?

4

2 に答える 2

8

ドライバーがソフトウェア バーテックス サブミッション (VBO からコマンド バッファーへの CPU コピー) にフォールバックしていた可能性があります。これはクライアント メモリで頂点配列を使用するよりも悪い場合があります。クライアント メモリは通常キャッシュされますが、VBO コンテンツは通常、iOS の書き込み結合メモリにあります。

Instruments で CPU サンプラーを使用すると、gleRunVertexSubmitARM の glDrawArrays/glDrawElements の下に大量の時間が表示されます。

SW CPU 送信にフォールバックする最も一般的な理由は、整列されていない属性です (現在の iOS デバイスでは、各属性を 4 バイトに整列する必要があります) が、表示された 3 つの属性には当てはまらないようです。次に多い原因は、1 つの頂点配列構成にクライアント配列とバッファー オブジェクトが混在していることです。

この場合、頂点アトリビュート バインドが不安定になっている可能性があります。他の配列要素がまだ有効になっており、クライアント配列を指している可能性があるため、すべてがハードウェア DMA パスから外れます。VAO を作成することにより、誤って構成されたデフォルトの VAO から切り替えたか、クライアント VAO を有効にしようとしているが、クライアント配列が減価償却され、VAO で使用すると機能しない (代わりに INVALID_OPERATION エラーをスローする) ため、保存されます。 .

于 2013-03-09T21:26:11.523 に答える
1

インデックスバッファに。を設定するglBufferData場合、2番目の引数は。で2*numIndicesはなくする必要がありstride*numIndicesます。

インデックスバッファは必要以上に大きいため、これがパフォーマンスの問題を説明している可能性があります。

于 2013-03-08T16:30:43.593 に答える