什么是 EGL

EGL 是 OpenGL ES 和本地窗口系统(Native Window System)之间的通信接口,它的主要作用:

  • 与设备的原生窗口系统通信;

  • 查询绘图表面的可用类型和配置;

  • 创建绘图表面;

  • 在OpenGL ES 和其他图形渲染API之间同步渲染;

  • 管理纹理贴图等渲染资源。

OpenGL ES 的平台无关性正是借助 EGL 实现的,EGL 屏蔽了不同平台的差异(Apple 提供了自己的 EGL API 的 iOS 实现,自称 EAGL)。

本地窗口相关的 API 提供了访问本地窗口系统的接口,而 EGL 可以创建渲染表面 EGLSurface ,同时提供了图形渲染上下文 EGLContext,用来进行状态管理,接下来 OpenGL ES 就可以在这个渲染表面上绘制。

egl、opengles 和设备之间的关系

图片中:

  • Display(EGLDisplay) 是对实际显示设备的抽象;

  • Surface(EGLSurface)是对用来存储图像的内存区域 FrameBuffer 的抽象,包括 Color Buffer(颜色缓冲区), Stencil Buffer(模板缓冲区) ,Depth Buffer(深度缓冲区);

  • Context (EGLContext) 存储 OpenGL ES 绘图的一些状态信息;

在 Android 平台上开发 OpenGL ES 应用时,类 GLSurfaceView 已经为我们提供了对 Display , Surface , Context 的管理,即 GLSurfaceView 内部实现了对 EGL 的封装,可以很方便地利用接口 GLSurfaceView.Renderer 的实现,使用 OpenGL ES API 进行渲染绘制,很大程度上提升了 OpenGLES 开发的便利性。

当然我们也可以自己实现对 EGL 的封装,本文就是在 Native 层对 EGL 进行封装,不借助于 GLSurfaceView ,实现图片后台渲染,利用 GPU 完成对图像的高效处理。

EGL 的应用

EGL 后台渲染实现效果图

使用 EGL 渲染的一般步骤:

  • 获取 EGLDisplay 对象,建立与本地窗口系统的连接调用 eglGetDisplay 方法得到 EGLDisplay。
  • 初始化 EGL 方法打开连接之后,调用 eglInitialize 方法初始化。
  • 获取 EGLConfig 对象,确定渲染表面的配置信息调用 eglChooseConfig 方法得到 EGLConfig。
  • 创建渲染表面 EGLSurface通过 EGLDisplay 和 EGLConfig ,调用 eglCreateWindowSurface 或 eglCreatePbufferSurface 方法创建渲染表面,得到 EGLSurface,其中 eglCreateWindowSurface 用于创建屏幕上渲染区域,eglCreatePbufferSurface 用于创建屏幕外渲染区域。
  • 创建渲染上下文 EGLContext 通过 EGLDisplay 和 EGLConfig ,调用 eglCreateContext 方法创建渲染上下文,得到 EGLContext。
  • 绑定上下文通过 eglMakeCurrent 方法将 EGLSurface、EGLContext、EGLDisplay 三者绑定,绑定成功之后 OpenGLES 环境就创建好了,接下来便可以进行渲染。
  • 交换缓冲OpenGLES 绘制结束后,使用 eglSwapBuffers 方法交换前后缓冲,将绘制内容显示到屏幕上,而屏幕外的渲染不需要调用此方法。
  • 释放 EGL 环境绘制结束后,不再需要使用 EGL 时,需要取消 eglMakeCurrent 的绑定,销毁  EGLDisplay、EGLSurface、EGLContext 三个对象。

代码实现:

