学习在Android中使用OpenGLES,就不得不提到一个控件:GLSurfaceView。本篇博客将介绍GLSurfaceView的基本使用、GLSurfaceView的源码的简单分析,以及使用GLSurfaceView渲染图像到SurfaceView/TextureView或者PBuffer上等。

关于GLSurfaceView

GLSurfaceView继承了SurfaceView,实现了SurfaceHolder.Callback2接口。
SurfaceView在View的基础上是创建了独立的Surface,拥有SurfaceHolder来管理它的Surface,渲染的工作可以不再在主线程中做了。可以通过SurfaceHolder得到Canvas,在单独的线程中,利用Canvas绘制需要显示的内容,然后更新到Surface上。
而GLSurfaceView,它主要是在SurfaceView的基础上实现了一个GLThread(EGLContext创建GL环境所在线程即为GL线程),绘制的工作直接通过OpenGL来进行,绘制的内容默认情况下依旧是绘制到SurfaceView所提供的Surface上。
参照GLSurfaceView的实现,我们可以自行创建GL环境,来进行GL渲染。实现自行制定指定载体、后台渲染等功能。

GLSurfaceView的使用

GLSurfaceView作为一个View,实例化上基本和其他View相当。可以选择在xml布局文件中增加,然后在Java代码中取得它的控制权。也可以在Java代码中直接new,然后呈现出来。GLSurfaceView必须加入到一个布局中,才能正确的使用,否则有可能会造成崩溃
,这和GLSurfaceView的attachToWindow和detachFromWindow中相关操作。
GLSurfaceView具有onResume和onPause两个同Activity及Fragment中的生命周期同名的方法。一般来说,在Activity或者Fragment中的onResume和onPause方法中,需要主动调用GLSurfaceView的实例的这两个方法。
GLSurfaceView的基本使用代码如下:

mGLView= (GLSurfaceView) findViewById(R.id.mGLView);//GLContext设置为OpenGLES2.0mGLView.setEGLContextClientVersion(2);//在setRenderer之前,可以调用以下方法来进行EGL设置//mGLView.setEGLConfigChooser();    //颜色、深度、模板等等设置//mGLView.setEGLWindowSurfaceFactory(); //窗口设置//mGLView.setEGLContextFactory();   //EGLContext设置//设置渲染器,渲染主要就是由渲染器来决定mGLView.setRenderer(new GLSurfaceView.Renderer(){    @Override    public void onSurfaceCreated(GL10 gl, EGLConfig config) {        //todo surface被创建后需要做的处理    }    @Override    public void onSurfaceChanged(GL10 gl, int width, int height) {        //todo 渲染窗口大小发生改变的处理    }    @Override    public void onDrawFrame(GL10 gl) {        //todo 执行渲染工作    }});/*渲染方式,RENDERMODE_WHEN_DIRTY表示被动渲染,只有在调用requestRender或者onResume等方法时才会进行渲染。RENDERMODE_CONTINUOUSLY表示持续渲染*/mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

GLSurfaceView源码分析

GLSurfaceView中,对于GL环境的操作,出queueEvent是将事件放入队列中,到GL线程中执行外,其他方法基本都是在主线程(也可以是其他线程,非当前GLSurfaceView实例的GL线程)中修改某个状态值,然后取消GL线程的等待,在GL线程中根据状态值作相应的操作,并在操作后反馈给调用方法的那个线程,当然有的方法也不需要反馈。
GLSurfaceView主要方法及中文注释如下:

