【问题标题】:Android Drawing text with opengl es crashes after a few minutesAndroid 使用 opengl es 绘制文本几分钟后崩溃
【发布时间】:2011-01-22 14:42:39
【问题描述】:

我创建了一个 opengl 表面,一切正常,但是当我尝试使用以下方法在其上绘制文本时:

public void loadFPSTexture(GL10 gl){

    Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.RGB_565);
    bitmap.eraseColor(Color.BLACK);
    Canvas canvas = new Canvas(bitmap);

    Paint textPaint = new Paint();
    textPaint.setTextSize(35);
    textPaint.setFakeBoldText(true);
    textPaint.setAntiAlias(true);
    textPaint.setARGB(255, 255, 255, 255);
    canvas.drawText("FPS "+reportedFramerate, 10,35, textPaint);
    gl.glGenTextures(1, texturesFPS, 0);

    gl.glBindTexture(GL10.GL_TEXTURE_2D, texturesFPS[0]);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle();
}

然后在我的 onDraw 函数中使用:

gl.glPushMatrix();
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texturesFPS[0]);
gl.glTranslatef(-surfaceSize.x/1.5f, surfaceSize.y/1.5f, 0.0f);
gl.glScalef(10, 10, 1.0f);
gl.glColor4f(1.0f, 1.0f, 1.0f, saturation_head); 
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0,vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureFPSBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,GL10.GL_UNSIGNED_SHORT, indexBuffer);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glPopMatrix();

我遇到了奇怪的崩溃,在此之后无法绘制表面。 Logcat 显示以下内容的恒定流:

E/Adreno200-EGL( 2578): eglLockWindowSurface: failed to map the memory for fd=32 offs=1536000
E/SurfaceFlinger( 2578): GL error 0x0505
E/Adreno200-EGL( 2578): eglLockWindowSurface: failed to map the memory for fd=32 offs=1536000
E/Adreno200-EGL( 2578): egliSwapWindowSurface: oglSwapBuffer failed
E/SurfaceFlinger( 2578): eglSwapBuffers: EGL error 0x3003 (EGL_BAD_ALLOC)

我不确定为什么会这样?任何帮助将不胜感激!

【问题讨论】:

    标签: android text opengl-es canvas frame-rate


    【解决方案1】:

    问题是我反复生成纹理而从未删除它们。只需在生成前添加一行就足以防止内存泄漏(似乎无需检查是否已生成纹理):

     gl.glDeleteTextures(1, texturesFPS, 1);
     gl.glGenTextures(1, texturesFPS, 1);
    

    就这么简单:)

    【讨论】:

    • 不会是“gl.glGenTextures(1, texturesFPS, 0);”在第二行?
    【解决方案2】:

    看起来您每次调用loadFPSTexture() 时都在创建一个新纹理,并且永远不会释放它。一段时间后,这会导致您的内存不足,这可以解释您日志中的 EGL_BAD_ALLOC

    最好只创建一次bitmapcanvastexturesFPS 变量,然后在loadFPSTexture() 函数中重复使用它们。在这种情况下,您可能应该使用GLUtils.texSubImage2D() 而不是GLUtils.texImage2D(),将新的位图数据上传到现有纹理。

    【讨论】:

    • 将尝试并告诉您进展如何。我认为 bitmap.recycle 会负责释放已使用的内存。我猜纹理被制作了,然后因为它在正常 GC 之外(由于缓冲区)它并没有真正清除纹理?
    【解决方案3】:

    我还没有评论访问权限(经常使用其他“帮助”网站,只是开始关注 SO),但想回应(并赞成)svdree 的注释,并添加更多详细信息 - 因为其他从 GLES 开始的人会肯定会遇到类似的问题。

    您的位图、画布和纹理(以及绘画!)应该创建一次,无论您从哪里开始设置 gles 资源。当您清理应用程序的资源时,它们应该被删除。除非您正在调整位图/纹理的大小,否则重新创建会不必要地破坏内存(cpu 和 gpu)。

    纹理的初始创建,你会使用 GLUtils.texImage2D 函数来准备纹理(可以按原样上传位图,不关心数据)。这确保了纹理由驱动程序分配,适当的宽度/高度缓冲区为以后的更新做好准备。

    渲染 fps 可能看起来更像:

    s_bitmap.eraseColor(Color.BLACK);
    s_canvas.drawText("FPS "+reportedFramerate, 10, 35, s_textPaint);
    gl.glBindTexture(GL10.GL_TEXTURE_2D, s_texturesFPS[0]);
    GLUtils.texSubImage2D(GL10.GL_TEXTURE_2D, 0, 0, 0, s_bitmap);
    

    ...就是这样。快了一个数量级,而且显然更干净。 :-)

    您可以让它更快,例如只擦除/填充正在绘制 fps 的位图矩形,然后直接使用 gl.glTexSubImage2D 仅上传文本渲染到的那些行(节省您的清除,并上传,比如说 220 行没有变化的额外数据......)。

    希望有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-23
      • 1970-01-01
      相关资源
      最近更新 更多