Android GLSurfaceView详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/TuGeLe/article/details/79199161
学习在Android中使用OpenGL ES,就不得不提到一个控件:GLSurfaceView

GLSurfaceView从Android 1.5(API level 3)开始加入,继承自SurfaceView,实现了SurfaceHolder.Callback2接口,拥有SurfaceView的全部特性,也有view所有的功能和属性,特别是处理事件的能力,它主要是在SurfaceView的基础上它加入了EGL的管理,并自带了一个GLThread绘制线程(EGLContext创建GL环境所在线程即为GL线程),绘制的工作直接通过OpenGL在绘制线程进行,不会阻塞主线程,绘制的结果输出到SurfaceView所提供的Surface上,这使得GLSurfaceView也拥有了OpenGlES所提供的图形处理能力,通过它定义的Render接口,使更改具体的Render的行为非常灵活性,只需要将实现了渲染函数的Renderer的实现类设置给GLSurfaceView即可。

GLSurfaceView提供了下列特性:
    1>  提供并且管理一个独立的Surface
    2>  提供并且管理一个EGL display,它能让opengl把内容渲染到上述的Surface上。
    3>  支持用户自定义渲染器(Render),通过setRenderer设置一个自定义的Renderer
    4>  让渲染器在独立的GLThread线程里运作,和UI线程分离。
    5>  支持按需渲染(on-demand)和连续渲染(continuous)两种模式。
    6>  GPU加速:GLSurfaceView的效率是SurfaceView的30倍以上,SurfaceView使用画布进行绘制,GLSurfaceView利用GPU加速提高了绘制效率。
    7>  View的绘制onDraw(Canvas canvas)使用Skia渲染引擎渲染,而GLSurfaceView的渲染器RendereronDrawFrame(GL10 gl)使用opengl绘制引擎进行渲染


2.GLSurfaceView的使用步骤

开发基于GLSurfaceView的程序,通常需要继承GLSurfaceView,并重载一些和用户输入事件有关的方法,如果你不需监听事件,也可以直接使用GLSurfaceView, 你可以使用set方法来修改默认的属性,例如setRenderer(Renderer)设置渲染器,主要的工作就是设置Renderer,其他过程,例如EGL的创建,Surface的分配以及OpenGLES的调用都被隐藏起来了,GLSurfaceView会启动一个工作线程来完成渲染,避免阻塞UI主线程,这个工作线程就是mGLThread,这个线程在应用程序setRederer的时候启动,然后不停地等待和处理事件,同时还负责开展Render工作。

第一步:创建GLSurfaceView

GLSurfaceView也是View,可以通过布局文件的方式将它加入整棵view树中,或者在java代码中创建并且添加。
在布局中,摆布好GLSurfaceView的位置.如下:
<android.opengl.GLSurfaceView
        android:id="@+id/glv_main"
        android:layout_width="match_parent"
        android:layout_height="200dp" />

在Activity中实例化,如下:
@Override
protected void onCreate(Bundle savedInstanceState){
    GLSurfaceView glv = (GLSurfaceView)findViewById(R.id.glv_main);
}

第二步:初始化OpenGLES环境

GLSurfaceView默认情况下已经初始化好了OpenGLES的运行环境,不需要做额外的工作就可以使用,当然也可以更改一些默认的设置。

第三步:设置Renderer
渲染是OpenGLES的核心工作,setRenderer可以将用户自定义的一个Renderer加入实际的渲染流程中。
public class GLRender implements GLSurfaceView.Renderer{

