用EGL_KHR_image_base代替glReadPixels以获得更快的像素复制

我试图在Android本机进程中使用EGL_KHR_image_base,以取代glReadPixels,因为它是慢(1280×800 RGBA 220毫秒)。

这是我到目前为止,但我产生一个空的缓冲区(只有零)

uint8_t *ptr; GLuint mTexture; status_t error; GraphicBufferAlloc* mGraphicBufferAlloc = new GraphicBufferAlloc(); sp<GraphicBuffer> window = mGraphicBufferAlloc->createGraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE,&error); EGLClientBuffer buffer = (EGLClientBuffer)window->getNativeBuffer(); EGLint eglImageAttributes[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_MATCH_FORMAT_KHR, EGL_FORMAT_RGBA_8888_KHR, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; EGLImageKHR image = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,buffer, eglImageAttributes); glGenTextures(1, &mTexture); glBindTexture(GL_TEXTURE_2D, mTexture); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); window->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, (void**)&ptr); memcpy(texture, ptr, width * height * 4); window->unlock(); 

我究竟做错了什么 ?

您正在创build一个空的缓冲区,然后从中读取内容。 遍历代码:

 GraphicBufferAlloc* mGraphicBufferAlloc = new GraphicBufferAlloc(); sp<GraphicBuffer> window = mGraphicBufferAlloc->createGraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE,&error); 

这将创build一个新的GraphicBuffer (有时称为“gralloc缓冲区”),具有指定的尺寸和像素格式。 使用标志允许它被用作纹理或从软件读取,这是你想要的。

 EGLClientBuffer buffer = (EGLClientBuffer)window->getNativeBuffer(); EGLint eglImageAttributes[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_MATCH_FORMAT_KHR, EGL_FORMAT_RGBA_8888_KHR, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; EGLImageKHR image = eglCreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,buffer, eglImageAttributes); 

这需要ANativeWindow对象(这是一个缓冲区下的队列),并附加一个EGLImage “句柄”。

 glGenTextures(1, &mTexture); glBindTexture(GL_TEXTURE_2D, mTexture); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); 

这将创build一个新的纹理对象,并将EGLImage到它。 所以现在ANativeWindow可以用作纹理对象。

 window->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, (void**)&ptr); memcpy(texture, ptr, width * height * 4); window->unlock(); 

这将locking读取缓冲区,将数据复制出来并解锁。 既然你没有画任何东西,没有什么可读的。

为了做一些有用的事情,你必须把东西渲染到纹理中。 您可以通过创buildFBO并将纹理附加到颜色缓冲区,或使用glCopyTexImage2D()将帧缓冲区中的像素复制到纹理来完成此操作。

在调用grallocBuffer->lock()之前,我可以通过添加以下内容来获得您的示例:

 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0); glFinish(); 

glFinish()对于确保GL在我们尝试查看它们之前完成复制像素是必需的。

编辑:我的办公室伙伴build议GL_TEXTURE_2D需要GL_TEXTURE_EXTERNAL_OES 。 还没有尝试过。

编辑:另见这个问题 。

GraphicBuffer是Android源代码的一部分,不在NDK中。 看到这个供你参考: https : //github.com/fuyufjh/GraphicBuffer