OpenGL 帧缓冲区附件泄漏 GPU 内存
OpenGL framebuffer attachments leak GPU memory
考虑以下 test code:
for (int i = 0; i < 100; ++i) {
GLuint fboid = 0;
GLuint colortex = 0;
GLuint depthtex = 0;
// create framebuffer & textures
glGenFramebuffers(1, &fboid);
glGenTextures(1, &colortex);
glGenTextures(1, &depthtex);
glBindTexture(GL_TEXTURE_2D, colortex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4000, 4000, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, depthtex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 4000, 4000, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fboid);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colortex, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthtex, 0);
assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER));
// clear it
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
// delete everything
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteFramebuffers(1, &fboid);
glDeleteTextures(1, &colortex);
glDeleteTextures(1, &depthtex);
}
// put breakpoint here
您会在 activity 监视器中看到底部的 "Memory used" 变得很高 (14 GB)。就好像 GPU 还在引用已经发布的纹理。
我尝试了以下方法:
- 在不同的地方调用 glFlush()
- 在不同的地方调用 glFinish()
- 更改 texture/fbo 删除的顺序
- 删除前从 fbo 分离附件
- 调用 [context flushBuffer];
None 其中有任何效果。
但是 (!) 如果我删除 glClear() 调用,问题就会消失。
这可能是什么原因造成的?它在 Windows 上也是可谴责的 ,并且 与另一个实现(不幸的是我无法分享并且无论如何要复杂得多)。
你们见过这样的内存泄漏问题吗?
更新:现在很明显,depth/stencil 缓冲区正在泄漏。如果我创建一个仅深度附件,那么问题又消失了!
更新:使用英特尔卡更容易重现。在我 2011 年底的 mbpro 上,代码在独立卡 (Radeon 6750M) 上运行正常,但在集成卡 (HD 3000) 上会产生所描述的泄漏。
更新:已在 High Sierra (10.13.x)
上修复
虽然我没有找到任何合适的解决方案,但我想出了一个解决方法 (不幸的是,这给 Radeon Pro 580 (?) 卡带来了不同的泄漏问题)。
解决方法如下:
- 首先,我启用 GL 上下文共享
- 然后每当我想删除 D24S8 纹理时,我都会将它放入缓存中
- 如果实现请求创建 D24S8 缓冲区,我首先查看缓存(不要忘记,MSAA 样本计数必须匹配!)
- 如果缓存中有合适的项目(>=比请求的大小),然后我把它拿出来,return它
- 如果没有,我会根据要求的大小创建一个
通过这个解决方案,我设法最大限度地减少了上述配置的泄漏...aaaaaaa 并在 AMD 卡上搞砸了(我想这是另一种驱动程序错误,但现在我可以'不要用小程序重现)。
考虑以下 test code:
for (int i = 0; i < 100; ++i) {
GLuint fboid = 0;
GLuint colortex = 0;
GLuint depthtex = 0;
// create framebuffer & textures
glGenFramebuffers(1, &fboid);
glGenTextures(1, &colortex);
glGenTextures(1, &depthtex);
glBindTexture(GL_TEXTURE_2D, colortex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4000, 4000, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, depthtex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 4000, 4000, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fboid);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colortex, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthtex, 0);
assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER));
// clear it
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
// delete everything
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteFramebuffers(1, &fboid);
glDeleteTextures(1, &colortex);
glDeleteTextures(1, &depthtex);
}
// put breakpoint here
您会在 activity 监视器中看到底部的 "Memory used" 变得很高 (14 GB)。就好像 GPU 还在引用已经发布的纹理。
我尝试了以下方法:
- 在不同的地方调用 glFlush()
- 在不同的地方调用 glFinish()
- 更改 texture/fbo 删除的顺序
- 删除前从 fbo 分离附件
- 调用 [context flushBuffer];
None 其中有任何效果。 但是 (!) 如果我删除 glClear() 调用,问题就会消失。
这可能是什么原因造成的?它在 Windows 上也是可谴责的 ,并且 与另一个实现(不幸的是我无法分享并且无论如何要复杂得多)。
你们见过这样的内存泄漏问题吗?
更新:现在很明显,depth/stencil 缓冲区正在泄漏。如果我创建一个仅深度附件,那么问题又消失了!
更新:使用英特尔卡更容易重现。在我 2011 年底的 mbpro 上,代码在独立卡 (Radeon 6750M) 上运行正常,但在集成卡 (HD 3000) 上会产生所描述的泄漏。
更新:已在 High Sierra (10.13.x)
上修复虽然我没有找到任何合适的解决方案,但我想出了一个解决方法 (不幸的是,这给 Radeon Pro 580 (?) 卡带来了不同的泄漏问题)。
解决方法如下:
- 首先,我启用 GL 上下文共享
- 然后每当我想删除 D24S8 纹理时,我都会将它放入缓存中
- 如果实现请求创建 D24S8 缓冲区,我首先查看缓存(不要忘记,MSAA 样本计数必须匹配!)
- 如果缓存中有合适的项目(>=比请求的大小),然后我把它拿出来,return它
- 如果没有,我会根据要求的大小创建一个
通过这个解决方案,我设法最大限度地减少了上述配置的泄漏...aaaaaaa 并在 AMD 卡上搞砸了(我想这是另一种驱动程序错误,但现在我可以'不要用小程序重现)。