Search code examples
androidglsurfaceviewtextureview

TextureView vs. GLSurfaceView or How to use GLSurfaceView with EGL14


I am getting confused with EGL.

My GLSurfaceView creates an EGLContext. Now I create a shared context. Now I need to use a EGLExtension.

The Method I have to use is called (>=API18):

EGLExt.eglPresentationTimeANDROID(android.opengl.EGLDisplay display, android.opengl.EGLSurface surface, long time);

The Problem is, that the GLSurfaceView does only creates javax.microedition.khronos.egl.EGLContext s.

Which tells me, NOT to use GLSurfaceView. So I tried TextureView, which is slightly similar, with the difference that you have to handle your own EGL stuff. Which is good for that purpose.

But: The TextureView is slower, at least it looked like that, so I recorded some diagrams with the Method Profiler:

Here the TextureView with own EGL Handling: enter image description here The Thread on the top is a clock that wakes the Thread in the middle, which renders onto the TextureView. The main Thread will be called after that, for redrawing the TextureView.

... and here the GLSurfaceView with their own EGL Handling The clock is in the middle this time, it calls the Thread on the top to render my image into a framebuffer, which I give directly into the SurfaceView (RENDERMODE_WHEN_DIRTY) and call requestRender to request the view to render. enter image description here

As you can see with a short look already that with the GLSurfaceView it looks way cleaner that with the TextureView.

On both Examples I havn't had anything else on the screen and they rendered exactly the same Meshes with the same shader.

To my question: Is there a way to use GLSurfaceView with EGL14 Contexts?

Did I do something wrong?


Solution

  • What you probably want to do is use a plain SurfaceView.

    Here's the short version:

    • SurfaceView has two parts, the Surface and a bit of fake stuff in the View. The Surface gets passed directly to the surface compositor (SurfaceFlinger), so when you draw on it with OpenGL there's relatively little overhead. This makes it fast, but it also makes it not play quite right with the View hierarchy, because the Surface is on one layer and the View-based UI is on a different layer.
    • TextureView also has two parts, but the part you draw on lives behind the scenes (that's where the SurfaceTexture comes in). When the frame is complete, the stuff you drew is blitted onto the View layer. The GPU can do this quickly, but "some work" is always slower than "no work".
    • GLSurfaceView is a SurfaceView with a wrapper class that does all the EGL setup and inter-thread messaging for you.

    Edit: the long version is available here.

    If you can do the GL/EGL setup and thread management yourself -- which, if you're now running on a TextureView, you clearly can -- then you should probably use a plain SurfaceView.

    Having said all that, it should be possible to make your original code work with GLSurfaceView. I expect you want to call eglPresentationTimeANDROID() on the EGL context that's shared with the GLSurfaceView, not from within GLSurfaceView itself, so it doesn't matter that GLSurfaceView is using EGL10 internally. What matters for sharing the context is the context client version (e.g. GLES2 vs. GLES3), not the EGL interface version used to configure the context.

    You can see examples of all of this working in Grafika. In particular:

    • "Show + capture camera" uses a GLSurfaceView, the camera, and the video encoder. Note the EGL context is shared. The example is convoluted and somewhat painful, mostly because it's deliberately trying to use GLSurfaceView and a shared EGL context. (Update: note this issue about race conditions with shared contexts.)
    • "Play video (TextureView)" and "Basic GL in TextureView" show TextureView in action.
    • "Record GL app with FBO" uses a plain SurfaceView.