I'm trying to find a way to check to see if a current EGLContext exists and is ready to use on Android. By specification, I've tried using
((EGL10)EGLContext.getEGL()).eglGetCurrentContext()
and then comparing it to EGL10.EGL_NO_CONTEXT (tried .equals() and != ). However, even though through debugging it 'seems' that it is returning an instance of 'EGL_NO_CONTEXT' (seems meaning all the internal values are uninitialized) however no matter what comparison I do I can't get it to work.
Anyone know of another/proper method to get this done? I don't want to do it by throwing a random GL call and catching the EGLError...
I ran into the problem of not being able to re-use the current EGLContext when trying to render what was on screen in a GLSurfaceView to an offscreen EGLPixelBufferSurface. From what I can tell, the problem with using the static method
EGLContext.getEgl()
is that it creates a default EGL instance - this would mean that the EGLContext associated with it is equivalent to EGL10.EGL_NO_CONTEXT.
Also, in Android the EGLContext can only be associated with one thread (Android developer Romain Guy says so here). So in order to properly use
EGL.getCurrentContext()
you would have to have a pre-existing EGL instance and call the getCurrentContext() method in the thread that created the EGLContext.
NOTE: Android now handles saving the EGLContext when the GLThread is paused/resumed in the GLSurfaceView class (take a look at the setPreserveEGLContextOnPause(boolean preserveOnPause) method).
There seems to be a bug in Android's implementation of EGL10.eglGetCurrentContext(), where the result of eglGetCurrentContxt() has to be compared using
result.equals(EGL10.EGL_NO_CONTEXT)
rather than
result == EGL10.EGL_NO_CONTEXT
For example:
if (((EGL10) EGLContext.getEGL()).eglGetCurrentContext().equals(EGL10.EGL_NO_CONTEXT)) {
// no current context.
}
You could try testing it to see if it is null, rather than equal to a given context. This is what I would do in a standard opengl program.
[EDIT] There's an example here which uses it as follows:
if ((eglGetCurrentContext () != context->egl_context) ||
(eglGetCurrentSurface ( EGL_READ ) != drawable->egl_surface))
I don't know if that's any help.
Related
I only want to send video from an Android WebRTC client. Do I need a GLSurfaceView.Renderer like the one obtained via VideoRendererGui? And if not, then what would you pass for the eglContext part of this:
PeerConnectionFactory.initializeAndroidGlobals(
Object context, boolean initializeAudio, boolean initializeVideo,
boolean vp8HwAcceleration, Object renderEGLContext)
Did you already found a solution ? My use case was similar to your's. I guess, you already explored how VideoCapturerAndroid.java library, specially "startCaptureOnCameraThread" function was implemented in webRTC, and found your solution. Just in case if you still having problems with it; Yes, you can sure escape creating a local egl surface renderer if you don't need to, and can just pass null for the fifth parameter.
I pass null on eglContext. I've checked the value of VideoRendererGui.getEGLContext() and it's null. So if you pass null is not a problem, audio/video/data streaming works great!
I have an implementation of WallpaperService.Engine that uses JNI to create a C++ renderer:
Engine (Java) -> Renderer (C++)
If the renderer was Java code I could simply state
private Renderer renderer = new Renderer();
to make sure the renderer was created with my Engine and destroyed automatically when it's not needed any more. So what is the cleanest way to do this?
P.S.: I was thinking:
int rendererId = createNativeRenderer();
...
draw(rendererId); // call all native renderer methods specifying the object id
...
deleteNativeRenderer(rendererId);
But it's not very elegant since it requires explicit deletion, which is easy to forget.
Yes it's not very elegant, but it's by far the most reliable way. Java tries to be a hammer for every nail, so there is this thing called finalizer - an Object method called upon garbage collecting your instance. So it ideally does exactly what you need but practically better be avoided. If you read the related Javadoc carefully, you'll find out that:
Your precious renderer deleting code will be called not when you or your code thinks it's appropriate, but when the reference counting engine decides. And even worse, not at that specific point, but at any time later.
You can't know and you can't influence, which thread will call the finalizer. A double barrel shot in the foot if the code is related to UI operations (i understand that your code is).
Though, you can use finalizer for a safety check.
wrap the renderer lifecycle (create/use/delete) in an object with public method for deleting
upon explicit deleting, set an internal flag
override finalize() and check the flag state there. If not marked as deleted, log nasty error
I am using OpenGL ES 1.1 with the NDK and occasionally when I call glGenTextures it does not change the value of name holder that I pass in (doesn't even set it to 0).
glGetError returns 0, no error.
All GL code is in a JNI method called from onDrawFrame of the surface renderer so the context shouldn't be a problem. (edit: this was a wrong assumption and was the cause of the problem)
The code works in some cases and not others. If I repeat the call each frame it works after about 5 tries. (I am generating glyphs on request).
The first lot of textures get created up to at least #32 but after that it is hit and miss.
Does anyone know of a reason why glGenTextures would appear to do nothing?
Is glGenTextures called with a valid OpenGL(-ES) context being active? If you're using multiple threads: A OpenGL(-ES) context can be active in only one thread at a time. But each thread may have a different context active.
I have got some strange and unexpected results from my program in OpenGL ES for android for example in the code below:
matrix = ThisRot.get();
gl.glMultMatrixf(matrix, 0);
currentRotation.toMatrix(matrix);
temp.set(matrix);
I set the matrix value before I use it as an argument for gl.glMultMatrixf and after that I change the value of matrix and use it for another purpose, but it has effect an the way the object rotate so it should have effect on gl.glMultMatrixf(). and that's not the only one, some other places in my code I had this unexpected results. so I have thought maybe these happen due to mutual exclusion and multitreading and those kind of things.
am I right? should we worry about multithreading when we code in Opengl ES for android? How can I avoid these kind of problems.
Of course you should worry about multithreading. In particular, Android creates its own GLThread for rendering, when you attach a GLRenderer-derived class to a GLSurfaceView using the setRenderer() function.
In fact, multithreading can cause crashes (not only unexpected behavior) in your programs especially when you loop through arrays adding/removing objects and such.
Check if you are modifying the same data inside the onDrawFrame function of your GLRenderer and your own thread. If you are, try adding the following around the modified code (in both threads):
synchronize(variable) {
modify(variable);
}
This will lock the variable throughout the modify() function until it ends the block. Try not to overuse it, though, only in places where you need it. One thread will block the other one until it's finished!
After creating textures in Android OpenGL ES, do I have to explicitly delete these textures later using glDeleteTextures()? If so, how would I set up a callback to do this?
Thanks in advance
If you are no longer using a texture, then you should call glDeleteTextures() so that the underlying hardware resources can be freed up.
But as EboMike said, you have to be careful about using a texture that was created from a previous context instance; to expand on that answer, I like to create a texture-wrangling class which wraps the texture's ID and which calls glDeleteTextures() from its finalize() method, but then also have an app-static int named "contextId" which gets incremented every time the GL context is created (i.e. in onSurfaceCreated); the texture wrangler should track the value of contextId when it's instantiated, and if the value changes on it, that means it should reload its textures (keeping in mind that the old texture IDs were already discarded along with the old context).
No, they are automatically deleted once you move away from your app. The greater pitfall actually is to disregard the texture IDs if your app becomes active again - keep that in mind when your onSurfaceChanged is called again.