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

jac*_*cob 4 android android-ndk egl

我试图在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();
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么 ?

fad*_*den 5

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

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);
Run Code Online (Sandbox Code Playgroud)

这将创建一个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);
Run Code Online (Sandbox Code Playgroud)

这将获取ANativeWindow对象(它是引擎盖下的缓冲区队列)并附加一个EGLImage"句柄".

glGenTextures(1, &mTexture);    
glBindTexture(GL_TEXTURE_2D, mTexture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
Run Code Online (Sandbox Code Playgroud)

这将创建一个新的纹理对象,并将其附加EGLImage到它.所以现在ANativeWindow可以用作纹理对象.

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

这会锁定缓冲区以进行读取,将数据复制出来并解锁.由于你没有画任何东西,所以没有什么可读的.

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

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

glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0);
glFinish();
Run Code Online (Sandbox Code Playgroud)

glFinish()是必要的,以确保GL已完成复制像素之前,我们尝试看看他们.

编辑:我的办公室伙伴建议GL_TEXTURE_2D需要GL_TEXTURE_EXTERNAL_OES.尚未尝试过.

编辑:另见这个问题.