Opengls eglCreateWindowSurface GL Error EGL_BAD_ALLOC

Jitesh Dalsaniya picture Jitesh Dalsaniya · Mar 30, 2016 · Viewed 7.3k times · Source

I am getting eglCreateWindowSurface GL Error EGL_BAD_ALLOC when open app first time after installing in Samsung Galaxy S6 and same code working fine in other device.

I tried to clean memory and destroy texture and deinitialize all opengl object on destroy but that cant help me.

03-30 09:21:32.983 21942-26083/com.example E/TextureSurfaceRenderer: createContext: EGL10.EGL_YES_CONTEXT com.google.android.gles_jni.GLImpl@24406d0
03-30 09:21:32.983 21942-26083/com.example E/libEGL: eglCreateWindowSurface: native_window_api_connect (win=0x7f7b100e10) failed (0xffffffea) (already connected to another API?)
03-30 09:21:32.983 21942-26083/com.example E/libEGL: eglCreateWindowSurface:485 error 3003 (EGL_BAD_ALLOC)
03-30 09:21:32.993 21942-26083/com.example E/GL Error:: EGL_BAD_ALLOC

Here is my code.

import android.graphics.SurfaceTexture;
import android.opengl.GLUtils;
import android.os.Handler;
import android.util.Log;

import javax.microedition.khronos.egl.*;

/**
 * Renderer which initializes OpenGL 2.0 context on a passed surface and starts
 * a rendering thread
 * 
 * This class has to be subclassed to be used properly
 */
public abstract class TextureSurfaceRenderer implements Runnable {
    private static final int EGL_OPENGL_ES2_BIT = 4;
    private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
    private static final String TAG = TextureSurfaceRenderer.class.getSimpleName();
    protected final SurfaceTexture texture;
    protected Handler myHandler;
    private EGL10 egl;
    private EGLDisplay eglDisplay;
    private EGLContext eglContext;
    private EGLSurface eglSurface;

    protected int width;
    protected int height;
    private boolean running;

    /**
     * @param texture
     *            Surface texture on which to render. This has to be called
     *            AFTER the texture became available
     * @param width
     *            Width of the passed surface
     * @param height
     *            Height of the passed surface
     */
    public TextureSurfaceRenderer(SurfaceTexture texture, int width, int height,Handler myHandler) {
        this.myHandler = myHandler;
        this.texture = texture;
        this.width = width;
        this.height = height;
        this.running = true;
        Thread thrd = new Thread(this);
        thrd.start();
    }

    @Override
    public void run() {
        initGL();
        if(eglSurface != null){
            initGLComponents();
            Log.d(TAG, "OpenGL init OK.");

            while (running) {
                long loopStart = System.currentTimeMillis();
                pingFps();
                boolean isDraw = draw();
//          Log.e(TAG, "eglSwapBuffers Before Draw " + isDraw);
                if (isDraw) {
                    if(!egl.eglSwapBuffers(eglDisplay, eglSurface)){
                        int error = egl.eglGetError();
                        Log.e(TAG, "eglSwapBuffers Error " + GLUtils.getEGLErrorString(error));
                    }

                }
                // Targeting 60 fps, no need for faster
                long waitDelta = 16 - (System.currentTimeMillis() - loopStart);
                if (waitDelta > 0) {
                    try {
                        Thread.sleep(waitDelta);
                    } catch (InterruptedException e) {
                        MyApplication.getInstance().trackException(e);
                        continue;
                    }
                }
            }

            deInitGLComponents();
            deinitGL();
        } else {
            Log.e(TAG, "Egl Surface is null " + GLUtils.getEGLErrorString(egl.eglGetError()));
        }
    }

    /**
     * Main draw function, subclass this and add custom drawing code here. The
     * rendering thread will attempt to limit FPS to 60 to keep CPU usage low.
     */
    protected abstract boolean draw();

    /**
     * OpenGL component initialization funcion. This is called after OpenGL
     * context has been initialized on the rendering thread. Subclass this and
     * initialize shaders / textures / other GL related components here.
     */
    public abstract void initGLComponents();
    public abstract void deInitGLComponents();

