Android中为线程EGL环境创建及代码示例

#.EGL介绍:
    OpenGl是一套跨平台的接口,它与各个平台本地窗口系统之间的交互,是借助于一个中间控制层,这个中间控制层就是EGL。 EGL也有自己的一套标准API,由各个平台的系统来完成其具体实现。
        EGL是OpenGL和本地窗口体系进行联系的桥梁,负责管理OpenGL的运行状态、渲染图像到本地窗口或缓冲区等功能。
        在Android中,OpenGL的每一步处理,都需要依赖于EGL提供的这些相关功能支持,所以必须先创建EGL环境,才能正常进行OpenGL处理。
        不过Android中GLSurfaceView会自己在GLThread中完成EGL环境的初始化,使用GLSurfaceView时,开发者并不需要自己来初始化EGL环境。
##.EGL环境配置整体流程:
1.获取默认的EGLDisplay,对EGLDisplay进行初始化。
2.输入预设置的参数获取EGL支持的EGLConfig。
3.通过EGLDisplay和EGLConfig创建一个EGLContext上下文环境。
4.创建一个EGLSurface来将EGL和设备的输出区(一般是个Surface)关联起来。
5.在渲染线程中绑定EGL环境,即绑定上面配置的EGLContext、EGLSurface等。
##.后继处理流程:
1.在绘制中,调用OpenGL ES的API进行绘制操作。(与EGL无关)
2.每次绘制完毕后,调用EGL的EGL14.eglSwapBuffers()切换双缓冲,并输出渲染画面。
3.在全部的绘制流程结束后,释放EGL相关资源EGLSurface、EGLContext、EGLDisplay。
##.要点说明:
1.EGLSurface相当于是OpenGL ES的画布,而创建EGLSurface时会关联一个Surface,这个Surface是画面实际的承载者。
    只是OpenGL绘制需要EGL环境支持,所以需要将Surface进一步封装,添加EGL相关的功能支持,才能供OpenGL使用。
2.Surface是双缓冲的,EGLSurface封装了Surface,也是双缓冲的,包括前台和后台图形缓冲区,
        后台缓冲区用于绘制图像,前台换乘功能区用于显示图像或提供给画面消费方使用。
       每次在后台Buffer上处理完图像后,需要切换两个缓冲区的身份:
             让之前的后台Buffer变为前台,以便显示前面的绘制结果;
             让之前显示的前台Buffer变为后台,以便用于下次绘制操作;
      这个切换,是通过调用eglSwapBuffers(egl_display, egl_surface)来完成的。
3.那为啥在GLSurfaceView中我们不需要手动调用eglSwapBuffers()这个方法呢?
      因为其内部的GLThread已经做好了相关的封装,查看GLSurfaceView的源码会发现,GLThread调用我们写在onDraw()中的代码后,自己会去调用eglSwapBuffers()。
##.关键代码示例:
(这里是用传入的EGLContext和Surface来初始化线程的EGL环境)
/*1.配置EglDisplay*/
// 返回默认的显示设备.
mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
// 需判断是否成功获取EGLDisplay
if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
    throw new RuntimeException("eglGetDisplay failed");
}
// mEglDisplay进行初始化
int[] version = new int[2];
if(!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
    mEglDisplay = null;
    throw new RuntimeException("eglInitialize failed");
}

/*2.配置EGLConfig*/
// 已经将OpenGL ES的输出与设备的屏幕桥接起来,需指定一些配置项
int[] attribList = {
        EGL14.EGL_RED_SIZE, 8, //颜色缓冲区各个颜色分量的位数为8
        EGL14.EGL_GREEN_SIZE, 8,
        EGL14.EGL_BLUE_SIZE, 8,
        EGL14.EGL_ALPHA_SIZE, 8, //颜色缓冲区各个透明度分量的位数为8
        EGL14.EGL_DEPTH_SIZE, 16, // 部分手机GPU可能不支持深度
        EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, // opengl es 2.0
        EGLExt.EGL_RECORDABLE_ANDROID, 1, // 告诉EGL它创建的surface必须和视频编解码器兼容
        EGL14.EGL_NONE }; // 总是以EGL_NONE标识作为结尾信息
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
// eglChooseConfig()方法得到配置选项信息
if(!EGL14.eglChooseConfig(mEglDisplay, attribList, 0, configs, 0,
        configs.length, numConfigs, 0)){
    throw new IllegalArgumentException("eglChooseConfig failed");
}
// 如果没有配置的Config
if (numConfigs[0] < 0) {
    throw new RuntimeException("Unable to find any matching EGL config");
}
mEglConfig = configs[0];
// 对应的Config不存在
if (mEglConfig == null) {
    throw new RuntimeException("eglChooseConfig returned null");
}

/*3.配置EGLContext*/
// 指定OpenGL ES2版本
int[] attrib_list = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL14.EGL_NONE };
//创建EGLContext上下文
//若传入的EGLContext非空,则使用传入的EGLContext
if(sharedContext != null){
    mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
            sharedContext, attrib_list, 0);
} else {
    mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
            EGL14.EGL_NO_CONTEXT, attrib_list, 0);
}
//需要检测Context是否存在
if (mEglContext == EGL14.EGL_NO_CONTEXT) {
    throw new RuntimeException("Failed to create EGL context");
}

/*4.配置EGLSurface*/
// 创建可显示的Surface
int[] surfaceAttribs = { EGL14.EGL_NONE };
//这里第三个参数可以是Surface或SurfaceTexture
mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface,
        surfaceAttribs, 0);
if (mEglSurface == null || mEglSurface == EGL14.EGL_NO_SURFACE) {
    throw new RuntimeException("createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
}

/*5.与线程绑定
    每个线程都需要初始化EGL环境,才可以开始执行OpenGL ES指令,
    可以通过eglMakeCurrent()将刚才创建的EglDisplay、mEglSurface、mEglContext绑定到当前执行的线程*/
if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
    ILog.e(TAG, "eglSetup: " + Integer.toHexString(EGL14.eglGetError()));
    throw new RuntimeException("egl makeCurrent failed");
}

猜你喜欢

转载自blog.csdn.net/u013914309/article/details/124690398