Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transfer textures from one OpenGL context to another

Background:

Android native camera app uses a OpenGL_1.0 context to display camera preview and gallery pictures. Now I want to add a live-filter on the native camera preview.

To add a live-filter on my own camera app preview is simple --- just use the OpenGL_2.0 to do the image-processing and display. Since OpenGL_1.0 doses't support image-process and somehow it is used for display in the Android native camera app. *I now want to create a new GL context based on OpenGL_2.0 for image-processing and pass the processed image to the other GL context based on OpenGL_1.0 for display.*

Problem:

The problem is how to transfer the processed image from the GL-context-process (based on OpenGL_2.0) to the GL-context-display (based on OpenGL_1.0). I have tried to use FBO: first copy the image pixels from texture in GL-context-process and then set them back to another texture in GL-context-display. But copy pixels from texture is quite slow, typically takes hundreds of milliseconds. That is too slow for camera preview.

*Is there a better way to transfer textures from one GL context to another? Especially, when one GL context is based on OpenGL_2.0 while the other is based on OpenGL_1.0.*

like image 239
Ethan J Avatar asked Feb 27 '14 08:02

Ethan J


1 Answers

I have found a solution using EGLImage. Just in case someone finds it useful:

Thread #1 that loads a texture:

EGLContext eglContext1 = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttributes); 
EGLSurface eglSurface1 = eglCreatePbufferSurface(eglDisplay, eglConfig, NULL); // pbuffer surface is enough, we're not going to use it anyway 
eglMakeCurrent(eglDisplay, eglSurface1, eglSurface1, eglContext1); 
int textureId; // texture to be used on thread #2 
// ... OpenGL calls skipped: create and specify texture 
//(glGenTextures, glBindTexture, glTexImage2D, etc.) 
glBindTexture(GL_TEXTURE_2D, 0); 
EGLint imageAttributes[] = { 
    EGL_GL_TEXTURE_LEVEL_KHR, 0, // mip map level to reference 
    EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, 
    EGL_NONE 
}; 
EGLImageKHR eglImage = eglCreateImageKHR(eglDisplay, eglContext1, EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(textureId), imageAttributes); 

Thread #2 that displays 3D scene:

// it will use eglImage created on thread #1 so make sure it has access to it + proper synchronization etc. 
GLuint texture; 
glGenTextures(1, &texture); 
glBindTexture(GL_TEXTURE_2D, texture); 
// texture parameters are not stored in EGLImage so don't forget to specify them (especially when no additional mip map levels will be used) 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage); 
// texture state is now like if you called glTexImage2D on it 

Reference: http://software.intel.com/en-us/articles/using-opengl-es-to-accelerate-apps-with-legacy-2d-guis https://groups.google.com/forum/#!topic/android-platform/qZMe9hpWSMU

like image 132
Ethan J Avatar answered Nov 09 '22 23:11

Ethan J