GLSurfaceView 源码分析 & EGL 创建过程

Posted 月盡天明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GLSurfaceView 源码分析 & EGL 创建过程相关的知识,希望对你有一定的参考价值。

文章目录

GLSurfaceView 源码分析

基本用法

mGLView.setEGLContextClientVersion(2);
//在setRenderer之前,可以调用以下方法来进行EGL设置
//mGLView.setEGLConfigChooser();    //颜色、深度、模板等等设置
//mGLView.setEGLWindowSurfaceFactory(); //窗口设置
//mGLView.setEGLContextFactory();   //EGLContext设置
//设置渲染器,渲染主要就是由渲染器来决定
mGLView.setRenderer(new GLSurfaceView.Renderer()
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) 
        // surface被创建后需要做的处理
    
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) 
        // 渲染窗口大小发生改变的处理
    
    @Override
    public void onDrawFrame(GL10 gl) 
        // 执行渲染工作
    
);

// RENDERMODE_WHEN_DIRTY表示被动渲染
// RENDERMODE_CONTINUOUSLY表示持续渲染*/
mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

GLSurfaceView 继承自 SurfaceView,实现了SurfaceHolder.Callback2 接口。

SurfaceHolder.Callback

使用 SurfaceView 的时候都会用到这个 Callback 回调。
一共有三个函数

  • surfaceCreated
  • surfaceChanged
  • surfaceDestroyed
    public interface Callback 
        /**
         * 当 surface 首次创建的时候回调
         */
        public void surfaceCreated(SurfaceHolder holder);

        /**
         * 当 surface 的 format 或者 size 发生改变时回调此函数。
         * 在回调surfaceCreated()之后,该函数至少被回调一次
         */
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height);

        /**
         * 在 surface 被销毁之前回调。此函数回调之后就不能在访问 surface 了。
         */
        public void surfaceDestroyed(SurfaceHolder holder);
    

SurfaceHolder.Callback2

  • surfaceRedrawNeeded
  • surfaceRedrawNeededAsync

这两个函数并不常用。

    /**
     * SurfaceHolder.Callback的扩展接口
     */
    public interface Callback2 extends Callback 
        /**
         * Called when the application needs to redraw the content of its
         * surface, after it is resized or for some other reason.  By not
         * returning from here until the redraw is complete, you can ensure that
         * the user will not see your surface in a bad state (at its new
         * size before it has been correctly drawn that way).  This will
         * typically be preceeded by a call to @link #surfaceChanged.
         *
         * As of O, @link #surfaceRedrawNeededAsync may be implemented
         * to provide a non-blocking implementation. If @link #surfaceRedrawNeededAsync
         * is not implemented, then this will be called instead.
         *
         * @param holder The SurfaceHolder whose surface has changed.
         */
        void surfaceRedrawNeeded(SurfaceHolder holder);

        /**
         * An alternative to surfaceRedrawNeeded where it is not required to block
         * until the redraw is complete. You should initiate the redraw, and return,
         * later invoking drawingFinished when your redraw is complete.
         *
         * This can be useful to avoid blocking your main application thread on rendering.
         *
         * As of O, if this is implemented @link #surfaceRedrawNeeded will not be called.
         * However it is still recommended to implement @link #surfaceRedrawNeeded for
         * compatibility with older versions of the platform.
         *
         * @param holder The SurfaceHolder which needs redrawing.
         * @param drawingFinished A runnable to signal completion. This may be invoked
         * from any thread.
         *
         */
        default void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable drawingFinished) 
            surfaceRedrawNeeded(holder);
            drawingFinished.run();
        
    

继续查看 GLSurfaceView的关键代码:

