将glReadPixels替换为EGL_KHR_image_base以实现更快的像素复制



我正试图在android本机进程中使用EGL_KHR_image_base来替换glReadPixels,因为它会变慢(1280x800 RGBA为220ms)。

这就是我目前所拥有的,但我的它会产生一个空缓冲区(只有零)

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();

我做错了什么?

您正在创建一个空缓冲区,然后从中读取内容

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);

这将创建一个新的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);

这创建了一个新的纹理对象,并将EGLImage附加到它上。因此,现在ANativeWindow可以用作纹理对象。

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

这会锁定缓冲区进行读取,从中复制数据,然后解锁。由于您没有绘制任何内容,因此没有什么可读取的。

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

通过在调用grallocBuffer->lock()之前添加以下内容,我能够使您的示例发挥作用:

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

glFinish()是必要的,以确保GL在我们尝试查看像素之前已经完成了对像素的复制。

编辑:我的同事建议GL_TEXTURE_2D需要是GL_TEXTURE_EXTERNAL_OES。还没试过。

编辑:另请参阅此问题。

GraphicBuffer是Android源代码的一部分,而不是NDK中的。请参阅以下内容以供参考:https://github.com/fuyufjh/GraphicBuffer

最新更新