glReadPixels
glReadPixels读取的是当前绑定的FBO的颜色缓冲区,所以当使用多个 FBO时,需要先绑定我们要读取的PBO。
调用glReadPixels时,首先会把Command Queue的所有GL命令发送到GPU,并且等待GPU执行完所有指令(隐式调用了glFinish),然后再读取像素数据,所以耗时比较久。
PBO
ImageReader
EGLImage
- API 26之前,EGLImageKHR
- API 26以后,Android NDK提供了Hardware Buffer APIs类
// EGLClientBuffer可以通过GraphicBuffer获取
EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
// EGLClientBuffer可以通过AHardwareBuffer获取
EGLClientBuffer clientBuf = eglGetNativeClientBufferANDROID(AHardwareBuffer);
// 创建EGLImageKHR,在Android平台上,ctx可以是EGL_NO_CONTEXT,target是EGL_NATIVE_BUFFER_ANDROID,buffer是由GraphicBuffer创建来的。
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
// 销毁EGLImageKHR
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image);
NDK提供了hardware_buffer_jni.h头文件用于转换Java层HardwareBuffer类和Native层AHardwareBuffer结构体。Java层HardwareBuffer类其实就是对Native层AHardwareBuffer结构的封装。
还提供了hardware_buffer.h用于操作AHardwareBuffer,具体实现在AHardwareBuffer.cpp源文件。
AHardwareBuffer和GraphicBuffer是一个结构体,之间可以直接转换,如下所示:
// AHardwareBuffer.cpp
GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer) {
return reinterpret_cast<GraphicBuffer*>(buffer);
}
AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) {
return reinterpret_cast<AHardwareBuffer*>(buffer);
}
GraphicBuffer并没有对外暴露接口,而是从API26开始,通过AHardwareBuffer结构体对外暴露了操作跨进程零拷贝图形缓冲区的能力。
通过AHardwareBuffer,可以从GPU零拷贝获取纹理像素数据,解决了glReadPixels的耗时问题。
- 先创建AHardwareBuffer,然后通过AHardwareBuffer创建EGLImageKHR(eglCreateImageKHR)。
- 接着把EGLImageKHR绑定到纹理(glEGLImageTargetTexture2DOES),这里的纹理可以是GL_TEXTURE_2D,也可以是GL_TEXTURE_EXTERNAL_OES。
- 把纹理绑定到FBO,进行OpenGL绘制。此时绘制内容会保存到AHardwareBuffer。
- 通过CPU访问方式从AHardwareBuffer copy出像素数据,AHardwareBuffer表示的图形数据在CPU和GPU之间是共享的,所以是零拷贝(不同进程间也是共享的)。具体方式是:先通过AHardwareBuffer_lock函数获取内存地址,然后从内存地址memcpy出像素数据,最后配对调用AHardwareBuffer_unlock函数。
HardwareBuffer(GraphicBuffer) <-> EGLImageKHR <-> 纹理
借助HardwareBuffer和EGLImageKHR,既可以实现把HardwareBuffer中的像素数据上传到纹理,也可以实现把纹理像素数据下载到HardwareBuffer。
- CPU -> AHardwareBuffer -> 纹理
- 纹理 -> AHardwareBuffer -> CPU