This is what I'm doing:
- In native code, I'm creating an EGL texture from AHardwareBuffer and pass ID of the EGL texture back to Java
- In java I create SurfaceTexture from that texture ID and Surface from that SurfaceTexture
- Pass Surface to native code and get ANativeWindow* from it using ANativeWindow_fromSurface
- In java, on the same thread I call UpdateTexImage on the SurfaceTexture in a loop
- C++, in a new thread I feed the ANativeWindow* to a decoder that starts writing frames to it.
UpdateTexImage fails with the following: bindTextureImage: clearing GL error: 0x502 bindTextureImage: error binding external image: 0x502
If I don't start the decoder, updateTexImage doesn't fail If I use a normal texture and not a AHardwareBuffer backed texture, updateTexImage and decoder don't fail
The reason I'm using AHardwareBuffer backed texture is because that makes it easy(ish) to do InterOp with Vulkan, and I will need that later. Relevant code stripped of error checking is below.
Grateful for advice.
This is how I create AHardwareBuffer
m_pAndroidHardwareBuffer = nullptr;
AHardwareBuffer_Desc desc = {};
desc.width = w;
desc.height = h;
desc.layers = 1;
desc.usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
desc.format = AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 ;//AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
int aRes = AHardwareBuffer_allocate(&desc, &m_pAndroidHardwareBuffer);
This is how I create EGL texture from the hardware buffer
// Create EGLClientBuffer from AHardwareBuffer
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(m_pAndroidHardwareBuffer);
const EGLint eglImageAttributes[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
// Create the EGLImage from EGLClientBuffer
EGLImageKHR eglImage = eglCreateImageKHR(m_eglDisplay, m_OutputContext, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, eglImageAttributes);
// generate EGL texture from EGLImage
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// Use the EGLImage as the texture's data source
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) eglImage);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
This is how I create SurfaceTexture and Surface in Java: (textureID is GLuint texture from above)
mDecodeTargetTexture = new SurfaceTexture(textureID, false);
mDecodeTargetTexture.setOnFrameAvailableListener(null);
mDecodeTargetSurface = new Surface(mDecodeTargetTexture);
I've been reading the implementation of UpdateTexImage here https://android.googlesource.com/platform/frameworks/native/+/marshmallow-mr2-release/libs/gui/GLConsumer.cpp And I'm starting to suspect that what I want to do is impossible.
I've also looked into other ways to do EGL-Vulkan Interop but this seems the most straight forward