public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 

	  private static final GLThreadManager sGLThreadManager = new GLThreadManager(); // 线程管理类

    private final WeakReference<GLSurfaceView> mThisWeakRef =
            new WeakReference<GLSurfaceView>(this);
    private GLThread mGLThread; // GL 线程
    private Renderer mRenderer; // GLSurfaceView 的回调接口
    private boolean mDetached;
    private EGLConfigChooser mEGLConfigChooser;
    private EGLContextFactory mEGLContextFactory;
    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
    private GLWrapper mGLWrapper;
    private int mDebugFlags;
    private int mEGLContextClientVersion;
    private boolean mPreserveEGLContextOnPause;


    public GLSurfaceView(Context context) 
        super(context);
        init();
    

    /**
     * Standard View constructor. In order to render something, you
     * must call @link #setRenderer to register a renderer.
     */
    public GLSurfaceView(Context context, AttributeSet attrs) 
        super(context, attrs);
        init();
    

    private void init() 
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
    

	  // 设置渲染接口
	  public void setRenderer(Renderer renderer) 
        checkRenderThreadState();
        if (mEGLConfigChooser == null) 
            mEGLConfigChooser = new SimpleEGLConfigChooser(true);
        
        if (mEGLContextFactory == null) 
            mEGLContextFactory = new DefaultContextFactory();
        
        if (mEGLWindowSurfaceFactory == null) 
            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
        
        mRenderer = renderer;
        mGLThread = new GLThread(mThisWeakRef);
        mGLThread.start();
    

	  // 检查渲染线程状态
	  private void checkRenderThreadState() 
        if (mGLThread != null) 
            throw new IllegalStateException(
                    "setRenderer has already been called for this instance.");
        
    

	/**
     * 设置渲染模式
     * @see #RENDERMODE_CONTINUOUSLY
     * @see #RENDERMODE_WHEN_DIRTY
     */
    public void setRenderMode(int renderMode) 
        mGLThread.setRenderMode(renderMode);
    

    /**
     * Override SurfaceHolder.Callback interface
     */
    public void surfaceCreated(SurfaceHolder holder) 
        mGLThread.surfaceCreated();
    

    /**
     * Override SurfaceHolder.Callback interface
     */
    public void surfaceDestroyed(SurfaceHolder holder) 
        // Surface will be destroyed when we return
        mGLThread.surfaceDestroyed();
    

    /**
     * Override SurfaceHolder.Callback interface
     */
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) 
        mGLThread.onWindowResize(w, h);
    		


通过 checkRenderThreadState() 函数可以看出,setRender() 函数调用多次会导致 ::IllegalStateException:: 。

有几个关键的类:

  • GLThreadManager
  • GLThread
  • Renderer
  • EGLConfigChooser
  • EGLContextFactory
  • EGLWindowSurfaceFactory
  • GLWrapper
  • EglHelper

要了解这几个类的用途,先来说下 EGL 的创建过程。

GLSurfaceView内部管理一个 surface,用来负责 OpenGL 的渲染工作,


EGL

EGL 环境的创建过程如下图:

  • 获取默认的显示设备
  • 初始化显示设备
  • 从系统中获取对应属性的配置
  • 创建 EglContext
  • 创建渲染的 Surface
  • 绑定 EglContext 和 Surface 到显示设备中
  • 刷新数据,显示渲染场景

初始化 EGL 环境通常使用 EGL10或者 EGL14。SDK版本大于17,优先使用 EGL14。

EGL10

创建EGL10环境的大概过程如下:

        // 1. 获取 EGL 实例
        val egl = EGLContext.getEGL() as EGL10
        // 2. 获取默认的显示设备
        val eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
        if (eglDisplay == EGL10.EGL_NO_DISPLAY) 
            // todo error
        
        // 3. 初始化显示设备
        val version = IntArray(2)
        val initializeResult = egl.eglInitialize(eglDisplay, version)
        if (!initializeResult) 
            // todo error
        
        // 4. 设置显示设备的属性
        val attributes = intArrayOf(
                EGL10.EGL_RED_SIZE, 8,
                EGL10.EGL_GREEN_SIZE, 8,
                EGL10.EGL_BLUE_SIZE, 8,
                EGL10.EGL_ALPHA_SIZE, 8,
                EGL10.EGL_DEPTH_SIZE, 8,
                EGL10.EGL_STENCIL_SIZE, 8,
                EGL10.EGL_RENDERABLE_TYPE, 4,
                EGL10.EGL_NONE)
        val configNum = IntArray(1)
        var chooseResult = egl.eglChooseConfig(eglDisplay, attributes, null, 1, configNum)
        if (!chooseResult) 
            // todo error
        
        // 5. 从系统中获取对应属性的配置
        val configs = arrayOfNulls<EGLConfig>(configNum[0])
        chooseResult = egl.eglChooseConfig(eglDisplay, attributes, configs, configNum[0], configNum)
        if (!chooseResult) 
            // todo error
        
        // 6. 创建 EGLContext
        val eglContext = egl.eglCreateContext(eglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, null)
        if (eglContext == EGL10.EGL_NO_CONTEXT) 
            // todo error
        
        // 7. 创建渲染的 Surface
        val eglSurface = egl.eglCreateWindowSurface(eglDisplay, configs[0], EGL10.EGL_NO_SURFACE, null)
        if (eglSurface == EGL10.EGL_NO_SURFACE) 
            //todo error
        
        // 8. 绑定 EGLContext 和 Surface 到显示设备上
        val makeCurrentResult = egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)
        if (makeCurrentResult) 
            // todo error
        
        
        // do sth.

        // 9. 刷新数据,显示渲染结果
        val result = egl.eglSwapBuffers(eglDisplay, eglSurface)
        if (!result) 
            // todo error
        

