OpenGL ES 之EGL(6)

OpenGL ES 之EGL(6)

简述

EGL是OpenGL ES的封装,目的是跨设备跨平台,隔离不同平台对窗口不同的实现。上一节我们基本没有使用到EGL,因为GLSurfaceView帮助我们处理了相关的逻辑,我们这一节来看一下EGL的一些概念以及接口的使用。

同时我们会介绍GLSurfaceView做了什么,是怎么配置EGL等。

EGL接口

  • 1.eglGetDisplay
    用于获取EGLDisplay,这里会关联原生窗口,EGLDisplay是对设备的抽象。
  • 2.eglInitialize(EGLDisplay display, EGLint *majorVersion, EGLint *minorVersion)
    初始化函数,第一个参数是eglGetDisplay返回值。
  • 3.eglChooseConfig
    EGL会根据设备配置选择合适的Config
  • 4.eglCreateWindowSurface
    通过前面EGLDisplay和EGLConfig创建EGLSurface
  • 5.eglCreateContext
    创建EGLContext,创建渲染上下文
  • 6.eglMakeCurrent
    绑定EGLContext,EGLSurface,EGLDisplay,之后即可调用openGL ES的api做图像渲染了。
  • 7.eglSwapBuffers
    交换缓冲区,调用后就会将内存中的图像显示到屏幕上。

GLSurfaceView流程

setRenderer

配置了Renderer之后,GLSurfaceView启动了一个GLThread线程

复制代码
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();
    }
    // 构造并启动了一个GLThread线程
    mGLThread = new GLThread(renderer);
    mGLThread.start();
}

GLThread

调用了guardedRun。

guardedRun通过一个EglHelper来调用EGL的接口。

guardedRun在一个死循环中,死循环中还有一个死循环,这里会通过mEglHelper.start来初始化EGL。在EGLSurface创建好后,就会跳出这个死循环,在外层循环后面的逻辑,首次会通过createSurface创建EGLSurface,并且回调Renderer.onSurfaceCreated,也会检查sizeChanged,如果sizeChanged则会回调Renderer.onSurfaceChanged。

每次循环都会回调Renderer.onDrawFrame,在回调onDrawFrame之后会调用mEglHelper.swap来执行交换区。

这里EglHelper的start/createSurface/swap,我们接下来看看这几个方法。

复制代码
private class GLThread extends Thread {
    // ...
    public void run() {
        setName("GLThread " + getId());
        if (LOG_THREADS) {
            DebugLog.i("GLThread", "starting tid=" + getId());
        }

        try {
            guardedRun();
        } catch (InterruptedException e) {
            // fall thru and exit normally
        } finally {
            sGLThreadManager.threadExiting(this);
        }
    }
}

