在 OpenGL Insights 中,它说“OpenGL 驱动程序必须等待,因为使用了 VBO
由上一帧的 glDrawElements 绘制”。
这让我很困惑。
据我所知,glBufferSubData会将数据复制到临时内存,然后再传输到GPU。
那么为什么司机还需要等待呢?它可以只将 Transfer 命令附加到命令队列,延迟将数据传输到 GPU,直到 glDrawElements 完成,对吧?
- - - 添加 - - - - - - - - - - - - - - - - - - - - - - ------------------------------------------
在 OpenGL Insights 中,它说:
http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf(第 397 页)
然而,当使用 glBufferSubData 或 glMapBuffer[Range] 时,没有任何内容
API本身阻止我们修改当前使用的数据
通过渲染前一帧的设备,如图
28.3。驱动程序必须通过阻止该函数直到不再使用所需的数据来避免此问题:这称为
隐式同步。
Valve 和 NVIDIA 的“Beyond Porting”中也提到:
http://media.steampowered.com/apps/steamdevdays/slides/beyondporting.pdf http://media.steampowered.com/apps/steamdevdays/slides/beyondporting.pdf
MAP_UNSYNCHRONIZED
- 避免应用程序-GPU 同步点(CPU-GPU
同步点)
- But causes the Client and Server threads to serialize
- 这
强制服务器线程中所有挂起的工作完成
- 相当
昂贵(几乎总是需要避免)
没有规定司机必须等待。它需要确保在使用旧内容的绘制调用完成执行之前缓冲区内容不被修改。并且需要消耗调用者之前传入的数据glBufferSubData()
呼叫返回。只要结果行为正确,驱动程序中的任何实现都是公平的。
让我们用一个典型的伪调用序列来说明这个问题,标记调用以便稍后解释:
(1) glBindBuffer(buf)
(2) glBufferSubData(dataA)
(3) glDraw()
(4) glBufferSubData(dataB)
(5) glDraw()
游戏中的限制条件是:
- 所指向的数据
dataA
调用 (2) 返回后,驱动程序无法访问。 OpenGL 规范允许调用者在调用返回后对数据执行任何操作,因此驱动程序需要在调用返回之前使用数据。
- 所指向的数据
dataB
调用 (4) 返回后,驱动程序无法访问。
- 需要执行调用(3)产生的绘制命令,同时执行
buf
is dataA
.
- 需要执行调用(5)产生的绘制命令,同时
buf
is dataB
.
由于 OpenGL 固有的异步特性,有趣的情况是调用 (4)。这么说吧dataA
已存储在buf
此时,调用(3)的绘制命令已排队等待GPU执行。但我们还不能依赖 GPU 执行该绘制命令。所以我们无法存储dataB
in buf
因为挂起的绘制命令必须由 GPU 执行dataA
仍然存储在buf
。但我们无法在消费之前从调用中返回dataB
.
有多种方法可以处理这种情况。强力解决方案是简单地阻止调用 (4) 的执行,直到 GPU 完成执行调用 (3) 中的绘制命令。这肯定会起作用,但可能会产生非常糟糕的性能影响。因为我们要等到 GPU 完成工作才提交新工作,所以 GPU 可能会暂时空闲。这通常被称为管道中的“泡沫”,并且是非常不可取的。最重要的是,在调用返回之前,应用程序也被阻止执行有用的工作。
解决此问题的最简单方法是让驱动程序复制dataB
在调用 (4) 中,然后将此数据副本放入buf
,在 GPU 完成调用 (3) 中的绘制命令之后,但在执行调用 (5) 中的绘制命令之前。缺点是它涉及额外的数据复制,但为了防止管道泡沫通常是值得的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)