EGL
EGL 是 Khronos 的渲染 API(如 OpenGL ES 或 OpenVG)与底层原生平台窗口系统之间的接口。 它处理图形上下文管理、surface/buffer 绑定和渲染同步,并使用其他 Khronos API 实现高性能、加速、混合模式 2D 和 3D 渲染。 EGL 还提供 Khronos 之间的互操作功能,以实现 API 之间的高效数据传输——例如在运行 OpenMAX AL 的视频子系统和运行 OpenGL ES 的 GPU 之间。
提供的能力
为什么需要 EGL
如果要使用 OpenGL ES 进行渲染,使用者需要为 OpenGL 提供存储其状态的 Context 和窗口系统。而 EGL 提供了创建 rendering surface 的机制,OpenGL ES 和 OpenVG 等客户端 API 可以在这些 surface 上绘制。
- 与设备的原生窗口系统通信
- 查询绘图 surface 的可用类型和配置
- 创建绘图 surface
- 在 OpenGL ES 3.0 和其他图形渲染 API 之间同步渲染
- 管理纹理贴图等渲染资源
使用
检查错误
EGL 中的大部分函数,在成功时返回 EGL_TRUE
,失败时返回 EGL_FALSE
。但是错误代码需要主动调用 elgGetError
获取。 EGLError eglGetError()
返回特定线程中最近调用的 EGL 函数的错误代码,如果返回 EGL_SUCCESS
,说明没有错误。
这样的错误检查机制,和 OpenGL 一样,不会在函数的调用结束时直接返回错误代码。其思想是让开发者只在开发和调试期间检查错误,当程序能够正常运作时,就可以减少错误检查。
与窗口系统通信
因为每个窗口系统都有不同的语义,所以 EGL 提供了不透明类型 EGLDisplay。该类型封装了所有系统相关的,用于和原生窗口系统通信的接口 —— EGLDisplay
任何 EGL 程序执行的第一个操作是创建和初始化与本地 EGLDisplay 的连接:
|
|
|
|
eglGetDisplay
函数负责打开与 EGLDisplay 服务的连接,display_id
指定显示连接,默认为 EGL_DEFAULT_DISPLAY
定义 EGLNativeDisplayType
是为了匹配原生窗口系统的显示类型。例如,在 Windows 上,EGLNativeDisplayType
将被实现为一个 HDC(Windows 设备上下文的句柄)。但是为了方便地将代码转移到不同操作系统和平台,应该使用 EGL_DEFAULT_DISPLAY
,返回与默认原生显示的连接。
初始化 EGL
成功的打开 EGLDisplay 连接之后,需要初始化 EGL:
|
|
- dpy: 指定 EGLDisplay
- major: 指定 EGL 实现返回的主版本号
- minor: 指定 EGL 实现返回的次版本号
这个函数初始化 EGL 内部数据结构,返回 EGL 实现的主版本号和次版本号。如果 EGL 无法初始化,这个调用将返回 EGL_FALSE
,并将 EGL 错误代码设置为:
- EGL_BAD_DISPLAY —— 没有指定有效的 EGLDisplay
- EGL_NOT_INITIALIZED —— EGL 不能初始化
|
|
EGLConfig
包含 EGL 启用的 surface 的所有信息的 EGL 内部数据结构
确定可用 surface 配置
一旦初始化了 EGL,就可以确定可用渲染 surface 的类型和配置了,有两种方法:
- 查询每个 surface 配置,找出最后选择
- 指定一组需求,让 EGL 推荐最佳匹配
|
|
eglGetConfigs
函数可以查询底层窗口系统支持的所有 EGL Surface 的配置。
调用 eglGetConfigs
有两种方式:
- 获取系统可用的 EGLConfig 的数量
|
|
系统可用的 EGLConfig 的数量将写入到 numConfig
的第一个元素中
- 获取指定数量的 EGLConfig
|
|
configs
数据中将会写入 2 个 EGLConfig 数据
查询 EGLConfig 属性
EGLConfig 包含了关于 EGL 启用的 Surface 的所有信息。包括关于可用颜色、与配置相关的其他缓冲区、Surface 类型和许多其他特性。
|
|
eglGetConfigAttrib
函数用于查询 EGLConfig 中特定的属性值。
EGL 属性表 https://www.khronos.org/files/egl-1-4-quick-reference-card.pdf
Attribute Name | Type | Sorting | Selection | Description and default value |
---|---|---|---|---|
EGL_BUFFER_SIZE | integer | (4) (-) | AtLeast | The total color component bits in the color buffer. Default is 0. |
EGL_RED_SIZE | integer | (3) (+) | AtLeast | EGL_DONT_CARE or the number of bits of Red in the color buffer. 0 means no Red is in the color buffer. |
EGL_GREEN_SIZE | integer | (3) (+) | AtLeast | EGL_DONT_CARE or the number of bits of Green in the color buffer. 0 means no Green is in the color buffer. |
EGL_BLUE_SIZE | integer | (3) (+) | AtLeast | EGL_DONT_CARE or the number of bits of Blue in the color buffer. 0 means no Blue is in the color buffer. |
EGL_LUMINANCE_SIZE | integer | (3) (+) | AtLeast | The number of bits of Luminance in the color buffer. 0 means no Luminance in the color buffer. |
EGL_ALPHA_SIZE | integer | (3) (+) | AtLeast | The number of bits of Alpha in the color buffer. 0 means no Alpha in the color buffer. |
EGL_ALPHA_MASK_SIZE | integer | (9) (-) | AtLeast | The number of bits of Alpha Mask in the color buffer. 0 means no Alpha Mask in the color buffer. |
EGL_BIND_TO_TEXTURE_RGB | boolean | (°) | Exact | EGL_DONT_CARE, EGL_TRUE, or EGL_FALSE. EGL_TRUE if bindable to RGB textures. |
EGL_BIND_TO_TEXTURE_RGBA | boolean | (°) | Exact | EGL_DONT_CARE, EGL_TRUE, or EGL_FALSE. EGL_TRUE if bindable to RGBA textures. |
EGL_COLOR_BUFFER_TYPE | enum | (2) (°) | Exact | EGL_DONT_CARE, EGL_RGB_BUFFER, or EGL_LUMINANCE_BUFFER to represent the color buffer type. |
EGL_CONFIG_CAVEAT | enum | (1) (+) | Exact | EGL_DONT_CARE or one of the following values indicating caveats for the configuration: EGL_NONE; EGL_SLOW_CONFIG - rendering to a surface may run at reduced performance; EGL_NON_CONFORMANT_CONFIG - rendering to a surface will not pass the required OpenGL ES conformance tests |
EGL_CONFIG_ID | integer | (11) (-) | Exact | EGL_DONT_CARE indicating unique EGLConfig identifier. |
EGL_CONFORMANT | bitmask | (°) | Mask | Indicates whether contexts created are conformant. May be 0 or one or more of the following values: EGL_OPENGL_BIT (OpenGL 1.x or 2.x), EGL_OPENGL_ES_BIT (OpenGL ES 1.x), EGL_OPENGL_ES2_BIT (OpenGL ES 2.x), EGL_OPENVG_BIT (OpenVG 1.x) |
EGL_DEPTH_SIZE | integer | (7) (-) | AtLeast | A positive integer indicating the number of bits of Z in the depth buffer. Default is 0. |
EGL_LEVEL | integer | (°) | Exact | The frame buffer level. Default is 0. |
EGL_MATCH_NATIVE_PIXMAP | integer | (°) | Special | EGL_NONE or handle of a valid native pixmap |
EGL_MAX_PBUFFER_WIDTH | integer | (°) | The maximum width of pbuffer. Default is 0. | |
EGL_MAX_PBUFFER_HEIGHT | integer | (°) | The maximum height of pbuffer. Default is 0. | |
EGL_MAX_PBUFFER_PIXELS | integer | (°) | The maximum size of pbuffer. Default is 0. | |
EGL_MAX_SWAP_INTERVAL | integer | (°) | Exact | EGL_DONT_CARE or the maximum value that can be passed to eglSwapInterval; indicating the maximum number of swap intervals that will elapse before a buffer swap takes place after calling eglSwapBuffers. |
EGL_MIN_SWAP_INTERVAL | integer | (°) | Exact | EGL_DONT_CARE or the minimum value that can be passed to eglSwapInterval; indicating the minimum number of swap intervals that will elapse before a buffer swap takes place after calling eglSwapBuffers. |
EGL_NATIVE_RENDERABLE | boolean | (°) | Exact | EGL_DONT_CARE, EGL_TRUE, or EGL_FALSE. EGL_TRUE if native rendering APIs can render to surface EGL_NATIVE_VISUAL_ID integer (°) Default is 0. |
EGL_NATIVE_VISUAL_TYPE | integer | (10) (+) | Exact | EGL_DONT_CARE, EGL_NONE, or the native visual type of the associated visual. |
EGL_RENDERABLE_TYPE | bitmask | (°) | Mask | Indicates which client APIs are supported. May be one or more of the following values: EGL_OPENGL_BIT (OpenGL 1.x or 2.x) EGL_OPENGL_ES_BIT (OpenGL ES 1.x), EGL_OPENGL_ES2_BIT (OpenGL ES 2.x), EGL_OPENVG_BIT (OpenVG 1.x) |
EGL_SAMPLE_BUFFERS | integer | (5) (-) | AtLeast | The number of multisample buffers. Default is 0. |
EGL_SAMPLES | integer | (6) (-) | AtLeast | The number of samples per pixel. Default is 0. |
EGL_STENCIL_SIZE | integer | (8) (-) | AtLeast | The number of bits of Stencil in the stencil buffer. 0 means no Stencil in the stencil buffer. |
EGL_SURFACE_TYPE | bitmask | (°) | Mask | The types of EGL surfaces are supported. May be one or more of EGL_WINDOW_BIT, EGL_PIXMAP_BIT, EGL_PBUFFER_BIT, MULTISAMPLE_RESOLVE_BOX_BIT, EGL_VG_ALPHA_FORMAT_PRE_BIT, EGL_SWAP_BEHAVIOR_PRESERVED_BIT, EGL_VG_COLORSPACE_LINEAR_BIT. |
EGL_TRANSPARENT_TYPE | enum | (°) | Exact | EGL_NONE means windows created with the EGLConfig will not have any transparent pixels; EGL_TRANSPARENT_RGB means the EGLConfig supports transparency. |
EGL_TRANSPARENT_RED_VALUE | integer | (°) | Exact | EGL_DONT_CARE or an integer in the range 0..2^EGL_RED_SIZE - 1 to indicate the transparent red value. |
EGL_TRANSPARENT_GREEN_VALUE | integer | (°) | Exact | EGL_DONT_CARE or an integer in the range 0..2^EGL_GREEN_SIZE - 1 to indicate the transparent green value. |
EGL_TRANSPARENT_BLUE_VALUE | integer | (°) | Exact | EGL_DONT_CARE or an integer in the range 0..2^EGL_BLUE_SIZE - 1 to indicate the transparent blue value. |
让 EGL 选择配置
可以看到 EGL 有很多属性,如果每个都由我们自己去配置,不免有些麻烦。
|
|
EGL 提供了 eglChooseConfig
函数让 EGL 根据你传入的部分属性,为你选择匹配的 EGLCofig,这样你只需要提供几个自己关心的属性和其对应的属性值就可以获取一个完整的 EGLConfig。
|
|
创建屏幕上的渲染区域
|
|
eglCreateWindowSurface
函数用于创建 EGL 窗口 Surface。
eglCreateWindowSurface()
将「窗口对象」(win
)作为参数,在 Android 上,该对象是 Surface。
Surface 是 BufferQueue 的生产方端。消费方(SurfaceView、SurfaceTexture、TextureView 或 ImageReader)创建 Surface。当调用 eglCreateWindowSurface()
时,EGL 将创建一个新的 EGLSurface 对象,并将其连接到窗口对象的 BufferQueue 的生产方接口。此后,渲染到该 EGLSurface 会导致一个缓冲区离开队列、进行渲染,然后排队等待消费方使用。
|
|
创建屏幕外的渲染区域
除了可以用 OpenGL ES 3.0 在屏幕上的窗口渲染之外,还可以渲染离屏缓冲区(pbuffer)。pbuffer 可以利用 OpenGL ES 中的任何硬件加速,pbuffer 常用于生成纹理贴图。
|
|
eglCreatePbufferSurface
用于创建 Pbuffer。和 Window Surface 一样,Pbuffer 支持所有 OpenGL ES 渲染机制,主要区别在于:无法在屏幕上显示 Pbuffer,渲染完成后,一般是从 Pbuffer 将数据复制到程序或者将 Pbuffer 的绑定更改为纹理。
|
|
创建渲染上下文
渲染上下文是 OpenGL ES 的内部数据结构,包含 OpenGL 操作需要的所有状态信息。
|
|
eglCreateContext
函数负责创建上下文 Context。
|
|
当一个程序中存在多个 EGLContext 时,在执行渲染前,需要将特定的 EGLContext 和渲染 Surface 进行关联。
|
|
eglMakeCurrent
函数就是执行这个过程的,通常叫做指定当前上下文。
Android
EGLSurface 和 OpenGL ES
为了创建 OpenGL ES 上下文并为 OpenGL ES 渲染提供窗口系统,Android 使用 EGL 库。OpenGL ES 调用用于渲染纹理多边形,而 EGL 调用用于将渲染放到屏幕上。在使用 OpenGL ES 进行绘制之前,您需要创建 OpenGL 上下文。在 EGL 中,这意味着要创建一个 EGLContext 和一个 EGLSurface。 OpenGL ES 操作适用于当前上下文,该上下文通过线程局部存储(ThreadLocal)访问,而不是作为参数进行传递。渲染代码应该在当前 OpenGL ES 线程(而不是界面线程)上执行。
iOS
EAGL
Apple 提供了自己的 EGL API 的实现 —— EAGL