为什么glBufferSubData需要等到glDrawElements不使用VBO?

时间:2014-06-14 13:48:10

标签: opengl

在OpenGL Insights中,它表示" OpenGL驱动程序必须等待,因为使用了VBO 来自前一帧的glDrawElements"。

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

那么为什么司机还需要等待?它可以将Transfer命令附加到命令队列,延迟将数据传输到GPU直到glDrawElements完成,对吗?

----- ADDED ----------------------------------------- ---------------------------------

在OpenGL Insights中,它说:

http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf(第397页)

  

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

还在" Beyond Porting"通过Valve& NVIDIA,它说:

http://media.steampowered.com/apps/steamdevdays/slides/beyondporting.pdf

  

MAP_UNSYNCHRONIZED

     
      
  • 避免应用程序-GPU同步点(CPU-GPU)   同步点)   
  •   
  • 但是导致客户端和服务器线程序列化   
        
    • 这   强制服务器线程中的所有待处理工作完成
    •   
    • 这很好   昂贵(几乎总是需要避免)
    •   
  •   

他们都指出glBufferSubData / glMapBuffer会阻塞应用程序线程,而不仅仅是驱动程序线程。

为什么?

1 个答案:

答案 0 :(得分:3)

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

让我们用典型的伪调用序列说明问题,标记调用以供日后解释:

(1) glBindBuffer(buf)
(2) glBufferSubData(dataA)
(3) glDraw()
(4) glBufferSubData(dataB)
(5) glDraw()

游戏中的限制是:

  • call(2)返回后,驱动程序无法访问dataA指向的数据。 OpenGL规范允许调用者在调用返回后对数据执行任何操作,因此在调用返回之前需要驱动程序使用它。
  • call(4)返回后,驱动程序无法访问dataB指向的数据。
  • buf的内容为dataA时,需要执行call(3)产生的绘制命令。
  • buf的内容为dataB时,需要执行call(5)产生的绘制命令。

由于OpenGL固有的异步特性,有趣的案例是call(4)。让我们说dataA此时已存储在buf中,并且调用(3)的绘制命令已排队等待GPU执行。但我们还不能依赖GPU执行绘制命令。因此,我们无法将dataB存储在buf中,因为待处理的绘制命令必须由GPU执行,而dataA仍存储在buf中。但是,在我们消费dataB之前,我们无法从通话中返回。

处理这种情况有多种方法。蛮力解决方案是简单地阻止call(4)的执行,直到GPU完成从call(3)执行draw命令。这肯定会奏效,但可能会产生非常糟糕的性能影响。因为我们等到GPU完成工作才提交新工作,GPU可能会暂时闲置。这通常被称为" bubble"在管道中,非常不受欢迎。最重要的是,在调用返回之前,应用程序也无法进行有用的工作。

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