EGL简介

作者: hlp22 | 来源:发表于2017-11-18 21:36 被阅读0次

    一、什么是EGL

    EGL用于管理绘图表面, 提供了如下机制:

    1. 与设备的原生窗口系统通信;
    2. 查询绘制表面的可用类型和配置;
    3. 创建绘图表面;
    4. 在OpenGL ES3.0 和其他图形渲染API直接同步渲染;
    5. 管理纹理贴图等渲染资源;

    总之:EGL提供了OpenGL ES3.0和运行于计算机上的原生窗口系统之间的一个“结合”层次。使用过程可分如下几个步骤:

    1. 初始化EGL
    2. 确定可用表面配置
    3. 创建渲染窗口
    4. 创建一个渲染上下文
    5. 设置为当前的渲染环境

    二、初始化EGL

    EGL10 egl10 =  (EGL10) EGLContext.getEGL();
    EGLDisplay eglDisplay = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
    if (EGL10.EGL_NO_DISPLAY == eglDisplay){
       //error msg         
        return;
    }
    int version[] = new int[2];
    if(!egl10.eglInitialize(eglDisplay, version)){
       //error msg
       return;
    }
    

    eglGetDisplay方法用于获得EGLDisplay, EGLDisplay为显示设备。获取成功后即可调用eglInitialize初始化EGL, 其中version[0]为主版本号,version[1]为子版本号。
    另外也可以调用eglQueryString来查询EGL的相关信息,如版本号、实现厂家等。
    例如:

    String vendor = egl10.eglQueryString(eglDisplay, EGL10.EGL_VENDOR);
    System.out.println("egl vendor: " + vendor); // 打印此版本EGL的实现厂商
    
    

    三、确定可用表面配置

    初始化EGL之后,就可以确定可用的渲染表面的类型和配置,有两种方法:

    1. 查询每个表面配置, 找出最好的选择;
    2. 指定一组需求, 让EGL推荐最佳匹配;

    1、 查询所有配置

    EGLConfig包含EGL相关的各种属性,如何获取EGL支持的所有配置呢?需要用到的函数为:

     boolean  eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
    

    其中:
    config_size为获取EGLConfig的数量,num_config为系统支持的所有EGLConfig数量。函数有两种使用方式:第一种是configs设为null,则num_config可返回可用配置的数量;第二种方式是将config_size设置为configs数组的大小,函数将返回config_size个可用配置。为了谨慎起见使用如下:

     int configsNum[] = new int[1];
     egl10.eglGetConfigs(eglDisplay, null, 0, configsNum);
    
     EGLConfig eglConfig[] = new EGLConfig[configsNum[0]];
     egl10.eglGetConfigs(eglDisplay, eglConfig, configsNum[0], configsNum);
        
    

    获取EGLConfig后可用eglGetConfigAttrib查询所支持的配置信息,如查询第i个EGLConfig中颜色缓冲区中所有颜色分量的位数:

    int colorBufferSize[] = new int[1];
    egl10.eglGetConfigAttrib(eglDisplay, eglConfig[i], EGL10.EGL_BUFFER_SIZE, colorBufferSize);
    System.out.println("EGL_BUFFER_SIZE:" + colorBufferSize[0]);
          
    

    2、让EGL选择配置

    使用函数:

    boolean  eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
      
    

    可匹配符合需要的EGLConfig。
    其中:attrib_list为匹配的熟悉列表。
    如果匹配成功则返回true。使用方式如下:

    int[] attributes = new int[] {
                    EGL10.EGL_RED_SIZE, 5,  //指定RGB中的R大小(bits)
                    EGL10.EGL_GREEN_SIZE, 6, //指定G大小
                    EGL10.EGL_BLUE_SIZE, 5,  //指定B大小
                    EGL10.EGL_DEPTH_SIZE, 1, //指定深度缓存(Z Buffer)大小
                    EGL10.EGL_NONE };
    int chooseNum = 10;
    EGLConfig chooseConfigs[] = new EGLConfig[chooseNum];
    int chooseMaxNum[] = new int[1];
    egl10.eglChooseConfig(eglDisplay, attributes,  chooseConfigs, chooseNum, chooseMaxNum);
    

    熟悉列表最后以EGL10.EGL_NONE结尾。

    四、创建渲染窗口

    当找到符合渲染需求的EGLConfig后,就可以创建显然窗口, 调用函数如下:

    EGLSurface  eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
    

    五、创建一个渲染上下文

     EGLContext  eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
      
    

    其中share_context表示是否有context共享,共享的contxt之间亦共享所有数据,EGL_NO_CONTEXT代表不共享;attrib_list表示可用属性,当前只有EGL_CONTEXT_CLIENT_VERSION, 1代表OpenGL ES 1.x, 2代表2.0。

    六、设置为当前的渲染环境

    boolean  eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
        
    

    其中:draw为绘图表面, read为读取表面。

    七、demo

    在Android中使用OpenGL ES一般都是直接利用GLSurfaceView控件, 其封装了EGL相关的操作,方便使用。那如何在SurfaceView中使用OpenGL ES呢? 例子如下:

    • MainActivity:
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    
    public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{
        private EGLUtils eglUtils;
        private SurfaceView view;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            view = new SurfaceView(this);
            view.getHolder().addCallback(this);
            setContentView(view);
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            eglUtils = new EGLUtils();
            if(eglUtils.CreateEGLEnv(holder)){
                Triangle triangle = new Triangle();
                triangle.draw();
                eglUtils.swapBuffer();
                eglUtils.destroy();
            }
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
    
        }
    }
    

    将EGL相关操作封装如下:

    • EGLUtils:
    import android.view.SurfaceHolder;
    import javax.microedition.khronos.egl.EGL10;
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.egl.EGLContext;
    import javax.microedition.khronos.egl.EGLDisplay;
    import javax.microedition.khronos.egl.EGLSurface;
    import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
    import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
    import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE;
    
    public class EGLUtils {
        private EGLDisplay eglDisplay;
        private EGL10  egl10;
        private EGLSurface eglSurface;
        private EGLContext eglContext;
    
        public boolean CreateEGLEnv(SurfaceHolder holder){
            egl10 =  (EGL10) EGLContext.getEGL();
            eglDisplay = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
            if (EGL10.EGL_NO_DISPLAY == eglDisplay){
                System.out.println("egl 不可用:err:" + egl10.eglGetError());
                return false;
            }
            int version[] = new int[2];
            if(!egl10.eglInitialize(eglDisplay, version)){
                //error msg
                return false;
            }
            int[] attributes = new int[] {
                    EGL10.EGL_RED_SIZE, 5,  //指定RGB中的R大小(bits)
                    EGL10.EGL_GREEN_SIZE, 6, //指定G大小
                    EGL10.EGL_BLUE_SIZE, 5,  //指定B大小
                    EGL10.EGL_DEPTH_SIZE, 1, //指定深度缓存(Z Buffer)大小
                    EGL10.EGL_NONE };
    
            int chooseNum = 10;
            EGLConfig chooseConfigs[] = new EGLConfig[chooseNum];
            int chooseMaxNum[] = new int[1];
            egl10.eglChooseConfig(eglDisplay, attributes,  chooseConfigs, chooseNum, chooseMaxNum);
            System.out.println("chooseMaxNum:" + chooseMaxNum[0]);
    
    
            eglSurface = egl10.eglCreateWindowSurface(eglDisplay, chooseConfigs[0], holder, null);
            if(eglSurface == EGL_NO_SURFACE){
                System.out.println("create surface failed,msg:" + egl10.eglGetError());
                return false;
            }
            int[] contextAttr = new int[]{
                    EGL_CONTEXT_CLIENT_VERSION, 2,
                    EGL10.EGL_NONE
            };
            eglContext = egl10.eglCreateContext(eglDisplay, chooseConfigs[0], egl10.EGL_NO_CONTEXT, contextAttr);
            if(eglContext == EGL_NO_CONTEXT){
                System.out.println("create context failed,msg:" + egl10.eglGetError());
                return false;
            }
            if(!egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)){
                System.out.println("eglMakeCurrent ailed, msg:" + egl10.eglGetError());
                return false;
            }
            return true;
        }
    
        public void destroy(){
            egl10.eglMakeCurrent(eglDisplay, EGL_NO_SURFACE,
                    EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            egl10.eglDestroySurface(eglDisplay, eglSurface);
            egl10.eglDestroyContext(eglDisplay, eglContext);
            egl10.eglTerminate(eglDisplay);
        }
    
        public  void swapBuffer(){
            egl10.eglSwapBuffers(eglDisplay, eglSurface);
        }
    }
    

    demo以绘制一个三角形为目的,三角形如下:

    • Triangle.java
    import android.opengl.GLES20;
    
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.nio.FloatBuffer;
    import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
    
    public class Triangle {
        private FloatBuffer vertexBuffer;
        private static final float VERTEXS[] = {
                -0.5f, 0.0f,
                0.5f, 0.0f,
                0.0f, 0.5f
        };
        private static final String vertexShaderCode =
                "attribute vec4 vPosition;" +
                        "void main() {" +
                        "gl_Position = vPosition;" +
                        "gl_PointSize = 10.0;" +
                        "}";
    
        private static final String fragmentShaderCode =
                "precision mediump float;" +
                        "uniform vec4 vColor;" +
                        "void main() {" +
                        "gl_FragColor = vColor;" +
                        "}";
    
        private int programId;
        private int vertexPositionId;
        private int colorPositionId;
    
        public  Triangle(){
            ByteBuffer vertexBytes = ByteBuffer.allocateDirect(
                    VERTEXS.length * 4);
            vertexBytes.order(ByteOrder.nativeOrder());
    
            vertexBuffer = vertexBytes.asFloatBuffer();
            vertexBuffer.put(VERTEXS);
            vertexBuffer.position(0);
    
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            programId = OpenGlUtils.loadProgram(vertexShaderCode, fragmentShaderCode);
        }
    
        public void draw(){
            GLES20.glClear(GL_COLOR_BUFFER_BIT);
            GLES20.glUseProgram(programId);
            vertexPositionId = GLES20.glGetAttribLocation(programId, "vPosition");
            colorPositionId = GLES20.glGetUniformLocation(programId, "vColor");
            GLES20.glVertexAttribPointer(vertexPositionId, 2,
                    GLES20.GL_FLOAT, false,
                    0, vertexBuffer);
            GLES20.glEnableVertexAttribArray(vertexPositionId);
            GLES20.glUniform4f(colorPositionId, 1.0f, 0.0f, 0.0f, 0.0f);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
            GLES20.glDisableVertexAttribArray(vertexPositionId);
        }
    }
    
    

    其中OpenGlUtils在文章2. 第一个三角形

    说明:本demo只是为了演示如果在SurfaceView中使用OpenGL ES,实际中如何使用可参考:Android example source code file (GLView.java)

    参考:

    1. 学习OpenGL-ES: 2 - EGL解析

    2. OpenGL ES 3.0编程指南

    相关文章

      网友评论

          本文标题:EGL简介

          本文链接:https://www.haomeiwen.com/subject/csuyvxtx.html