GLSurfaceView的简单分析及巧妙借用_seteglcontextfactory-程序员宅基地

技术标签: android  video  

https://blog.csdn.net/junzia/article/details/73717506

 

GLSurfaceView的简单分析及巧妙借用

2017年06月25日 14:59:39 湖广午王 阅读数:10582 标签: android opengl es 更多

个人分类: OpenGLES Android 午王

所属专栏: Android OpenGLES

版权声明:欢迎转载,转载请保留文章出处。 https://blog.csdn.net/junzia/article/details/73717506

学习在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.0
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) {
        //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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

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<GLSurfaceView> 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 {

    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315

渲染的主要逻辑在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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315

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();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

那么如何办呢?我们可以新建一个类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);
    }
});
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010029439/article/details/85542382

智能推荐

js-选项卡原理_选项卡js原理-程序员宅基地

文章浏览阅读90次。【代码】js-选项卡原理。_选项卡js原理

设计模式-原型模式(Prototype)-程序员宅基地

文章浏览阅读67次。原型模式是一种对象创建型模式,它采用复制原型对象的方法来创建对象的实例。它创建的实例,具有与原型一样的数据结构和值分为深度克隆和浅度克隆。浅度克隆:克隆对象的值类型(基本数据类型),克隆引用类型的地址;深度克隆:克隆对象的值类型,引用类型的对象也复制一份副本。UML图:具体代码:浅度复制:import java.util.List;/*..._prototype 设计模式

个性化政府云的探索-程序员宅基地

文章浏览阅读59次。入选国内首批云计算服务创新发展试点城市的北京、上海、深圳、杭州和无锡起到了很好的示范作用,不仅促进了当地产业的升级换代,而且为国内其他城市发展云计算产业提供了很好的借鉴。据了解,目前国内至少有20个城市确定将云计算作为重点发展的产业。这势必会形成新一轮的云计算基础设施建设的**。由于云计算基础设施建设具有投资规模大,运维成本高,投资回收周期长,地域辐射性强等诸多特点,各地在建...

STM32问题集之BOOT0和BOOT1的作用_stm32boot0和boot1作用-程序员宅基地

文章浏览阅读9.4k次,点赞2次,收藏20次。一、功能及目的 在每个STM32的芯片上都有两个管脚BOOT0和BOOT1,这两个管脚在芯片复位时的电平状态决定了芯片复位后从哪个区域开始执行程序。BOOT1=x BOOT0=0 // 从用户闪存启动,这是正常的工作模式。BOOT1=0 BOOT0=1 // 从系统存储器启动,这种模式启动的程序_stm32boot0和boot1作用

C语言函数递归调用-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏22次。C语言函数递归调用_c语言函数递归调用

明日方舟抽卡模拟器wiki_明日方舟bilibili服-明日方舟bilibili服下载-程序员宅基地

文章浏览阅读410次。明日方舟bilibili服是一款天灾驾到战斗热血的创新二次元废土风塔防手游,精妙的二次元纸片人设计,为宅友们源源不断更新超多的纸片人老婆老公们,玩家将扮演废土正义一方“罗德岛”中的指挥官,与你身边的感染者们并肩作战。与同类塔防手游与众不同的几点,首先你可以在这抽卡轻松获得稀有,同时也可以在战斗体系和敌军走位机制看到不同。明日方舟bilibili服设定:1、起因不明并四处肆虐的天灾,席卷过的土地上出..._明日方舟抽卡模拟器

随便推点

Maven上传Jar到私服报错:ReasonPhrase: Repository version policy: SNAPSHOT does not allow version: xxx_repository version policy snapshot does not all-程序员宅基地

文章浏览阅读437次。Maven上传Jar到私服报错:ReasonPhrase: Repository version policy: SNAPSHOT does not allow version: xxx_repository version policy snapshot does not all

斐波那契数列、素数、质数和猴子吃桃问题_斐波那契日-程序员宅基地

文章浏览阅读1.2k次。斐波那契数列(Fibonacci Sequence)是由如下形式的一系列数字组成的:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …上述数字序列中反映出来的规律,就是下一个数字是该数字前面两个紧邻数字的和,具体如下所示:示例:比如上述斐波那契数列中的最后两个数,可以推导出34后面的数为21+34=55下面是一个更长一些的斐波那契数列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584,_斐波那契日

PHP必会面试题_//该层循环用来控制每轮 冒出一个数 需要比较的次数-程序员宅基地

文章浏览阅读363次。PHP必会面试题1. 基础篇1. 用 PHP 打印出前一天的时间格式是 2017-12-28 22:21:21? //&gt;&gt;1.当前时间减去一天的时间,然后再格式化echo date('Y-m-d H:i:s',time()-3600*24);//&gt;&gt;2.使用strtotime,可以将任何字符串时间转换成时间戳,仅针对英文echo date('Y-m-d H:i:s',str..._//该层循环用来控制每轮 冒出一个数 需要比较的次数

windows用mingw(g++)编译opencv,opencv_contrib,并install安装_opencv mingw contrib-程序员宅基地

文章浏览阅读1.3k次,点赞26次,收藏26次。windows下用mingw编译opencv貌似不支持cuda,选cuda会报错,我无法解决,所以没选cuda,下面两种编译方式支持。打开cmake gui程序,在下面两个框中分别输入opencv的源文件和编译目录,build-mingw为你创建的目录,可自定义命名。1、如果已经安装Qt,则Qt自带mingw编译器,从Qt安装目录找到编译器所在目录即可。1、如果已经安装Qt,则Qt自带cmake,从Qt安装目录找到cmake所在目录即可。2、若未安装Qt,则安装Mingw即可,参考我的另外一篇文章。_opencv mingw contrib

5个高质量简历模板网站,免费、免费、免费_hoso模板官网-程序员宅基地

文章浏览阅读10w+次,点赞42次,收藏309次。今天给大家推荐5个好用且免费的简历模板网站,简洁美观,非常值得收藏!1、菜鸟图库https://www.sucai999.com/search/word/0_242_0.html?v=NTYxMjky网站主要以设计类素材为主,办公类素材也很多,简历模板大部个偏简约风,各种版式都有,而且经常会更新。最重要的是全部都能免费下载。2、个人简历网https://www.gerenjianli.com/moban/这是一个专门提供简历模板的网站,里面有超多模板个类,找起来非常方便,风格也很多样,无须注册就能免费下载,_hoso模板官网

通过 TikTok 联盟提高销售额的 6 个步骤_tiktok联盟-程序员宅基地

文章浏览阅读142次。你听说过吗?该计划可让您以推广您的产品并在成功销售时支付佣金。它提供了新的营销渠道,使您的产品呈现在更广泛的受众面前并提高品牌知名度。此外,TikTok Shop联盟可以是一种经济高效的产品或服务营销方式。您只需在有人购买时付费,因此不存在在无效广告上浪费金钱的风险。这些诱人的好处是否足以让您想要开始您的TikTok Shop联盟活动?如果是这样,本指南适合您。_tiktok联盟