public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 {    public final static int RENDERMODE_WHEN_DIRTY = 0;    public final static int RENDERMODE_CONTINUOUSLY = 1;    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);        }        if (mEGLContextFactory == null) {            mEGLContextFactory = new DefaultContextFactory();        }        if (mEGLWindowSurfaceFactory == null) {            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();        }        mRenderer = renderer;        mGLThread = new GLThread(mThisWeakRef);        mGLThread.start();    }    //设置EGLContext工厂,不设置就用默认的    public void setEGLContextFactory(EGLContextFactory factory);    //设置EGLSurface工厂,不设置就用默认的    public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory);    //设置EglConfig,一般颜色深度等等,利用此方法设置。不设置就用默认的    public void setEGLConfigChooser(EGLConfigChooser configChooser);    //内部调用setEGLConfigChooser    public void setEGLConfigChooser(boolean needDepth);    //内部调用setEGLConfigChooser    public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,            int alphaSize, int depthSize, int stencilSize);    //设置EGLContextVersion,比如2,即OpenGLES2.0    public void setEGLContextClientVersion(int version);    //设置渲染方式,有RENDERMODE_CONTINUOUSLY表示不断渲染    //以及RENDERMODE_WHEN_DIRTY表示在需要的时候才会渲染    //渲染的时候要求调用requestRender,必须在setRenderer后调用    public void setRenderMode(int renderMode);    public int getRenderMode();    //主动请求渲染    public void requestRender();    public void surfaceCreated(SurfaceHolder holder);    public void surfaceDestroyed(SurfaceHolder holder);    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h);    @Override    public void surfaceRedrawNeeded(SurfaceHolder holder) {        if (mGLThread != null) {            mGLThread.requestRenderAndWait();        }    }    //生命周期,一般在Activity、Fragment的onPause中调用    public void onPause();    //生命周期,一般在Activity、Fragment的onResume中调用    public void onResume();    //向GL线程发送一个任务    public void queueEvent(Runnable r);    //附加到Window上时被调用,外部不可调用    protected void onAttachedToWindow();     //从Window上被移除时调用,外部不可调用    protected void 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 glSurfaceViewWeakRef) {            mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;        }        //EGL的初始化,可以参考此方法        public void start() {            if (LOG_EGL) {                Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());            }            /*             * Get an EGL instance             */            mEgl = (EGL10) EGLContext.getEGL();            /*             * Get to the default display.             */            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {                throw new RuntimeException("eglGetDisplay failed");            }            /*             * We can now initialize EGL for that display             */            int[] version = new int[2];            if(!mEgl.eglInitialize(mEglDisplay, version)) {                throw new RuntimeException("eglInitialize failed");            }            GLSurfaceView view = mGLSurfaceViewWeakRef.get();            if (view == null) {                mEglConfig = null;                mEglContext = null;            } else {                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() {            if (LOG_EGL) {                Log.w("EglHelper", "createSurface()  tid=" + Thread.currentThread().getId());            }            /*             * Check preconditions.             */            if (mEgl == null) {                throw new RuntimeException("egl not initialized");            }            if (mEglDisplay == null) {                throw new RuntimeException("eglDisplay not initialized");            }            if (mEglConfig == null) {                throw new RuntimeException("mEglConfig not initialized");            }            /*             *  The window size has changed, so we need to create a new             *  surface.             */            destroySurfaceImp();            /*             * Create an EGL surface we can render into.             */            GLSurfaceView view = mGLSurfaceViewWeakRef.get();            if (view != null) {                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();        //绘制完成之后,调用此方法,将绘制的内容输出到前台,让用户可以看到        public int swap();        //销毁Surface的方法,具体实现在destroySurfaceImp方法中        public void destroySurface();        //销毁GL环境        public void finish();    }    //GL线程,此类中存在的方法,GLSurfaceView中有同名的,    //基本都是提供给GLSurfaceView作为真正的实现调用    static class GLThread extends Thread {        //销毁EglSurface        private void stopEglSurfaceLocked();        //销毁EglContext        private void stopEglContextLocked();        //GL线程的主要逻辑都在这个方法里面,这个方法比较复杂        //GLSurfaceView的核心就在这个里面了,最后在单独分析这个里面的逻辑        private void guardedRun() throws InterruptedException;        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);        public int getRenderMode();        //请求一次渲染        public void requestRender();        //请求一次渲染,并等待渲染完成        public void requestRenderAndWait();        //创建Surface        public void surfaceCreated();        //销毁Surface        public void surfaceDestroyed();        public void onPause();        public void onResume();        //Surface的大小被改变时调用        public void onWindowResize(int w, int h);        //请求退出渲染线程,并等待退出        public void requestExitAndWait();        //请求是否EglContext        public void requestReleaseEglContextLocked();        //向GL线程发送一个任务        public void queueEvent(Runnable r);    }    //debug使用的    static class LogWriter extends Writer {    }    //很多方法都会调用此方法,会检查mGLThread不为null    //即保证调用此方法的方法,必须在setRenderer之前调用    private void checkRenderThreadState();    //主要就是用来做同步用的,利用Object的wait和notifyAll    private static class GLThreadManager {    }}