相关的类有

  • EGLContext
  • EGL
  • EGL10

而 EGL10继承自 EGL,同时也是一个接口。通过 EGlContext获取到的 EGL 实例为什么是 EGL10呢?

通过 EGLContext 的源码可以看出,getEGL() 是一个com.google.android.gles_jni.EGLImpl 对象。

通过 http://androidxref.com 这个网址可以查看 Android 源码

对应接口的实现类的位置:

/frameworks/base/opengl/java/com/google/android/gles_jni/

Jni接口的位置: /frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp

继续看 EGLImpl 的源码:

package com.google.android.gles_jni;

import javax.microedition.khronos.egl.*;

import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.SurfaceHolder;

public class EGLImpl implements EGL10 
    private EGLContextImpl mContext = new EGLContextImpl(-1);
    private EGLDisplayImpl mDisplay = new EGLDisplayImpl(-1);
    private EGLSurfaceImpl mSurface = new EGLSurfaceImpl(-1);

    public native boolean     eglInitialize(EGLDisplay display, int[] major_minor);
    public native boolean     eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
    public native boolean     eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
    /** @hide **/
    public native boolean     eglReleaseThread();
    public native boolean     eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
    public native boolean     eglGetConfigAttrib(EGLDisplay display, EGLConfig config, int attribute, int[] value);
    public native boolean     eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
    public native int         eglGetError();
    public native boolean     eglDestroyContext(EGLDisplay display, EGLContext context);
    public native boolean     eglDestroySurface(EGLDisplay display, EGLSurface surface);
    public native boolean     eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
    public native String      eglQueryString(EGLDisplay display, int name);
    public native boolean     eglSwapBuffers(EGLDisplay display, EGLSurface surface);
    public native boolean     eglTerminate(EGLDisplay display);
    public native boolean     eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
    public native boolean     eglWaitGL();
    public native boolean     eglWaitNative(int engine, Object bindTarget);
    
    /** @hide **/
    public static native int  getInitCount(EGLDisplay display);

    public EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list) 
        long eglContextId = _eglCreateContext(display, config, share_context, attrib_list);
        if (eglContextId == 0) 
            return EGL10.EGL_NO_CONTEXT;
        
        return new EGLContextImpl( eglContextId );
    

    public EGLSurface eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list) 
        long eglSurfaceId = _eglCreatePbufferSurface(display, config, attrib_list);
        if (eglSurfaceId == 0) 
            return EGL10.EGL_NO_SURFACE;
        
        return new EGLSurfaceImpl( eglSurfaceId );
    

    public EGLSurface eglCreatePixmapSurface(EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list) 
        EGLSurfaceImpl sur = new EGLSurfaceImpl();
        _eglCreatePixmapSurface(sur, display, config, native_pixmap, attrib_list);
        if (sur.mEGLSurface == 0) 
            return EGL10.EGL_NO_SURFACE;
        
        return sur;
    

    public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list) 
        Surface sur = null;
        if (native_window instanceof SurfaceView) 
            SurfaceView surfaceView = (SurfaceView)native_window;
            sur = surfaceView.getHolder().getSurface();
         else if (native_window instanceof SurfaceHolder) 
            SurfaceHolder holder = (SurfaceHolder)native_window;
            sur = holder.getSurface();
         else if (native_window instanceof Surface) 
            sur = (Surface) native_window;
        

        long eglSurfaceId;
        if (sur != null) 
            eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
         else if (native_window instanceof SurfaceTexture) 
            eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
                    native_window, attrib_list);
         else 
            throw new java.lang.UnsupportedOperationException(
                "eglCreateWindowSurface() can only be called with an instance of " +
                "Surface, SurfaceView, SurfaceHolder or SurfaceTexture at the moment.");
        

        if (eglSurfaceId == 0) 
            return EGL10.EGL_NO_SURFACE;
        
        return new EGLSurfaceImpl( eglSurfaceId );
    

    public synchronized EGLDisplay eglGetDisplay(Object native_display) 
        long value = _eglGetDisplay(native_display);
        if (value == 0) 
            return EGL10.EGL_NO_DISPLAY;
        
        if (mDisplay.mEGLDisplay != value)
            mDisplay = new EGLDisplayImpl(value);
        return mDisplay;
    

    public synchronized EGLContext eglGetCurrentContext() 
        long value = _eglGetCurrentContext();
        if (value == 0) 
            return EGL10.EGL_NO_CONTEXT;
        
        if (mContext.mEGLContext != value)
            mContext = new EGLContextImpl(value);
        return mContext;
    

    public synchronized EGLDisplay eglGetCurrentDisplay() 
        long value = _eglGetCurrentDisplay();
        if (value == 0) 
            return EGL10.EGL_NO_DISPLAY;
        
        if (mDisplay.mEGLDisplay != value)
            mDisplay = new EGLDisplayImpl(value);
        return mDisplay;
    

    public synchronized EGLSurface eglGetCurrentSurface(int readdraw) 
        long value = _eglGetCurrentSurface(readdraw);
        if (value == 0) 
            return EGL10.EGL_NO_SURFACE;
        
        if (mSurface.mEGLSurface != value)
            mSurface = new EGLSurfaceImpl(value);
        return mSurface;
    

    private native long _eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
    private native long _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
    private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
    private native long _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
    private native long _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
    private native long _eglGetDisplay(Object native_display);
    private native long _eglGetCurrentContext();
    private native long _eglGetCurrentDisplay();
    private native long _eglGetCurrentSurface(int readdraw);

    native private static void _nativeClassInit();
    static  _nativeClassInit(); 