    //控制旋转的角度
    private float rotate;

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //关闭抗抖动
        gl.glDisable(GL10.GL_DITHER);
        //设置系统对透视进行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        gl.glClearColor(0, 0, 0, 0);
        //设置阴影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        //启动深度测试
        gl.glEnable(GL10.GL_DEPTH_TEST);
        //设置深度测试的类型
        gl.glDepthFunc(GL10.GL_LEQUAL);

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //设置3D视窗的大小及位置
        gl.glViewport(0, 0, width, height);
        //将当前矩阵模式设为投影矩形
        gl.glMatrixMode(GL10.GL_PROJECTION);
        //初始化单位矩阵
        gl.glLoadIdentity();
        //计算透视窗口的宽度高度比
        float ratio = (float) width / height;
        //调用此方法设置透视窗口的空间大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //清除屏幕缓存和深度缓存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        //启用顶点坐标数据
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        //启用顶点颜色数据
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        //设置当前矩阵堆栈为模型堆栈
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        //------绘制第一个图形-----
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(0.95f, -0.8f, -1.5f); //1⃣
        //设置顶点位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, PointData.floatBufferUtil(PointData.triangleData));
        //设置顶点颜色数据
        gl.glColorPointer(4, GL10.GL_FIXED, 0, PointData.intBufferUtil(PointData.triangleColor));
        //根据顶点数据绘制平面图形
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);

        //-----绘制第二个图形-----
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(0.95f, 0.8f, -1.5f);
        //设置顶点位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, PointData.floatBufferUtil(PointData.rectData));
        //设置顶点颜色数据
        gl.glColorPointer(4, GL10.GL_FIXED, 0, PointData.intBufferUtil(PointData.rectColor));
        //更具顶点数据绘制平面图形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

        //-----绘制第三个图形----
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(-0.95f, 0.8f, -1.5f);
        //设置顶点位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, PointData.floatBufferUtil(PointData.rectData2));
        //根据顶点数据绘制平面图形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

        //-----绘制第四个图形-----
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(-0.95f, -0.8f, -1.5f);
        //设置使用纯色填充 **需要注意: 使用纯色填充需要禁用顶点颜色数组
        gl.glColor4f(1.0f, 0.2f, 0.2f, 0.0f);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        //设置顶点位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, PointData.floatBufferUtil(PointData.pentacle));
        //根据顶点数据绘制图形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 5);

        //----绘制第五个图形---
        //重置当前的模型视图矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(0f, 0f, -1.5f);
        gl.glRotatef(rotate, 0f, 0.2f, 0f);
        //设置顶点位置数据
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, PointData.floatBufferUtil(TDPointData.taperVertices));
        //启用顶点颜色组
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        //设置顶点颜色数据
        gl.glColorPointer(4, GL10.GL_FIXED, 0, PointData.intBufferUtil(TDPointData.taperColors));
        //按taperFacetsBuffer指定的面绘制三角形
        ByteBuffer byteBuffer = PointData.byteBufferUtil(TDPointData.taperFacets);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, byteBuffer.remaining(), GL10.GL_UNSIGNED_BYTE, byteBuffer);


        //绘制结束
        gl.glFinish();
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        //旋转角度+1
        rotate += 1;
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_glsurface);
    glv = (GLSurfaceView)findViewById(R.id.glv_opengl);
    GLRender render = new GLRender();
    glv.setRenderer(render);
}

第四步:设置RenderingMode

GLSurfaceView在onAttachedToWindow后就启动了一个无线循环的GLThread线程,GLSurfaceView默认采用的是RENDERMODE_CONTINUOUSLY连续渲染的方式,刷新的帧率是60FPS,16ms就重绘一次,可以通过mGLView.setRenderMode()更改其渲染方式为RENDERMODE_WHEN_DIRTY,表示被动渲染,在surfaceCreate的时候会绘制一次,之后只有在调用requestRender或者onResume等方法主动请求重绘时才会进行渲染,如果你的界面不需要频繁的刷新最好使用RENDERMODE_WHEN_DIRTY,这样可以降低CPU和GPU的活动

第五步:状态处理

使用GLSurfaceView需要注意程序的生命周期,Activity及Fragment会有暂停和恢复等状态,GLSurfaceView也需根据这些状态来做相应的处理,GLSurfaceView具有onResume和onPause两个同Activity及Fragment中的生命周期同名的方法,在Activity或者Fragment中的onResume和onPause方法中,需要主动调用GLSurfaceView的实例的这两个方法,这样能使OpenGLES的内部线程做出正确的判断,从而保证应用程序的稳定性。

第六部:事件处理
为了处理事件,一般都是继承GLSurfaceView类并重载它的事件方法,但是由于GLSurfaceView是多线程的,渲染器在独立的渲染线程里,你应该使用Java的跨线程机制跟渲染器通讯,GLSurfaceView提供的queueEvent(Runnable)方法就是一种相对简单的操作,queueEvent()方法被安全地用于在UI线程和渲染线程之间进行交流通信
public void queueEvent(Runnable r) {
    mGLThread.queueEvent(r);
}

