7

並べ替え操作を実行するために GPU バッファーを CPU に転送する際に問題が発生しました。バッファはGL_SHADER_STORAGE_BUFFER300.000 個の float 値で構成されています。での転送動作glGetBufferSubDataは 10msglMapBufferRange程度、 では 100ms 以上かかります。

私が使用しているコードは次のとおりです。

std::vector<GLfloat> viewRow;
unsigned int viewRowBuffer = -1;
int length = -1;

void bindRowBuffer(unsigned int buffer){
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, buffer);
}

void initRowBuffer(unsigned int &buffer, std::vector<GLfloat> &row, int lengthIn){
    // Generate and initialize buffer
    length = lengthIn;
    row.resize(length);
    memset(&row[0], 0, length*sizeof(float));
    glGenBuffers(1, &buffer);
    bindRowBuffer(buffer);
    glBufferStorage(GL_SHADER_STORAGE_BUFFER, row.size() * sizeof(float), &row[0], GL_DYNAMIC_STORAGE_BIT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);

    glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}

void cleanRowBuffer(unsigned int buffer) {
    float zero = 0.0;
    glClearNamedBufferData(buffer, GL_R32F, GL_RED, GL_FLOAT, &zero);
}

void readGPUbuffer(unsigned int buffer, std::vector<GLfloat> &row) {
    glGetBufferSubData(GL_SHADER_STORAGE_BUFFER,0,length *sizeof(float),&row[0]);
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}

void readGPUMapBuffer(unsigned int buffer, std::vector<GLfloat> &row) {
    float* data = (float*)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, length*sizeof(float), GL_MAP_READ_BIT); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
     memcpy(&row[0], data, length *sizeof(float));
    glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}

主なことは次のとおりです。

    bindRowBuffer(viewRowBuffer);
    cleanRowBuffer(viewRowBuffer);
    countPixs.bind();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, gPatch);
    countPixs.setInt("gPatch", 0);
    countPixs.run(SCR_WIDTH/8, SCR_HEIGHT/8, 1);
    countPixs.unbind();
    readGPUbuffer(viewRowBuffer, viewRow);

countPixs は計算シェーダーですが、実行コマンドにコメントを付けると、読み取りにまったく同じ時間がかかるため、問題はないと確信しています。

奇妙なことに、float が 1 つだけの getbuffer を実行すると、次のようになります。

glGetBufferSubData(GL_SHADER_STORAGE_BUFFER,0, 1 *sizeof(float),&row[0]);

まったく同じ時間がかかります...だから、何かが間違っていると思います...おそらくに関連していGL_SHADER_STORAGE_BUFFERますか?

4

1 に答える 1

3

これは、GPU と CPU の同期/ラウンド トリップによる遅延である可能性があります。つまり、バッファをマップすると、バッファに触れた前の GL コマンドがすぐに完了する必要があり、パイプラインのストールが発生します。ドライバーは怠惰であることに注意してください: GL コマンドがまだ実行を開始していない可能性が非常に高いです。

できる場合:glBufferStorage(..., GL_MAP_PERSISTENT_BIT)バッファを永続的にマップします。これにより、GPU メモリの完全な再マッピングと割り当てが回避され、マップされたポインターを描画呼び出しで保持できますが、いくつかの注意事項があります。

  • データが GPU から実際に利用可能になったときに検出/待機するために、GPU フェンスも必要になる可能性があります。(ゴミを読むのが好きでない限り。)
  • マップされたバッファーはサイズ変更できません。(すでに glBufferStorage() を使用しているので問題ありません)
  • GL_MAP_PERSISTENT_BIT を GL_MAP_COHERENT_BIT と組み合わせるのがおそらく良い考えです。

GL 4.5のドキュメントをもう少し読んだ後glFenceSync、GL_MAP_COHERENT_BITを使用しても、データがGPUから到着したことを保証するために必須であることがわかりました。

GL_MAP_COHERENT_BIT が設定されていて、サーバーが書き込みを行う場合、アプリは GL_SYNC_GPU_COMMANDS_COMPLETE (または glFinish) で glFenceSync を呼び出す必要があります。同期が完了すると、CPU は書き込みを認識します。

于 2020-06-05T07:36:33.397 に答える