Minimizing OpenGL texture reloads on pause/resume

Problems with Canvas, OpenGL, etc...

Minimizing OpenGL texture reloads on pause/resume

Postby bxm » Tue May 10, 2011 2:57 am

Hey everyone,

I've been working on a project for quite some time and it's progress is coming along well. However, I have one concern that is bugging me: every time the phone goes to sleep (either by inactivity, or the power button being pressed) or receives a phone call mid-game and resumes afterwards, OpenGL has to recreate the surface and as such, all textures must be reloaded...

I suppose this is "okay" but looking at Angry Birds and Replica Island (whose code for this feature seems to be a hack that is hard to reproduce) they do not need to spend the time reloading them after this happens.

Does anyone know how to either preserve the textures or GL context/surface?

I am currently using the standard GLSurfaceView as my drawing interface, reloading textures in onSurfaceCreated if the eglContext != previous eglContext [it has never been the same in testing thus far anyways]

Appreciate any insight!
bxm
Junior Developer
Junior Developer
 
Posts: 24
Joined: Tue May 10, 2011 2:51 am

Top

Re: Minimizing OpenGL texture reloads on pause/resume

Postby bxm » Tue May 10, 2011 4:25 am

Figured it out on my own - a modified GLSurfaceView is required for this, as the default one will create a new EGLContext after every thread pause. Not too hard to work around for anyone else who needs it!
bxm
Junior Developer
Junior Developer
 
Posts: 24
Joined: Tue May 10, 2011 2:51 am

Re: Minimizing OpenGL texture reloads on pause/resume

Postby Sweep88 » Tue May 10, 2011 2:53 pm

bxm wrote:Figured it out on my own - a modified GLSurfaceView is required for this, as the default one will create a new EGLContext after every thread pause. Not too hard to work around for anyone else who needs it!


Hi bxm,

I'm having the same problem, can you share the (parts) of the modified GLSurfaceView with us?

Kind regards!
Sweep88
Freshman
Freshman
 
Posts: 5
Joined: Tue Apr 12, 2011 3:23 pm
Location: Germany

Re: Minimizing OpenGL texture reloads on pause/resume

Postby bxm » Tue May 10, 2011 11:07 pm

Sweep88 wrote:Hi bxm,

I'm having the same problem, can you share the (parts) of the modified GLSurfaceView with us?

Kind regards!


Sure thing, I took my GLSurfaceView.java from google, the Android source is pretty wide spread and it hasn't changed much since it's first incarnation. Anyways, after you find the source:

In guardedRun () of the GLThread, the lines below need to be commented out or removed so that the EGLContext is not recreated every time the rendering thread is paused:
Code: Select all
if (mPaused) {
    mEglHelper.finish();
    needStart = true;
}


After doing this, you need to check the result of "mEglHelper.swap();" when it is called later on in this function to see if it has failed, if it failed - the EGLContext has been lost and needs to be recreated - simply adding "needStart = true" if the swap call failed should recreate the EGLContext and surface the next iteration of the loop.

I also added a callback called onContextCreated to the Renderer class to inform my game when a new Context has been created, so it would only reload the textures after a flag is set in this callback. I call this callback from the GLThread every time mEglHelper.start(); is called (there are two occurances - needStart flag and the original context).
bxm
Junior Developer
Junior Developer
 
Posts: 24
Joined: Tue May 10, 2011 2:51 am

Re: Minimizing OpenGL texture reloads on pause/resume

Postby bxm » Tue May 10, 2011 11:16 pm

For simplicity's sake, here is the code to my modified guardedRun ():

Code: Select all
private void guardedRun () throws InterruptedException
{
    mEglHelper = new EglHelper ();
    mEglHelper.start ();
   
    GL10 gl = null;
    boolean tellRendererSurfaceCreated = true;
    boolean tellRendererSurfaceChanged = true;
    boolean tellRendererContextCreated = true;

    /*
     * This is our main activity thread's loop, we go until
     * asked to quit.
     */
    while (!mDone)
    {
        /*
         *  Update the asynchronous state (window size)
         */
        int w, h;
        boolean changed;
        boolean needStart = false;
       
        synchronized (this)
        {
            Runnable r;
            while ((r = getEvent ()) != null)
            {
                r.run();
            }
            /*if (mPaused) -- removed for Context preservation
            {
                mEglHelper.finish();
                needStart = true;
            }*/
            while (needToWait ())
            {
                wait();
            }
            if (mDone)
            {
                break;
            }
            changed = mSizeChanged;
            w = mWidth;
            h = mHeight;
            mSizeChanged = false;
        }
        if (needStart)
        {
            mEglHelper.start ();
            tellRendererContextCreated = true;
            tellRendererSurfaceCreated = true;
            changed = true;
        }
        if (tellRendererContextCreated)      // added to notify the renderer to reload GL data
        {
           mRenderer.onContextCreated ();
           tellRendererContextCreated = false;
        }
        if (changed)
        {
            gl = (GL10)mEglHelper.createSurface (getHolder ());
            tellRendererSurfaceChanged = true;
        }
        if (tellRendererSurfaceCreated)
        {
            mRenderer.onSurfaceCreated (gl, mEglHelper.mEglConfig);
            tellRendererSurfaceCreated = false;
        }
        if (tellRendererSurfaceChanged)
        {
            mRenderer.onSurfaceChanged (gl, w, h);
            tellRendererSurfaceChanged = false;
        }
        if (w > 0 && h > 0)
        {
            /* draw a frame here */
            mRenderer.onDrawFrame (gl);

            /*
             * Once we're done with GL, we need to call swapBuffers()
             * to instruct the system to display the rendered frame
             */
            if (!mEglHelper.swap ())
               needStart = true;      // we've lost our Context, recreate it
        }
     }

    /*
     * clean-up everything...
     */
    mEglHelper.finish ();
}


Please note that I've also removed any debugging and render-mode (continuous/dirty) from my GLSurfaceView, so it may be missing from this function if it was previously implemented.
bxm
Junior Developer
Junior Developer
 
Posts: 24
Joined: Tue May 10, 2011 2:51 am

Re: Minimizing OpenGL texture reloads on pause/resume

Postby manni1981 » Sat Feb 04, 2012 2:58 pm

Hi bxm,

thanks for your input on the guardedrun. We're running into a similar problem when creating a live wallpaper with the andengine live wallpaper extension. On pause the surface gets destroyed, and on recreating the surface all textures get reloaded by andengine, which takes forever.

We've tried to integrate your change in the guardedrun, but still the surfacedestroyed method of the glthread is called from outside. That means, even if we do not destroy the the surface on pausing, it will get destroyed (or recreated) when the surface lost flag was set, which in turn also reloads all textures, causing the stall.

Since i don't know my way around openGL es very well i'm quite stuck right now, despite your nice modified guardedrun. I'd be really grateful if you could help me out here, if it is too much work for you, perhaps we can arrange it via p.m. and i can pay you to help us out.

Thanks for your help
cheers, manni
manni1981
Once Poster
Once Poster
 
Posts: 1
Joined: Sat Feb 04, 2012 2:30 pm

Top

Return to Android 2D/3D Graphics - OpenGL Problems

Who is online

Users browsing this forum: No registered users and 4 guests