通过该类的继承关系可以看出,EGLContext.getEGL() 返回的对象就是 EGL10类型。

  • EGLContextImpl
  • EGLDisplayImpl
  • EGLSurfaceImpl

EGLDisplayImpl

/frameworks/base/opengl/java/com/google/android/gles_jni/EGLDisplayImpl.java

package com.google.android.gles_jni;
import javax.microedition.khronos.egl.*;

public class EGLDisplayImpl extends EGLDisplay 
    long mEGLDisplay;

    public EGLDisplayImpl(long dpy) 
        mEGLDisplay = dpy;
    

    @Override
    public boolean equals(Object o) 
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EGLDisplayImpl that = (EGLDisplayImpl) o;

        return mEGLDisplay == that.mEGLDisplay;

    

    @Override
    public int hashCode() 
        /*
         * Based on the algorithm suggested in
         * http://developer.android.com/reference/java/lang/Object.html
         */
        int result = 17;
        result = 31 * result + (int) (mEGLDisplay ^ (mEGLDisplay >>> 32));
        return result;
    

EGLDisplayImpl 这个类本身没有什么特别的东西,直接继承了 EGLDisplay 。

public abstract class EGLDisplay

EGLSurfaceImpl

/frameworks/base/opengl/java/com/google/android/gles_jni/EGLSurfaceImpl.java

package com.google.android.gles_jni;

import javax.microedition.khronos.egl.*;

public class EGLSurfaceImpl extends EGLSurface 
    long mEGLSurface;
    public EGLSurfaceImpl() 
        mEGLSurface = 0;
    
    public EGLSurfaceImpl(long surface) 
        mEGLSurface = surface;
    

    @Override
    public boolean equals(Object o) 
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EGLSurfaceImpl that = (EGLSurfaceImpl) o;

        return mEGLSurface == that.mEGLSurface;

    

    @Override
    public int hashCode() 
        /*
         * Based on the algorithm suggested in
         * http://developer.android.com/reference/java/lang/Object.html
         */
        int result = 17;
        result = 31 * result + (int) (mEGLSurface ^ (mEGLSurface >>> 32));
        return result;
    

