On android, the GLSurfaceView documentation says this:
A GLSurfaceView must be notified when the activity is paused and
resumed. GLSurfaceView clients are required to call onPause() when the
activity pauses and onResume() when the activity resumes. These calls
allow GLSurfaceView to pause and resume the rendering thread, and also
allow GLSurfaceView to release and recreate the OpenGL display.
So I'm supposed to do something like this in my activity:
public void onPause() {
myGlSurfaceView.onPause();
}
public void onResume() {
myGlSurfaceView.onResume();
}
I'm observing in my code that if I don't call onPause() and onResume() then the context is not lost when I press the home button, so I can switch between applications and then go back to my game and everything is working. What I see is that if I close the game using the back button then the screen is black when I open it again, but I can change the back button behaviour to totally close the game and avoid this problem.
So my question is: when is the OpenGL context destroyed? If I don't call onPause() and onResume() can I assume that it will never be destroyed?
EDIT:
I'm targeting Android 2.2, so setPreserveEGLContextOnPause() is not an option to me.
The OpenGL might be lost only after Actvity::onPause() is called, and only in this case. See the setPreserveEGLContextOnPause documentation :
Whether the EGL context is actually preserved or not depends upon whether the Android device that the program is running on can support an arbitrary number of EGL contexts or not. Devices that can only support a limited number of EGL contexts must release the EGL context in order to allow multiple applications to share the GPU.
[...] the EGL context [can be] released when the GLSurfaceView is paused, and recreated when the GLSurfaceView is resumed.
EDIT : The situation described in the documentation is valid on all Android version. Not matter you have access to setPreserveEGLContextOnPause
In my opinion, this is one major drawback is Android OGLES implementation : you can't be certain.
The documentation itself is vague (EGL Context Lost note) :
There are situations where the EGL rendering context will be lost. This typically happens when device wakes up after going to sleep
I noticed the same behavior as you about the Home and Back button. Calls are not exactly the sames (but can't remember them precisely).
The only way to be sure that the OpenGL context is available is to create all OpenGL resources in onSurfaceCreated
Note about setPreserveEGLContextOnPause. Once again, this documentation comment demonstrates the "random" behavior of context destruction :
If set to true, then the EGL context may be preserved when the GLSurfaceView is paused. [...]
setPreserveEGLContextOnPause is an option for you, you just have to implement the GlSurfaceView yourself.
See my answer here to a similar question:
Prevent onPause from trashing OpenGL Context
Related
I'm successfully drawing simple shapes on my GLSurfaceView using OpenGL ES 2.0. So far i'm not using any textures. The problem is that when i re-run for the second time the activity with GLSurfaceView the screen is empty (black), shapes are not being drawn again. I have to reinstall the whole app to make it work again.
I don't have any special methods onPause & onResume so i assume the new instance of GLSurfaceView should redraw the screen each time i re-run the application.
Does anyone have any clue what am i missing here?
I don't have any special methods onPause & onResume
That's likely your problem. You need to follow the documentation of GLSurfaceView, specifically what it says under "Activity Life-cycle":
A GLSurfaceView must be notified when the activity is paused and resumed. GLSurfaceView clients are required to call onPause() when the activity pauses and onResume() when the activity resumes. These calls allow GLSurfaceView to pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate the OpenGL display.
I have a GLSurfaceView renderer and method onSurfaceCreated is called only once (basically only when activity is created or re-created).
I need to test behavior when EGL context is lost and surface is recreated during normal activity life cycle, however I am unable to put app into such situation no matter what I do.
Is there anything that I can do to simulate situation in which is onSurfaceCreated called again? How to make my app lose EGL context?
Edit: After a few days I noticed that the problem was gone and the app started to behave properly as said in specs:
public abstract void onSurfaceCreated (GL10 gl, EGLConfig config)
Called when the surface is created or recreated.
Called when the rendering thread starts and whenever the EGL context is lost.
The EGL context will typically be lost when the Android device awakes
after going to sleep
Before that, every time the device went to sleep, the activity was destroyed and recreated on awake which was preventing me to test if the code in OnSurfaceCreated worked well.
Now it behaves much better when sleep/awake occurs - it usually does not destroy the activity and just calls OnSurfaceCreated method which is the situation I was aiming for.
I'm not sure but the only thing that i can think of is to switch the GLSUrfaceView with a new one using the same GLSurfaceView.Renderer.
That should create a new EGL context and call the onSurfaceCreated() a second time.
According to the documentation, GLSurfaceView.Renderer.onSurfaceCreated is called when the surface is created or recreated.
Called when the rendering thread starts and whenever the EGL context is lost. The EGL context will typically be lost when the Android device awakes after going to sleep.
Have you tried locking your device's screen and unlocking it?
Maybe you can look at onScreenStateChanged method but it's available for API 16 or higher. If you mean "pausing and resuming the activity" by "normal activity life ciycle" maybe you can use onPause or onResume to track this.
What exactly do you want to do with onSurfaceCreated() ? You can force the rendering by requestRender() method of SurfaceView and do the necessary calculations inside onDrawFrame() of GLSurfaceView.Renderer
If your view is in a fragment, you can detach and re-attach the fragment.
The documentation for the setPreserveEGLContextOnPause Android function states the following:
"...If set to true, then the EGL context may be preserved when the GLSurfaceView is paused..."
How do I check if the EGLContext was preserved or not upon the resumption of my activity?
If the EGLContext was not preserved I need to reload all of my textures, that is why it is important to me.
The only thing I was able to find that I though might be related to this question was the getPreserveEGLContextOnPause() method. But this method only returns true if the EGLContext will be saved, and even if it is saved it may be deleted by the system later, so this doesn't really seem to help.
According to this text, you don't need to. The context loss is implicit and cannot be observed. When onSurfaceCreated() is called, you know the context (has been lost|was never created) and must be recreated.
Alternatively, a possible workaround is to create some small object that is actually never used, but indicates that the context was not lost in the meantime. I'm not sure if this will work, though.
I have a normal Main activity that calls the Game Activity Surface (in Open GL), which loads all the textures so play the game.
If I drop the activity with OpenGl surface, the engine delete the textures and close the activity game. Seems ok, but...
In Main Activity (normal activity), if I call the game activity (repeating load textures) the game drain much memory in heap (seems duplicate) and the frame-rate of the game get slow. If I repeat the process, the memory heap is increasing.
And what happens if I close the entire app? The Android free-up and I could re-open the app in normal speed and memory consume.
I tried garbage ... seems something related to opengl surface.
My question: closing the surface activity that contains Open gl, the open gl buffer still allocated in heap? After closed, open a new activity with open gl will duplicate the open gl size ? In memory seems that its happens, but I could finding out the reason.
I got the solution.
Because a weak reference, Android guarded all context in memory.
My game has a pause in game mainThread and show a Toast Message. The user can left or re-enter in the game. If he left the screen, Android keeps the reference of dead activity in memory, probable with all open gl surface too, only because the Toast message, with dead activity reference still popup after close the last activity. I'm just use getApplicationContext().
try to dispose all the texture in the onDestroy() method. that way all the texture will be destroyed when you exit/finish the activity.
#Override
protected void onDestroy() {
super.onDestroy();
for(Texture t:textures) {
t.dispose();
}
}
note : I don't really know that Android has it own texture class. I used libgdx and there's a dispose method to call. maybe you should find a way to dispose all those garbage. If i recall there's a recycle() method in Bitmap class that do similiar thing.
My game is working correctly except in the case where I press the HOME button then resume. What needs to be done to use the textures again? I have tried calling onPause and onResume on the GLSurfaceView (when the activity's onPause and onResume are called).
Any ideas what I could be doing wrong?
If all else fails, reload the textures:
Pseudocode
for tex in textures:
if glIsTexture(tex.opengl_name) == false:
glGenTextures(1, &tex.opengl_name)
glBindTexture(tex.texture_target);
glTexImage(..., texture.image);
Even if you fixed your problem, just to give a bit of explanation that might help others.
Android does not guaranty to keep the OpenGL context alive when the activity is paused.
You have to recreate every OpenGL-resources on resume (texture in you case, but also VBOs etc etc).
Since API 11, you can ask kindly Android to keep the context, but there is no guaranty it would.
After trying:
do not call GLSurfaceView#onPause/onResume in Activity's onPause/onResume
call GLSurfaceView#onPause/onResume, but also set GLSurfaceView#setPreserveEGLContextOnPause(true)
Both of cases fix the HOME-resume-black-texture issue.
Guess Android implementation failed to re-create the EGL context when resume. Since onPause/onResume are required to call, should always set setPreserveEGLContextOnPause to true.