You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL ES 2.0 FrameBuffer黑屏及FBO初始化代码位置咨询

解决FBO与纹理每帧创建导致的GPU资源泄漏问题

兄弟,我太懂你踩的这个坑了!把FBO和纹理的初始化代码放在onDrawFrame()里,刚开始能正常显示但运行一段时间就出异常,核心问题就是GPU资源泄漏——你每帧都在创建新的FBO和纹理对象,但从来没销毁过它们,显存会被慢慢占满,最终导致应用崩溃或者渲染异常。

核心思路:资源只初始化一次,销毁时务必释放

1. 把初始化代码移到合适的生命周期方法

FBO和纹理属于GPU资源,只需要创建一次(除非Surface尺寸变化需要重新调整纹理大小),所以应该把初始化逻辑放在:

  • onSurfaceCreated():当Surface第一次创建时初始化(适合固定尺寸的纹理)
  • onSurfaceChanged():当Surface尺寸变化时初始化/重新创建(适合和Surface同尺寸的纹理)

2. 代码示例:正确的生命周期管理

首先在类中声明成员变量保存FBO和纹理ID:

private int mFboId = 0;
private int mTextureId = 0;
private int mTextureWidth = 0;
private int mTextureHeight = 0;

初始化(以onSurfaceChanged()为例):

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    // 如果之前已经创建过资源,先释放旧的
    releaseResources();

    mTextureWidth = width;
    mTextureHeight = height;

    // 创建渲染目标纹理
    int[] textures = new int[1];
    gl.glGenTextures(1, textures, 0);
    mTextureId = textures[0];
    gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
    // 设置纹理参数,避免拉伸变形或边缘问题
    gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
    gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
    gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
    // 分配纹理内存
    gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, mTextureWidth, mTextureHeight, 0,
            GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, null);

    // 创建FBO并绑定纹理
    int[] fbos = new int[1];
    gl.glGenFramebuffers(1, fbos, 0);
    mFboId = fbos[0];
    gl.glBindFramebuffer(GL10.GL_FRAMEBUFFER, mFboId);
    // 将纹理附着到FBO的颜色缓冲区
    gl.glFramebufferTexture2D(GL10.GL_FRAMEBUFFER, GL10.GL_COLOR_ATTACHMENT0,
            GL10.GL_TEXTURE_2D, mTextureId, 0);

    // 检查FBO是否完整,避免渲染错误
    if (gl.glCheckFramebufferStatus(GL10.GL_FRAMEBUFFER) != GL10.GL_FRAMEBUFFER_COMPLETE) {
        Log.e("FBO_ERROR", "Framebuffer is not complete!");
        releaseResources();
        return;
    }

    // 解绑FBO,回到默认帧缓冲
    gl.glBindFramebuffer(GL10.GL_FRAMEBUFFER, 0);
}

onDrawFrame()中只做渲染逻辑:

@Override
public void onDrawFrame(GL10 gl) {
    if (mFboId == 0 || mTextureId == 0) {
        return; // 资源未初始化,跳过渲染
    }

    // 第一步:渲染到FBO(纹理)
    gl.glBindFramebuffer(GL10.GL_FRAMEBUFFER, mFboId);
    gl.glViewport(0, 0, mTextureWidth, mTextureHeight);
    // 这里执行你的渲染操作,比如绘制3D模型、特效等

    // 第二步:切换回默认帧缓冲,绘制四边形显示纹理
    gl.glBindFramebuffer(GL10.GL_FRAMEBUFFER, 0);
    gl.glViewport(0, 0, surfaceWidth, surfaceHeight); // surfaceWidth是当前Surface的宽高
    // 绑定纹理,绘制四边形
    gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
    // 执行四边形绘制逻辑(比如绑定VAO、Shader,调用glDrawArrays等)
}

销毁资源(在onSurfaceDestroyed()中):

private void releaseResources() {
    if (mFboId != 0) {
        int[] fbos = {mFboId};
        GLES20.glDeleteFramebuffers(1, fbos, 0);
        mFboId = 0;
    }
    if (mTextureId != 0) {
        int[] textures = {mTextureId};
        GLES20.glDeleteTextures(1, textures, 0);
        mTextureId = 0;
    }
}

@Override
public void onSurfaceDestroyed(GL10 gl) {
    releaseResources();
}

为什么之前的代码会出问题?

GPU的显存是有限的,每帧创建新的FBO和纹理时,系统会不断分配显存空间,但这些对象没有被glDeleteFramebuffers()和glDeleteTextures()销毁,显存会被持续占用,直到耗尽——这时候就会出现渲染异常、卡顿甚至应用崩溃。

这样调整后,资源只会在必要时创建一次,销毁时也能完全释放,就不会有泄漏问题了。

内容的提问来源于stack exchange,提问作者Lucas Berger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:30:20