EGLContextImpl

/frameworks/base/opengl/java/com/google/android/gles_jni/EGLContextImpl.java

package com.google.android.gles_jni;

import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.GL;

public class EGLContextImpl extends EGLContext 
    private GLImpl mGLContext;
    long mEGLContext;

    public EGLContextImpl(long ctx) 
        mEGLContext = ctx;
        mGLContext = new GLImpl();
    

    @Override
    public GL getGL() 
        return mGLContext;
    

    @Override
    public boolean equals(Object o) 
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EGLContextImpl that = (EGLContextImpl) o;

        return mEGLContext == that.mEGLContext;
    

    @Override
    public int hashCode() 
        /*
         * Based on the algorithm suggested in
         * http://developer.android.com/reference/java/lang/Object.html
         */
        int result = 17;
        result = 31 * result + (int) (mEGLContext ^ (mEGLContext >>> 32));
        return result;
    

com_google_android_gles_jni_EGLImpl.cpp

/frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp

eglGetDisplay()
static jlong jni_eglGetDisplay(JNIEnv *_env, jobject _this, jobject native_display) 
    return reinterpret_cast<jlong>(eglGetDisplay(EGL_DEFAULT_DISPLAY));


EGL14

EGL14创建 egl 环境的大概过程如下:

		  private val attributes = intArrayOf(
                EGL14.EGL_RED_SIZE, 8, //指定RGB中的R大小(bits)
                EGL14.EGL_GREEN_SIZE, 8, //指定G大小
                EGL14.EGL_BLUE_SIZE, 8, //指定B大小
                EGL14.EGL_ALPHA_SIZE, 8, //指定Alpha大小,以上四项实际上指定了像素格式
                EGL14.EGL_DEPTH_SIZE, 16, //指定深度缓存(Z Buffer)大小
                EGL14.EGL_RENDERABLE_TYPE, 4, //指定渲染api类别, 如上一小节描述,这里或者是硬编码的4(EGL14.EGL_OPENGL_ES2_BIT)
                EGL14.EGL_NONE)  //总是以EGL14.EGL_NONE结尾

		  // 1. 创建与本地窗口系统的连接
        eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)
        if (eglDisplay == EGL14.EGL_NO_DISPLAY) 
            // TODO error
        

        // 2. 初始化 EGl
        val version = IntArray(2)
        val initializeResult = EGL14.eglInitialize(eglDisplay, version, 0, version, 1)
        if (!initializeResult) 
            // TODO error
        

        // 3. 确定可用的渲染表面配置
        val configs = arrayOfNulls<EGLConfig>(1)
        val numConfig = IntArray(1)
        val result = EGL14.eglChooseConfig(eglDisplay, attributes, 0, configs, 0, configs.size, numConfig, 0)
        if (!result) 
            // TODO error
        
        eglConfig = configs[0]!!

        // 4. 创建 EGLContext
        val contextAttributes = intArrayOf(EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE)
        eglContext = EGL14.eglCreateContext(eglDisplay, eglConfig, EGL14.EGL_NO_CONTEXT, contextAttributes, 0)

        // 5. 创建渲染表面
        val eglSurfaceAttributes = intArrayOf(EGL14.EGL_NONE)
        eglSurface = EGL14.eglCreateWindowSurface(eglDisplay, eglConfig, surface, eglSurfaceAttributes, 0)

        // 6. 绑定上下文
        val makeCurrentResult = EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, eglSurface, eglContext)
        if (!makeCurrentResult) 
            // TODO error
        

基本过程与EGL10的方式一致。
同时也可以参考系统类 【 ** android.hardware.camera2.legacy*
*.SurfaceTextureRenderer.java ** 】 里面的写法。


GLThread

了解了 EGL的创建过程,继续接着 GLSurfaceView 的代码看。
注意到 setRender() 函数中初始化的及各类。

  • SimpleEGLConfigChooser 对应 eglChooseConfig() 的过程
  • DefaultContextFactory 对应 eglCreateContext() 的过程
  • DefaultWindowSurfaceFactory 对应 eglCreateWindowSurface() 的过程

