Opengl 为什么glBufferSubData需要等待,直到GLDrawerElements不使用VBO?

Opengl 为什么glBufferSubData需要等待,直到GLDrawerElements不使用VBO?,opengl,Opengl,在OpenGL Insights中,它说“OpenGL驱动程序必须等待,因为使用了VBO 通过“上一帧中的元素” 这让我很困惑。 据我所知,glBufferSubData会将数据复制到临时内存中,然后再传输到GPU 那为什么司机还要等呢?它只需将传输命令附加到命令队列中,延迟将数据传输到GPU,直到GLD元素完成,对吗 -----增加-------------------------------------------------------------------------- 在OpenGL

在OpenGL Insights中,它说“OpenGL驱动程序必须等待,因为使用了VBO 通过“上一帧中的元素”

这让我很困惑。 据我所知,glBufferSubData会将数据复制到临时内存中,然后再传输到GPU

那为什么司机还要等呢?它只需将传输命令附加到命令队列中,延迟将数据传输到GPU,直到GLD元素完成,对吗

-----增加--------------------------------------------------------------------------

在OpenGL Insights中,它说:

(第397页)

但是,当使用glBufferSubData或glMapBuffer[Range]时,中没有任何内容 API本身阻止我们修改当前使用的数据 由设备渲染上一帧,如图所示 28.3. 驱动程序必须通过阻塞函数来避免此问题,直到不再使用所需的数据:这称为 隐式同步

在Valve&NVIDIA的“Beyond Porting”一书中,也提到:

映射未同步

  • 避免应用程序GPU同步点(CPU-GPU 同步点)
  • 但会导致客户端和服务器线程序列化
    • 这个 强制完成服务器线程中所有挂起的工作
    • 这很有趣 昂贵(几乎总是需要避免)
他们都指出glBufferSubData/glMapBuffer将阻塞应用程序线程,而不仅仅是驱动程序线程


为什么会这样?

没有规定司机必须等待。它需要确保在使用旧内容的绘制调用完成执行之前,不会修改缓冲区内容。它需要在
glBufferSubData()
调用返回之前使用调用方传入的数据。只要结果行为正确,驱动程序中的任何实现都是公平的

让我们用一个典型的伪调用序列来说明这个问题,为调用添加标签以供稍后解释:

(1) glBindBuffer(buf)
(2) glBufferSubData(dataA)
(3) glDraw()
(4) glBufferSubData(dataB)
(5) glDraw()
其中的制约因素包括:

  • 调用(2)返回后,驾驶员无法访问
    dataA
    指向的数据。OpenGL规范允许调用方在调用返回后对数据执行任何操作,因此需要在调用返回之前由驱动程序使用数据
  • 调用(4)返回后,驾驶员无法访问
    dataB
    指向的数据
  • 调用(3)产生的draw命令需要在
    buf
    的内容为
    dataA
    时执行
  • 调用(5)产生的draw命令需要在
    buf
    的内容为
    dataB
    时执行
由于OpenGL固有的异步特性,有趣的例子是调用(4)。假设此时,
dataA
已存储在
buf
中,用于调用(3)的draw命令已排队等待GPU执行。但是我们不能依赖GPU已经执行了这个draw命令。因此,我们不能将
dataB
存储在
buf
中,因为挂起的draw命令必须由GPU执行,而
dataA
仍存储在
buf
中。但是,在使用
dataB
之前,我们无法从通话中返回

处理这种情况有多种方法。蛮力解决方案是简单地阻止调用(4)的执行,直到GPU完成从调用(3)执行draw命令为止。这当然会起作用,但可能会对性能产生非常糟糕的影响。因为我们要等到GPU完成工作后再提交新的工作,所以GPU可能会暂时闲置。这通常被称为管道中的“泡沫”,是非常不可取的。除此之外,在调用返回之前,应用程序也被阻止执行有用的工作


解决此问题的最简单方法是,驱动程序在调用(4)中复制
dataB
,然后在GPU完成调用(3)中的绘制命令后,但在执行调用(5)中的绘制命令之前,将此数据副本放入
buf
。缺点是它需要额外的数据复制,但防止管道冒泡通常是值得的。

这就是“等待”的意义所在。它将传输延迟到旧命令完成之后。它的意思正是。驱动程序无法开始使用新内容传输和覆盖GPU内存中的缓冲区,因为它当前正在使用。避免这种行为。同一本书应该提出两个备选方案:使用循环缓冲区集、缓冲区孤立、
ARB\u buffer\u存储
…谢谢大家,我已经更新了这个问题,请再次检查。我在下面发布了一个解释它的答案。非常感谢。我已经更新了这个问题,请再次检查。我发现有几篇文章说它会产生管道气泡,这就是为什么我很困惑的原因。(第397页)您在问题中添加了
glMapBuffer
案例。我对此不太了解,但我认为可以采取类似的处理方式。我想我已经解释了
glBufferSubData
的问题,以及如何在驱动程序中处理它(有阻塞和无阻塞)。我的回答中是否有不清楚的具体部分?但它说“当使用glBufferSubData时……驱动程序必须通过阻止函数直到不再使用所需的数据来避免此问题”,根据您的回答,它不需要阻止。