// 创建 GLES 环境int BgRender::CreateGlesEnv(){    // EGL config attributes    const EGLint confAttr[] =    {            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,            EGL_SURFACE_TYPE,EGL_PBUFFER_BIT,//EGL_WINDOW_BIT EGL_PBUFFER_BIT we will create a pixelbuffer surface            EGL_RED_SIZE,   8,            EGL_GREEN_SIZE, 8,            EGL_BLUE_SIZE,  8,            EGL_ALPHA_SIZE, 8,// if you need the alpha channel            EGL_DEPTH_SIZE, 8,// if you need the depth buffer            EGL_STENCIL_SIZE,8,            EGL_NONE    };

    // EGL context attributes    const EGLint ctxAttr[] = {            EGL_CONTEXT_CLIENT_VERSION, 2,            EGL_NONE    };

    // surface attributes    // the surface size is set to the input frame size    const EGLint surfaceAttr[] = {            EGL_WIDTH, 1,            EGL_HEIGHT,1,            EGL_NONE    };    EGLint eglMajVers, eglMinVers;    EGLint numConfigs;

    int resultCode = 0;    do    {        //1. 获取 EGLDisplay 对象,建立与本地窗口系统的连接        m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);        if(m_eglDisplay == EGL_NO_DISPLAY)        {            //Unable to open connection to local windowing system            LOGCATE("BgRender::CreateGlesEnv Unable to open connection to local windowing system");            resultCode = -1;            break;        }

        //2. 初始化 EGL 方法        if(!eglInitialize(m_eglDisplay, &eglMajVers, &eglMinVers))        {            // Unable to initialize EGL. Handle and recover            LOGCATE("BgRender::CreateGlesEnv Unable to initialize EGL");            resultCode = -1;            break;        }

        LOGCATE("BgRender::CreateGlesEnv EGL init with version %d.%d", eglMajVers, eglMinVers);

        //3. 获取 EGLConfig 对象,确定渲染表面的配置信息        if(!eglChooseConfig(m_eglDisplay, confAttr, &m_eglConf, 1, &numConfigs))        {            LOGCATE("BgRender::CreateGlesEnv some config is wrong");            resultCode = -1;            break;        }

        //4. 创建渲染表面 EGLSurface, 使用 eglCreatePbufferSurface 创建屏幕外渲染区域        m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConf, surfaceAttr);        if(m_eglSurface == EGL_NO_SURFACE)        {            switch(eglGetError())            {                case EGL_BAD_ALLOC:                    // Not enough resources available. Handle and recover                    LOGCATE("BgRender::CreateGlesEnv Not enough resources available");                    break;                case EGL_BAD_CONFIG:                    // Verify that provided EGLConfig is valid                    LOGCATE("BgRender::CreateGlesEnv provided EGLConfig is invalid");                    break;                case EGL_BAD_PARAMETER:                    // Verify that the EGL_WIDTH and EGL_HEIGHT are                    // non-negative values                    LOGCATE("BgRender::CreateGlesEnv provided EGL_WIDTH and EGL_HEIGHT is invalid");                    break;                case EGL_BAD_MATCH:                    // Check window and EGLConfig attributes to determine                    // compatibility and pbuffer-texture parameters                    LOGCATE("BgRender::CreateGlesEnv Check window and EGLConfig attributes");                    break;            }        }

        //5. 创建渲染上下文 EGLContext        m_eglCtx = eglCreateContext(m_eglDisplay, m_eglConf, EGL_NO_CONTEXT, ctxAttr);        if(m_eglCtx == EGL_NO_CONTEXT)        {            EGLint error = eglGetError();            if(error == EGL_BAD_CONFIG)            {                // Handle error and recover                LOGCATE("BgRender::CreateGlesEnv EGL_BAD_CONFIG");                resultCode = -1;                break;            }        }

        //6. 绑定上下文        if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglCtx))        {            LOGCATE("BgRender::CreateGlesEnv MakeCurrent failed");            resultCode = -1;            break;        }        LOGCATE("BgRender::CreateGlesEnv initialize success!");    }    while (false);

    if (resultCode != 0)    {        LOGCATE("BgRender::CreateGlesEnv fail");    }

    return resultCode;}

//渲染void BgRender::Draw(){    LOGCATE("BgRender::Draw");    if (m_ProgramObj == GL_NONE) return;    glViewport(0, 0, m_RenderImage.width, m_RenderImage.height);

    // Do FBO off screen rendering    glUseProgram(m_ProgramObj);    glBindFramebuffer(GL_FRAMEBUFFER, m_FboId);

    glBindVertexArray(m_VaoIds[0]);    glActiveTexture(GL_TEXTURE0);    glBindTexture(GL_TEXTURE_2D, m_ImageTextureId);    glUniform1i(m_SamplerLoc, 0);

    if (m_TexSizeLoc != GL_NONE) {        GLfloat size[2];        size[0] = m_RenderImage.width;        size[1] = m_RenderImage.height;        glUniform2fv(m_TexSizeLoc, 1, &size[0]);    }

    //7. 渲染    GO_CHECK_GL_ERROR();    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void *)0);    GO_CHECK_GL_ERROR();    glBindVertexArray(GL_NONE);    glBindTexture(GL_TEXTURE_2D, GL_NONE);

    //一旦解绑 FBO 后面就不能调用 readPixels    //glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);

}

