1

我正在使用以下代码将数据复制到 GraphicBuffer:

uint8_t *ptr;
sp<GraphicBuffer> gBuffer = new GraphicBuffer(width,height,format,usage);
gBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&ptr));
//Copy Data
gBuffer->unlock();

EGLClient clientBuffer = (EGLClientBuffer)gBuffer->getNativeBuffer();

EGLImageKHR img = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,clientBuffer, NULL);

glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureHandle);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img);

//Finished using img, Crash Here:

eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), img);

当调用 eglDestroyImageKHR 时,问题就出现了,它在某些设备中崩溃,而在另一些设备中则没有。这是回溯:

00 pc 00006488 /system/lib/libui.so
01 pc 00006719 /system/lib/libui.so (android::GraphicBuffer::free_handle()+52)
02 pc 00006813 /system/lib/libui.so (android::GraphicBuffer::~GraphicBuffer()+22)
03 pc 00006841 /system/lib/libui.so (android::GraphicBuffer::~GraphicBuffer()+4)
04 pc 0000f823 /system/lib/libutils.so (android::RefBase::decStrong(void const*) const+40)
05 pc 00003bbb /system/vendor/lib/egl/eglsubAndroid.so
06 pc 0001b5f4 /system/vendor/lib/egl/libEGL_adreno.so (egliDoDestroyEGLImage+80)
07 pc 00006c88 /system/vendor/lib/egl/libEGL_adreno.so (eglDestroyImageKHR+16)
08 pc 0000e749 /system/lib/libEGL.so (eglDestroyImageKHR+44)

以下是几个完整的回溯:

http://pastebin.com/S0Ax6eNp

http://pastebin.com/bGWeWruw

不调用 eglDestroyImageKHR 会导致泄漏,当再次调用上述例程时,gbuffer->lock() 失败并显示内存不足错误消息。

例如在galaxy S4、galaxy s2、xperia z1 上崩溃并且不会在nexus 4、nexus 7、galaxy ace 2 等中崩溃

我将不胜感激任何帮助。

-编辑-

我发现的唯一解决方法是将引用计数器减少到 0,以便调用 GraphicBuffer 析构函数并释放内存。

if(gBuffer->getStrongCount() > 0){
    gBuffer->decStrong(gBuffer->handle);
}
4

2 回答 2

2

FWIW,在 MozillaAndroidGraphicBuffer.cpp代码中,作者写道

/**
 * XXX: eglDestroyImageKHR crashes sometimes due to refcount badness (I think)
 *
 * If you look at egl.cpp (https://github.com/android/platform_frameworks_base/blob/master/opengl/libagl/egl.cpp#L2002)
 * you can see that eglCreateImageKHR just refs the native buffer, and eglDestroyImageKHR
 * just unrefs it. Somehow the ref count gets messed up and things are already destroyed
 * by the time eglDestroyImageKHR gets called. For now, at least, just not calling      
 * eglDestroyImageKHR should be fine since we do free the GraphicBuffer below.
 *
 * Bug 712716
 */

并且基本上不调用eglDestroyImageKHR()在这种情况下显然是可以的。错误报告在这里Mozilla 代码的作者 James Willcox也是snorp 博客文章的作者。

于 2014-12-22T14:17:29.760 回答
2

我对 EGL 表面也有同样的问题。从 4.3 开始,三星 ROM 在销毁任何一个时都不会停用活动上下文和表面。代码现在看起来像这样:

// This line had to be added to prevent crashes:
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);

mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);

堆栈跟踪看起来非常相似。您是否尝试过在调用 eglDestroyImageKHR 之前销毁 gBuffer?

于 2014-02-19T20:27:57.223 回答