androidandroid-canvassurfaceviewegl

EGL_BAD_ALLOC after switching SurfaceView Surface from canvas to OpenGL


I'm not able to lock Surface to EGL (using eglCreateWindowSurface()) after drawing to it with Surface.lockCanvas(null) even if I released it with Surface.unlockCanvasAndPost()

error code:

EGLNativeWindowType 0x61dff830 already connected to another API
eglCreateWindowSurface:414 error 3003 (EGL_BAD_ALLOC)

I do not need to keep on the surface the drawing done by the canvas, I only need to be able to update the SurfaceView surface and show it

If I don't draw to the Surface Before using EGL it works as it should, and if I only put:

Canvas c = mSurface.lockCanvas(null);
c.drawColor(Color.RED);
mSurface.unlockCanvasAndPost(c);

...I get this error

Is this the expected behaviour? This happens both on a real device 4.1.2 and on AVD API25

Is there a way to completely unlock a Surface from Canvas drawing (even with native if necessary)?

The opposite just works (EGL to Canvas)

Same behaviour with TextureView

Workaround:

If in my TextureView I destroy the local Surface object and recreate it from the same SurfaceTexture owned by the previous Surface with new Surface(mOldSurfaceTexture), the error does not appear.


Solution

  • This is the expected behaviour, as stated on the official documentation

    When you lock a Surface for Canvas access, the "CPU renderer" connects to the producer side of the BufferQueue and does not disconnect until the Surface is destroyed. Most other producers (like GLES) can be disconnected and reconnected to a Surface, but the Canvas-based "CPU renderer" cannot. This means you can't draw on a surface with GLES or send it frames from a video decoder if you've ever locked it for a Canvas.

    https://source.android.com/devices/graphics/arch-sh.html#canvas

    So the only way is to use the workaround I posted in my question

    ------------------ EDIT: -----------------

    I've found another way to do it: if you need to draw using a Canvas, you have to create an EGL/OpenGL context, and a Canvas from a Bitmap(that you have to create of the same size of your surface, So you can draw to this canvas, load the bitmap as opengl texture and draw it from OpenGL