我目前正在开发一个多线程安全渲染系统,我想知道你在前一个场景当前渲染时如何正确更新游戏世界中的下一步的想法。目前我正在使用LWJGL Opengl Bindings和Java。这是我目前设置的游戏循环的伪代码(这可能只是大多数人都熟悉的基本循环):
//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
到目前为止,我的性能有了显着提高。我可能会看到一些竞争条件问题,但总体而言我很满意这种改进。
答案 0 :(得分:1)
在swapBuffers()方法中,因为它阻塞直到渲染场景
通过完成渲染,缓冲区交换的阻塞只是部分的。由于等待回扫,它通常也会阻塞。但是OpenGL保证,在任何绘图命令返回后,可以安全地修改它访问的缓冲区,而不会影响任何挂起的渲染操作。需要实现对所有数据进行复制或写时复制映射。
或者简称:只需修改缓冲区中的数据即可。一旦绘图调用(glDrawArrays,glDrawElements)返回它就可以安全地执行。