Android OpenGL ES Context lost

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
porcus
Posts: 149
Joined: Sun May 27, 2007 6:24 pm
Location: Germany

Android OpenGL ES Context lost

Post by porcus »

Hi,

I'm currently trying to port an irrlicht project to android but I have problems with the context loss when pressing the home button.
After reading http://irrlicht.sourceforge.net/forum// ... 61#p265961 I tried to implement a recreate method (contains basically all important stuff from the constructors) for the COGLES2Driver:

Code: Select all

void COGLES2Driver::recreate(const SIrrlichtCreationParameters& params,
            const SExposedVideoData& data, io::IFileSystem* io
#if defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_)
            , CIrrDeviceIPhone* device
#endif
            ){
        ExposedData = data;
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
        EglWindow = (NativeWindowType)data.OpenGLWin32.HWnd;
        HDc = GetDC((HWND)EglWindow);
        EglDisplay = eglGetDisplay((NativeDisplayType)HDc);
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
        EglWindow = (NativeWindowType)ExposedData.OpenGLLinux.X11Window;
        EglDisplay = eglGetDisplay((NativeDisplayType)ExposedData.OpenGLLinux.X11Display);
#elif defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_)
        Device = device;
#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
        EglWindow = ((struct android_app *)(params.PrivateData))->window;
        EglDisplay = EGL_NO_DISPLAY;
        //mustRecreate = false;
#endif
    //changed:
    //COGLES2ExtensionHandler Konstruktor
    EGLVersion= 0; Version = 0; MaxTextureUnits = 0; MaxSupportedTextures = 0; MaxAnisotropy = 1; MaxTextureSize = 1; MaxIndices = 0xffff; MaxTextureLODBias = 0.f; StencilBuffer = false;
        for (u32 i=0; i<IRR_OGLES2_Feature_Count; ++i)
            FeatureAvailable[i] = false;
 
        CurrentRenderMode = ERM_NONE;
        ResetRenderStates = true;
        Transformation3DChanged = true;
        AntiAlias = params.AntiAlias;
        BridgeCalls = 0;
        RenderTargetTexture = 0;
        CurrentRendertargetSize = core::dimension2d<u32>(0, 0);
        ColorFormat = ECF_R8G8B8;
#ifdef EGL_VERSION_1_0
        EglDisplay = EGL_NO_DISPLAY;
#endif
    //stuff from Null Device Constructor
    setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true);
    setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true);
    memset(&ExposedData, 0, sizeof(ExposedData));
    for (u32 i=0; i<video::EVDF_COUNT; ++i)
        FeatureEnabled[i]=true;
 
    InitMaterial2D.AntiAliasing=video::EAAM_OFF;
    InitMaterial2D.Lighting=false;
    InitMaterial2D.ZWriteEnable=false;
    InitMaterial2D.ZBuffer=video::ECFN_DISABLED;
    InitMaterial2D.UseMipMaps=false;
    for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
    {
        InitMaterial2D.TextureLayer[i].BilinearFilter=false;
        InitMaterial2D.TextureLayer[i].TextureWrapU=video::ETC_REPEAT;
        InitMaterial2D.TextureLayer[i].TextureWrapV=video::ETC_REPEAT;
    }
    OverrideMaterial2D=InitMaterial2D;
    //HWBufferLinks:
    HWBufferMap.clear();
    //changed end
