Android OpenGL ES -------GLSurfaceView源码解析

GLSurfaceView简介

GLSurfaceView继承于SurfaceView,主要用于配合OpenGL ES的接口执行渲染窗口的任务。

一、创建及使用

1、在layout文件中使用android.opengl.GLSurfaceView,代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.opengl.GLSurfaceView
        android:id="@+id/surfaceview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

2、自定义Renderer

public class TestRenderer implements GLSurfaceView.Renderer{
     
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
     

    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
     
        //设置窗口大小
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
     
        //执行清屏
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glClearColor(0.0f, 0.1f, 0.0f, 1.0f);
    }
}

3、给GLSurfaceView设置Renderer

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
     
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
    glSurfaceView = (GLSurfaceView)findViewById(R.id.surfaceview);
    TestRenderer renderer = new TestRenderer();
    glSurfaceView.setRenderer(renderer);
}

4、执行效果
Android OpenGL ES -------GLSurfaceView源码解析_第1张图片

二、GLSurfaceView原理

上面我们执行GLSurfaceView的setRenderer方法,界面就执行绘制,那么我们从这个方法源码入手:

public void setRenderer(Renderer renderer) {
     
    //第一步,检查GLThread线程是否已经存在,存在则抛出IllegalStateException异常
    checkRenderThreadState();
    //判断EGL设置是否已经设置过了,没有的话,就会选择最接近安装设备的参数进行设置
    if (mEGLConfigChooser == null) {
     
        mEGLConfigChooser = new SimpleEGLConfigChooser(true);
    }
    //EGLContext上下文创建
    if (mEGLContextFactory == null) {
     
        mEGLContextFactory = new DefaultContextFactory();
    }
    //EGLWindowSurfaceFactory创建
    if (mEGLWindowSurfaceFactory == null) {
     
        mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
    }
    mRenderer = renderer;
    //开启一个线程,执行相关操作,这里才是重头戏
    mGLThread = new GLThread(mThisWeakRef);
    mGLThread.start();
}

从源码上看,setRenderer这个方法前面都是一些初始化环境的判断及创建,后面开启一个GLThread线程,这个线程才是重头戏,我们来看下这个线程的run方法:

@Override
public void run() {
     
    setName("GLThread " + getId());
    if (LOG_THREADS) {
     
        Log.i("GLThread", "starting tid=" + getId());
    }

    try {
     
    	//只调用了这个方法
        guardedRun();
    } catch (InterruptedException e) {
     
       
    } finally {
     
        sGLThreadManager.threadExiting(this);
    }
}

我们来看看这个guardedRun方法源码干了什么事:

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) {
     
                    if (mShouldExit) {
     
                        return;
                    }

                    if (! mEventQueue.isEmpty()) {
     
                        event = mEventQueue.remove(0);
                        break;
                    }

                    // Update the pause state.
                    boolean pausing = false;
                    if (mPaused != mRequestPaused) {
     
                        pausing = mRequestPaused;
                        mPaused = mRequestPaused;
                        sGLThreadManager.notifyAll();
                        if (LOG_PAUSE_RESUME) {
     
                            Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
                        }
                    }

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

                    // Have we lost the EGL context?
                    if (lostEglContext) {
     
                        stopEglSurfaceLocked();
                        stopEglContextLocked();
                        lostEglContext = false;
                    }

                    // When pausing, release the EGL surface:
                    if (pausing && mHaveEglSurface) {
     
                        if (LOG_SURFACE) {
     
                            Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
                        }
                        stopEglSurfaceLocked();
                    }

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

                    // Ready to draw?
                    if (readyToDraw()) {
     

                        // If we don't have an EGL context, try to acquire one.
                        if (! mHaveEglContext) {
     
                            if (askedToReleaseEglContext) {
     
                                askedToReleaseEglContext = false;
                            } else {
     
                                try {
     
                                    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) {
     
                            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().
                    if (LOG_THREADS) {
     
                        Log.i("GLThread", "waiting tid=" + getId()
                            + " mHaveEglContext: " + mHaveEglContext
                            + " mHaveEglSurface: " + mHaveEglSurface
                            + " mFinishedCreatingEglSurface: " + mFinishedCreatingEglSurface
                            + " mPaused: " + mPaused
                            + " mHasSurface: " + mHasSurface
                            + " mSurfaceIsBad: " + mSurfaceIsBad
                            + " mWaitingForSurface: " + mWaitingForSurface
                            + " mWidth: " + mWidth
                            + " mHeight: " + mHeight
                            + " mRequestRender: " + mRequestRender
                            + " mRenderMode: " + mRenderMode);
                    }
                    sGLThreadManager.wait();
                }
            } // end of synchronized(sGLThreadManager)

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

            if (createEglSurface) {
     
                if (LOG_SURFACE) {
     
                    Log.w("GLThread", "egl createSurface");
                }
                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");
                        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");
                        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) {
     
                    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();
        }
    }
}

guardedRun方法源码很长,下面是我简化后的描述:

private void guardedRun() throws InterruptedException {
     
    //创建EglHelper
    mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);

    try {
     
        //创建GL10,Runnable,及一系列boolean状态值
        ...

        //开启第一层死循环,执行生命周期回调及界面绘制工作
        while (true) {
     
            synchronized (sGLThreadManager) {
     

                //开启第二层死循环,获取Runnable,获取到就跑到上一层死循环执行绘制,
                while (true) {
     
                    //如果Runnable队列不为空,则取出来,跳到第一层死循环
                    if (!mEventQueue.isEmpty()) {
     
                        //注意这个event,会在上一层死循环调用
                        event = mEventQueue.remove(0);
                        break;
                    }


                    // 判断是否需要暂停
                    boolean pausing = false;
                    if (mPaused != mRequestPaused) {
     
                        pausing = mRequestPaused;
                        mPaused = mRequestPaused;
                        sGLThreadManager.notifyAll();
                        if (LOG_PAUSE_RESUME) {
     
                            Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
                        }
                    }

                    //判断EGL context上下文是否正常,一系列检测,包括SurfaceView引用是否丢失,环境的判断是否正常等等
                    ...


                    // 判断是否准备绘制,如果是,那么执行绘制前的一系列环境判断,
                    if (readyToDraw()) {
     
                        //...
                        //主要是开启EglHelper.start方法,这个方法主要是初始化EGL环境的配置
                        mEglHelper.start();
                        //...
                    }else {
     
                        ...
                        //如果还没准备好绘制,则停止上一次的绘制
                        finishDrawingRunnable.run();
                        ...
                    }
                    sGLThreadManager.wait();
                }
            }

            //从第二次死循环拿到的绘制Runnable
            if (event != null) {
     
                event.run();
                event = null;
                continue;
            }
            //如果没有绘制的Runnable需要执行,那么做一系列状态值及环境获取操作,及Renderer的生命周期回调
            ...

            //举例子,这里回调了Renderer.onSurfaceChanged(gl, w, h)方法
            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");
                        view.mRenderer.onSurfaceChanged(gl, w, h);
                    } finally {
     
                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                    }
                }
                sizeChanged = false;
            }
            //把渲染的EGL画面显示到屏幕上
            int swapError = mEglHelper.swap();
        }

    } finally {
     
        /*
        * 释放资源
        */
    }
}

GLSurfaceView分析就到这里,希望大家多多看看源码,能学到很多东西,比如这个GLThread为什么要声明为静态内部类,及其内部对于GLSurfaceView的持有使用WeakReference弱引用,线程之间notify和wait机制,Android的设计模式等等。

你可能感兴趣的:(Android,OpenGL,ES)