在OpenGL中更新纹理的有效方法

use*_*083 3 opengl jogl

我想使用OpenGL渲染多个视频流.目前我正在使用JOGL提供的glTexImage2D并在Swing窗口上渲染.为了更新每个视频帧的纹理内容,我调用glTexImage2D.我想知道有没有更快的方法来更新纹理而不需要为每个帧调用glTexImage2D.

Dam*_*mon 6

你将永远使用glTexImage2D,但不同的是数据来自缓冲对象(这是什么?)而不是指针.

更新纹理的速度慢不是更新纹理,而是同步(阻塞)当前的绘制操作和PCIe传输.当你调用时glTexImage,OpenGL必须等到它完成绘制最后一帧,在此期间它仍在从纹理中读取.在此期间,您的应用程序被阻止并且什么都不做(这是必要的,因为否则您可以修改或释放在OpenGL复制之前指向的内存!).然后它必须复制数据并将其传输到图形卡,然后才能继续运行您的应用程序.
虽然人们不能更快地完成这个过程,但可以让它以异步方式运行,因此这种延迟几乎消失了.

这样做的最简单方法是视频帧的是建立一个缓冲区名称,将其绑定,并储备初始化一次.
然后,在每个后续帧上,通过glBufferData使用空数据指针调用来丢弃初始化它,并使用非保留调用或通过映射缓冲区的完整范围来填充它.

你想要做这个奇怪的舞蹈而不是简单地覆盖缓冲区的原因是这不会阻止.OpenGL将同步对缓冲区对象的访问,因此您在仍然从中读取数据时不会覆盖数据.glBufferData使用空数据指针是一种告诉OpenGL你并不真正关心缓冲区并且你不需要相同缓冲区的方法.所以它只会分配另一个并给你那个,继续阅读旧的,并在完成后秘密交换它们.

由于已经使用了"同步"这个词,我将glMapBufferRange在上面的链接中解释我的选择,实际上你想要映射整个缓冲区,而不是某个范围.为什么会这样想?
即使OpenGL在使用上述丢弃技术时大多可以避免同步,有时也可能需要.
此外,它仍然必须运行某种内存分配算法来管理缓冲区,这需要驱动程序时间. glMapBufferRange允许您指定其他标志,特别是(在以后的OpenGL版本中)一个标记"不同步".这允许更复杂但更快的方法,在该方法中,您创建两倍于您需要的大小的单个缓冲区,然后保持映射/写入下半部分或上半部分,告诉OpenGL根本不同步.然后你有责任知道什么时候它是安全的(大概是通过使用栅栏对象),但你尽可能地避免所有开销.