#ifdef EGL_VERSION_1_0
        if (EglDisplay == EGL_NO_DISPLAY)
        {
            os::Printer::log("Getting OpenGL-ES2 display.");
            EglDisplay = eglGetDisplay((NativeDisplayType) EGL_DEFAULT_DISPLAY);
        }
        if (EglDisplay == EGL_NO_DISPLAY)
        {
            os::Printer::log("Could not get OpenGL-ES2 display.");
        }
 
        EGLint majorVersion, minorVersion;
        if (!eglInitialize(EglDisplay, &majorVersion, &minorVersion))
        {
            os::Printer::log("Could not initialize OpenGL-ES2 display.");
        }
        else
        {
            char text[64];
            sprintf(text, "EglDisplay initialized. Egl version %d.%d\n", majorVersion, minorVersion);
            os::Printer::log(text);
        }
 
        EGLint attribs[] =
        {
            EGL_RED_SIZE, 5,
            EGL_GREEN_SIZE, 5,
            EGL_BLUE_SIZE, 5,
            EGL_ALPHA_SIZE, params.WithAlphaChannel ? 1 : 0,
            EGL_BUFFER_SIZE, params.Bits,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            //EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
            EGL_DEPTH_SIZE, params.ZBufferBits,
            EGL_STENCIL_SIZE, params.Stencilbuffer,
            EGL_SAMPLE_BUFFERS, params.AntiAlias ? 1 : 0,
            EGL_SAMPLES, params.AntiAlias,
#ifdef EGL_VERSION_1_3
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
#endif
            EGL_NONE, 0
        };
        EGLint contextAttrib[] =
        {
#ifdef EGL_VERSION_1_3
            EGL_CONTEXT_CLIENT_VERSION, 2,
#endif
            EGL_NONE, 0
        };
 
        EGLConfig config;
        EGLint num_configs;
        u32 steps=5;
        while (!eglChooseConfig(EglDisplay, attribs, &config, 1, &num_configs) || !num_configs)
        {
            switch (steps)
            {
            case 5: // samples
                if (attribs[19]>2)
                {
                    --attribs[19];
                }
                else
                {
                    attribs[17]=0;
                    attribs[19]=0;
                    --steps;
                }
                break;
            case 4: // alpha
                if (attribs[7])
                {
                    attribs[7]=0;
                    if (params.AntiAlias)
                    {
                        attribs[17]=1;
                        attribs[19]=params.AntiAlias;
                        steps=5;
                    }
                }
                else
                    --steps;
                break;
            case 3: // stencil
                if (attribs[15])
                {
                    attribs[15]=0;
                    if (params.AntiAlias)
                    {
                        attribs[17]=1;
                        attribs[19]=params.AntiAlias;
                        steps=5;
                    }
                }
                else
                    --steps;
                break;
            case 2: // depth size
                if (attribs[13]>16)
                {
                    attribs[13]-=8;
                }
                else
                memset(&ExposedData, 0, sizeof(ExposedData));
    for (u32 i=0; i<video::EVDF_COUNT; ++i)
        FeatureEnabled[i]=true;
 
    InitMaterial2D.AntiAliasing=video::EAAM_OFF;
    InitMaterial2D.Lighting=false;
    InitMaterial2D.ZWriteEnable=false;
    InitMaterial2D.ZBuffer=video::ECFN_DISABLED;
    InitMaterial2D.UseMipMaps=false;
    for (u32 i=0; i<video::MATERIAL_MAX_TEXTURES; ++i)
    {
        InitMaterial2D.TextureLayer[i].BilinearFilter=false;
        InitMaterial2D.TextureLayer[i].TextureWrapU=video::ETC_REPEAT;
        InitMaterial2D.TextureLayer[i].TextureWrapV=video::ETC_REPEAT;
    }
    OverrideMaterial2D=InitMaterial2D;      --steps;
                break;
            case 1: // buffer size
                if (attribs[9]>16)
                {
                    attribs[9]-=8;
                }
                else
                    --steps;
                break;
            default:
                os::Printer::log("Could not get config for OpenGL-ES2 display.");
                return;
            }
        }
        if (params.AntiAlias && !attribs[17])
            os::Printer::log("No multisampling.");
        if (params.WithAlphaChannel && !attribs[7])
            os::Printer::log("No alpha.");
        if (params.Stencilbuffer && !attribs[15])
            os::Printer::log("No stencil buffer.");
        if (params.ZBufferBits > attribs[13])
            os::Printer::log("No full depth buffer.");
        if (params.Bits > attribs[9])
            os::Printer::log("No full color buffer.");
        os::Printer::log(" Creating EglSurface with nativeWindow...");
        EglSurface = eglCreateWindowSurface(EglDisplay, config, EglWindow, NULL);
        if (EGL_NO_SURFACE == EglSurface)
        {
            os::Printer::log("FAILED\n");
            EglSurface = eglCreateWindowSurface(EglDisplay, config, NULL, NULL);
            os::Printer::log("Creating EglSurface without nativeWindows...");
        }
        else
            os::Printer::log("SUCCESS\n");
        if (EGL_NO_SURFACE == EglSurface)
        {
            os::Printer::log("FAILED\n");
            os::Printer::log("Could not create surface for OpenGL-ES2 display.");
        }
        else
            os::Printer::log("SUCCESS\n");
 
#ifdef EGL_VERSION_1_2
        if (minorVersion>1)
            eglBindAPI(EGL_OPENGL_ES_API);
#endif
        os::Printer::log("Creating EglContext...");
        EglContext = eglCreateContext(EglDisplay, config, EGL_NO_CONTEXT, contextAttrib);
        if (EGL_NO_CONTEXT == EglContext)
        {
            os::Printer::log("FAILED\n");
            os::Printer::log("Could not create Context for OpenGL-ES2 display.");
        }
 
        eglMakeCurrent(EglDisplay, EglSurface, EglSurface, EglContext);
        if (testEGLError())
        {
            os::Printer::log("Could not make Context current for OpenGL-ES2 display.");
        }
 
        genericDriverInit(params.WindowSize, params.Stencilbuffer);
 
        // set vsync
        if (params.Vsync)
            eglSwapInterval(EglDisplay, 1);
#elif defined(GL_ES_VERSION_2_0)
        glGenFramebuffers(1, &ViewFramebuffer);
        glGenRenderbuffers(1, &ViewRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, ViewRenderbuffer);
 
