利用openGL进行多线程处理

时间:2015-01-04 09:06:48

标签: android c++ multithreading opengl-es

在基于openGL渲染器的游戏环境中进行交谈:

让我们假设有两个线程:

  1. 更新游戏对象中的gameLogic和物理等

  2. 根据游戏对象中的数据(线程1不断更新)对每个游戏对象进行openGL绘制调用

  3. 除非您在游戏的当前状态下拥有每个游戏对象的两个副本,否则您必须暂停线程1而线程2进行绘制调用,否则游戏对象将在绘制调用中间更新对于那个对象!这是不可取的!

    但是停止线程1以安全地从线程2进行绘制调用会破坏多线程/共存的整个目的

    除了使用数百或数千个或同步对象/围栏之外,还有更好的方法可以利用多核架构来提高性能吗?

    我知道我仍然可以使用multiThreading来加载纹理并为尚未成为当前游戏状态的部分的对象编译着色器 但是如何为活动/可见对象执行此操作没有引起与更新的冲突?

2 个答案:

答案 0 :(得分:3)

通常的做法是完成游戏步骤后的模拟线程将状态提交到中间缓冲区,然后向渲染器线程发出信号。由于OpenGL以异步方式执行,渲染线程应该很快完成,从而为下一个状态释放中间缓冲区。

你不应该直接从游戏状态渲染,因为渲染器需要做的工作以及模拟产生的东西并不总是相同的东西。因此,无论如何都可能需要一些映射。

答案 1 :(得分:1)

这是你要问的一个普遍的问题。如果你问10个不同的人,你可能会得到10个不同的答案。在过去,我实现了类似的东西,这就是我所做的(经过一系列的优化周期)。

在后台线程上运行的模型更新循环应如下所示:

while(true)
{
  updateAllModels()
}

正如你所说,当GL线程启动时,这将导致一个问题,因为它可能很好地渲染基于渲染一半的模型的视图,这可能导致最佳情况下的UI故障。 / p>

处理此问题的直接方法是同步更新:

while (true)
{
  synchronized(...)
  {
    updateAllModels();
  }
}

与此同步的对象与您用于同步绘图方法的对象相同。

现在我们有了一种改进的方法,它不会在UI中引起毛刺,但整体渲染可能会受到非常严重的性能影响,因为所有渲染需要等到所有模型更新完成,否则反之亦然 - 模型更新需要等到所有绘图完成。

现在,让我们想一想 - 我们真正需要同步的是什么?

在我的应用程序(太空游戏)中,在更新模型时,我需要计算向量,检查碰撞并更新所有对象的位置,旋转,比例等。

在所有这些事情中,视图唯一关心的是位置,旋转,比例以及UI为了正确渲染游戏世界而需要知道的一些其他小考虑因素。渲染过程并不关心游戏对象的向量,AI代码,碰撞测试等。考虑到这一点,我改变了我的更新代码,看起来像这样:

while (true)
{
  synchronized(...)
  {
     updateVisibleChanges(); // sets all visible changes - positions, rotations, etc
  }

  updateInvisibleChanges(); // alters vectors, AI calculations, collision tests, etc  
}

与以前一样,我们正在同步更新和绘制方法,但这次,临界区比以前小得多。本质上,应该在updateVisibleChanges方法中设置的唯一事物是与应该呈现的对象的位置,旋转,比例等有关的事物。之后执行所有其他计算(通常是最详尽的计算),并且不会停止渲染。

此方法的额外好处 - 当您执行不可见的更改时,您可以确保所有对象都处于他们需要的位置(这对于准确的碰撞测试非常有用)。例如,在最后一个之前的方法中,对象A移动,然后对象A测试与尚未移动的对象B的碰撞。在对象A测试碰撞之前移动对象B可能会有不同的结果。

当然,我展示的最后一个例子并不完美 - 你仍然需要挂起渲染方法和/或updateVisible方法以避免冲突,但我担心这总是一个问题,而且关键是尽量减少您在任何线程敏感方法中所做的工作量。

希望这有帮助:)