是否可以在不将整个纹理加载到常规RAM的情况下将纹理加载到OpenGL中?

g6ll5ycj  于 2023-04-29  发布在  其他
关注(0)|答案(3)|浏览(148)

通常,当我们将纹理加载到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扩展可以做到这一点。

ifmq2ha2

ifmq2ha21#

大多数图像文件格式都是压缩的或重编码的。因此,它们中至少有一部分必须首先通过常规系统内存。但是,如果您使用OpenGL缓冲区对象,则没有必要在 system RAM中为整个图像分配缓冲区。然而,它最终可能会在VRAM中分配缓冲区对象,* 因此您至少在一段时间内有两次数据 *。
关于如何使用它的悬崖笔记是

size_t buffer_size = ...;
GLuint buffer_id;
glGenBuffers(1, &buffer_id);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer_id);
glBufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL, GL_STATIC_DRAW);

void *buffer_ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
size_t offset_into_buffer = ...;
read_image_pixels_into_buffer((char*)buffer_ptr + offset_into_buffer);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);

glTexImage2D(..., (void*)((uintptr_t)offset_into_buffer));

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glDeleteBuffers(1, &buffer_id);

请注意,如果像上面的代码那样简单地使用缓冲区对象,性能和效率 * 可能 * 会受到影响。通常,缓冲区对象用作内存池,根据需要从内存池中剪切块,而缓冲区不会不断地创建和删除。然而,也有通过缓冲区孤立的流,这实际上重新创建缓冲区:https://www.khronos.org/opengl/wiki/Buffer_Object_Streaming

@BDL评论更新

使用OpenGL,你真的无法控制事情将如何发生,但你可以将代码路径推到某个方向。有一件事必须始终记住的是,OpenGL根本没有内存模型。一切都应该是正常的。不知怎么的
其副作用是,为了满足要求,基于GPU的OpenGL实现可能在任何时刻被迫驱逐GPU存储器中的一些数据到其他地方。...很可能是系统RAM,但甚至可能是磁盘交换空间。由于现代操作系统倾向于过量使用内存,因此很可能OpenGL实现将简单地保留与所有分配的OpenGL对象所需的实际页面错误内存相同的内存量。对于非流式数据,始终在系统内存(或交换)中拥有数据的副本非常有意义,因为这将驱逐转换为清除一些VRAM内存分配条目。
现在在缓冲区对象的情况下,我上面概述的代码路径实际上可以避免一个额外的副本,通过重命名缓冲区,即即,当将数据加载到纹理中时,实际上不复制数据,而仅复制被设置为指向缓冲器对象中的该特定区域的纹理描述符。..直到缓冲区中的该区域被覆盖,这随后触发副本的创建。然而,在将缓冲区对象(名称)加载到纹理中之后立即删除缓冲区对象(名称)实际上可能将缓冲区的整个存储器降级到纹理对象。* 然而,这只是一个潜在的优化,OpenGL实现可以实现,但不必实现。*
整个OpenGL规范是非常模糊的,这使得开发一个高性能的OpenGL实现明惊人的困难工作。

8nuwlpux

8nuwlpux2#

可以跳过一次加载整个纹理,而是像代码中显示的那样逐块加载。您只需要使用glTexSubImage2D上传块,并使用支持有效阅读切片的文件格式(例如,(例如TIFF):

... open file ...
... create texture ...

for each tile in file {
    tile = f.read_tile();
    glTexSubImage2D(GL_TEXTURE_2D, 0, tilex, tiley, tilew, tileh, format, type, tile);
}

然而,与加载整个内容并在一个GL调用中传输相比,这可能会慢一些。
例如,如果您的图像通过网络连接逐步加载,它仍然很有用。

wgxvkvu9

wgxvkvu93#

如果不先将纹理加载到RAM中,就无法将其传递给OpenGL。OpenGL不以任何方式处理文件访问。
大多数时候(除了未压缩的纹理或使用DDS压缩的纹理),无论如何都必须进行一些处理,以将压缩文件内容转换为OpenGL可以理解的格式。

相关问题