这里直接调用GLThread的queueEvent(Runnable r)方法GLThread的mEventQueue队列中添加Runnable 
     public void queueEvent(Runnable r) {  
      
         synchronized(sGLThreadManager) {  
             mEventQueue.add(r);  
             sGLThreadManager.notifyAll();  
         }  
       
     }  

GLThread的guardenRun()方法中有如下代码:
  1. if (! mEventQueue.isEmpty()) {  
  2.     event = mEventQueue.remove(0);  
  3.     break;  
  4. }  
  5.                   
  6. ...  
  7.                   
  8. if (event != null) {  
  9.     event.run();  
  10.     event = null;  
  11.     continue;  
  12. }  
一般事件的使用如下:
  1. class MyGLSurfaceView extends GLSurfaceView {    
  2.     private MyRenderer mMyRenderer;    
  3.     
  4.     public boolean onKeyDown(int keyCode, KeyEvent event) {    
  5.     
  6.        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {    
  7.            queueEvent(new Runnable() {    
  8.               // 这个方法会在渲染线程里被调用    
  9.               public void run() {    
  10.                     mMyRenderer.handleDpadCenter();    
  11.            }});    
  12.            return true;    
  13.        }    
  14.     
  15.        return super.onKeyDown(keyCode, event);    
  16.    }    

  17.    public boolean onTouchEvent(final MotionEvent event) {
  18.             queueEvent(new Runnable(){
  19.                public void run() {
  20.                 mRenderer.setColor(event.getX() / getWidth(),
  21.                         event.getY() / getHeight(), 1.0f);
  22.             }});
  23.             return true;
  24.          }    
  25. }    
如果在UI线程里调用渲染器的方法,因为UI事件和渲染绘制是在不同的线程里,会收到“call to OpenGL ES API with no current context”的警告,典型的案例就是在键盘或触摸事件方法里直接调用opengl es的API。

GLSurfaceView源码分析
GLSurfaceView中对于GL环境的操作,除queueEvent是将事件放入队列中然后到GL线程中执行外,其他方法基本都是在主线程中修改某个状态值(某个属性属性),然后调用sGLThreadManager.notifyAll()取消GL线程的等待,在GL线程中根据属性的状态值作不同的操作,并在操作后反馈给主线程,当然有的方法也不需要反馈。
相关类图如下,GLSurfaceView中的EglHelper和GLThread分别实现了上面提到的管理EGL环境和渲染线程的工作,GLSurfaceView的使用者需要实现Renderer接口。

渲染的整体步骤如下:

  • 获取EGLDisplay对象,初始化与EGLDisplay 之间的连接
  • 获取EGLConfig对象
  • 创建EGLContext 实例
  • 创建EGLSurface实例
  • 连接EGLContext和EGLSurface.
  • 是否需要重新申请EGLSurface,如果尺寸发生了变化,此时createEGLSurface为true
  • 是否需要申请GLObject,此时createGLinterface为true
  • 是否需要生成EGLContext,此时createEGLContext为true
  • 尺寸是否变化,sizeChanged为true,此时需要通知观察者
  • 一切准备好之后,使用GL指令绘制图形,调用view.mRenderer.onDrawFrame进行真正的渲染
  • 最后通过swap把渲染结果显示到屏幕
  • 断开并释放与EGLSurface关联的EGLContext对象
  • 删除EGLSurface对象
  • 删除EGLContext对象
  • 终止与EGLDisplay之间的连接