private void guardedRun() throws InterruptedException {
    mEglHelper = new EglHelper();
    // ...
    try {
        // ...
        while (true) {
            synchronized (sGLThreadManager) {
                while (true) {
                    // ...
                    if ((! mHasSurface) && (! mWaitingForSurface)) {
                        if (LOG_SURFACE) {
                            DebugLog.i("GLThread", "noticed surfaceView surface lost tid=" + getId());
                        }
                        if (mHaveEglSurface) {
                            stopEglLocked();
                        }
                        mWaitingForSurface = true;
                        sGLThreadManager.notifyAll();
                    }
                    // ...
                    // Ready to draw?
                    if ((!mPaused) && mHasSurface
                        && (mWidth > 0) && (mHeight > 0)
                        && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {

                        if (mHaveEglContext && !mHaveEglSurface) {
                    		// 检测EGL上下文
                    		if (!mEglHelper.verifyContext()) {
                    			mEglHelper.finish();
                    			mRenderer.onSurfaceLost();
                    			mHaveEglContext = false;
                    		}
                    	}

                        if ((! mHaveEglContext) && sGLThreadManager.tryAcquireEglSurfaceLocked(this)) {
                        	mHaveEglContext = true;
                            // 启动EGLHelper.start,这里会做EGL的初始化
                            mEglHelper.start();
                            
                            sGLThreadManager.notifyAll();
                        }
                        // ...

                        if (mHaveEglSurface) {
                            // ... 配置宽高
                            break;
                        }
                    }

                    sGLThreadManager.wait();
                }
            } // end of synchronized(sGLThreadManager)

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

            if (mHasFocus) {
                if (createEglSurface) {
                    // 调用createSurface,初始化EGL上下文
                    gl = (GL10) mEglHelper.createSurface(getHolder());
                    // ...
                    // 回调Renderer.onSurfaceCreated
                    mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
                    createEglSurface = false;
                    framesSinceResetHack = 0;
                }
                    

                if (sizeChanged) {
                    // ...
                    // 回调Renderer.onSurfaceChanged
                    mRenderer.onSurfaceChanged(gl, w, h);
                    sizeChanged = false;
                }
                // ...
                    
                mWatchDog.reset();
                // 回调Renderer.onDrawFrame
                mRenderer.onDrawFrame(gl);
                    
                framesSinceResetHack++;
                // 调用eglSwapBuffers,交换缓冲区上屏显示
                if(!mEglHelper.swap()) {
                    // ...
                        
                    stopEglLocked();
                }
                
            }
            if (wantRenderNotification) {
                doRenderNotification = true;
            }
        }
            
    } finally {
    	// ... 释放EGL上下文
    }
}

EglHelper

EglHelper就是对EGL对接口进行封装,这些EGL的接口作用在前面都介绍过了。

复制代码
public void start(){
    mEgl = (EGL10) EGLContext.getEGL();

    // 通过eglGetDisplay获取EglDisplay
    mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
    // ...
    int[] version = new int[2];
    // 调用eglInitialize进行初始化
    if(!mEgl.eglInitialize(mEglDisplay, version)) {
        throw new RuntimeException("eglInitialize failed");
    }
    // 调用eglChooseConfig获取EglConfig
    mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
    // 创建EglContext
    mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
    if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
        throwEglException("createContext");
    }

    mEglSurface = null;
}

public GL createSurface(SurfaceHolder holder) {
    // 如果之前创建过EglSurface,直接调用eglMakeCurrent进行关联
    if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
        mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
        mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
    }
    // 调用createWindowSurface创建EglSurface  
    mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
            mEglDisplay, mEglConfig, holder);

    if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
        throwEglException("createWindowSurface");
    }

    // 调用eglMakeCurrent关联
    if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
        throwEglException("eglMakeCurrent");
    }

    GL gl = mEglContext.getGL();
    if (mGLWrapper != null) {
        gl = mGLWrapper.wrap(gl);
    }

    // ... 配置debug相关flag
    return gl;
}

public boolean swap() {
    // 调用eglSwapBuffers交换Buffer显示
    mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);

    return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST;
}

小结

EGL的接口比较简单,流程也基本是固定的,我们以GLSurfaceView为例介绍了它的使用流程,GLSurfaceView就是启动一个线程,除了处理固定的EGL上下文初始化,还控制了Renderer回调的几个生命周期。

介绍完EGL后,我们后面就可以专注于OpenGL ES的api使用了。

相关推荐
EQ-雪梨蛋花汤43 分钟前
【Part 2安卓原生360°VR播放器开发实战】第四节|安卓VR播放器性能优化与设备适配
android·性能优化·vr
每次的天空1 小时前
Android学习总结之kotlin篇(二)
android·学习·kotlin
刘洋浪子1 小时前
Android Studio中Gradle中Task列表显示不全解决方案
android·ide·android studio
橙子199110161 小时前
Kotlin 中 infix 关键字的原理和使用场景
android·开发语言·kotlin
后端码匠8 小时前
MySQL 8.0安装(压缩包方式)
android·mysql·adb
梓仁沐白9 小时前
Android清单文件
android
董可伦11 小时前
Dinky 安装部署并配置提交 Flink Yarn 任务
android·adb·flink
每次的天空12 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭12 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin
flying robot14 小时前
小结:Android系统架构
android·系统架构