EGL 介绍和使用

一、简介
EGL 是渲染 API(如 OpenGL ES)和原生窗口系统之间的接口。

通常来说,OpenGL 是一个操作 GPU 的 API,它通过驱动向 GPU 发送相关指令,控制图形渲染管线状态机的运行状态,但是当涉及到与本地窗口系统进行交互时,就需要这么一个中间层,且它最好是与平台无关的。

因此 EGL 被设计出来,作为 OpenGL 和原生窗口系统之间的桥梁。

二、功能
EGL API 是独立于 OpenGL ES 各版本标准的独立的一套 API,其主要作用是为 OpenGL 指令 创建 Context 、绘制目标 Surface 、配置 FrameBuffer 属性、Swap 提交绘制结果 等。

EGL 提供如下机制:

(1)与设备原生窗口通信
(2)查询绘制 surface 的可用类型和配置
(3)创建绘制 surface
(4)在 OpenGL ES 3.0 或其他渲染 API 之间同步渲染
(5)管理纹理贴图等渲染资源

三、介绍

EGL 包含了自己的一组数据类型,同时也提供了对一组平台相关的本地数据类型的支持。这些 Native 数据类型定义在 EGL 系统的头文件中。EGL中的一些类型和define抽象了平台的窗口与显存类型,如果理解了这些类型,即可对EGL进行相关配置,有些复杂的类型不比太过纠结底层如何实现。

标准 EGL 数据类型如下所示:

EGLBoolean ——EGL_TRUE =1, EGL_FALSE=0
EGLint ——int 数据类型
EGLDisplay ——系统显示 ID 或句柄,可以理解为一个前端的显示窗口
EGLConfig ——Surface的EGL配置,可以理解为绘制目标framebuffer的配置属性
EGLSurface ——系统窗口或 frame buffer 句柄 ,可以理解为一个后端的渲染目标窗口。
EGLContext ——OpenGL ES 图形上下文,它代表了OpenGL状态机;如果没有它,OpenGL指令就没有执行的环境。

下面几个类型比较复杂,通过例子可以更深入的理解。这里要说明的是这几个类型在不同平台其实现是不同的,EGL只提供抽象标准。

NativeDisplayType——Native 系统显示类型,标识你所开发设备的物理屏幕
NativeWindowType ——Native 系统窗口缓存类型,标识系统窗口
NativePixmapType ——Native 系统 frame buffer,可以作为 Framebuffer 的系统图像(内存)数据类型,该类型只用于离屏渲染.


四、使用
1. 首先介绍一下检查错误的方法:
EGL 中大部分函数成功时都是返回 EGL_TRUE,失败返回 EGL_FALSE。

至于故障原因,需要调用如下函数获取:

EGLint eglGetError();
返回最近调用 EGL 函数的错误代码,如果返回 EGL_SUCCESS 说明没有错误。

2. 创建,建立本地系统和 OpenGL ES 的连接
EGLDisplay eglDisplay(EGLNativeDisplayType displayId);
displayId 指定显示连接,一般使用默认的 EGL_DEFAULT_DISPLAY,即返回与默认原生窗口的连接。

相关错误码:
EGL_NO_DISPLAY :连接不可用
2. 初始化

EGLBoolean eglInitialize(EGLDisplay display, // 创建步骤时返回的对象
                         EGLint *majorVersion, // 返回 EGL 主版本号
                         EGLint *minorVersion); // 返回 EGL 次版本号


相关错误码:
EGL_NO_DISPLAY :EGL 不能初始化
EGL_BAD_DISPLAY :没有指定有效的 display
示例:

EGLint majorVersion;
EGLint minorVersion;
EGLDisplay display;
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
    // Unable to open connection to local windowing system
}
if (!eglInitialize(display, &majorVersion, &minorVersion)) {
    // Unable to initialize EGL. Handle and recover
}



3. 确定可用的 Surface 的配置
一旦初始化了EGL,就可以确定可用渲染表面的类型和配置了。有两种方法:

先使用 eglGetConfigs 查询每个配置,再使用 eglGetConfigAttrib 找出最好的选择
指定一组需求,使用 eglChooseChofig 让 EGL 推荐最佳配置
通常使用第二种方式更简单。两种方法均得到 EGLConfig 对象。EGLConfig 包含了渲染表面的所有信息,包括可用颜色、缓冲区等其他特性。

获取所有配置的函数

EGLBoolean eglGetConfigs(EGLDisplay display, // 指定显示的连接
                         EGLConfig *configs, // 指定 GLConfig 列表
                         EGLint maxReturnConfigs, // 最多返回的 GLConfig 数
                         EGLint *numConfigs); // 实际返回的 GLConfig 数



查询 EGLConfig 配置

EGLBoolean eglGetConfigAttrib(EGLDisplay display, // 指定显示的连接
                              EGLConfig config, // 指定要查询的 GLConfig
                              EGLint attribute, // 返回特定属性
                              EGLint *value); // 返回值



让 EGL 选择配置

EGLBoolean eglChooseChofig(EGLDispay display, // 指定显示的连接
                           const EGLint *attribList, // 指定 configs 匹配的属性列表,可以为 NULL
                           EGLConfig *config,   // 调用成功,返会符合条件的 EGLConfig 列表
                           EGLint maxReturnConfigs, // 最多返回的符合条件的 GLConfig 数
                           ELGint *numConfigs );  // 实际返回的符合条件的 EGLConfig 数