渲染的主要逻辑在GLThread的guardedRun()方法中,对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;        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();                        if (LOG_PAUSE_RESUME) {                            Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());                        }                    }                    // 需要释放EglContext时候执行的工作                    if (mShouldReleaseEglContext) {                        if (LOG_SURFACE) {                            Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());                        }                        stopEglSurfaceLocked();                        stopEglContextLocked();                        mShouldReleaseEglContext = false;                        askedToReleaseEglContext = true;                    }                    // EglContext丢失时,销毁EglSurface和EglContext                    if (lostEglContext) {                        stopEglSurfaceLocked();                        stopEglContextLocked();                        lostEglContext = false;                    }                    //接收了暂停信号,而且当前EglSurface存在时,销毁EglSurface                    if (pausing && mHaveEglSurface) {                        if (LOG_SURFACE) {                            Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());                        }                        stopEglSurfaceLocked();                    }                    /*接收了暂停信号,而且当前EglContext存在时,根据用户设置,来决定是否销毁EglContext*/                    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());                            }                        }                    }                    /*Surface不存在(不是EglSurface),而且当前并没有在等待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();                    }                    // Surface存在,而且在等待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 (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;                                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,跳出等待的循环                            break;                        }                    }                    // 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();                }            }             /*外部请求在GL线程中处理的事件没有处理完时,就优先处理这些事件*/            if (event != null) {                event.run();                event = null;                continue;            }            //后续就是根据上面的判断设置,来执行相应的操作            if (createEglSurface) {                if (LOG_SURFACE) {                    Log.w("GLThread", "egl createSurface");                }                //创建EglSurface                if (mEglHelper.createSurface()) {                           synchronized(sGLThreadManager) {                        mFinishedCreatingEglSurface = true;                        sGLThreadManager.notifyAll();                    }                } else {                    synchronized(sGLThreadManager) {                        mFinishedCreatingEglSurface = true;                        mSurfaceIsBad = true;                        sGLThreadManager.notifyAll();                    }                    continue;                }                createEglSurface = false;            }            if (createGlInterface) {                gl = (GL10) mEglHelper.createGL();                createGlInterface = false;            }            if (createEglContext) {                if (LOG_RENDERER) {                    Log.w("GLThread", "onSurfaceCreated");                }                GLSurfaceView view = mGLSurfaceViewWeakRef.get();                if (view != null) {                    try {                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated");                        //调用GLSurfaceView设置的renderer的onSurfceCreated方法                        view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);                    } finally {                        Trace.traceEnd(Trace.TRACE_TAG_VIEW);                    }                }                createEglContext = false;            }            //surface大小被改变            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);                    } 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:                    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();        }    }}

SurfaceView/TextureView或Pbuffer上的OpenGLES渲染

根据上面的分析,我们知道,GLSurfaceView有setEGLWindowSurfaceFactory借助此方法,我们可以将图像渲染到其他的地方,比如我们创建一个如下的自定义GLSurfaceView,就可以将图像渲染到外部指定surface上。但是遗憾的是,在某些手机上,这种方式会失效。

private class GLView extends GLSurfaceView{    public GLView(Context context) {        super(context);        init();    }    private void init(){        getHolder().addCallback(null);        setEGLWindowSurfaceFactory(new GLSurfaceView.EGLWindowSurfaceFactory() {            @Override            public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig                config, Object window) {                return egl.eglCreateWindowSurface(display,config,surface,null);            }            @Override            public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {                egl.eglDestroySurface(display, surface);            }        });        setEGLContextClientVersion(2);        setRenderer(TextureController.this);        setRenderMode(RENDERMODE_WHEN_DIRTY);        setPreserveEGLContextOnPause(true);    }    public void attachedToWindow(){        super.onAttachedToWindow();    }    public void detachedFromWindow(){        super.onDetachedFromWindow();    }}

那么如何办呢?我们可以新建一个类GLEnvironment,将GLSurfaceView内容全部复制出来,然后取消其继承和接口实现,将所有报错的代码删除掉,这样就相当于剔除了GLSurfaceView的SurfaceView而保留了它的GL环境,我们可以使用GLEnvironment来进行渲染,并自由的指定渲染载体,可以是SurfaceView/TextureView或Pbuffer,也可以是Pixmap。
同样是利用setEGLWindowSurfaceFactory方法来设置,当然可以改个名字更为贴切,比如setEGLSurfaceFactory,如下:

mEnv.setEGLSurfaceFactory(new GLEnvironment.EGLSurfaceFactory() {    @Override    public EGLSurface createSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow) {        /*使用SurfaceView或者TextureView,customWindow可以为SurfaceTexture\SurfaceHolder或者Surface等*/        egl.eglCreateWindowSurface(display,config,customWindow,null);        //使用pbuffer        //reture egl.eglCreatePbufferSurface();        //使用pixmap        //return egl.eglCreatePixmapSurface();    }    @Override    public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {         egl.eglDestroySurface(display,surface);    }});

具体代码请参考AndroidOpenGLDemo,在其中搜索GLEnvironment。

更多相关文章

  1. Android学习笔记-ProgressBar和ListView使用方法(二)
  2. Android getResources().getConfiguration()方法的作用
  3. 快速搭建Android 开发环境-使用ADT Bundle
  4. 【Android】UI界面外的线程,控制刷新UI界面
  5. 我的Android环境搭建
  6. Android读取文件方法总结

随机推荐

  1. Android之UI- listview特别的属性
  2. 自定义View组件
  3. ARFoundation快速入门-06ARCore设备支持
  4. Android导航栏ActionBar的详细分析
  5. android获取当前正在运行的桌面launcher
  6. eventloop(ril.cpp)函数中定义的管道的作
  7. Windows 下 Charles 如何配置抓取 Androi
  8. 【Android】从无到有:手把手一步步教你使
  9. 第19天android:《android从零开始》视频(6-
  10. Android(安卓)SystemUI 的一些主要操作