创建 EGL环境的对象有了,那么开始创建的这一些过程在哪呢? 答案是::GLThread::

private final WeakReference<GLSurfaceView> mThisWeakRef =
            new WeakReference<GLSurfaceView>(this);
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();

GLThread的构造传入了一个引用当前 GLSurfaceView 的对象,是一个弱引用。

static class GLThread extends Thread 
		  private boolean mShouldExit;
        private boolean mExited;
        private boolean mRequestPaused;
        private boolean mPaused;
        private boolean mHasSurface;
        private boolean mSurfaceIsBad;
        private boolean mWaitingForSurface;
        private boolean mHaveEglContext;
        private boolean mHaveEglSurface;
        private boolean mFinishedCreatingEglSurface;
        private boolean mShouldReleaseEglContext;
        private int mWidth;
        private int mHeight;
        private int mRenderMode;
        private boolean mRequestRender;
        private boolean mWantRenderNotification;
        private boolean mRenderComplete;
        private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>(); // 待执行的任务队列
        private boolean mSizeChanged = true;
        private Runnable mFinishDrawingRunnable = null;

        private EglHelper mEglHelper; // EGL环境的帮助类
        private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;

		  // 构造函数
        GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) 
            super();
            mWidth = 0;
            mHeight = 0;
            mRequestRender = true;
            mRenderMode = RENDERMODE_CONTINUOUSLY;
            mWantRenderNotification = false;
            mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
        
	

可以看出 GLThread 就是一个线程,也就是所谓的 ”GL 线程“。

  public void run() 
       setName("GLThread " + getId());
       if (LOG_THREADS) 
            Log.i("GLThread", "starting tid=" + getId());
        
       try 
           guardedRun();
        catch (InterruptedException e) 
           // fall thru and exit normally
        finally 
           sGLThreadManager.threadExiting(this);
       
  

最重要的 guardedRun() 函数登场了。

// 判断是否准备好开始 draw
private boolean readyToDraw() 
            return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
                && (mWidth > 0) && (mHeight > 0)
                // 如果是 RENDERMODE_CONTINUOUSLY 渲染模式,则不需要调用 requestRender() 也会一直调用onDrawFrame() 进行渲染
                && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
        
private void guardedRun() throws InterruptedException 
            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) 
                            // ...

                            // Ready to draw?
                            if (readyToDraw()) 
                                // 如果还没有 EGL环境,先创建一个
                                if (! mHaveEglContext) 
                                    try 
                                        // 创建EGL环境
                                        mEglHelper.start();
                                     catch (RuntimeException t) 
                                        sGLThreadManager.releaseEglContextLocked(this);
                                        throw t;
                                    
                                    mHaveEglContext = true;
                                    createEglContext = true;
                                    sGLThreadManager.notifyAll();
                                
                            

                                if (mHaveEglContext && !mHaveEglSurface) 
                                    mHaveEglSurface = true;
                                    createEglSurface = true;
                                    createGlInterface = true;
                                    sizeChanged = true;
                                

                                if (mHaveEglSurface) 
                                    // mSizeChanged 默认值为 true
                                    if (mSizeChanged) 
                                        sizeChanged = true;
                                        w = mWidth;
                                        h = mHeight;

                                        // Destroy and recreate the EGL surface.
                                        createEglSurface = true;

                                        mSizeChanged = false;
                                    
                                    mRequestRender = false;
                                    sGLThreadManager.notifyAll();
                                    break;
                                
                             else 
                                // ...
                            
                            sGLThreadManager.wait();
                        
                     // end of synchronized(sGLThreadManager)

                    if (event != null) 
                        event.run();
                        event = null;
                        continue;
                    

                    if (createEglSurface) 
                        // 创建 eglSurface 并绑定 context
                        if (mEglHelper.createSurface()) 
                            // ...
                         else 
                            // ...
                            continue;
                        
                        createEglSurface = false;
                    

                    // 获取 gl 对象
                    if (createGlInterface) 
                        gl = (GL10) mEglHelper.createGL();

                        createGlInterface = false;
                    

                    if (createEglContext) 
                        
                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                        if (view != null) 
                            try 
                                // 回调 onSurfaceCreated() 函数
                                view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
                             finally 
                        
                        createEglContext = false;
                    

                    if (sizeChanged) 

                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                        if (view != null) 
                            try 
                                // 回调 onSurfaceChanged() 函数
                                view.mRenderer.onSurfaceChanged(gl, w, h);
                             finally 
                        
                        sizeChanged = false;
                    

                    // 回调 onDrawFrame() 函数,一般在此函数中做绘制工作。
                    
                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                        if (view != null) 
                            try 
                                view.mRenderer.onDrawFrame(gl);
                                if (finishDrawingRunnable != null) 
                                    finishDrawingRunnable.run();
                                    finishDrawingRunnable = null;
                                
                             finally 
                        
                    
                    
                    // 交换缓冲区显示渲染的数据
                    int swapError = mEglHelper.swap();
                    // ...

                

             finally 
                // clean-up
            
        

