0

私は現在、マルチスレッドの安全なレンダリング システムに取り組んでいます。前のシーンが現在レンダリングされている間に、ゲーム ワールドの次のステップを正しく更新する方法についての考えを知りたいです。現在、Java で LWJGL Opengl バインディングを使用しています。現在設定されているゲーム ループの疑似コードを次に示します (これはおそらく、ほとんどの人が慣れ親しんでいる基本的なループにすぎません)。

//DrawingLayers are wrappers for in game entities and has an update 
//and render method

game-loop:
    addInputEventsToInputStack()

    removeCompletedDrawingLayers()

    foreach layer in DrawingLayerQueue :
        layer.update(deltaTime) //update position/color/size for entity
        layer.render() //performs OpenGL calls
        if(layer.isCompleted):
            addToCompletedDrawingLayersList()


    swapBuffers() //blocks until scene is fully rendered
goto game-loop

私の問題はswapBuffers()、シーンがレンダリングされるまでブロックするメソッドにあります。つまり、レンダリング中は更新を実行できません。これを回避する方法についての私の考えは次のとおりです。

エンティティの状態を更新するために使用するすべての DrawingLayers のコピーを用意し、レンダリング スレッドの参照として他のコピーを用意します。swapBuffers()フレームのレンダリング中に、使用されていないコピーを更新する直前にスレッドを開始します。

すべてのフレームの前にコピーを作成すると、システムの速度が必要以上に低下するため、このアプローチには慎重です。

私のアプローチは理にかなっていますか?そうでない場合、これを行う方法について何か推奨事項はありますか? 私は完全なリストラにオープンです。

更新: datenwolf の提案に基づいて、ゲームループを次のように変更しました。

//DrawingLayers are wrappers for in game entities and has an update 
//and render method


//A future for the pre-processing task
Future preProcess = null

game-loop:

    //Update: checks if we have a preprocessed update to wait for
    //and waits for it to complete
    if(preProcess != null):
        preProcess.get()
        preProcess = null

    addInputEventsToInputStack()

    removeCompletedDrawingLayers()

    foreach layer in DrawingLayerQueue :
        layer.render() //performs OpenGL calls
        if(layer.isCompleted):
            addToCompletedDrawingLayersList()

    //UPDATE: the following just calls all the update methods for the layers
    // in a new thread
    preProcess = executorService.submit(new UpdateRunnable())

    swapBuffers() //blocks until scene is fully rendered
goto game-loop

これまでのところ、パフォーマンスが大幅に向上しています。見えない競合状態の問題がいくつかあるかもしれませんが、全体的にはこの改善に満足しています.

4

1 に答える 1

1

シーンがレンダリングされるまでブロックする swapBuffers() メソッドで

バッファ スワップのブロックは、レンダリングを終了することによって部分的にのみ行われます。通常、リトレースを待つためにブロックします。ただし、OpenGL は、描画コマンドが返された後、保留中のレンダリング操作が損なわれることなく、それによってアクセスされるバッファーを安全に変更できることを保証します。すべてのデータに対してコピーまたはコピー オン ライト マッピングを作成するには、実装が必要です。

要するに、バッファ内のデータを変更するだけです。描画呼び出し (glDrawArrays、glDrawElements) が返されるとすぐに、そうしても安全です。

于 2012-07-13T00:10:02.300 に答える