Skip to content

Latest commit

 

History

History
713 lines (626 loc) · 31.4 KB

3.GLSurfaceView源码解析.md

File metadata and controls

713 lines (626 loc) · 31.4 KB

3.GLSurfaceView源码解析

我感觉还是先看一下源码,了解一下内部的流程,再接着学习其他的OpenGL部分会更合适。

从上一篇文章中GLSurfaceView的使用中可以看到入口是setRenderer()方法,这里就看一下setRenderder(Renderer renderer)方法的实现:

  • Renderer接口
public interface Renderer {
    // surface创建的回调
    void onSurfaceCreated(GL10 gl, EGLConfig config);
    // surface大小改变的回调
    void onSurfaceChanged(GL10 gl, int width, int height);
    // 开始绘制每一帧的回调
    void onDrawFrame(GL10 gl);
}
  • setRenderer()方法
public void setRenderer(Renderer renderer) {
  // 保证setRenderer方法只能被调用一次
  checkRenderThreadState();
  if (mEGLConfigChooser == null) {
      // 设置EGLConfgi,如果不设置就用默认的一个RGB_888的Surface选择器
      mEGLConfigChooser = new SimpleEGLConfigChooser(true);
  }
  if (mEGLContextFactory == null) {
    	// 设置EGLContext工厂,如果不设置就用默认的EGLContext的工厂类,用他来创建EGLContext
      mEGLContextFactory = new DefaultContextFactory();
  }
  if (mEGLWindowSurfaceFactory == null) {
      // 设置EGLSurface工厂,如果不设置就用默认的EGLSurface的工厂类,我们可以通过这个方法来设置让图像渲染到其他地方的surface上,例如textureview上
      mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
  }
  mRenderer = renderer;
  // 创建并开启GLThread,GL线程
  mGLThread = new GLThread(mThisWeakRef);
  mGLThread.start();
}
  • 接下来看一下GLThread的线程的实现,GLThread是GLSurfaceView自带的一个渲染线程,同步的,不会阻塞线程,主要用来执行OpenGL的绘制工作:

    static class GLThread extends Thread {
            GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
                super();
                mWidth = 0;
                mHeight = 0;
                // 连续渲染模式下是true,如果是按需渲染模式就为false,然后通过requesetRender()方法来修改它的值
                mRequestRender = true;
                // 默认的渲染模式
                mRenderMode = RENDERMODE_CONTINUOUSLY;
                mWantRenderNotification = false;
                mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
            }
    
            @Override
            public void run() {
                setName("GLThread " + getId());
                if (LOG_THREADS) {
                    Log.i("GLThread", "starting tid=" + getId());
                }
    
                try {
                    // 具体的run方法,内部实现在下面,所有的核心都在里面,把这个方法单独放到下面说
                    guardedRun();
                } catch (InterruptedException e) {
                    // fall thru and exit normally
                } finally {
                    sGLThreadManager.threadExiting(this);
                }
            }
              // GLSurfaceView的onPause方法会调用到这里
              public void onPause() {
                synchronized (sGLThreadManager) {
                    if (LOG_PAUSE_RESUME) {
                        Log.i("GLThread", "onPause tid=" + getId());
                    }
    
                    mRequestPaused = true;
                    // 这里使用了GLThreadManager这个类,这个类是提供线程同步控制功能的,最后会说这个类,通知EGL线程解除堵塞
                    sGLThreadManager.notifyAll();
                  	// 保证onPause方法执行后GLThread也是pause的状态
                    while ((! mExited) && (! mPaused)) {
                        if (LOG_PAUSE_RESUME) {
                            Log.i("Main thread", "onPause waiting for mPaused.");
                        }
                        try {
                            sGLThreadManager.wait();
                        } catch (InterruptedException ex) {
                            Thread.currentThread().interrupt();
                        }
                    }
                }
            }
            // GLSurfaceView的onResume方法会调用到这里
            public void onResume() {
                synchronized (sGLThreadManager) {
                    if (LOG_PAUSE_RESUME) {
                        Log.i("GLThread", "onResume tid=" + getId());
                    }
                    // 修改状态变量
                    mRequestPaused = false;
                    // 重绘一次
                    mRequestRender = true;
                    mRenderComplete = false;
                    sGLThreadManager.notifyAll();
                  	// 保证onResume执行后,GLThread也是resume的状态
                    while ((! mExited) && mPaused && (!mRenderComplete)) {
                        if (LOG_PAUSE_RESUME) {
                            Log.i("Main thread", "onResume waiting for !mPaused.");
                        }
                        try {
                            sGLThreadManager.wait();
                        } catch (InterruptedException ex) {
                            Thread.currentThread().interrupt();
                        }
                    }
                }
            }
        }
  • guardeRun()方法:

    核心就是用一个while true循环,内部加了各种场景的判断,最后会调用renderer.onDrawFrame()方法进行绘制。

    private void guardedRun() throws InterruptedException {
                //GL帮助类,内部建立GL环境
                mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
                mHaveEglContext = false;
                mHaveEglSurface = false;
                mWantRenderNotification = false;
    
                try {
                    GL10 gl = null;
                    boolean createEglContext = false;
                    boolean createEglSurface = false;
                    boolean createGlInterface = false;
                    boolean lostEglContext = false;
                    boolean sizeChanged = false;
                    boolean wantRenderNotification = false;
                    boolean doRenderNotification = false;
                    boolean askedToReleaseEglContext = false;
                    int w = 0;
                    int h = 0;
                    Runnable event = null;
                    Runnable finishDrawingRunnable = null;
    
                    while (true) {
                        synchronized (sGLThreadManager) {
                            while (true) {
                                // 外部请求退出
                                if (mShouldExit) {
                                    return;
                                // 如果还有GL线程中要处理的事件没处理完,就先处理事件
                                if (! mEventQueue.isEmpty()) {
                                    event = mEventQueue.remove(0);
                                    break;
                                }
                                // 更新onResume和onPause时的状态变化
                                // Update the pause state.
                                boolean pausing = false;
                                if (mPaused != mRequestPaused) {
                                    pausing = mRequestPaused;
                                    mPaused = mRequestPaused;
                                    // onPause和onResume的时候都会用wait方法等待GL线程的响应,这时候主线程堵塞。需要调用notifyAll
                                    sGLThreadManager.notifyAll();
                                    if (LOG_PAUSE_RESUME) {
                                        Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
                                    }
                                }
                                // 需要释放EGLContext
                                // Do we need to give up the EGL context?
                                if (mShouldReleaseEglContext) {
                                    if (LOG_SURFACE) {
                                        Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
                                    }
                                    stopEglSurfaceLocked();
                                    stopEglContextLocked();
                                    mShouldReleaseEglContext = false;
                                    askedToReleaseEglContext = true;
                                }
    		                    // 如果EGLContext丢失,需要销毁EGLSurface和EGLContext
                                // Have we lost the EGL context?
                                if (lostEglContext) {
                                    stopEglSurfaceLocked();
                                    stopEglContextLocked();
                                    lostEglContext = false;
                                }
                                // 如果onPause了并且当前GLSurface已经存在了,就销毁EGLSurface
                                // When pausing, release the EGL surface:
                                if (pausing && mHaveEglSurface) {
                                    if (LOG_SURFACE) {
                                        Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
                                    }
                                    stopEglSurfaceLocked();
                                }
                                // 接受了onPuase信号,并且当前EGLContext存在时,需要根据用户的设置来决定是否销毁EGLContext
                                // When pausing, optionally release the EGL Context:
                                if (pausing && mHaveEglContext) {
                                    GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                                    boolean preserveEglContextOnPause = view == null ?
                                            false : view.mPreserveEGLContextOnPause;
                                    if (!preserveEglContextOnPause) {
                                        stopEglContextLocked();
                                        if (LOG_SURFACE) {
                                            Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
                                        }
                                    }
                                }
    														
                                // Have we lost the SurfaceView surface?
                                if ((! mHasSurface) && (! mWaitingForSurface)) {
                                    if (LOG_SURFACE) {
                                        Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId());
                                    }
                                    if (mHaveEglSurface) {
                                        stopEglSurfaceLocked();
                                    }
                                    mWaitingForSurface = true;
                                    mSurfaceIsBad = false;
                                    sGLThreadManager.notifyAll();
                                }
    
                                // Have we acquired the surface view surface?
                                if (mHasSurface && mWaitingForSurface) {
                                    if (LOG_SURFACE) {
                                        Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId());
                                    }
                                    mWaitingForSurface = false;
                                    sGLThreadManager.notifyAll();
                                }
    
                                if (doRenderNotification) {
                                    if (LOG_SURFACE) {
                                        Log.i("GLThread", "sending render notification tid=" + getId());
                                    }
                                    mWantRenderNotification = false;
                                    doRenderNotification = false;
                                    mRenderComplete = true;
                                    sGLThreadManager.notifyAll();
                                }
    
                                if (mFinishDrawingRunnable != null) {
                                    finishDrawingRunnable = mFinishDrawingRunnable;
                                    mFinishDrawingRunnable = null;
                                }
                                // readyToDraw()方法内部会判断是否已经pause或者mRequestRender是否是true以及是否是主动渲染模式。如果是被动渲染的模式mRequestRender就会是false,只有调用requestRender()方法后才会是true,如果是主动渲染模式readyToDraw()就不用根据mRequestRender来判断。
                                // Ready to draw?
                                if (readyToDraw()) {
                                    // 没有EGLContext就去调用EGLHelper来创建,第一次会走到这里先创建EGLContext
                                    // If we don't have an EGL context, try to acquire one.
                                    if (! mHaveEglContext) {
                                        if (askedToReleaseEglContext) {
                                            askedToReleaseEglContext = false;
                                        } else {
                                            try {
                                                // 后面会看这个EglHelper.start()方法,初始化EGL环境,内部会去创建各种GL EGL EGLContext EGLDisplay等环境
                                                mEglHelper.start();
                                            } catch (RuntimeException t) {
                                                sGLThreadManager.releaseEglContextLocked(this);
                                                throw t;
                                            }
                                          	// 创建完后把该变量变成true
                                            mHaveEglContext = true;
                                            createEglContext = true;
    
                                            sGLThreadManager.notifyAll();
                                        }
                                    }
    
                                    if (mHaveEglContext && !mHaveEglSurface) {
                                        mHaveEglSurface = true;
                                        createEglSurface = true;
                                        createGlInterface = true;
                                        sizeChanged = true;
                                    }
    
                                    if (mHaveEglSurface) {
                                        if (mSizeChanged) {
                                            sizeChanged = true;
                                            w = mWidth;
                                            h = mHeight;
                                            mWantRenderNotification = true;
                                            if (LOG_SURFACE) {
                                                Log.i("GLThread",
                                                        "noticing that we want render notification tid="
                                                        + getId());
                                            }
    
                                            // Destroy and recreate the EGL surface.
                                            createEglSurface = true;
    
                                            mSizeChanged = false;
                                        }
                                        mRequestRender = false;
                                        sGLThreadManager.notifyAll();
                                        if (mWantRenderNotification) {
                                            wantRenderNotification = true;
                                        }
                                        break;
                                    }
                                } else {
                                    if (finishDrawingRunnable != null) {
                                        Log.w(TAG, "Warning, !readyToDraw() but waiting for " +
                                                "draw finished! Early reporting draw finished.");
                                        finishDrawingRunnable.run();
                                        finishDrawingRunnable = null;
                                    }
                                }
                                // By design, this is the only place in a GLThread thread where we wait().
                                sGLThreadManager.wait();
                            }
                        } // end of synchronized(sGLThreadManager)
    
                        if (event != null) {
                           // 执行event的run方法,这个event是GLSurfaceView中提供的queueEvent(runnable run)实现的,该方法会把runnable添加到EventQueue中,然后再在这里去执行该runnable
                            event.run();
                            event = null;
                            continue;
                        }
    
                        if (createEglSurface) {
                            // EglHelper创建EglSurface                      
                            if (mEglHelper.createSurface()) {
                                synchronized(sGLThreadManager) {
                                    mFinishedCreatingEglSurface = true;
                                    sGLThreadManager.notifyAll();
                                }
                            } else {
                                synchronized(sGLThreadManager) {
                                    mFinishedCreatingEglSurface = true;
                                    mSurfaceIsBad = true;
                                    sGLThreadManager.notifyAll();
                                }
                                continue;
                            }
                            createEglSurface = false;
                        }
    
                        if (createGlInterface) {
                            gl = (GL10) mEglHelper.createGL();
    
                            createGlInterface = false;
                        }
    
                        if (createEglContext) {
                            if (LOG_RENDERER) {
                                Log.w("GLThread", "onSurfaceCreated");
                            }
                            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                            if (view != null) {
                                try {
                                    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated");
                                  	// 回调onSurfaceCreated
                                    view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
                                } finally {
                                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                                }
                            }
                            createEglContext = false;
                        }
    
                        if (sizeChanged) {
                            if (LOG_RENDERER) {
                                Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
                            }
                            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                            if (view != null) {
                                try {
                                    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceChanged");
                                    // 回调onSurfaceChangeed
                                    view.mRenderer.onSurfaceChanged(gl, w, h);
                                } finally {
                                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                                }
                            }
                            sizeChanged = false;
                        }
    
                        if (LOG_RENDERER_DRAW_FRAME) {
                            Log.w("GLThread", "onDrawFrame tid=" + getId());
                        }
                        {
                            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                            if (view != null) {
                                // 调用renderder.onDrawFrame方法开始绘制
                                try {
                                    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
                                    view.mRenderer.onDrawFrame(gl);
                                    if (finishDrawingRunnable != null) {
                                        finishDrawingRunnable.run();
                                        finishDrawingRunnable = null;
                                    }
                                } finally {
                                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                                }
                            }
                        }
                        int swapError = mEglHelper.swap();
                        switch (swapError) {
                            case EGL10.EGL_SUCCESS:
                                break;
                            case EGL11.EGL_CONTEXT_LOST:
                                if (LOG_SURFACE) {
                                    Log.i("GLThread", "egl context lost tid=" + getId());
                                }
                                lostEglContext = true;
                                break;
                            default:
                                // Other errors typically mean that the current surface is bad,
                                // probably because the SurfaceView surface has been destroyed,
                                // but we haven't been notified yet.
                                // Log the error to help developers understand why rendering stopped.
                                EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError);
    
                                synchronized(sGLThreadManager) {
                                    mSurfaceIsBad = true;
                                    sGLThreadManager.notifyAll();
                                }
                                break;
                        }
    
                        if (wantRenderNotification) {
                            doRenderNotification = true;
                            wantRenderNotification = false;
                        }
                    }
    
                } finally {
                    /*
                     * clean-up everything...
                     */
                    synchronized (sGLThreadManager) {
                        stopEglSurfaceLocked();
                        stopEglContextLocked();
                    }
                }
            }

