通过在OpenGL中持久映射缓冲区存储,仅在绘制之前和交换之后触摸,是否真的需要进一步同步?

时间:2016-03-03 21:36:47

标签: c++ c opengl sdl-2

我掀起了一个简单的C程序(on 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);

我知道将glBufferStorageMAP_PERSISTENT_BIT一起使用时,同步是我的责任,但我不确定我需要防范什么。 我唯一一次触摸triData就是在调用glDrawArrays之前,并且在调用SDL_GL_SwapWindow之后,我知道最后一帧的绘制完成了,我还没有打电话给我绘制这个框架即将开始。 即使禁用了vsync,这似乎也能正常工作。

The wiki说:

  

交换Default Framebuffer上的后缓冲区和前缓冲区可能   导致某种形式的同步......如果还有命令   影响尚未完成的默认帧缓冲区。   交换缓冲区在技术上只需要同步到最后一个命令   这会影响默认的帧缓冲区,但它可能会执行完整的   glfinish在

但我读过的关于此主题的每篇文章都广泛使用GLsync 指针,虽然也许他们只是假设我可能想以更复杂的方式使用缓冲区? 现在,我是否相信SDL_GL_SwapWindow正在提供足够的同步?

3 个答案:

答案 0 :(得分:2)

以前的答案是正确的,即使您使用交换后也需要同步。但我想更清楚地知道这不仅仅是一个理论问题。

交换操作通常同步。让渲染在显示前提前1-2帧是很常见的。这样做是为了减少GPU暂时进入空闲状态的“气泡”。如果您的交换呼叫是同步的,那么GPU在返回时将不可避免地处于空闲状态,因为之前提交的所有工作都已完成。即使您立即再次开始渲染,也需要一点时间才能真正到达GPU执行。所以你有时间GPU什么都不做,至少只要你的渲染完全受GPU限制就会伤害性能。

现在,您显然不希望渲染在显示之前太远。不希望的副作用是响应用户输入(这对游戏来说是一个大问题)的延迟增加,以及排队的渲染命令的过多内存使用。因此,在此之前需要进行限制。这种限制通常作为交换操作的一部分应用,但几乎任何时候都可能发生。

因此,如果您测量交换呼叫返回所花费的挂钟时间,那么它足够长以表明它正在阻塞是相当常见的。但这并不表示呼叫本身是同步的。它可能只是阻塞,直到前一帧完成,以防止渲染在显示器前面太远。

答案 1 :(得分:1)

这是关于任何多线程/异步代码的favorite advice

  

如果多线程代码没有立即显然可证明是正确的,那么它几乎肯定是错误的。

您无法证明OpenGL不会从您正在写入的值中读取。因此,即使没有明显的问题,也是错误的。

是的,您需要进行显式同步。即使您连贯地映射缓冲区,当OpenGL可能正在读取缓冲区时,您仍然无法更改其中的值。您必须等到最后一次从该数据读取的调用之后再次写入该数据。 OpenGL必须等待它完成的唯一方法是glFinishglClientWaitSync

答案 2 :(得分:0)

  

我知道使用glBufferStorage时,同步是我的责任,

不,不一定。使用glBufferStorage创建的缓冲区与使用glBuffer创建的缓冲区没有什么不同,除非您无法重新指定它。

使用MAP_PERSISTENT_BIT进行映射时,您只需要进行手动同步(glBufferStorage包含在<script type="text/javascript"> // Post Form Validate $(document).ready(function () { $('#postForm').validate({ errorElement: "div", rules: { name: { required: true }, details: { required: true }, category: { required: true } } }); $('#restform').click(function(){ $('#postForm')[0].reset(); }); }); // Chosen multi-select var config = { '.chosen-select' : {}, '.chosen-select-deselect' : {allow_single_deselect:true}, '.chosen-select-no-single' : {disable_search_threshold:10}, '.chosen-select-no-results': {no_results_text:'Oops, nothing found!'}, '.chosen-select-width' : {width:"95%"} } for (var selector in config) { $(selector).chosen(config[selector]); } </script>ARB_buffer_storage)中。