iOS 中 OpenGL ES 纹理的显存占用

问题

最近调试一个 OpenGL ES 问题,最终发现是临时纹理太多。

开发 iOS App 时,Xcode 带有工具测量内存占用和泄露。但应该如何测量 OpenGL ES 纹理占多少显存,是否有纹理泄露呢?GL 活在另一个世界,并非 CPU 和内存,而是 GPU 和显存。

我搜索网页,也试验 Instruments 带的测量模块。但遗憾的是,我找不到方法来直接测量显存占用,但似乎有个间接方法,我不能十分确定,只好用“似乎”这个模糊字眼。

记录

下面记录我试验的过程,使用 iPhone 7+ 测试,iOS 系统 11.3.1。

Xcode 自带 Memory 测量,这个图应该很熟悉了。

Memory

于是自然产生一个问题,这个 Memory Use 是否包括纹理显存?写代码试验。

local tex = context:createTexture(1024, 1024)
print(tex)

我们为了方便编写效果,已经导出了一批 lua Api。上面的 lua 代码创建了一个纹理不释放,每帧跑一次。纹理是 1024 * 1024, RGBA 格式,于是占用 4M。假如 Memory Use 统计了纹理显存,应该可以看到数值会飞快地涨。

实际结果 Memory Use 的数值增长很缓慢。

那是否就证实 Memory Use 不包括纹理显存呢?还不能立即下结论。假如每次泄露 4M,按道理 App 应该很快就崩溃掉,或者出现某些异常。但我注意到 App 一直运行正常,而 Windows 7 运行上述代码,很快就弄崩溃程序。

于是有猜测 1:在 iOS 上创建一定数量的纹理,到达了极限值后,之后创建纹理就会失败,不再泄露显存,因而 App 也不会崩溃。

基于上述猜测,在对应的 C++ 代码中加检测:

glTexImage2D(d._target, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, OF_NULL);
GL_CHECK_ERROR();

GL_CHECK_ERROR 的定义为

#if GL_DEBUG
#define GL_CHECK_ERROR() gl::checkGLError(__FILE__, __LINE__);
#else
#define GL_CHECK_ERROR()
#endif
void checkGLError(const char* file, int line) {
    GLenum error = glGetError();
    if (error) {
    	 // xxxx
        printf("%d\n", (int)error);