OpenGL纹理存储

时间:2018-03-23 18:20:40

标签: opengl-es opengl-es-2.0

我试图了解在OpenGL中创建新纹理时会发生什么。

时我一直以为
glTexImage2D 
运行

,纹理存储在CPU中,直到激活它才开始

glActiveTexture; 
glBindTexture;

将图像复制到GPU。但是看了一下后,我觉得我的理解是错的。我意识到许多OpenGL版本不可能读回纹理像素值,这让我认为数据存储在GPU上,这就是为什么没有能力回读像素的原因。 GLreadpixels很慢,因为它是从GPU内存复制信息。 glTexImage2D是否在GPU上创建内存,而激活纹理和绑定纹理只是设置程序的句柄来使用图像?这是有意义的,因为每次使用图像时来回复制图像数据太昂贵。这是gl特定的实现吗?文档没有提供有关数据存储位置的任何信息,我也无法在线找到任何答案。

1 个答案:

答案 0 :(得分:1)

通常我认为在将数据存储在GPU上时,它取决于驱动程序,大多数OpenGL函数倾向于将数据推向GPU VBO-s,例如明确说明结果对象在GPU内存中。在OpenGL中,您提供了一个指向纹理数据的指针,然后实现处理它,但从不拥有您提供的内存,因此您可以在调用后立即释放它。

glTexImage glTexSubImage 不要直接使用您提供的缓冲区:

void glTexImage2D(  GLenum target,
                    GLint level,
                    GLint internalFormat,
                    GLsizei width,
                    GLsizei height,
                    GLint border,
                    GLenum format,
                    GLenum type,
                    const GLvoid * data);

internalFormat - 是一个有趣的参数,因为它表示内部存储,但是永远不能保证它会像这样存储,我以前读过的文章说过一些ATI / AMD GPUS甚至不支持非RGBA格式,所以如果你说GL_RGB用于 internalFormat 它会将它转换为RGBA,因为它支持的是什么,这是在Vulkan中修复的,因为你可以查询实际支持的格式和上传纹理的格式将存储在GPU上。 格式类型数据是必需的,因为实施需要知道它将从您那里得到什么。判断执行纹理上传所需的时间以及使用它时没有后来的打嗝,我认为可以安全地假设纹理更新很可能直接上传到GPU内存。

使用PBO(像素缓冲区对象),因为你做了同样的事情,所以不做任何改变,但你为数据参数指定NULL并绑定一个保证在GPU内存中充当的PBO上传源。

glGenTextures 调用只是在CPU端创建对象,将其视为一个包含纹理信息的数组"对象"你得到了id-s。稍后您使用这些ID通过 glTexImage 初始化纹理,您可以使用 glTexSubImage 指定存储和基本参数,然后可以使用它来更新整个或部分图像。使用 glTexSubImage 来更新纹理也比调用tex glTexImage 更快,这表明实现的方式不同。

glReadPixels 很慢,因为它将驻留在GPU中的帧缓冲区读入CPU内存空间,因为GPU制造商倾向于尽可能在GPU端推送负载,例如转换反馈解决了需要从CPU空间中提供GPU的问题,您可以随意刷洗缓冲区,而无需从CPU空间触摸它们,并轻松模拟1M粒子,否则会因CPU瓶颈而死亡。

如果您的假设确实是在第一次使用纹理时上传信息,那么第一次渲染大型场景时,您将获得惊人的巨大延迟,因为所有纹理都是一个接一个地上传。您可以通过上传大量纹理并测量 glTexImage 花费的时间以及首次显示它们所需的时间来测试。据我所知, glTexImage 调用可能需要花费大量时间,具体取决于纹理大小,当然这也取决于设备,但是让我们说15毫秒上传一个纹理是一个很多。