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

标签 multithreading opengl gpu undefined-behavior vbo

我有保存地形 block 网格的顶点缓冲区。每当玩家编辑地形时,相应 block 的网格必须重新生成并上传到顶点缓冲区。由于重新生成网格需要一些时间,我在异步工作线程中进行。

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

这对我来说很有意义,我们当然不应该同时写入和读取相同的数据。因此,我没有更新旧缓冲区,而是创建了一个新缓冲区,填充并交换它们。交换只是更改存储在地形 block 结构中的缓冲区 ID,因此应该是原子的。然而,这并没有帮助。

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

我还尝试了一种切换缓冲区的替代方法,使用互斥锁进行缓冲区访问。主线程在绘制时锁定互斥体,工作线程在上传新缓冲区数据时锁定它。然而,这也无济于事,这也可能是因为 OpenGL 的异步特性。主线程实际上并没有绘制,只是向 GPU 发送绘制命令。另一方面,当真的只有一个命令队列时,上传缓冲区和绘制缓冲区永远不会同时发生,不是吗?

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

最佳答案

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

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

关于multithreading - 如何同步多线程 OpenGL 缓冲区访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22363644/

相关文章:

cuda - 使用 CUDA 以编程方式找出 GPU 链接拓扑

java - Java 中的默认线程

c# - 在 C# 中多线程访问 WPF GUI

java - 为什么 onActivityResult() 被工作线程阻塞?

c++ - 获取或生成 "C++"中的系统信息

parallel-processing - python : how to write this code to run on GPU?

c - 如何在 Linux 内核中加入多个线程

c# - 什么实际处理 Windows 壁纸的绘制?

c++ - glBufferData() 的段错误

c++ - 单独类中的 opengl 扩展函数