我使用MFC和OpenGL在C++中创建了一个简单的2D图像查看器.该图像查看器允许用户打开图像,放大/缩小,平移,以及以不同颜色层(青色,黄色,品红色,黑色)查看图像.该程序非常适合合理大小的图像.但是我正在对一些非常大的图像进行压力测试,而且我很容易耗尽内存.我有一个这样的图像是16,700x15,700.我的程序会耗尽内存,甚至可以绘制任何东西,因为我动态创建UCHAR[]一个大小为height x width x 4.我将它乘以4,因为当我将此数组提供给每个RGBA值时,有一个字节glTexImage2D(GLTEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGBA, GLUNSIGNED_BYTE, (GLvoid*)myArray)
我做了一些搜索并阅读了一些关于将图像分割成瓷砖的信息,而不是单个四边形上的一个大纹理.这是我应该做的事吗?这对我的记忆有什么帮助?或者我应该做些什么更好的事情?
小智 0
您的分配大小为 16.7k * 15.7k * 4,大小约为 1GB。其余的答案取决于您是编译为 32 位还是 64 位可执行文件,以及您是否使用物理地址扩展 (PAE)。顺便说一句,如果您不熟悉 PAE,很可能您没有使用它。
假设32位
如果您有 32 位可执行文件,则可以寻址 3GB 内存,因此在一次分配中将使用三分之一的内存。现在,更严重的问题是,当您分配一块内存时,该内存必须作为单个连续的空闲内存范围可用。您可能很容易拥有超过 1GB 的可用内存,但内存块小于 1GB,这就是为什么人们建议您将纹理分割成图块。将其拆分为 32 x 32 的较小块意味着您要分配 1024 个 1MB 的分配(这可能是不必要的细粒度)。 注意:需要引用,但某些 Linux 模式只允许 2GB。
假设 64 位
您似乎不太可能构建 64 位可执行文件,但如果您是这样,那么逻辑可寻址内存要高得多。典型数字为 2^42 或 2^48(分别为 4096 GB 和 256 TB)。这意味着除了人工压力测试之外,大型分配不应在任何其他情况下失败,并且您将在耗尽逻辑内存之前杀死交换文件。
如果您的限制/硬件允许,我建议构建为 64 位而不是 32 位。否则,请参见下文
平铺与子采样
平铺和二次采样在前面并不相互排斥。您可能只需要进行一项更改即可解决问题,但您可能会选择实施更复杂的解决方案。
如果您处于 32 位地址空间,则平铺是一个好主意。它使代码变得复杂,但消除了您似乎面临的单个 1GB 连续块问题。如果您必须构建 32 位可执行文件,我更喜欢对图像进行二次采样。
对图像进行二次采样意味着您有一个额外的(尽管较小)内存块用于二次采样与原始图像。它在 openGL 中可能具有性能优势,但要针对额外的内存压力进行设置。
第三种方法会带来额外的复杂性,那就是在必要时从磁盘流式传输图像。如果缩小以显示整个图像,则在 1920 x 1200 显示器上,每个屏幕像素将进行 >100 个像素的二次采样。您可以选择创建默认情况下显着二次采样的图像,并使用它,直到您充分放大到需要图像子集的更高分辨率版本为止。如果您使用 SSD,这可以提供可接受的性能,但会增加很多额外的复杂性。