OpenGL ES无法在内存中删除我的纹理

6
我目前正在开发一个iOS应用程序(iPad和iPhone),使用OpenGL ES 1.0来渲染一些基本的纹理。我使用贴图集来存储和呈现我的纹理。
我的主要贴图集比较大(2000×2000),但是我的内部算法会将纹理加载和调整大小到2048×2048,因为OpenGL ES只接受2的幂次方大小的纹理。我能够绘制瓷砖,这方面都很好。
每当我尝试加载和卸载(销毁)纹理时,我都会遇到严重的内存泄漏问题。这在最终版本中应该会发生,但我需要确保我的加载和卸载没有问题。在内存中,纹理占用2048×2048×4(RGBA)字节=约16MB。这是一个巨大的字节数,所以你可以理解我的问题非常烦人(iOS在几分钟后就会杀死应用程序..)
当我加载纹理时,Instruments会指示应用程序使用的总内存增加了16MB,这是正确的(我使用“真实内存”列)。问题出现在我需要销毁纹理以释放所有可能使用的字节时:它从未释放这16MB...而且由于我在循环中加载和卸载,内存仍然在被使用,从未被释放。
以下是我如何加载纹理的方式:
GLubyte *outData = malloc((_dataWidth * _dataHeight * 4) * sizeof(*outData));
GLuint _texture; // declared as un instance variable so its address never changes
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _dataWidth, _dataHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, outData);
free(outData);

以下是我卸载纹理的方法(这就是它被称为的方式,我已经检查过了)

glDeleteTextures(1, &_texture);

我在每个地方都使用了glGetError()来检查是否发生错误,但它总是返回0(即使在glDeleteTexture之后)。

有没有人有想法呢? 谢谢!


顺便提一下,从 iPhone 3G S 及更新的每个 iOS 设备都应该支持 OpenGL ES 1.1 中的非二次幂纹理:https://dev59.com/Dm445IYBdhLWcg3wpL5_#4761453。此外,您是否考虑过将您的图集转换为使用 PowerVR 纹理压缩(PVRTC)?以这种方式压缩的纹理实际上以其压缩形式存储在内存中,这可以使它们的占用空间比未压缩的纹理小得多。这不会解决您的泄漏问题,但总体而言可能是一个好主意。 - Brad Larson
2个回答

14

确保在创建上下文的同一线程上销毁纹理。如果没有上下文,进行任何GL调用将不会出现错误。


1
Max,这个答案帮助我追踪到了Core Image中一个非常严重的纹理泄漏问题(因为CIContext被跨线程共享)。非常感谢您这篇简短但非常有用的文章! - chockenberry

1
你有尝试使用 GL_APPLE_client_storage 扩展吗?这意味着,OpenGL 不再需要拷贝纹理内存,而是由你承诺保留传递给 glTexImage2D 的数据块,直到调用 glDeleteTextures

是的,我认为那个扩展只适用于Mac。在iOS 5.0上,我们可以在纹理缓存中使用类似的东西,但这似乎不是这种情况。 - Brad Larson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接