OpenGL帧缓冲附件泄漏GPU内存

5
请看以下测试代码:

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

在活动监视器中,您会看到底部的“已使用内存”飙升(14 GB)。就好像GPU仍在引用已经释放的纹理一样。我尝试了以下操作:调用各种位置的glFlush();调用各种位置的glFinish();更改纹理/帧缓冲对象删除的顺序;在删除之前从帧缓冲对象中分离附件;调用[context flushBuffer()];但是这些都没有任何效果。然而,如果我删除glClear()调用,问题就消失了。可能是什么原因导致的呢?这个问题也可以在Windows上重现,并且在另一个实现中也可以重现(不幸的是我无法分享,而且它本身更加复杂)。你们有没有见过类似的内存泄漏问题?更新:现在很明显,深度/模板缓冲正在泄漏。如果我创建一个仅深度的附件,那么问题又消失了!更新:使用英特尔显卡更容易重现。在我晚期2011年的mbpro上,代码在独立显卡(Radeon 6750M)上运行良好,但在集成显卡(HD 3000)上产生了所述的泄漏。更新:它已经在High Sierra(10.13.x)上修复了。

你应该制作一个 [mcve],即一个短小的代码片段,我们可以编译并使用原始的GL调用而不是你的自定义包装器。 - HolyBlackCat
好的,已修改帖子,并附上了简单的重现代码(包括Xcode项目文件)。 - Asylum
只是出于好奇,您是否尝试在删除帧缓冲之前删除纹理? - Robinson
我无法在我的MacOS 10.10.5 iMac上复制这个问题。最好的猜测是:这只发生在您在initWithCoder中调用OpenGL函数之前,而视图prepareOpenGL之后。如果您将[self memoryTest]移动到prepareOpenGL或drawRect中,它是否仍会泄漏? - Hugh Fisher
不是每台Mac都能复制它。到目前为止,我们在以下配置上复制了它(可能所有的10.12.x [Sierra]或更高版本):iMac Retina 4K,21.5英寸,2017年Radeon Pro 555 2 GB; iMac(21.5英寸,2012年末)NVIDIA GeForce GT 640M 512 MB; iMac(4K Retina,2015年末)Radeon Pro 555 2 GB; iMac 2013英特尔酷睿pro;关于initWithCoder:我不这么认为,因为我们在一个简单的单元测试中也遇到了这个问题。 - Asylum
2
@Robinson:是的,我尝试了几乎所有可以做的事情。看起来只有这个D24S8格式会导致内存泄漏(例如简单的D24则不会)。我已向苹果报告了这个问题。 - Asylum
1个回答

0

虽然我没有找到任何合适的解决方案,但我想出了一个解决方法(不幸的是,这会带来与Radeon Pro 580 (?)卡不同的泄漏问题)

解决方法如下:

  • 首先,我启用GL上下文共享
  • 每当我想删除D24S8纹理时,我将其放入缓存中
  • 如果实现请求创建D24S8缓冲区,则首先查看缓存(不要忘记,MSAA样本计数必须匹配!)
  • 如果缓存中有一个符合条件(>=所请求的大小)的项目,则将其取出并返回
  • 如果没有,则创建一个所请求大小的缓冲区

通过这个解决方案,我成功地将泄漏最小化在提到的配置上...并且在那张AMD卡上搞砸了(我想这可能是另一种驱动程序错误,但现在我无法使用小程序重现它)。


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