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
相关产品推荐
相关产品推荐