//释放 GLES 环境void BgRender::DestroyGlesEnv(){    //8. 释放 EGL 环境    if (m_eglDisplay != EGL_NO_DISPLAY) {        eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);        eglDestroyContext(m_eglDisplay, m_eglCtx);        eglDestroySurface(m_eglDisplay, m_eglSurface);        eglReleaseThread();        eglTerminate(m_eglDisplay);    }

    m_eglDisplay = EGL_NO_DISPLAY;    m_eglSurface = EGL_NO_SURFACE;    m_eglCtx = EGL_NO_CONTEXT;

}

Java 层的代码,主要是一个 ImageView 用于展示渲染前后的图像。

// 创建渲染对象NativeBgRender mBgRender = new NativeBgRender();// 初始化创建 GLES 环境mBgRender.native_BgRenderInit();// 加载图片数据到纹理loadRGBAImage(R.drawable.java, mBgRender);// 离屏渲染mBgRender.native_BgRenderDraw();// 从缓冲区读出渲染后的图像数据,加载到 ImageViewmImageView.setImageBitmap(createBitmapFromGLSurface(0, 0, 421, 586));// 释放 GLES 环境mBgRender.native_BgRenderUnInit();

private void loadRGBAImage(int resId, NativeBgRender render) {    InputStream is = this.getResources().openRawResource(resId);    Bitmap bitmap;    try {        bitmap = BitmapFactory.decodeStream(is);        if (bitmap != null) {            int bytes = bitmap.getByteCount();            ByteBuffer buf = ByteBuffer.allocate(bytes);            bitmap.copyPixelsToBuffer(buf);            byte[] byteArray = buf.array();            render.native_BgRenderSetImageData(byteArray, bitmap.getWidth(), bitmap.getHeight());        }    }    finally    {        try        {            is.close();        }        catch(IOException e)        {            e.printStackTrace();        }    }}

private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h) {    int bitmapBuffer[] = new int[w * h];    int bitmapSource[] = new int[w * h];    IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);    intBuffer.position(0);    try {        GLES20.glReadPixels(x, y, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,                intBuffer);        int offset1, offset2;        for (int i = 0; i             offset1 = i * w;            offset2 = (h - i - 1) * w;            for (int j = 0; j                 int texturePixel = bitmapBuffer[offset1 + j];                int blue = (texturePixel >> 16) & 0xff;                int red = (texturePixel <16) & 0x00ff0000;                int pixel = (texturePixel & 0xff00ff00) | red | blue;                bitmapSource[offset2 + j] = pixel;            }        }    } catch (GLException e) {        return null;    }    return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);}

技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。

推荐阅读:

音视频面试基础题

OpenGL ES 学习资源分享

一文读懂 YUV 的采样与格式

OpenGL 之 GPUImage 源码分析

推荐几个堪称教科书级别的 Android 音视频入门项目

觉得不错,点个在看呗~

