如何同步多线程OpenGL缓冲区访问?

dan*_*jar 7 opengl multithreading gpu vbo undefined-behavior

我有顶点缓冲区保存地形块的网格.每当玩家编辑地形时,必须重新生成相应块的网格并将其上载到顶点缓冲区.由于重新生成网格需要一些时间,因此我在异步工作线程中执行此操作.

问题是主线程在工作线程上传新数据的同一时刻绘制缓冲区.这意味着,在玩家编辑地形之后,一个损坏的块会被渲染一帧.它只会爆发一次,之后会得到正确的缓冲区.

这种方式对我来说很有意义,我们不应该在同一时间写入和读取相同的数据.因此,我没有更新旧缓冲区,而是创建了一个新缓冲区,填充它并交换它们.交换只是改变了存储在terrain chunk结构中的缓冲区id,因此应该是原子的.不过,这没有帮助.

由于OpenGL命令被发送到GPU上的队列,因此当CPU上的应用程序继续时,不必执行它们.所以我可能在新缓冲区实际准备好之前交换了缓冲区.

我还尝试了使用互斥锁进行缓冲区访问来切换缓冲区的替代方法.主线程在绘制时锁定互斥锁,工作线程在上载新缓冲区数据时将其锁定.然而,这也没有帮助,也可能是因为OpenGL的异步性质.主线程实际上没有绘制,只是将绘图命令发送到GPU.另一方面,当真的只有一个命令队列时,上传缓冲区和绘制它们可能永远不会同时发生,是吗?

如何从两个线程同步顶点缓冲区访问以防止为一帧绘制未定义的缓冲区?

der*_*ass 5

您必须确保缓冲区更新实际已完成,然后才能在绘制线程中使用该缓冲区.最简单的解决方案是glFinish在发出所有更新GL命令后调用更新线程,并仅在返回后通知绘制线程.

为了对同步进行更精细的控制,我建议您查看fence同步对象(如GL_ARB_sync扩展中所述).您可以在发出更新命令后发出fence同步,并实际将同步对象句柄与缓冲区句柄一起存储,以便绘制线程可以检查更新是否实际完成(或等待它).请注意,同步对象有点特殊,因为它们是唯一与GL上下文关联的对象,因此可以在多上下文设置中使用它们.

  • @danijar:您可以使用我在答案中概述的ARB_sync方法.您的工作线程将更新的缓冲区排队,并且绘制线程检查队列的头部是否实际完成了更新.如果是这样,它可以使用它.如果没有,它可以继续使用旧缓冲区进行渲染,并将在下一帧再次检查. (3认同)