public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 {

    public final static int RENDERMODE_WHEN_DIRTY = 0;//按需渲染模式
    public final static int RENDERMODE_CONTINUOUSLY = 1;//连续渲染模式

    private static final GLThreadManager sGLThreadManager = new GLThreadManager();

    private final WeakReference<GLSurfaceView> mThisWeakRef new WeakReference<GLSurfaceView>(this);
    private GLThread mGLThread;
    private Renderer mRenderer;
    private boolean mDetached;
    private EGLConfigChooser mEGLConfigChooser;
    private EGLContextFactory mEGLContextFactory;
    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
    private int mDebugFlags;
    private int mEGLContextClientVersion;
    private boolean mPreserveEGLContextOnPause;

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

    public GLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    //调试用的
    public void setDebugFlags(int debugFlags);
    public int getDebugFlags();

    //设置暂停的时候是否保持EglContext
    public void setPreserveEGLContextOnPause(boolean preserveOnPause);
    public boolean getPreserveEGLContextOnPause();

    //设置渲染器,这个非常重要,渲染工作就依靠渲染器了
    //调用此方法会开启一个新的线程,即GL线程
    public void setRenderer(Renderer renderer) {
        checkRenderThreadState();//检查渲染线程是否已经创建了,如果已经创建了就抛出异常
        if (mEGLConfigChooser == null) {
            mEGLConfigChooser = new SimpleEGLConfigChooser(true);//默认的设置EglConfig的方法
        }
        if (mEGLContextFactory == null) {
            mEGLContextFactory = new DefaultContextFactory();//默认的EGLContext工厂
        }
        if (mEGLWindowSurfaceFactory == null) {
            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();//默认的EGLSurface工厂
        }
        mRenderer = renderer;
        mGLThread = new GLThread(mThisWeakRef);
        mGLThread.start();
    }

    //设置EGLContext工厂,不设置就用默认的
    public void setEGLContextFactory(EGLContextFactory factory){
    checkRenderThreadState();
    mEGLContextFactory = factory;
    }

    //设置EGLSurface工厂,不设置就用默认的
    public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory){
    checkRenderThreadState();
     mEGLWindowSurfaceFactory = factory;
    }
    //设置EglConfig,一般颜色深度等等,利用此方法设置。不设置就用默认的
    public void setEGLConfigChooser(EGLConfigChooser configChooser){
    checkRenderThreadState();
    mEGLConfigChooser = configChooser;
    }

    //内部调用setEGLConfigChooser
    public void setEGLConfigChooser(boolean needDepth){
    setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
    }

    //内部调用setEGLConfigChooser
    public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
            int alphaSize, int depthSize, int stencilSize){
    setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
blueSize, alphaSize, depthSize, stencilSize));
    }

    //设置EGLContextVersion,比如2,即OpenGLES2.0
    public void setEGLContextClientVersion(int version){
     checkRenderThreadState();
     mEGLContextClientVersion = version;
    }

    //设置渲染方式,有RENDERMODE_CONTINUOUSLY表示不断渲染
    //以及RENDERMODE_WHEN_DIRTY表示在需要的时候才会渲染
    //渲染的时候调用requestRender必须在setRenderer后
    public void setRenderMode(int renderMode){
    mGLThread.setRenderMode(renderMode);
    }

    public int getRenderMode(){
    return mGLThread.getRenderMode();
    }

    //主动请求渲染
    public void requestRender(){
     mGLThread.requestRender();
    }


    public void surfaceCreated(SurfaceHolder holder){
    mGLThread.surfaceCreated();
    }

    public void surfaceDestroyed(SurfaceHolder holder){
     mGLThread.surfaceDestroyed();
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h){
    mGLThread.onWindowResize(w, h);
    }

    @Override
    public void surfaceRedrawNeeded(SurfaceHolder holder) {
        if (mGLThread != null) {
            mGLThread.requestRenderAndWait();
        }
    }

    //生命周期,一般在Activity、Fragment的onPause中调用
    public void onPause(){
     mGLThread.onPause();
    }

    //生命周期,一般在Activity、Fragment的onResume中调用
    public void onResume(){
     mGLThread.onResume();
    }

    //向GL线程发送一个任务
    public void queueEvent(Runnable r){
    mGLThread.queueEvent(r);
    }

    //附加到Window上时被调用,外部不可调用
    protected void onAttachedToWindow(){
    super.onAttachedToWindow();
    if (mDetached && (mRenderer != null)) {
    int renderMode = RENDERMODE_CONTINUOUSLY;
    if (mGLThread != null) {
    renderMode = mGLThread.getRenderMode();
    }
    mGLThread = new GLThread(mThisWeakRef);
    if (renderMode != RENDERMODE_CONTINUOUSLY) {
    mGLThread.setRenderMode(renderMode);
    }
    mGLThread.start();
    }
    mDetached = false;
    }

     //从Window上被移除时调用,外部不可调用
    protected void onDetachedFromWindow(){
    if (mGLThread != null) {
    mGLThread.requestExitAndWait();
    }
    mDetached = true;
    super.onDetachedFromWindow();
    }

    //渲染器接口
    public interface Renderer {

        //Surface被创建时被调用,通常在此进行渲染的初始化
        void onSurfaceCreated(GL10 gl, EGLConfig config);

        //Surface大小被改变时被调用
        void onSurfaceChanged(GL10 gl, int width, int height);

        //执行渲染时被调用,以完成用户渲染工作
        void onDrawFrame(GL10 gl);

    }

    //非常重要的一个EGL帮助类,GL环境的建立依靠此类
    private static class EglHelper {
        public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
            mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
        }

        //EGL的初始化,可以参考此方法
        public void start() {
           
            /*
             * 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 {
                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,使GL的渲染,能够渲染到用户指定的Surface
        //默认的Surface就是SurfaceHolder的Surface
        public boolean createSurface() {
            
            /*
             * 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) {
                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;
            }

            /*
             * 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;
        }

        //通过EGL得到GL,然后用户设置了Wrapper的话会给得到的GL做个包装
        //同时也会解析一下用户的Debug意图,看看要不要debug
        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 int swap(){
        if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
        return mEgl.eglGetError();
        }
        return EGL10.EGL_SUCCESS;
        }

        //销毁Surface的方法,具体实现在destroySurfaceImp方法中     
        public void destroySurface() {  
            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) {
                    view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
                }
                mEglSurface = null;
            }
        }
        //销毁GL环境
        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;
            }
        }
    }
----------------------------------------------------------------------------------------------
    //GL线程,此类中存在的方法在GLSurfaceView中都有同名的,都是提供给GLSurfaceView作为真正的实现调用
    static class GLThread extends Thread {

    GLSurfaceView中对于GL环境的操作,除queueEvent是将事件放入队列中然后到GL线程中执行外,
    其他方法基本都是在主线程中修改某个状态值(下面的某个属性属性),然后调用sGLThreadManager.notifyAll()取消GL线程的等待,
    在GL线程中根据属性的状态值作不同的操作,并在操作后反馈给主线程,当然有的方法也不需要反馈。
        
        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;

        // End of member variables protected by the sGLThreadManager monitor.
        private EglHelper mEglHelper;

        private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;

        GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
        super();
         mWidth = 0;
        mHeight = 0;
        mRequestRender = true;//开始需要刷新一次
        mRenderMode = RENDERMODE_CONTINUOUSLY;//默认的渲染模式
        mWantRenderNotification = false;
        mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
        }

        
        @Override
        public void run() {
        setName("GLThread " + getId());
        try {
        guardedRun();//处理所有渲染逻辑

        } catch (InterruptedException e) {
      
        } finally {
        sGLThreadManager.threadExiting(this);
        }
        }

        

        //销毁EglSurface
        private void stopEglSurfaceLocked(){
        if (mHaveEglSurface) {
        mHaveEglSurface = false;
        mEglHelper.destroySurface();
        }
        }

        //销毁EglContext
        private void stopEglContextLocked(){
        if (mHaveEglContext) {
        mEglHelper.finish();
        mHaveEglContext = false;
        sGLThreadManager.releaseEglContextLocked(this);
        }
        }

        //GLSurfaceView的核心就在这个方法里面,GL线程渲染的主要逻辑都在这个方法里面,这个方法比较复杂    
        第一步:判断事件队列是否为空,如果有事件需要处理,则直接跳出内循环去处理事件,否则依然在内循环运行
        第二步:1.判断是否需要释放EGLSurface,
                        2.判断是否丢失了Surface,mHasSurface表示当前有没有可用的Surface,mWaitingForSurface表示是否在申请Surface的过程中,
                        3.是否需要放弃EGLContext
        第三步:经过以上的判断之后,程序进入图形渲染前的准备工作,也就是readyToDraw之间的代码
        第四步:一旦程序执行到这里也就是跳出了内循环,有两种可能,第一是EventQueue中有需要处理的事件,第二是需要执行渲染工作
      private void guardedRun() throws InterruptedException {
            mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);//初始化EglHelper
            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;

                while (true) {
                        synchronized (sGLThreadManager) {
                        while (true) {//死循环,除非主动跳出
                                //外部请求退出GL线程
                            if (mShouldExit) {
                                return;
                            }

                            /*外部请求在GL线程中处理的事件没有处理完时,就优先处理这些事件*/
                                    if (! mEventQueue.isEmpty()) {
                                event = mEventQueue.remove(0);
                                         break;
                            }

                                    //暂停和恢复状态变化时,onResume和onPause状态变化
                                    boolean pausing = false;
                                    if (mPaused != mRequestPaused) {
                                pausing = mRequestPaused;
                                mPaused = mRequestPaused;
                                        /*GLSurfaceView的onPause和onResume都会用wait方法等待GL线程的响应,这时候主线程阻塞。
                                    此处调用notifyAll通知onPause和onResume,放弃主线程的阻塞。
                                    GLSurfaceView中其他很多方法也存在wait方法,基本与此类似
                                */
                                sGLThreadManager.notifyAll();
                            }

                                    // 需要释放EglContext时候执行的工作
                                    if (mShouldReleaseEglContext) {
                        
                                stopEglSurfaceLocked();
                                stopEglContextLocked();
                                mShouldReleaseEglContext = false;
                                askedToReleaseEglContext = true;
                            }

                                    // EglContext丢失时,销毁EglSurface和EglContext
                                    if (lostEglContext) {
                                stopEglSurfaceLocked();
                                stopEglContextLocked();
                                lostEglContext = false;
                            }

                                    //如果acitivity已经暂停,接收了暂停信号,而且当前EglSurface存在时,销毁EglSurface
                                    if (pausing && mHaveEglSurface) {
                                stopEglSurfaceLocked();
                            }

                                /*接收了暂停信号,而且当前EglContext存在时,根据用户设置,来决定是否销毁EglContext*/
                                if (pausing && mHaveEglContext) {
                                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                                boolean preserveEglContextOnPause = view == null ? false : view.mPreserveEGLContextOnPause;
                                        if (!preserveEglContextOnPause) {
                                    stopEglContextLocked();
                                }
                          }

                                /*Surface不存在而且当前并没有在等待Surface*/
                                if ((! mHasSurface) && (! mWaitingForSurface)) {
                                if (mHaveEglSurface) {
                                stopEglSurfaceLocked();
                            }
                            mWaitingForSurface = true;
                            mSurfaceIsBad = false;
                            sGLThreadManager.notifyAll();
                        }

                        // Surface存在,而且在等待Surface
                            if (mHasSurface && mWaitingForSurface) {
                        
                            mWaitingForSurface = false;
                            sGLThreadManager.notifyAll();
                        }

                            if (doRenderNotification) {
                       
                            mWantRenderNotification = false;
                            doRenderNotification = false;
                            mRenderComplete = true;
                            sGLThreadManager.notifyAll();
                        }

                       // 判断当前环境准备好了渲染执行,否则进入下一轮等待及判断
                            判断两个关键因素:EGLContext和EGLSurface是否存在并有效,如果没有EGLContext,就需要获取一个,
                            如果当前有EGLSurface但尺寸发生了变化,那么就需要销毁他并重新申请Surface。
                            可以渲染图形的条件是:
                            1.程序当前不处于pause状态,2.已经成功获得Surface,3.有合适的尺寸,4.处于自动持续渲染状态或用户发起了渲染请求
                        if (readyToDraw()) {

                            // 没有EglContext就需要借助EglHelper来创建EglContext
                            if (! mHaveEglContext) {
                            if (askedToReleaseEglContext) {
                                askedToReleaseEglContext = false;
                            } else {
                                try {
                                    mEglHelper.start();
                                } catch (RuntimeException t) {
                                    sGLThreadManager.releaseEglContextLocked(this);
                                    throw t;
                                }
                                mHaveEglContext = true;
                                createEglContext = true;

                                sGLThreadManager.notifyAll();
                            }
                        }

                        /*有了EglContext,但是没有EglSurface,就需要设置一些状态,以便后续操作*/
                        if (mHaveEglContext && !mHaveEglSurface) {
                            mHaveEglSurface = true;
                            createEglSurface = true;
                            createGlInterface = true;
                            sizeChanged = true;
                        }

                        /*有eglSurface时,需要判断是否需要执行surface sizechange*/
                        if (mHaveEglSurface) {
                            if (mSizeChanged) {
                                sizeChanged = true;
                                w = mWidth;
                                h = mHeight;
                                mWantRenderNotification = true;
                               
                                // Destroy and recreate the EGL surface.
                                createEglSurface = true;

                                mSizeChanged = false;
                            }
                            mRequestRender = false;
                            sGLThreadManager.notifyAll();
                            if (mWantRenderNotification) {
                                wantRenderNotification = true;
                            }
                            //注意此处break,跳出等待的循环
                            break;
                        }
                    }

                    // By design, this is the only place in a GLThread thread where we wait().
                    sGLThreadManager.wait();
                }
            }

            /*外部请求在GL线程中处理的事件没有处理完时,就优先处理这些事件*/
            if (event != null) {
                event.run();
                event = null;
                continue;
            }

            //后续就是根据上面的判断设置,来执行相应的操作
            if (createEglSurface) {//EglSurface需要被创建
                //创建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) {

                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                if (view != null) {
                    try {
                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated");
                        //调用GLSurfaceView设置的renderer的onSurfceCreated方法
                        view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
                    } finally {
                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                    }
                }
                createEglContext = false;
            }

            //surface大小被改变
            if (sizeChanged) {
                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                if (view != null) {
                    try {
                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceChanged");
                        view.mRenderer.onSurfaceChanged(gl, w, h);//通知应用程序尺寸发生了变化
                    } finally {
                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                    }
                }
                sizeChanged = false;
            }

            //每帧绘制
            {
                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
                if (view != null) {
                    try {
                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onDrawFrame");
                        view.mRenderer.onDrawFrame(gl);//调用应用程序的Renderer渲染
                    } finally {
                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                    }
                }
            }
            //提交绘制结果,通过swap把渲染结果显示到屏幕上
            int swapError = mEglHelper.swap();
            switch (swapError) {
                case EGL10.EGL_SUCCESS:
                    break;
                case EGL11.EGL_CONTEXT_LOST:
                    lostEglContext = true;
                    break;
                default:
                    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();
        }
    }

}

        public boolean ableToDraw() {
            return mHaveEglContext && mHaveEglSurface && readyToDraw();
        }

        private boolean readyToDraw() {
            return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
                && (mWidth > 0) && (mHeight > 0)
                && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
        }

        //设置渲染方法,见GLSurfaceView的setRenderMode
        public void setRenderMode(int renderMode){
        if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
        throw new IllegalArgumentException("renderMode");
        }
        synchronized(sGLThreadManager) {
        mRenderMode = renderMode;
        sGLThreadManager.notifyAll();
        }
        }

        public int getRenderMode(){
        synchronized(sGLThreadManager) {
        return mRenderMode;
        }
        }

        //请求一次渲染
        public void requestRender(){
        synchronized(sGLThreadManager) {
        mRequestRender = true;
        sGLThreadManager.notifyAll();
        }
        }

        //请求一次渲染,并等待渲染完成
        public void requestRenderAndWait(){
        synchronized(sGLThreadManager) {
        if (Thread.currentThread() == this) {
         return;
        }

         mWantRenderNotification = true;
        mRequestRender = true;
        mRenderComplete = false;

        sGLThreadManager.notifyAll();

        while (!mExited && !mPaused && !mRenderComplete && ableToDraw()) {
        try {
        sGLThreadManager.wait();
        } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
        }
        }

         }
        }
        //创建Surface
        public void surfaceCreated(){
        synchronized(sGLThreadManager) {
        mHasSurface = true;
        mFinishedCreatingEglSurface = false;
        sGLThreadManager.notifyAll();
        while (mWaitingForSurface
    && !mFinishedCreatingEglSurface
     && !mExited) {
        try {
    sGLThreadManager.wait();
        } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        }
         }
        }
        }

        //销毁Surface
        public void surfaceDestroyed(){
        synchronized(sGLThreadManager) {
        mHasSurface = false;
        sGLThreadManager.notifyAll();
         while((!mWaitingForSurface) && (!mExited)) {
        try {
        sGLThreadManager.wait();
        } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        }
        }
        }
        }

        public void onPause(){
        synchronized (sGLThreadManager) {
        mRequestPaused = true;
        sGLThreadManager.notifyAll();
        while ((! mExited) && (! mPaused)) {
        try {
        sGLThreadManager.wait();
        } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
        }
        }
        }
        }
        public void onResume(){
        synchronized (sGLThreadManager) {
        mRequestPaused = false;
        mRequestRender = true;
        mRenderComplete = false;
        sGLThreadManager.notifyAll();
        while ((! mExited) && mPaused && (!mRenderComplete)) {
        try {
        sGLThreadManager.wait();
        } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
        }
        }
        }
        }

        //Surface的大小被改变时调用
        public void onWindowResize(int w, int h){
        synchronized (sGLThreadManager) {
        mWidth = w;
         mHeight = h;
        mSizeChanged = true;
        mRequestRender = true;
        mRenderComplete = false;

        if (Thread.currentThread() == this) {
        return;
        }

        sGLThreadManager.notifyAll();

        while (! mExited && !mPaused && !mRenderComplete
    && ableToDraw()) {
        try {
        sGLThreadManager.wait();
        } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
        }
        }
         }
        }

        //请求退出渲染线程,并等待退出
        public void requestExitAndWait(){
        synchronized(sGLThreadManager) {
        mShouldExit = true;
        sGLThreadManager.notifyAll();
        while (! mExited) {
        try {
        sGLThreadManager.wait();
        } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
        }
        }
        }
        }

        //请求回收EglContext
        public void requestReleaseEglContextLocked(){
        mShouldReleaseEglContext = true;
        sGLThreadManager.notifyAll();
        }

        //向GL线程发送一个任务
        public void queueEvent(Runnable r){
        if (r == null) {
        throw new IllegalArgumentException("r must not be null");
        }
        synchronized(sGLThreadManager) {
        mEventQueue.add(r);
        sGLThreadManager.notifyAll();
        }
        }

    }


    //很多方法都会调用此方法,会检查mGLThread不为null,即保证调用此方法的方法,必须在setRenderer之前调用
    private void checkRenderThreadState(){
    if (mGLThread != null) {
    throw new IllegalStateException(
"setRenderer has already been called for this instance.");
    }
    }

    //主要就是用来做同步用的,利用Object的wait和notifyAll
    private static class GLThreadManager {

            public synchronized void threadExiting(GLThread thread) {
                thread.mExited = true;
                notifyAll();
            }

            public void releaseEglContextLocked(GLThread thread) {
                notifyAll();
            }
    }

}




