Android 使用 opengl es 绘制文本几分钟后崩溃
我创建了一个 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)
我不确定为什么会发生这种情况?任何帮助将不胜感激!
I've created an opengl surface and everything works fine, however when I try to draw text onto it using the following method:
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();
}
Then used in my onDraw function with:
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();
I get a weird crash and the surface is unable to be drawn after this point. Logcat shows a constant stream of the following:
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)
I'm not sure why this is happening? any help would be much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题是我重复生成纹理而没有删除它们。只需在生成之前添加一行就足以防止内存泄漏(似乎不需要检查纹理是否已经生成):
就这么简单:)
The trouble is that I was generating textures repeatedly without ever deleting them. Simply adding one line before generation is enough to prevent a memory leak (it seems there is no need to check that a texture has already been generated):
Simple as that :)
看起来您每次调用
loadFPSTexture()
时都会创建一个新纹理,并且永远不会释放它。一段时间后,这将导致您耗尽内存,这可以解释日志中的EGL_BAD_ALLOC
。最好只创建一次
bitmap
、canvas
和texturesFPS
变量,然后在loadFPSTexture
中重用它们() 功能。在这种情况下,您可能应该使用GLUtils.texSubImage2D()
而不是GLUtils.texImage2D()
,将新位图数据上传到现有纹理。Looks like you're creating a new texture each time you call
loadFPSTexture()
, and never release it. After some time this will cause you to run out of memory, which could explain theEGL_BAD_ALLOC
in your logs.It would be better to create your
bitmap
,canvas
andtexturesFPS
variables just once, and reuse them in theloadFPSTexture
() function. In that case, you should probably useGLUtils.texSubImage2D()
instead ofGLUtils.texImage2D()
, to upload new bitmap data to the existing texture.我还没有评论访问权限(经常访问其他“帮助”网站,只是这样),但想回应(并赞成)svdree 的注释,并添加更多详细信息 - 因为其他从 GLES 开始的人肯定会遇到类似的问题问题。
无论您从哪里开始设置gles资源,您的位图、画布和纹理(以及绘画!)都应该创建一次。当您清理应用程序的资源时,应删除它们。除非您调整位图/纹理的大小,否则重新创建会不必要地破坏内存(CPU 和 GPU)。
纹理的初始创建,您可以使用 GLUtils.texImage2D 函数来准备纹理(可以按原样上传位图,不关心数据)。这可确保驱动程序分配纹理,并为以后的更新准备适当的宽度/高度缓冲区。
渲染 fps 可能看起来更像:
...就是这样。速度快了一个数量级,而且显然更干净。 :-)
你可以让它更快,例如只擦除/填充正在绘制 fps 的位图矩形,然后直接使用 gl.glTexSubImage2D 只上传文本渲染到的那些行(节省你的清除,并上传,比如 220 行额外的不变数据……)。
希望有帮助!
I don't have comment access yet (frequent other 'help' sites, just getting up on SO), but wanted to echo (and upvoted) svdree's note, and add more details -- because other people starting with GLES will certainly hit similar issues.
Your bitmap, canvas, and texture (and paint!) should be created once, wherever you set up your gles resources to begin with. They should be deleted when you clean up resources for the app. Unless you are resizing the bitmap/texture, recreating is thrashing memory (cpu and gpu) unnecessarily.
The initial creation of the texture, you'd use the GLUtils.texImage2D function to prepare the texture (can just upload the bitmap as-is, don't care about the data). That ensures the texture is allocated by the driver, proper width/height buffer ready for later updates.
Rendering the fps might then look more like:
... and that's it. An order of magnitude faster, and obviously much cleaner. :-)
You can make it even faster beyond that, for example only erase/fill the bitmap rectangle where the fps is being drawn, and then use gl.glTexSubImage2D directly to upload only those rows the text is rendered to (saving you clearing, and uploading, say 220 extra rows of data that isn't changing...).
Hope that helps!