【问题标题】:OpenGL multithreading/shared context and glGenBuffersOpenGL 多线程/共享上下文和 glGenBuffers
【发布时间】:2014-05-20 16:34:17
【问题描述】:

如果我打算在 OpenGL 中使用多线程,我是否应该为每个上下文设置单独的缓冲区(来自 glGenBuffers)?

我还不太了解 OpenGL 多线程(目前我在“单”线程中工作)。我需要知道我是否可以共享已经推送到视频内存的缓冲区(使用 glBufferData/glBufferSubData),或者我必须为另一个线程保留缓冲区副本。

【问题讨论】:

  • 首先,你想用多线程做什么?如果您在上下文之间共享资源,则缓冲区对象名称(glGenBuffers (...) 返回的内容)将具有共享池。 VAO、FBO 和状态机的其他部分是共享的 - 基本上只有实际存储数据的对象(如缓冲区对象、纹理和 GLSL 程序)是共享的。此外,如果您在其他线程中修改这些缓冲区,而这些缓冲区正在被尚未完成的绘图命令使用,您将严重损害您的性能。
  • @AndonM.Coleman 那么,VBO 是共享的吗?关于为什么...我认为一个线程可以将数据推送到 VBO,而其他渲染先前已推送。但是知道我对此有疑问.. stackoverflow.com/questions/11097170/… 有人说它会自动并行化,即使你有某种 SLI。我说的对吗?
  • 是的,VBO 是共享的如果您设置了具有共享的渲染上下文(默认情况下不在上下文之间共享)。这与您拥有的 GPU 数量无关。如果您有一个绘制命令在管道中排队,则在完成之前不允许修改它使用的数据,否则您会产生无效的结果。因此,驱动程序要么复制您的缓冲区,要么停止管道以防止这种情况发生。
  • Andon M. Coleman 我不会尝试绘制 VBO,我当时在并行线程中将其移动到内存中。它是这样的:1 线程绘制 VBO1,2 线程推送 VBO2;然后 1 线程绘制 VBO2,2 线程推送 VBO3
  • 在适当的条件下,无论您使用多少 GPU,这都可以提高性能,特别是如果您可以处理线程 2 中上传的数据可能延迟 1 帧到达的情况。但是,当您开始为此使用多个上下文时,需要注意一些额外的同步问题。在单个上下文中,驱动程序会自动对所有命令进行正确排序,但在多个上下文中则不会,您需要栅栏同步或glFinish (...) 和 CPU 信号才能发生这种情况。

标签: c++ multithreading opengl


【解决方案1】:

您不想在多个线程中使用多个上下文。你真的没有。

虽然这听起来是个好主意,但实际上多上下文多线程是复杂的、麻烦的,并且在驱动程序端的支持很差,而且它只能略微提高(甚至可能降低!)性能。

真正想要的是只有一个线程与 OpenGL 对话(显然是一个上下文),映射一个缓冲区,并将内存指针传递给另一个线程,最好使用 3 个缓冲区(3 个3x 大小缓冲区的子缓冲区)与immutable storage and persistent mapping(如果可用)。
那,并进行间接渲染调用,其中第二个线程为间接调用读取的缓冲区提供数据。

有关持久映射主题的更多信息:请特别参阅 GDC2014 presentation 的第 22-25 张幻灯片,这基本上是对 Cass Everitt 2013 年 SIGGRAPH 演讲的翻版。
另请参阅 Everitt 的原始演讲:Beyond porting

【讨论】:

  • 为什么是 3(三个)缓冲区?
  • 嗯,实际上你没有。您使用 one三倍大 (实际上是 3 个缓冲区,但在一个缓冲区对象中)。您必须至少有两个缓冲区(或缓冲区“子区域”),因为您在 GPU 读取时正在写入,因此您必须小心不要在使用数据时踩到数据。使用 3 个缓冲区而不是 2 个意味着你很可能永远不会(或很少)在栅栏上阻塞,而如果你只使用 2 个,你会经常阻塞,几乎每次都会阻塞(浪费时间)。
  • 措辞不同:使用 1 个缓冲区,您必须等待 GPU 完成才能执行任何操作。使用 2 个缓冲区,您可以在 GPU 读取 #1 时写入 #2,您可以在 GPU 读取 #2 时写入 #1。在这两者之间,您必须等待(停顿),以确保您不会损坏东西。使用 3 个缓冲区,您可以在 GPU 读取 #1 时写入 #2,并在 GPU 可能仍完成 #1 或读取 #2 时继续写入 #3。您只需要在那之后进行同步,但很可能到那时 #1 已经再次空闲了。
【解决方案2】:

Vao 不是共享的,因此您需要为每个 context 的每个对象生成一个新的 vao,否则在删除/创建新对象时行为将变得不可预测且不正确。 这可能是主要的错误来源。 vbo 可以共享,因此每个对象只需要一个 vbo。

【讨论】:

  • 这个问题是关于缓冲区对象 (glGenBuffers),而不是顶点数组对象。
  • "vbo 可以共享,所以每个对象只需要一个 vbo。" - 好吧,我认为这就是问题的答案。
猜你喜欢
  • 1970-01-01
  • 2014-01-25
  • 2021-01-24
  • 2016-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-05
相关资源
最近更新 更多