我想使用OpenGL渲染多个视频流。目前我正在使用JOGL提供的glTexImage2D并在Swing窗口上渲染。 为了更新每个视频帧的纹理内容,我调用glTexImage2D。我想知道有没有更快的方法来更新纹理而不需要为每个帧调用glTexImage2D。
答案 0 :(得分:6)
您将始终使用glTexImage2D
,但区别在于数据来自缓冲区对象(what is this?),而不是来自指针。
更新纹理的速度有点不是更新纹理,而是同步(阻塞)当前的绘制操作和PCIe传输。当你调用glTexImage
时,OpenGL必须等到它完成绘制最后一帧,在此期间它仍在从纹理中读取。在此期间,您的应用程序被阻止并且什么都不做(这是必要的,因为否则您可以修改或释放在OpenGL复制之前指向的内存!)。然后它必须复制数据并将其传输到图形卡,然后才能继续运行您的应用程序
虽然人们不能更快地完成这个过程,但可以让它以异步方式运行,因此这种延迟几乎消失了。
最简单的方法是将视频帧设为create a buffer name,然后将其绑定,reserve-initialize 一次。
然后,在每个后续帧上,通过使用空数据指针调用glBufferData
来对其进行丢弃初始化,并使用non-reserving调用或mapping the buffer's complete range填充它。
你想要做这种奇怪的舞蹈而不是简单地覆盖缓冲区的原因是这不会阻止。 OpenGL将同步对缓冲区对象的访问,因此在数据仍然从中读取时不会覆盖数据。带有空数据指针的glBufferData
是一种告诉OpenGL您并不真正关心缓冲区并且不需要相同缓冲区的方法。所以它只会分配另一个并给你那个,继续阅读旧的,并在完成后秘密交换它们。
由于已经使用了“同步”这个词,我将在上面的链接中解释我对glMapBufferRange
的选择,实际上你想要映射整个缓冲区,而不是某个范围。为什么会这样想?
即使OpenGL在使用上述丢弃技术时大多可以避免同步,有时也可能需要
此外,它仍然必须运行某种内存分配算法来管理缓冲区,这需要驱动程序时间。 glMapBufferRange
允许您指定其他标志,特别是(在以后的OpenGL版本中)标记为“不同步”的标志。这允许更复杂但更快的方法,在该方法中,您创建两倍于您需要的大小的单个缓冲区,然后保持映射/写入下半部分或上半部分,告诉OpenGL根本不同步。那么你有责任知道什么时候它是安全的(大概是通过使用栅栏对象),但你尽可能地避免所有开销。
答案 1 :(得分:0)
如果不更新纹理,则无法更新纹理。
此外,我不认为对glTexImage
的一次调用可能是一个真正的性能问题。如果你这么关心哦,创建两个纹理并将其中一个用于写入时使用另一个进行绘制,然后交换(就像双缓冲工作一样)。
如果您可以将处理转移到GPU,则根本不需要调用该函数,这大约是100%的加速。