Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15e1c6dc authored by Jack Palevich's avatar Jack Palevich
Browse files

Allow GLSurfaceView clients to customize EGL Surfaces and Contexts.

This API is hidden for now, will expose once it's been tested more.
parent 1bd888ba
Loading
Loading
Loading
Loading
+184 −94
Original line number Diff line number Diff line
@@ -271,17 +271,51 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
     * @param renderer the renderer to use to perform OpenGL drawing.
     */
    public void setRenderer(Renderer renderer) {
        if (mGLThread != null) {
            throw new IllegalStateException(
                    "setRenderer has already been called for this instance.");
        }
        checkRenderThreadState();
        if (mEGLConfigChooser == null) {
            mEGLConfigChooser = new SimpleEGLConfigChooser(true);
        }
        if (mEGLContextFactory == null) {
            mEGLContextFactory = new DefaultContextFactory();
        }
        if (mEGLWindowSurfaceFactory == null) {
            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
        }
        mGLThread = new GLThread(renderer);
        mGLThread.start();
    }

    /**
     * @hide
     * Install a custom EGLContextFactory.
     * <p>If this method is
     * called, it must be called before {@link #setRenderer(Renderer)}
     * is called.
     * <p>
     * If this method is not called, then by default
     * a context will be created with no shared context and
     * with a null attribute list.
     */
    public void setContextFactory(EGLContextFactory factory) {
        checkRenderThreadState();
        mEGLContextFactory = factory;
    }

    /**
     * @hide
     * Install a custom EGLWindowSurfaceFactory.
     * <p>If this method is
     * called, it must be called before {@link #setRenderer(Renderer)}
     * is called.
     * <p>
     * If this method is not called, then by default
     * a window surface will be created with a null attribute list.
     */
    public void setWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
        checkRenderThreadState();
        mEGLWindowSurfaceFactory = factory;
    }

    /**
     * Install a custom EGLConfigChooser.
     * <p>If this method is
@@ -294,10 +328,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
     * @param configChooser
     */
    public void setEGLConfigChooser(EGLConfigChooser configChooser) {
        if (mGLThread != null) {
            throw new IllegalStateException(
                    "setRenderer has already been called for this instance.");
        }
        checkRenderThreadState();
        mEGLConfigChooser = configChooser;
    }

@@ -577,6 +608,56 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
        void onDrawFrame(GL10 gl);
    }

    /**
     * @hide
     * An interface for customizing the eglCreateContext and eglDestroyContext calls.
     * <p>
     * This interface must be implemented by clients wishing to call
     * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
     */
    public interface EGLContextFactory {
        EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
        void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
    }

    private static class DefaultContextFactory implements EGLContextFactory {

        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
            return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
        }

        public void destroyContext(EGL10 egl, EGLDisplay display,
                EGLContext context) {
            egl.eglDestroyContext(display, context);
        }
    }

    /**
     * @hide
     * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
     * <p>
     * This interface must be implemented by clients wishing to call
     * {@link GLSurfaceView#setEGLContextCreator(EGLContextCreator)}
     */
    public interface EGLWindowSurfaceFactory {
        EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
                Object nativeWindow);
        void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
    }

    private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {

        public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
                EGLConfig config, Object nativeWindow) {
            return egl.eglCreateWindowSurface(display, config, nativeWindow, null);
        }

        public void destroySurface(EGL10 egl, EGLDisplay display,
                EGLSurface surface) {
            egl.eglDestroySurface(display, surface);
        }
    }

    /**
     * An interface for choosing an EGLConfig configuration from a list of
     * potential configurations.
@@ -751,8 +832,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
            * Create an OpenGL ES context. This must be done only once, an
            * OpenGL context is a somewhat heavy object.
            */
            mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig,
                    EGL10.EGL_NO_CONTEXT, null);
            mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);

            mEglSurface = null;
        }
@@ -774,14 +854,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
                 */
                mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                        EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
                mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
            }

            /*
             * Create an EGL surface we can render into.
             */
            mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay,
                    mEglConfig, holder, null);
            mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
                    mEglDisplay, mEglConfig, holder);

            /*
             * Before we can issue GL commands, we need to make sure
@@ -790,7 +870,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
            mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
                    mEglContext);


            GL gl = mEglContext.getGL();
            if (mGLWrapper != null) {
                gl = mGLWrapper.wrap(gl);
@@ -831,14 +910,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
                mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                        EGL10.EGL_NO_SURFACE,
                        EGL10.EGL_NO_CONTEXT);
                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
                mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
                mEglSurface = null;
            }
        }

        public void finish() {
            if (mEglContext != null) {
                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
                mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
                mEglContext = null;
            }
            if (mEglDisplay != null) {
@@ -898,6 +977,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback

        private void guardedRun() throws InterruptedException {
            mEglHelper = new EglHelper();
            try {
                mEglHelper.start();

                GL10 gl = null;
@@ -947,7 +1027,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
                        if (mHasSurface && mWaitingForSurface) {
                            changed = true;
                            mWaitingForSurface = false;
                        mRequestRender = true; // Forces a redraw for RENDERMODE_RENDER_WHEN_DIRTY
                        }
                    }
                    if (needStart) {
@@ -978,13 +1057,14 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
                        mEglHelper.swap();
                    }
                 }

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

        private boolean needToWait() {
            if (mDone) {
@@ -1038,7 +1118,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
            synchronized(this) {
                mHasSurface = false;
                notify();
                while(!mWaitingForSurface) {
                while(!mWaitingForSurface && isAlive()) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
@@ -1149,11 +1229,21 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
        private StringBuilder mBuilder = new StringBuilder();
    }


    private void checkRenderThreadState() {
        if (mGLThread != null) {
            throw new IllegalStateException(
                    "setRenderer has already been called for this instance.");
        }
    }

    private static final Semaphore sEglSemaphore = new Semaphore(1);
    private boolean mSizeChanged = true;

    private GLThread mGLThread;
    private EGLConfigChooser mEGLConfigChooser;
    private EGLContextFactory mEGLContextFactory;
    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
    private GLWrapper mGLWrapper;
    private int mDebugFlags;
}