run() 函数内部有两层 while 循环。内层 while 循环首先调用 readyToDraw() 来判断是否可以往下走。首次 mHasSurface = false。

    public void surfaceCreated() 
            synchronized(sGLThreadManager) 
                mHasSurface = true;
                mFinishedCreatingEglSurface = false;
                sGLThreadManager.notifyAll();
                while (mWaitingForSurface
                       && !mFinishedCreatingEglSurface
                       && !mExited) 
                    try 
                        sGLThreadManager.wait();
                     catch (InterruptedException e) 
                        Thread.currentThread().interrupt();
                    
                
            
        
	  public void surfaceCreated(SurfaceHolder holder) 
        mGLThread.surfaceCreated();
    

GLSurfaceView 实现了 SurfaceHolder.Callback接口,在 surfaceCreated() 回调中调用了 GLThead.surfaceCreated(),在此函数中将 mHasSurface 置为 true。

然后 run() 函数内部 if (readyToDraw()) 函数就可以执行进去了。
内部主要调用了EglHelper 的几个关键函数。

EGLHelper

  • start()
  • createSurface()
  • createGL()
  • swap()
  • destroySurfaceImp()
  • finish()

EGLHelper.start()

public void start() 
            // 创建 egl 实例
            mEgl = (EGL10) EGLContext.getEGL();

            // 获取默认 display
            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

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

            // 初始化
            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 
                // 创建 EGLConfig
                mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);

                // 创建 EGLContext
                mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
            
            if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) 
                mEglContext = null;
                throwEglException("createContext");
            

            mEglSurface = null;
        

EGLHelper.createSurface()

public boolean createSurface() 
            // 检查前置条件
            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");
            

            // 销毁旧的 surface
            destroySurfaceImp();

            // 创建 EglSurface
            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
            if (view != null) 
                mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
                        mEglDisplay, mEglConfig, view.getHolder());
             else 
                mEglSurface = null;
            

            if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) 
                int error = mEgl.eglGetError();
                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) 
                    Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
                
                return false;
            

            // 绑定上下文
            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) 
                logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
                return false;
            

            return true;
        

从 start() 和 createSurface() 这两个函数可以看出,自己创建 egl 环境时,也是参考 EGLHelper 的方式来的。可以看到本篇文章上面介绍 【EGL 环境】时,创建 egl 环境的大体步骤也是如此。

EGLHelper.swap()

  // 交换缓冲,显示数据
	public int swap() 
            if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) 
                return mEgl.eglGetError();
            
            return EGL10.EGL_SUCCESS;
        

EGLHelper. destroySurfaceImp()

// 销毁 surface
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) 
                    view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
                
                mEglSurface = null;
            
        

在创建 egl 绑定上下文的时候,mEgl.eglMakeCurrent() 传入的都是有效surface 和 context,销毁 surface 传入 EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT 即可。

EGLHelper. finish()

public void finish() 
            if (mEglContext != null) 
                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                if (view != null) 
                    view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
                
                mEglContext = null;
            
            if (mEglDisplay != null) 
                mEgl.eglTerminate(mEglDisplay);
                mEglDisplay = null;
            
        

mGLContextFactory = DefaultContextFactory()

public void destroyContext(EGL10 egl, EGLDisplay display,
                EGLContext context) 
            if (!egl.eglDestroyContext(display, context)) 
                EglHelper.throwEglException("eglDestroyContex", egl.eglGetError());
            
        

