Sharing OpenGL textures across multiple threads

11,505 views
Skip to first unread message

Tomei

unread,
Mar 16, 2011, 12:51:54 AM3/16/11
to android-platform
Hello,

Is it possible to have

+ multiple threads generating OpenGL textures concurrently (e.g., each
for a tile of the screen)
+ multiple threads drawing the texture tiles onto the screen (*not
concurrently* -- each frame is drawn by exactly one thread, but
multiple threads may need to draw to the screen at different times).

This is with Honeycomb + Tegra II

Thanks!

Romain Guy

unread,
Mar 16, 2011, 1:40:36 AM3/16/11
to android-...@googlegroups.com
Using EGLImage you can generate textures from another thread (that's what the Browser does) but you cannot draw using multiple threads, even if only one thread draws at a time. The EGL context is associated to a single thread.


--
You received this message because you are subscribed to the Google Groups "android-platform" group.
To post to this group, send email to android-...@googlegroups.com.
To unsubscribe from this group, send email to android-platfo...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-platform?hl=en.




--
Romain Guy
Android framework engineer
roma...@android.com

Note: please don't send private questions to me, as I don't have time to provide private support.  All such questions should be posted on public forums, where I and others can see and answer them

Tomei

unread,
Mar 16, 2011, 2:05:44 AM3/16/11
to android-platform
Can I create a separate OpenGL context in each thread, but bind them
to the same Window?

If so, I think on Windows there is a way to share a texture by
multiple OpenGL contexts. Does such a thing exist for Android?

Thanks
> romain...@android.com

Wiktor

unread,
Apr 15, 2011, 9:04:46 AM4/15/11
to android-platform
Hi all,

I have a similar problem of sharing OpenGL ES textures between two
threads on Honeycomb device (Motorola Xoom).
According to EGL 1.4 specification it should be possible by using
EGLContext from the main thread as "share_context" parameter to
eglCreateContext during creation of the second EGLContext on the
second thread.
The problem is no matter what I do calling eglMakeCurrent on second
thread always fails with EGL_BAD_ACCESS.
I want to be able to take a texture id generated on one thread (main
thread), bind it and construct it (for example by glTexImage2D,
GLUtils.texImage2D) on second thread and then use it on the main
thread.

Main thread is a rendering thread in android.view.GLSurfaceView.java
(but I can create a custom class for that if any behavior of the
default one needs to be changed) so it calls:
- eglInitialize with a default display,
- eglChooseConfig to obtain config that I'll call mainEGLConfig,
- eglCreateWindowSurface to create a window surface from
android.view.Surface it is using,
- eglCreateContext to create mainEGLContext (EGL_NO_CONTEXT is used
as "share_context" parameter),
- eglMakeCurrent,
- creates some GL objects (including textures via glGenTextures),
- renders scene in onDrawFrame etc.

Second thread obtains mainEGLConfig and mainEGLContext from the main
thread and calls:
- eglInitialize with a default display,
- eglCreatePbufferSurface to create a pixel buffer surface that will
not be used anyway (mainEGLConfig used as config),
- eglCreateContext with mainEGLConfig as "share_context" parameter
(mainEGLConfig used as config),
- eglMakeCurrent fails with EGL_BAD_ACCESS.

Above error is not generated if EGL_NO_CONTEXT is used as
"share_context" but textures are not shared this way of course.
EGL spec gives three conditions when such error can be generated by
eglMakeCurrent but in my opinion none of them apply here.
On the other hand Android implementation of eglMakeCurrent (at least
in Gingerbread sources) generates EGL_BAD_ACCESS in case an unknown
error occured.

I hope that my logic is fundamentally wrong somewhere above and a fix
is easy - any help appreciated :)


On Mar 16, 7:40 am, Romain Guy <romain...@android.com> wrote:
> Using EGLImage you can generate textures from another thread (that's what
> the Browser does) but you cannot draw using multiple threads, even if only
> one thread draws at a time. The EGL context is associated to a single
> thread.

This sounds interesting, could you give some examples how to use
EGLImage extension in this case?
I've read its description in Khronos EGL registry but I'm still not
sure how to use it properly to share textures in the first part of my
post.
http://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt
http://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image.txt

Thanks,
Wiktor

Wiktor

unread,
May 30, 2011, 9:57:20 AM5/30/11
to android-platform
Just in case someone finds it useful, here's how I solved it using
EGLImage.
Code will be pseudo C++ code without error checking and
synchronization between threads to make is more clear.

Common part for each thread:
EGLConfig eglConfig; // I assume that eglConfig is valid for each
thread and was obtained at some point
EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglBindAPI(EGL_OPENGL_ES_API);
EGLint contextAttributes[] = {
EGL_CONTEXT_CLIENT_VERSION, 2, // I'm using OpenGL ES 2
EGL_NONE
};


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://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt
http://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_gl_image.txt
http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image.txt

俞晓磊

unread,
Jul 11, 2011, 3:34:39 AM7/11/11
to android-platform
Hello, Wiktor,
I followed your method but got stuck at glMakeCurrent (EGL_BAD_MATCH).
Do you have any sample code available?

Wiktor

unread,
Jul 14, 2011, 8:36:47 AM7/14/11
to android-platform
Did you create both context and pbuffer surface using the same
EGLConfig?
Also make sure that all calls succeeded so you don't pass
EGL_NO_CONTEXT or EGL_NO_SURFACE to eglMakeCurrent.

Unfortunately I have no more samples.

--
Wiktor
Reply all
Reply to author
Forward
0 new messages