通常,当我们将纹理加载到OpenGL中时,我们或多或少是这样做的
- 打开文件
- 将所有字节读入系统RAM
- 调用glTexImage 2D(),将字节发送到VRAM
- 释放系统RAM中的字节
有没有一种方法来流/加载字节到VRAM跳过整个加载到系统RAM的一部分。就像这样:
char chunk[1000];
f = openfile("some file")
glBindTexture(....)
glTexParameteri(...)
glTexParameteri(...)
glTexParameteri(...)
while (f.eof == false) {
chunk = f.read_chunk(1000);
glTexImage2D..... (here's the chunk)
}
closefile(f);
我想知道是否有一些新的OpenGL扩展可以做到这一点。
3条答案
按热度按时间ifmq2ha21#
大多数图像文件格式都是压缩的或重编码的。因此,它们中至少有一部分必须首先通过常规系统内存。但是,如果您使用OpenGL缓冲区对象,则没有必要在 system RAM中为整个图像分配缓冲区。然而,它最终可能会在VRAM中分配缓冲区对象,* 因此您至少在一段时间内有两次数据 *。
关于如何使用它的悬崖笔记是
请注意,如果像上面的代码那样简单地使用缓冲区对象,性能和效率 * 可能 * 会受到影响。通常,缓冲区对象用作内存池,根据需要从内存池中剪切块,而缓冲区不会不断地创建和删除。然而,也有通过缓冲区孤立的流,这实际上重新创建缓冲区:https://www.khronos.org/opengl/wiki/Buffer_Object_Streaming
@BDL评论更新
使用OpenGL,你真的无法控制事情将如何发生,但你可以将代码路径推到某个方向。有一件事必须始终记住的是,OpenGL根本没有内存模型。一切都应该是正常的。不知怎么的
其副作用是,为了满足要求,基于GPU的OpenGL实现可能在任何时刻被迫驱逐GPU存储器中的一些数据到其他地方。...很可能是系统RAM,但甚至可能是磁盘交换空间。由于现代操作系统倾向于过量使用内存,因此很可能OpenGL实现将简单地保留与所有分配的OpenGL对象所需的实际页面错误内存相同的内存量。对于非流式数据,始终在系统内存(或交换)中拥有数据的副本非常有意义,因为这将驱逐转换为清除一些VRAM内存分配条目。
现在在缓冲区对象的情况下,我上面概述的代码路径实际上可以避免一个额外的副本,通过重命名缓冲区,即即,当将数据加载到纹理中时,实际上不复制数据,而仅复制被设置为指向缓冲器对象中的该特定区域的纹理描述符。..直到缓冲区中的该区域被覆盖,这随后触发副本的创建。然而,在将缓冲区对象(名称)加载到纹理中之后立即删除缓冲区对象(名称)实际上可能将缓冲区的整个存储器降级到纹理对象。* 然而,这只是一个潜在的优化,OpenGL实现可以实现,但不必实现。*
整个OpenGL规范是非常模糊的,这使得开发一个高性能的OpenGL实现明惊人的困难工作。
8nuwlpux2#
可以跳过一次加载整个纹理,而是像代码中显示的那样逐块加载。您只需要使用
glTexSubImage2D
上传块,并使用支持有效阅读切片的文件格式(例如,(例如TIFF):然而,与加载整个内容并在一个GL调用中传输相比,这可能会慢一些。
例如,如果您的图像通过网络连接逐步加载,它仍然很有用。
wgxvkvu93#
如果不先将纹理加载到RAM中,就无法将其传递给OpenGL。OpenGL不以任何方式处理文件访问。
大多数时候(除了未压缩的纹理或使用DDS压缩的纹理),无论如何都必须进行一些处理,以将压缩文件内容转换为OpenGL可以理解的格式。