与context的关系_你还不知道 OpenGL ES 和 EGL 的关系?相关推荐

  1. OpenGL ES与EGL的关系(二十一)

    什么是OpenGL? Open Graphics Library (OpenGL) is a cross-language, cross-platform application programmin ...

  2. OpenGL ES和EGL关系(二十五)

    什么是 EGL EGL 是 OpenGL ES 和本地窗口系统(Native Window System)之间的通信接口,它的主要作用: 与设备的原生窗口系统通信: 查询绘图表面的可用类型和配置: 创 ...

  3. 高德地拖缩放怎么保证中心点不变_你还不知道考研英语作文怎么准备吗?

    作文一般是在八月份之后根据各自的进度来陆陆续续安排复习的.我自己当初是九月份就开始复习了,我有一个舍友慢一点,十月份才开始复习.并非是想拖到那么晚,实在是因为作文开始复习的条件太苛刻,在准备工作还没做 ...

  4. ajax可以在localhost上用吗_你还不知道跨域问题是怎样造成的吗?

    跨域问题的由来 相信很多人都或多或少了解过跨域问题,尤其在现如今前后端分离大行其道的时候. 你在本地开发一个前端项目,这个项目是通过 node 运行的,端口是9528,而服务端是通过 spring b ...

  5. word更新域后图片错误_你还不知道Word中F1~F12键作用?

    今天给大家分享一下,关于Word文档中F1到F12所有功能键的作用及使用方法! 01F1获取帮助 在文档中按下F1键,可以打开帮助对话框,有什么不知道的问题,可以在这里搜索一下. 02F2移动文本和图 ...

  6. 怎样清理苹果手机内存空间_你还不知道?苹果手机这样清理垃圾,轻松腾出10G内存!...

    这年头手机内存不够和电量不足已经成为了广大手机用户的梦魇,不过在手机电量不足这一块儿好歹还有充电宝和快充可以拯救一下.可是手机内存不足可就比较棘手了,这一点相信很多苹果用户的感触尤为深刻.尽管如今苹果 ...

  7. 不合法的偏移量 钉钉接口_你还不知道钉钉服务端API全局错误码吗?

    -1 系统繁忙 服务器暂不可用,建议稍后再重试1次,最多重试3次 0 请求成功 接口调用成功 88 鉴权异常 地址不存在,检查下url是否和文档里写的一致 404 请求的URI地址不存在 服务器暂不可 ...

  8. 表单设置默认值_你还不知道表单怎么设计吗?看这里!

    表单是电子商务.社交互动和大多数基于生产力应用类型的网站的关键.尽可能简单,微小的变化都有可能极大的提高用户体验. 一.设计原则 尽量减少痛苦 填写过程尽量简洁.容易. 说明填写完成路径 清晰的告诉人 ...

  9. 3. 什么是icmp?icmp与ip的关系_你知道如何跟女生,确定恋人关系吗?

    哈喽!同学你好!我是子伯,是一名情感咨询.今天我想给你分享,和女生再暧昧期,如何去确定关系,因为...... 在我做咨询当中,有很多男生跟女生,不管是在聊天上,还是在线下的交往中,都进入到了暧昧状态, ...

最新文章

  1. 微型计算机外文文献,电子信息科学与技术专业Microcomputer-Systems微型计算机控制系统大学毕业论文外文文献翻译及原文.doc...
  2. java aio事件模型_IO模型之AIO代码及其实践详解
  3. 应该在什么时候使用Hadoop
  4. “数据分析”如何作用于“用户研究”?--转载微博
  5. 吴恩达机器学习 Coursera 笔记(二) - 单变量线性回归...
  6. 11月女性时尚行业动态:浏览热度走势曲折 起伏大
  7. mysql函数思维导图
  8. 计算机组成原理简答题第二章
  9. Homebrew国内加速
  10. React router v6写法总结
  11. java列举生活中类和对象_趣味解读Python面向对象编程 (类和对象)
  12. 【机器人学习】MPU6050数据的换算
  13. 10个BS后台UI框架
  14. cs6制作拼图游戏 dreamweaver_Dreamweaver制作拼图步骤
  15. angular中自定义组件实现双向绑定
  16. Unity防破解 —— 加密Dll与Key保护
  17. Codeforces Round #817 (Div. 4)
  18. 怎么用计算机按反三角函数的导数,反三角函数求导过程
  19. 怎么修改SQL的密码?
  20. [枚举]Stormwind 2022杭电多校第8场 1011

热门文章

  1. pandas基础知识
  2. Android缓存学习入门(二)
  3. ❤️ 给你的Linux把把脉(内存、磁盘、CPU、网络)❤️
  4. Java8 Stream详解~ 提取/组合
  5. 如何阅读一本书~阅读的层次
  6. freedos能够编译c语言嘛,Freedos freedos核心源代码包含汇编和C语言代码 - 下载 - 搜珍网...
  7. Modbus协议栈应用实例之六:Modbus ASCII从站应用
  8. 实现Modbus TCP多网段客户端应用
  9. React Native使用指南-原生模块
  10. 敏捷软件开发宣言–Manifesto for Agile Software Development