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 回答