[英]With persistently mapped buffer storage in OpenGL, touched only before draw and after swap, is any further synchronization really needed?
我掀起了一个简单的C程序( 在github上 ),它使用OpenGL从一个缓冲区中绘制一堆三角形,这个缓冲区分配了glBufferStorage
如下所示:
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLbitfield bufferStorageFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
glBufferStorage(GL_ARRAY_BUFFER, vboSize, 0, bufferStorageFlags);
vert *triData = glMapBufferRange(GL_ARRAY_BUFFER, 0, vboSize, bufferStorageFlags);
我知道在使用glBufferStorage
和MAP_PERSISTENT_BIT
时同步是我的责任,但我不确定我需要防范什么。 我触摸triData
的唯一一次是在它上面调用glDrawArrays
之前,并且在调用SDL_GL_SwapWindow
,所以我知道最后一帧的绘制完成了,我还没有要求绘制这个帧。 即使禁用了vsync,这似乎也能正常工作。
维基说:
在默认帧缓冲区上交换后缓冲区和前缓冲区可能会导致某种形式的同步...如果仍有命令影响默认帧缓冲区尚未完成。 交换缓冲区在技术上只需要同步到影响默认帧缓冲区的最后一个命令,但它可以执行完整的glFinish。
但是我读过的关于这个主题的每篇文章都广泛使用了GLsync
指针,尽管它们可能只是假设我可能想以更复杂的方式使用缓冲区? 现在,我是否相信SDL_GL_SwapWindow
正在提供足够的同步?
以前的答案是正确的,即使您使用交换后也需要同步。 但我想更清楚地知道这不仅仅是一个理论上的问题。
交换操作通常不同步。 让渲染在显示前提前1-2帧是很常见的。 这样做是为了减少GPU暂时进入空闲状态的“气泡”。 如果您的交换呼叫是同步的,那么GPU在返回时将不可避免地处于空闲状态,因为之前提交的所有工作都已完成。 即使您立即再次开始渲染,也需要一点时间才能真正到达GPU执行。 因此,您有时无需做任何事情,只要您的渲染完全受GPU限制,就会损害性能。
现在,您显然不希望渲染超出显示范围。 不希望的副作用是响应用户输入(这对游戏来说是一个大问题)的延迟增加,以及排队的渲染命令的过多内存使用。 因此,在此之前需要进行限制。 这种限制通常作为交换操作的一部分应用,但它几乎可能发生在任何情况下。
因此,如果您测量交换呼叫返回所花费的挂钟时间,那么它足够长以表明它正在阻塞是相当常见的。 但这并不表示呼叫本身是同步的。 它可能只是阻塞,直到前一帧完成,以防止渲染在显示器前面太远。
这是我最喜欢的任何多线程/异步代码的建议:
如果多线程代码不是立即,显然,可证明是正确的,那么它几乎肯定是错误的。
您无法证明OpenGL不会从您正在写入的值中读取。 因此,即使没有明显的问题,这也是错误的。
是的,您需要进行显式同步。 即使您连贯地映射缓冲区,当OpenGL可能正在读取缓冲区时,您仍然无法更改其中的值。 您必须等到最后一次从该数据读取的调用之后再次写入该数据。 OpenGL必须等待它完成的唯一方法是glFinish
或glClientWaitSync
。
我知道使用glBufferStorage时同步是我的责任,
不,不一定。 使用glBufferStorage
创建的缓冲区与使用glBuffer
创建的缓冲区没有什么不同,除了您无法重新指定它。
你只用映射时需要做的手动同步MAP_PERSISTENT_BIT
(这是包含在同一扩展glBufferStorage
是, ARB_buffer_storage
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.