    private long lastFpsOutput = 0;
    private int frames;

    private void pingFps() {
        if (lastFpsOutput == 0)
            lastFpsOutput = System.currentTimeMillis();

        frames++;

        if (System.currentTimeMillis() - lastFpsOutput > 1000) {
            Log.d(TAG, "FPS: " + frames);
            lastFpsOutput = System.currentTimeMillis();
            frames = 0;
        }
    }

    /**
     * Call when activity pauses. This stops the rendering thread and
     * deinitializes OpenGL.
     */
    public void onPause() {
        running = false;
    }

    private void initGL() {
        egl = (EGL10) EGLContext.getEGL();
        eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

        int[] version = new int[2];
        egl.eglInitialize(eglDisplay, version);
        EGLConfig eglConfig = chooseEglConfig();
        eglContext = createContext(egl, eglDisplay, eglConfig);

        eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, texture,
                null); // Here I am getting null eglSurface first Time.
        if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) {
            myHandler.sendEmptyMessage(0);
            Log.e("GL Error: "
                    ,""+ GLUtils.getEGLErrorString(egl.eglGetError()));
            return;
        }

        if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
            myHandler.sendEmptyMessage(0);
            Log.e("GL Make current error: "
                    , "" + GLUtils.getEGLErrorString(egl.eglGetError()));
            return;
        }
    }

    private void deinitGL() {
        egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE,
                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
        egl.eglDestroySurface(eglDisplay, eglSurface);
        egl.eglDestroyContext(eglDisplay, eglContext);
        egl.eglTerminate(eglDisplay);
        Log.d(TAG, "OpenGL deinit OK.");
    }

    private EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay,
            EGLConfig eglConfig) {
        int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
        EGLContext eglContext = egl.eglCreateContext(eglDisplay, eglConfig,
                EGL10.EGL_NO_CONTEXT, attribList);
        if(eglContext.getGL().equals(EGL10.EGL_NO_CONTEXT)){
            Log.e(TAG, "createContext: EGL10.EGL_NO_CONTEXT");
        } else {
            Log.e(TAG, "createContext: EGL10.EGL_YES_CONTEXT " + eglContext.getGL().toString());
        }
        return eglContext;
    }

    private EGLConfig chooseEglConfig() {
        int[] configsCount = new int[1];
        EGLConfig[] configs = new EGLConfig[1];
        int[] configSpec = getConfig();

        if (!egl.eglChooseConfig(eglDisplay, configSpec, configs, 1,
                configsCount)) {
            Log.e(TAG , "Failed to choose config: " + GLUtils.getEGLErrorString(egl.eglGetError()));
        } else if (configsCount[0] > 0) {
            return configs[0];
        }
        return null;
    }

    private int[] getConfig() {
        return new int[] { EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
                EGL10.EGL_RED_SIZE, 8, EGL10.EGL_GREEN_SIZE, 8,
                EGL10.EGL_BLUE_SIZE, 8, EGL10.EGL_ALPHA_SIZE, 8,
                EGL10.EGL_DEPTH_SIZE, 0, EGL10.EGL_STENCIL_SIZE, 0, EGL10.EGL_NONE };
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        running = false;
    }
}

Answer

Jon Goodwin picture Jon Goodwin · Jan 18, 2019

Workaround-to-losing-the-opengl-context-when-android-pauses

So your Activity's onPause() should look like this:

@Override
public void onPause() {
    eglSurface.setVisibility(View.GONE);
    super.onPause();
    ...
}

And you restore your GLSurfaceView to the hierarchy not from onResume() but from onWindowFocusChanged() :

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && eglSurface.getVisibility() == View.GONE) {
         eglSurface.setVisibility(View.VISIBLE);
    }
    ...
}

See also:

eglCreateWindowSurface: native_window_api_connect failed

fixing-common-android-lifecycle-issues

Links

GLSurfaceView, GLSurfaceView.Renderer