7

我刚刚找到了以下OpenGL 规范ARB_map_buffer_range

我想知道是否可以使用此扩展进行非阻塞地图调用?

目前在我的应用程序中,我正在渲染到一个 FBO,然后我将其映射到一个主机 PBO 缓冲区。

glMapBuffer(target_, GL_READ_ONLY);  

但是,这样做的问题是它在传输数据时会阻塞渲染线程。

我可以通过流水线渲染来减少这个问题,但延迟是我的应用程序中的一个大问题。

我的问题是我是否可以将 map_buffer_range 与 MAP_UNSYNCHRONIZED_BIT 一起使用并等待映射操作在另一个线程上完成,或者在渲染线程渲染下一帧时推迟同一线程上的映射操作。

例如

thread 1:

map();
render_next_frame();

thread 2:

wait_for_map

或者

thread 1:

map();
while(!is_map_ready())
   do_some_rendering_for_next_frame();

我不确定的是我如何知道映射操作何时准备就绪,规范仅提到“其他同步技术以确保正确操作”。

有任何想法吗?

4

2 回答 2

7

如果您使用 映射缓冲区GL_MAP_UNSYNCHRONIZED_BIT,驱动程序将不会等到 OpenGL 完成该内存后才为您映射它。因此,您将或多或少地立即访问它。

问题在于,这并不意味着您可以随意读/写该内存。如果 OpenGL 正在读取或写入该缓冲区并且您更改它...欢迎使用未定义的行为。其中可能包括崩溃。

因此,为了实际使用非同步映射,您必须将您的行为与 OpenGL 对该缓冲区的访问同步。这将涉及使用ARB_sync 对象(如果您仅在 NVIDIA 上并且最近没有更新驱动程序,则为 NV_fence)。

话虽如此,如果您使用栅栏对象来同步对缓冲区的访问,那么您实际上根本不需要GL_MAP_UNSYNCHRONIZED_BIT。一旦你完成了栅栏,或者检测到它已经完成,你可以正常映射缓冲区并且它应该立即完成(除非其他一些操作也在读/写)。

通常,当您需要对缓冲区进行细粒度的写访问时,最好使用非同步访问。在这种情况下,充分利用同步对象将为您提供真正需要的东西(能够判断映射操作何时完成)。


附录:以上内容现已过时(取决于您的硬件)。感谢 OpenGL 4.4/ ARB_buffer_storage,您现在不仅可以不同步映射,还可以无限期地保持缓冲区映射。是的,您可以在使用时映射缓冲区。

这是通过创建不可变存储并为该存储提供(除其他外)GL_MAP_PERSISTENT_BIT. 然后你glMapBufferRange,也提供相同的位。

现在从技术上讲,这几乎没有改变。您仍然需要将您的操作与 OpenGL 同步。如果您将内容写入缓冲区的某个区域,则需要发出屏障显式刷新缓冲区的该区域。如果你正在阅读,你仍然需要使用栅栏同步对象来确保数据在阅读之前确实存在GL_MAP_COHERENT_BIT(除非你也使用,否则你需要在阅读之前发出屏障)。

于 2011-08-06T22:19:18.130 回答
6

一般来说,做“非阻塞映射”是不可能的,但可以不阻塞映射。

没有“非阻塞映射”的原因是函数调用返回的那一刻,您可以访问数据,因此驱动程序必须肯定地确保它在那里。如果数据还没有传输,驱动程序除了阻塞还能做什么。
线程并没有使这变得更好,并且可能使情况变得更糟(添加同步和上下文共享问题)。线程不能神奇地消除传输数据的需要。

这导致如何不阻塞映射:仅在确定传输完成时才映射。一种安全的方法是在翻转缓冲区或glFinish等待查询/围栏对象之后或之后映射缓冲区。如果你不能等到缓冲区被交换,那么使用栅栏是最好的方法。栅栏不会停止管道,但会告诉您传输是否完成(glFinish可能会或可能不会,但可能会停止)。交换缓冲区后读取也是 100% 安全的,但如果您需要同一帧内的数据,则可能无法接受(不过,对于屏幕截图或计算色调映射的直方图非常有效)。

一个不太安全的方法是插入“一些其他的东西”,并希望同时传输已经完成。


关于以下评论:
这个答案是正确的。没有比在数据可用后访问数据更好的了(这应该是显而易见的)。这意味着您必须以一种或另一种方式同步/阻止,别无选择。
尽管从非常迂腐的角度来看,您当然可以使用来获得非阻塞映射操作,但这完全无关紧要,因为除非您如上所述显式重现隐式GL_MAP_UNSYNCHRONIZED_BIT同步,否则它不起作用。您无法安全访问的映射毫无用处。

映射和访问 OpenGL 在不同步/阻塞(隐式或显式)的情况下将数据传输到的缓冲区意味着“未定义的行为”,这只是“可能是垃圾结果,可能是崩溃”的更好措辞。
另一方面,如果您显式同步(例如,使用上述栅栏),那么您是否使用 unsynchronized 标志是无关紧要的,因为无论如何都不需要发生更多的隐式同步。

于 2011-08-06T14:53:16.533 回答