如果 eglChooseChofig 成功返回,则返回一组匹配你的标准的 EGLConfig。示例:

EGLint attribList[] = {
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
    EGL_RED_SIZE, 5,
    EGL_GREEN_SIZE, 6,
    EGL_BLUE_SIZE, 5,
    EGL_DEPTH_SIZE, 1,
    EGL_NONE
};

const EGLint MaxConfigs = 10;
EGLConfig configs[MaxConfigs]; // We'll only accept 10 configs
EGLint numConfigs;
if (!eglChooseConfig(dpy, attribList, configs, MaxConfigs, &numConfigs)) {
    // Something didn't work … handle error situation
} else {
    // Everything's okay. Continue to create a rendering surface
}


4. 创建渲染区域 Surface
当有了符合条件的 EGLConfig 后,就可以通过 eglCreateWindowSurface 函数创建渲染区域。

EGLSurface eglCreateWindowSurface(EGLDisplay display, // 指定显示的连接
                                  EGLConfig config, // 符合条件的 EGLConfig
                                  EGLNatvieWindowType window, // 指定原生窗口
                                  const EGLint *attribList); // 指定窗口属性列表,可为 NULL


eglCreateWindowSurface 方法在很多情况下可能失败,失败返回 EGL_NO_SURFACE。我们可以通过 eglGetError 获取相关错误。相关错误码:
EGL_BAD_MATCH :提供了与窗口属性不匹配的 EGLConfig,或该 EGLConfig 不支持渲染到窗口
EGL_BAD_CONFIG :提供的 EGLConfig 没有得到系统支持
EGL_BAD_NATIVE_WINDOW :提供的原生窗口句柄无效
EGL_BAD_ALLOC :无法为新的窗口分配资源,或已经有和提供的原生窗口关联的 EGLConfig
示例:

EGLint attribList[] = {
  EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
  EGL_NONE
);

// 这里先省略了创建原生窗口的过程
EGLRenderSurface window = eglCreateWindowSurface(display, config, nativeWindow, attribList);

if (window == EGL_NO_SURFACE) {
    switch (eglGetError()) {
    case EGL_BAD_MATCH:
        // Check window and EGLConfig attributes to determine
        // compatibility, or verify that the EGLConfig
        // supports rendering to a window,
        break;
    case EGL_BAD_CONFIG:
        // Verify that provided EGLConfig is valid
        break;
    case EGL_BAD_NATIVE_WINDOW:
        // Verify that provided EGLNativeWindow is valid
        break;
    case EGL_BAD_ALLOC:
        // Not enough resources available. Handle and recover
        break;
    }
}



5. 创建上下文
上下文包含了操作所需的所有状态信息,OpenGL ES 3.0 必须有一个可用的上下文才能进行绘图。

EGLContext eglCreateContext(EGLDisplay display, // 指定显示的连接
                            EGLConfig config, // 前面选好的 EGLConfig
                            EGLContext shareContext, // 允许其它 EGLContext 共享数据,使用 EGL_NO_CONTEXT 表示不共享
                            const EGLint* attribList); // 指定操作的属性列表,只能接受一个属性 EGL_CONTEXT_CLIENT_VERSION


示例:

const ELGint attribList[] = {
    EGL_CONTEXT_CLIENT_VERSION, 3,
    EGL_NONE
};

EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, attribList);

if (context == EGL_NO_CONTEXT) {
    EGLError error = eglGetError();
    if (error == EGL_BAD_CONFIG) {
        // Handle error and recover
    }
}



6. 关联上下文
指定某个 EGLContext 为当前上下文,关联特定的 EGLContext 和 EGLSurface。

EGLBoolean eglMakeCurrent(EGLDisplay display, // 指定显示的连接
                          EGLSurface draw, // EGL 绘图表面
                          EGLSurface read, // EGL 读取表面
                          EGLContext context); // 指定连接到该表面的上下文



这里存在两个 EGLSurface,具有更好的灵活性,在后续一些高级的 EGL 用法中将利用它。目前我们先把它们设置为同一个值。

7. 使用 OpenGL 相关 API 进行绘制
这个就是 OpenGL 里的东西了,这里不做介绍。

五、总结
概念
EGL 是 OpenGL 和原生窗口系统之间的桥梁接口。

使用流程
1. 创建连接
EGLDisplay eglDisplay(EGLNativeDisplayType displayId);

2. 初始化连接
EGLBoolean eglInitialize(EGLDisplay display, EGLint *majorVersion, EGLint *minorVersion);

3. 获取配置
EGLBoolean eglChooseChofig(EGLDispay display, 
                           const EGLint *attribList,
                           EGLConfig *config,
                           EGLint maxReturnConfigs,
                           ELGint *numConfigs );

4. 创建渲染区域
EGLSurface eglCreateWindowSurface(EGLDisplay display,
                                  EGLConfig config,
                                  EGLNatvieWindowType window,
                                  const EGLint *attribList);

5. 创建渲染上下文
EGLContext eglCreateContext(EGLDisplay display,
                            EGLConfig config,
                            EGLContext shareContext,
                            const EGLint* attribList);

6. 关联上下文和渲染区域
EGLBoolean eglMakeCurrent(EGLDisplay display,
                          EGLSurface draw,
                          EGLSurface read,
                          EGLContext context);

 

系统通常还支持另外两种Surface:PixmapSurface和PBufferSurface,这两种都不是可显示的Surface,PixmapSurface是保存在系统内存中的位图,PBuffer则是保存在显存中的帧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值