接着看一下上面提到的几个类:

  • EGLHelper
/**
     * An EGL helper class.
     */

    private static class EglHelper {
        public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
            mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
        }

        /**
         * 初始化EGL环境,创建EGL EGLContext EGLDisplay
         * Initialize EGL for a given configuration spec.
         * @param configSpec
         */
        public void start() {
            if (LOG_EGL) {
                Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
            }
            /*
             * Get an EGL instance
             */
            mEgl = (EGL10) EGLContext.getEGL();

            /*
             * Get to the default display.
             */
            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
                throw new RuntimeException("eglGetDisplay failed");
            }

            /*
             * We can now initialize EGL for that display
             */
            int[] version = new int[2];
            if(!mEgl.eglInitialize(mEglDisplay, version)) {
                throw new RuntimeException("eglInitialize failed");
            }
            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
            if (view == null) {
                mEglConfig = null;
                mEglContext = null;
            } else {
                // 使用setRender方法中setEGLConfigChooser和setEGLContextFactory中设置的部分来创建
                mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);

                /*
                * Create an EGL context. We want to do this as rarely as we can, because an
                * EGL context is a somewhat heavy object.
                */
                mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
            }
            if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
                mEglContext = null;
                throwEglException("createContext");
            }
            if (LOG_EGL) {
                Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
            }

            mEglSurface = null;
        }

        /**
         * 创建EGLSurface
         * Create an egl surface for the current SurfaceHolder surface. If a surface
         * already exists, destroy it before creating the new surface.
         *
         * @return true if the surface was created successfully.
         */
        public boolean createSurface() {
            if (LOG_EGL) {
                Log.w("EglHelper", "createSurface()  tid=" + Thread.currentThread().getId());
            }
            /*
             * Check preconditions.
             */
            if (mEgl == null) {
                throw new RuntimeException("egl not initialized");
            }
            if (mEglDisplay == null) {
                throw new RuntimeException("eglDisplay not initialized");
            }
            if (mEglConfig == null) {
                throw new RuntimeException("mEglConfig not initialized");
            }

            /*
             *  The window size has changed, so we need to create a new
             *  surface.
             */
            destroySurfaceImp();

            /*
             * Create an EGL surface we can render into.
             */
            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
            if (view != null) {
            	// 也是通过EGLWindowSurfaceFactory来创建EGLSurface,如果没有设置就会调用默认的DefaultWindowSurfaceFactory。后面说一下这里
                mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
                        mEglDisplay, mEglConfig, view.getHolder());
            } else {
                mEglSurface = null;
            }

            /*
            将EGLContext上下文加载到当前线程环境
             * Before we can issue GL commands, we need to make sure
             * the context is current and bound to a surface.
             */
            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
                /*
                 * Could not make the context current, probably because the underlying
                 * SurfaceView surface has been destroyed.
                 */
                logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
                return false;
            }

            return true;
        }

        /**
         获取OpenGL ES的编程接口
         * Create a GL object for the current EGL context.
         * @return
         */
        GL createGL() {
            GL gl = mEglContext.getGL();
            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
            if (view != null) {
                if (view.mGLWrapper != null) {
                    gl = view.mGLWrapper.wrap(gl);
                }

                if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) {
                    int configFlags = 0;
                    Writer log = null;
                    if ((view.mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) {
                        configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR;
                    }
                    if ((view.mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) {
                        log = new LogWriter();
                    }
                    gl = GLDebugHelper.wrap(gl, configFlags, log);
                }
            }
            return gl;
        }
        public void destroySurface() {
            if (LOG_EGL) {
                Log.w("EglHelper", "destroySurface()  tid=" + Thread.currentThread().getId());
            }
            destroySurfaceImp();
        }

        private void destroySurfaceImp() {
            if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
                mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                        EGL10.EGL_NO_SURFACE,
                        EGL10.EGL_NO_CONTEXT);
                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                if (view != null) {
                	// EGLWindowSurfaceFactory除了创建EGLSurface还有销毁的功能
                    view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
                }
                mEglSurface = null;
            }
        }
        private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
        EGL10 mEgl;
        EGLDisplay mEglDisplay;
        EGLSurface mEglSurface;
        EGLConfig mEglConfig;
        EGLContext mEglContext;

    }
  • EGLWindowSurfaceFactory
    /**
     * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
     * <p>
     * This interface must be implemented by clients wishing to call
     * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
     */
    public interface EGLWindowSurfaceFactory {
        /**
         *  @return null if the surface cannot be constructed.
         */
        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) {
            EGLSurface result = null;
            try {
                result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
            } catch (IllegalArgumentException e) {
                // This exception indicates that the surface flinger surface
                // is not valid. This can happen if the surface flinger surface has
                // been torn down, but the application has not yet been
                // notified via SurfaceHolder.Callback.surfaceDestroyed.
                // In theory the application should be notified first,
                // but in practice sometimes it is not. See b/4588890
                Log.e(TAG, "eglCreateWindowSurface", e);
            }
            return result;
        }

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

看到这里我们知道可以自定义WindowSurfaceFactory然后使用其他SurfaceView或者TextureView的Surface来创建EGLSurface,让其把渲染后的内容输出到SurfaceView或者TextureView上显示。

  • GLThreadManager类

    上面看到wait和notifyall的时候sGLThreadManager.notifyAll();都用到了GLThreadManager类。它就是线程同步的锁。

    这个类主要提供的是线程同步控制的功能,因为在GLSurfaceView里面有两个线程: GL线程和调用线程。所以对一些变量必须要进行同步。