了解副本岛渲染系统。为什么它有渲染命令的双缓冲区?

时间:2017-05-29 09:58:12

标签: java android multithreading opengl-es renderer

我制作了一个相对简单的结构化Android游戏,可以很容易地更新游戏逻辑并在GLSurfaceView的渲染线程中的onDrawFrame函数内进行渲染。但是,考虑到未来的项目,我已经开始探索多线程选项,包括在渲染线程之外运行主游戏更新逻辑,这就是复制岛所做的。这里有一篇关于它的博文:http://replicaisland.blogspot.co.nz/2009/10/rendering-with-two-threads.html

诸如副本岛源代码(https://code.google.com/archive/p/replicaisland/source)之类的资源有助于理解这种双缓冲的渲染命令注册多线程渲染器的想法。游戏循环更新对象和那些想要绘制的对象在当前未使用的缓冲区中注册。该缓冲区在某个时刻被交换,渲染器处理那些渲染命令以使用opengl绘制它们。

有些事情我还没有真正理解。

复制岛游戏线程循环(GameThread.java)以等待渲染器停止渲染的块开始(mRenderer.waitDrawingComplete)。然后它更新游戏逻辑,然后交换缓冲区。交换缓冲区会通知渲染器在下一批处理中启动。渲染器完成后,游戏循环将再次更新,依此类推。 这种方法似乎并没有运行游戏逻辑和并行循环渲染对象的代码?它们似乎以锁步方式运行,并且在onDrawFrame函数完成后opengl实际完成渲染时,从游戏逻辑中获取性能提升而不必阻塞。

我测试了类似的代码,这肯定比单个线程更快,当有大量的东西被绘制时。但是,因为渲染循环不会在游戏线程也使用它们时循环遍历对象,所以似乎没有任何固有的需要具有多个渲染命令缓冲区。从我能读到的内容(我猜我错了)游戏更新实际上并没有在渲染器使用第一个时更新第二个缓冲区。如果是这种情况那么为什么要有两个缓冲区呢?

为什么游戏线程等待渲染器在更新之前停止绘制?

1 个答案:

答案 0 :(得分:0)

Doom 3做同样的事情:处理所有app输入和事件,然后kick off a separate thread运行并绘制下一帧,同时将前一帧提交到渲染系统。然后,它在交换缓冲区之前等待Game Thread to return

两个线程都设计为使用特定的缓冲帧,renderdraw帧。因为它们仅限于特定的缓冲区,所以您不需要使用互斥锁或同步原语来控制访问。等待线程 同步。

它还使渲染和绘图保持同步。您已经在后面渲染一个框架,并希望将滞后保持在最低限度。仅向前绘制一个帧意味着插值代码更接近于经过的时间,并且每个渲染帧只需要发出一次渲染命令。 (而不是不断地渲染帧并让渲染线程掉线/跳过)。

  

为什么游戏线程等待渲染器在更新之前停止绘制?

渲染系统是一个状态机,您不能同时执行命令。 Draw发出渲染命令,可以在另一个线程上异步执行。 Draw会发送它们并忘记忘记。它不关心国家或他们发生了什么。这是异步。

将窗口模式从全屏切换到窗口,更改表面分辨率或通常任何其他渲染状态更新需要在继续(同步或阻塞)之前完全执行,并且必须使用已知的API状态执行。这些和其他更新可能会影响绘制状态,窗口状态等...

因此,智慧是在单个同步线程上执行事件处理和更新(),以便我们可以在需要时阻止并更改影响状态的任何内容(任何状态)。然后拆分并在draw线程上发出渲染命令,并在render线程上执行上一组。