5

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

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

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

我究竟做错了什么 ?

4

2 回答 2

7

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

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 并将纹理附加到它作为颜色缓冲区,或者通过使用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. 还没试过。

编辑:另见这个问题

于 2014-01-18T01:52:18.610 回答
0

GraphicBuffer是 Android 源代码的一部分,不在 NDK 中。请参阅此供您参考: https ://github.com/fuyufjh/GraphicBuffer

于 2016-12-28T06:51:47.060 回答