#if defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_)
        ExposedData.OGLESIPhone.AppDelegate = Device;
        Device->displayInitialize(&ExposedData.OGLESIPhone.Context, &ExposedData.OGLESIPhone.View);
#endif
 
        GLint backingWidth;
        GLint backingHeight;
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
 
        glGenRenderbuffers(1, &ViewDepthRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, ViewDepthRenderbuffer);
 
        GLenum depthComponent = GL_DEPTH_COMPONENT16;
 
        if (params.ZBufferBits >= 24)
            depthComponent = GL_DEPTH_COMPONENT24_OES;
 
        glRenderbufferStorage(GL_RENDERBUFFER, depthComponent, backingWidth, backingHeight);
 
        glBindFramebuffer(GL_FRAMEBUFFER, ViewFramebuffer);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ViewRenderbuffer);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ViewDepthRenderbuffer);
 
        core::dimension2d<u32> WindowSize(backingWidth, backingHeight);
        CNullDriver::ScreenSize = WindowSize;
        CNullDriver::ViewPort = core::rect<s32>(core::position2d<s32>(0,0), core::dimension2di(WindowSize));
 
        genericDriverInit(WindowSize, params.Stencilbuffer);
#endif
 
    //Recreate Textures
    for (u32 i=0; i<Textures.size(); ++i)
        ((COGLES2Texture*)(Textures[i].Surface))->recreate();
}
Recreate method for COGLES2Texture:

Code: Select all

void COGLES2Texture::recreate(){
    glGenTextures(1, &TextureName);
    uploadTexture(true, NULL);
    regenerateMipMapLevels();
}
The method gets called on the APP_CMD_RESUME event.
I've tried it with a modified version of the UserInterface Example:
Image

But after pressing home and returning to the app the gui is no longer visible (but reacts on input):
Image

I've already spent days trying to fix this with no success. Can anybody help me please?

Thank you very much in advance.
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Android OpenGL ES Context lost

Post by Nadro »

Please use the latest ogl-es branch. This bug - context lost after resume is already fixed :) I applied commit related to this issue few days ago.

BTW. I'm not sure if you know but in ogl-es branch we provide support for Android. Android.mk for Irrlicht is available in source/Irrlicht/Android. Example no. 17 already support android too.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
porcus
Posts: 149
Joined: Sun May 27, 2007 6:24 pm
Location: Germany

Re: Android OpenGL ES Context lost

Post by porcus »

@Nadro
Thank you very much! It works now very well. :D
Btw.: Perhaps you are interested in the following modifications?: http://irrlicht.sourceforge.net/forum/v ... =2&t=49241
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Android OpenGL ES Context lost

Post by Nadro »

Thanks for it, I'll try to implement this really nice stuff soon :)
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
xiejianjun417
Posts: 2
Joined: Tue Aug 16, 2016 3:28 am

Re: Android OpenGL ES Context lost

Post by xiejianjun417 »

Hi, @Nadro
I have the same problem, but the version of irrlicht is 1.7.3, and I don't want to change irrlicht to new one version, so can you tell me how you fix this problem?
thanks very much.
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Android OpenGL ES Context lost

Post by CuteAlien »

@xiejianjun417: Irrlicht 1.7.3 doesn't have ogl-es or Android support. So I'm not sure what you mean. The only Irrlicht version where this is implemented so far is the ogl_es branch in svn.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
xiejianjun417
Posts: 2
Joined: Tue Aug 16, 2016 3:28 am

Re: Android OpenGL ES Context lost

Post by xiejianjun417 »

CuteAlien wrote:@xiejianjun417: Irrlicht 1.7.3 doesn't have ogl-es or Android support. So I'm not sure what you mean. The only Irrlicht version where this is implemented so far is the ogl_es branch in svn.
I find the version of irrlicht in IrrCompileConfig.h,

Code: Select all

//! Irrlicht SDK Version
#define IRRLICHT_VERSION_MAJOR 1
#define IRRLICHT_VERSION_MINOR 7
#define IRRLICHT_VERSION_REVISION 0
and because I'm a learner, so I don't quite understand.
But I have solved my problem, thanks for you and your reply.
I use GLSurfaceView.setPreserveEGLContextOnPause(true) to prevent opengl context to destroy, and change the elements of irrlicht with GLSurfaceView.queueEvent.
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Android OpenGL ES Context lost

Post by CuteAlien »

Ah ok. But that was never really released (still isn't). Basically there is only one development branch right now with Android support and that is the ogl_es branch in svn. Usual fix is to update your version. Probably the easiest solution and you also get all other fixes made in the meantime.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Android OpenGL ES Context lost

Post by Nadro »

@xiejianjun417
It looks like you use an unofficial Android port for v1.7.3, so I can just recommend to switch to official ogl-es branch.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Post Reply