私は現在、マルチスレッドの安全なレンダリング システムに取り組んでいます。前のシーンが現在レンダリングされている間に、ゲーム ワールドの次のステップを正しく更新する方法についての考えを知りたいです。現在、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
これまでのところ、パフォーマンスが大幅に向上しています。見えない競合状態の問題がいくつかあるかもしれませんが、全体的にはこの改善に満足しています.