EGLHelper
readyToDraw后调用了EGLHelper.start方法初始化,然后跳出readyToDraw后调用了EGLHelper.createSurface方法创建一个EglSurface,
最后绘制完成以后通过EGLHelper.swap把渲染结果显示到屏幕上。

第一步:EGLHelper.start()方法初始化EGLHelper的内容
public void start() {
    mEgl = (EGL10) EGLContext.getEGL();//获取一个EGL实例
        //获取一个EGLDisplay
    mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

       //初始化EGL并返回版本号
    if(!mEgl.eglInitialize(mEglDisplay, version)) {
    }
    GLSurfaceView view = mGLSurfaceViewWeakRef.get();
        //选取一个配置
    mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
        //创建EGLContext
    mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
    mEglSurface = null;
}

第二步:如果需要创建EglSurface,调用mEglHelper.createSurface()方法
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");
    }
    GLSurfaceView view = mGLSurfaceViewWeakRef.get();
   
    mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
                mEglDisplay, mEglConfig, view.getHolder());

    return true;
}

private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {

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

}

第三步:提交绘制结果,通过mEglHelper.swap()把渲染结果显示到屏幕上
public int swap() {
     if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
          return mEgl.eglGetError();
     }
     return EGL10.EGL_SUCCESS;
}

总结GLSurfaceView使用EGL的流程如下:
1.生成一个EGL实例
mEgl = (EGL10) EGLContext.getEGL();
2.获取一个EGL Display  
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
3.初始化EGL并返回版本号
if(!mEgl.eglInitialize(mEglDisplay, version)) {}
4.选取一个配置
mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
5.创建一个EGLContext
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
6.创建EGLSurface
egl.eglCreateWindowSurface(display, config, nativeWindow, null);
7.通过swap将渲染内容显示到屏幕
mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)

展开阅读全文

没有更多推荐了,返回首页