最终调用的是 EGLImpl 类的 eglDestroyContext() 函数。

Render 接口

在if (readyToDraw()) 函数体内部的准备工作进行完之后,break guardedRun() 的内存 while 循环。

调用EGLHelper 的 createSurface() 之后,回调了 RenderonSurfaceCreated(GL10 gl, EGLConfig config) 函数, onSurfaceChanged(GL10 gl, intwidth, intheight) 函数,onDrawFrame(GL10 gl) 函数。

我们一般在onDrawFrame() 函数中做一些自己的绘制操作。

最后调用了 EGLHelper的 swap() 来切换缓冲区,显示渲染的结果。

queueEvent

由于操作 OpenGL 环境只能通过 GL线程,所以GLSurfaceView 提供了 queueEvent() 函数,将待执行的 runnable 添加到 GLThread 中的队列中。

    public void queueEvent(Runnable r) 
        mGLThread.queueEvent(r);
    
	   public void queueEvent(Runnable r) 
            if (r == null) 
                throw new IllegalArgumentException("r must not be null");
            
            synchronized(sGLThreadManager) 
                mEventQueue.add(r);
                sGLThreadManager.notifyAll();
            
        

GLThread 的 run() 内部循环执行时,就会从队列中取出 event 来执行。

				while (true) 
                    synchronized (sGLThreadManager) 
                        while (true) 
                            if (mShouldExit) 
                                return;
                            
							   // 取出Runnable
                            if (! mEventQueue.isEmpty()) 
                                event = mEventQueue.remove(0);
                                break;
                            
                        	// 省略

                        
                     // end of synchronized(sGLThreadManager)

					   // 执行Runnable
                    if (event != null) 
                        event.run();
                        event = null;
                        continue;
                    
                    // 省略
                

生命周期管理

  • onAttachedToWindow()
  • onDetachedFromWindow()
  • onResume()
  • onPause()

onAttachedToWindow()

	  @Override
    protected void onAttachedToWindow() 
        super.onAttachedToWindow();
        // 如果已经 detach 并且 renderer 为空时
        if (mDetached && (mRenderer != null)) 
            int renderMode = RENDERMODE_CONTINUOUSLY;
            if (mGLThread != null) 
                renderMode = mGLThread.getRenderMode();
            
			  // 创建 GLThread,并设置渲染模式
            mGLThread = new GLThread(mThisWeakRef);
            if (renderMode != RENDERMODE_CONTINUOUSLY) 
                mGLThread.setRenderMode(renderMode);
            
            mGLThread.start();
        
        mDetached = false;
    

onDetachedFromWindow()

	  @Override
    protected void onDetachedFromWindow() 
        if (mGLThread != null) 
            mGLThread.requestExitAndWait();
        
        // 设置变量的值
        mDetached = true;
        super.onDetachedFromWindow();
    
		public void requestExitAndWait() 
                synchronized(sGLThreadManager) 
			      // 设置变量的值
                mShouldExit = true; 
                sGLThreadManager.notifyAll();
                while (! mExited) 
                    try 
                        sGLThreadManager.wait();
                     catch (InterruptedException ex) 
                        Thread.currentThread().interrupt();
                    
                
            
        

mShouldExit 被设置为 true 之后, 在guardedRun() 函数中,则会直接 return,不会再往下回调 onDrawFrame() 来绘制。

				while (true) 
                    synchronized (sGLThreadManager) 
                        while (true) 
                            if (mShouldExit) 
                                return;
                            

                            // ...
                        
                    
                

reference

以上是关于GLSurfaceView 源码分析 & EGL 创建过程的主要内容,如果未能解决你的问题,请参考以下文章

Android GLSurfaceView EGL_BAD_CONFIG 源码分析定位

Android GLSurfaceView EGL_BAD_CONFIG 源码分析定位

Android GLSurfaceView EGL_BAD_CONFIG 源码分析定位

GLSurfaceView的简单分析及巧妙借用

Android OpenGL ES 学习 – GLSurfaceView 源码解析GL线程以及自定义 EGL

Android OpenGL ES 学习 – GLSurfaceView 源码解析GL线程以及自定义 EGL