OpenGL 帧缓冲附件泄漏 GPU 内存

Posted

技术标签:

【中文标题】OpenGL 帧缓冲附件泄漏 GPU 内存【英文标题】:OpenGL framebuffer attachments leak GPU memory 【发布时间】:2018-01-12 12:51:29 【问题描述】:

考虑以下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() 更改纹理/fbo 删除的顺序 删除前从 fbo 中分离附件 调用[上下文flushBuffer];

这些都没有任何效果。 但是(!)如果我删除 glClear() 调用,那么问题就会消失。

什么可能导致这种情况? 在 Windows 上也是可重现的,并且 与另一个实现(不幸的是我无法分享,而且无论如何都要复杂得多)。

你们中有人见过这样的内存泄漏问题吗?

更新:现在很明显,深度/模板缓冲区正在泄漏。如果我创建一个仅深度的附件,那么问题就会再次消失!

更新:使用英特尔卡更容易重现。在我 2011 年末的 mbpro 上,代码在独立卡 (Radeon 6750M) 上运行正常,但在集成卡 (HD 3000) 上产生了所描述的泄漏。

更新:它已在 High Sierra (10.13.x) 上修复

【问题讨论】:

您应该创建一个minimal reproducible example,即我们可以编译的短 sn-p,它使用原始 GL 调用而不是您的自定义包装器。 好的,修改帖子,附上简单的repro代码(带有xcode项目文件)。 出于好奇,您是否尝试过在删除帧缓冲区之前删除纹理? 我无法在我的 MacOS 10.10.5 iMac 上复制该问题。最佳猜测:这只是因为您在视图 prepareOpenGL 之前在 initWithCoder 中调用 OpenGL 函数。如果将 [self memoryTest] 移动到 prepareOpenGL 或 drawRect 中,它还会泄漏吗? @Robinson:是的,我几乎尝试了所有可以做的事情。似乎只有这种 D24S8 格式会导致内存泄漏(例如,简单的 D24 不会)。我向 Apple 报告了这个问题。 【参考方案1】:

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

解决方法如下:

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

通过这个解决方案,我设法最大限度地减少了上述配置的泄漏...aaaaaaa 并在 AMD 卡上搞砸了(我想这是另一种驱动程序错误,但现在我无法重现它一个小程序)。

【讨论】:

以上是关于OpenGL 帧缓冲附件泄漏 GPU 内存的主要内容,如果未能解决你的问题,请参考以下文章

◮OpenGL-帧缓冲

OpenGL VBO 会泄漏内存吗?

iOS OpenGL ES Analyzer 列出“不存在的帧缓冲区附件”和“缺少帧缓冲区附件”,但 FBO 工作

OpenGL 帧缓冲区颜色附件到计算着色器

OpenGL 编程指南 (3.2)

在 OpenGL ES 中为帧缓冲区使用深度和模板渲染缓冲区附件