我目前正在本机 Android 框架中的一个平台上工作,在该平台上我使用 GraphicBuffer 来分配内存,然后从中创建 EGLImage。然后将其用作 OpenGL 中的纹理(使用简单的全屏四边形)。
问题是,当我从 GraphicBuffer 读取渲染的像素数据时,我希望它在内存中采用线性 RGBA 格式,但结果是一个纹理,其中包含三个并行的较小图像克隆并具有重叠像素。也许这个描述并没有说太多,但重点是实际的像素数据是有意义的,但内存布局似乎不是线性 RGBA。我认为这是因为图形驱动程序以线性 RGBA 以外的内部格式存储像素。
如果我渲染到标准 OpenGL 纹理并使用 glReadPixels 读取一切工作正常,所以我认为问题在于我使用 GraphicBuffer 的自定义内存分配。
如果原因是驱动程序的内部存储器布局,是否有任何方法可以强制布局为线性 RGBA?我已经尝试了提供给 GraphicBuffer 构造函数的大部分使用标志,但没有成功。如果没有,是否有办法在着色器中以不同的方式输出数据以“取消”内存布局?
我正在为 Nexus 5 构建 Android 4.4.3。
//Allocate graphicbuffer
outputBuffer = new GraphicBuffer(outputFormat.width, outputFormat.height, outputFormat.bufferFormat,
GraphicBuffer::USAGE_SW_READ_OFTEN |
GraphicBuffer::USAGE_HW_RENDER |
GraphicBuffer::USAGE_HW_TEXTURE);
/* ... */
//Create EGLImage from graphicbuffer
EGLint eglImageAttributes[] = {EGL_WIDTH, outputFormat.width, EGL_HEIGHT, outputFormat.height, EGL_MATCH_FORMAT_KHR,
outputFormat.eglFormat, EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, EGL_NONE};
EGLClientBuffer nativeBuffer = outputBuffer->getNativeBuffer();
eglImage = _eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, nativeBuffer, eglImageAttributes);
/* ... */
//Create output texture
glGenTextures(1, &outputTexture);
glBindTexture(GL_TEXTURE_2D, outputTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);
/* ... */
//Create target fbo
glGenFramebuffers(1, &targetFBO);
glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, outputTexture, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/* ... */
//Read from graphicbuffer
const Rect lockBoundsOutput(quadRenderer->outputFormat.width, quadRenderer->outputFormat.height);
status_t statusgb = quadRenderer->getOutputBuffer()->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &result);