一、 EGL簡介
EGL (Embedded-System Graphics Library) 函式庫是一個介於 Khronos 渲染函式庫 (如 OpenGL、OpenGL ES、OpenVG 等) 與下層平台視窗系統 (如 Microsoft Windows、Linux X Window、Mac Quartz) 之間的介面。EGL 用於圖形上下文管理 (graphics context management)、表層 / 緩衝區綁定 (surface/buffer binding)、渲染同步 (rendering synchronization) 與激活 Khronos 高效能 2D / 3D 渲染函式庫。EGL 函式庫實現了 OpenGL、OpenGL ES 等函式庫的跨平台特性。
舉個例子來說,EGL 是一個畫廊的工作員,負責的工作就是將畫家會使用到得工具準備好 (Initial),例如:畫架、畫布、調色盤等等 。然後讓畫家 OpenGL 在準備好的環境裡作畫。等 OpenGL 完成畫作後, EGL 要把先前準備給畫家使用的工具都收好 (Destroy) ,所以 EGL 的工作只有 Initial 與 Destroy 兩件事,下面會針對這兩件工作的操作流程作說明。
圖1.1、EGL / 渲染函式庫 / 平台視窗系統關係示意圖 |
二、 EGL初始化操作流程
圖 2.1、EGL 初始化流程圖 |
- 定義EGL 設備的結構 (EGL device structure),初始化 EGL 會使用到的項目 (item),並將項目集成一個結構。其中包含:顯示類型、顯示、配置屬性、配置、視窗、表面、上下文屬性、上下文。如下面代碼:
struct egl_device { EGLNativeDisplayType display_type; EGLDisplay display; const EGLint *config_attributes; EGLConfig config; EGLNativeWindowType window; EGLSurface surface; const EGLint *context_attributes; EGLContext context; }; |
- 使用fbGetDisplayByIndex() API 與 FB 系統申請用於顯示的 Frame Buffer。
使用說明:
fbGetDisplayByIndex(Num);
Num:frame buffer 的索引
- 使用eglGetDisplay() API 將申請到的 Frame Buffer 作為 EGL 顯示設備。
使用說明:
eglGetDisplay(DisType)
DisType:從 fbGetDisplayByIndex() API 取得的顯示類型
- 使用eglInitialize() API 作 EGL 初始化。
使用說明:
eglInitialize(display, major, minor)
display:指定 EGL 顯示裝置
major:EGL 主要版本的回傳值,可為 NULL
minor:EGL 主要版本的回傳值,可為 NULL
- 使用eglBindAPI() AP 將 EGL 顯示設備與渲染函式庫作連接。
使用說明:
eglBindAPI(api)
api: 指定渲染函式庫,可為 EGL_OPENGL_API、EGL_OPENGL_ES_API、EGL_OPENVG_API
- 設定EGL 配置屬性,屬性設定結尾必須使用 EGL_NONE 作為結尾。詳細的屬性設定請參考 Khronos 官方網站:
https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglChooseConfig.xhtml
- 使用eglChooseConfig() API 設定最佳配置屬性。
使用說明:
eglChooseConfig(display, attrib_list, configs, config_size, num_config)
display: 指定 EGL 顯示設備
attrib_list: 指定 EGL 配置屬性
configs: 最佳配置屬性的回傳值
config_size: 指定配置屬性的陣列大小
num_config: 配置屬性個數的回傳值
- 使用fbCreateWindow() API 開啟顯示視窗。
使用說明:
fbCreateWindow(display, x, y, width, height)
display: 指定 EGL 顯示設備
x: 指定視窗的水平位置
y: 指定視窗的垂直位置
width: 指定視窗的寬度
height: 指定視窗的高度
- 使用eglCreateWindowSurface() API 開啟顯示視窗表面。
使用說明:
eglCreateWindowSurface(display, config, native_window, attrib_list)
display: 指定 EGL 顯示設備
config: 指定 EGL 配置屬性
native_window: 指定顯示視窗
attrib_list: 指定表面屬性,可為 NULL
- 設定上下文屬性,屬性設定結尾必須使用EGL_NONE 作為結尾。詳細的屬性設定請參考 Khronos 官方網站:
https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglCreateContext.xhtml
- 使用eglCreateContext() API 開啟上下文。
使用說明:
eglCreateContext(display, config, share_context, attrib_list)
display: 指定 EGL 顯示設備
config: 指定 EGL 配置屬性
share_context: 指定共享資訊的上下文,設定為 EGL_NO_CONTEXT 表示不分享資訊
attrib_list: 指定上下文屬性
- 使用eglMakeCurrent() API 將目前 EGL 設定作為顯示。
使用說明:
eglMakeCurrent(display, draw, read, context)
display: 指定 EGL 顯示設備
draw: 指定EGL 寫入的顯示視窗表面
read: 指定EGL 讀取的顯示視窗表面
context: 指定 EGL 用於渲染的上下文
依照上述步驟就可以完成 EGL 初始化,參考代碼如下:
device->display_type = (EGLNativeDisplayType)fbGetDisplayByIndex(0); device->display = eglGetDisplay(device->display_type); eglInitialize(device->display, NULL, NULL); eglBindAPI(EGL_OPENGL_ES_API); static const EGLint config_attributes[] = { EGL_SAMPLES, 0, EGL_RED_SIZE,8, EGL_GREEN_SIZE,8, EGL_BLUE_SIZE,8, EGL_ALPHA_SIZE,EGL_DONT_CARE, EGL_DEPTH_SIZE,0, EGL_SURFACE_TYPE,EGL_WINDOW_BIT, EGL_NONE }; EGLint config_count = 0; eglChooseConfig(device->display, config_attributes, &device->config, 1, &config_count); device->config_attributes = config_attributes; device->window = fbCreateWindow(device->display_type, 0, 0, 1080, 1080); device->surface = eglCreateWindowSurface(device->display, device->config, device->window, NULL); static const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION,2, EGL_NONE }; device->context = eglCreateContext(device->display, device->config, EGL_NO_CONTEXT, context_attributes); device->context_attributes = context_attributes; eglMakeCurrent(device->display, device->surface, device->surface, device->context); |
三、 EGL 去初始化操作流程
當你使用完渲染函式庫,要結束應用成事時,需要將 EGL 作去初始化的動作,以便將占用到的資源返還給系統。EGL 去初始化的流程需要符合類似 FILO (First In Last Out) 的原則。因此,去初始化的操作流程會如下面流程圖:
圖 2.2、EGL 去初始化流程圖 |
- 使用 eglMakeCurrent() API 設定 EGL 設備為無表面、無上下文。
使用說明:
eglMakeCurrent(display, draw, read, context)
display: 指定 EGL 顯示設備
draw: 設定為 EGL_NO_SURFACE 表示無表面連結
read: 設定為 EGL_NO_SURFACE 表示無表面連結
context: 設定為 EGL_NO_CONTEXT 標示無上下文連結
- 使用eglDestroyContext() API 銷毀上下文。
使用說明:
eglDestroyContext(display, context)
display: 指定 EGL 顯示設備
context: 指定 EGL 上下文
- 使用 eglDestroySurface() API 銷毀表面。
使用說明:
eglDestroySurface(display, surface)
display: 指定 EGL 顯示設備
surface: 指定 EGL 表面
- 使用 fbDestroyWindow() API 銷毀顯示視窗。
使用說明:
fbDestroyWindow(window)
window: 指定顯示視窗
- 使用 eglTerminate() API 終止 EGL 顯示設備。
使用說明:
eglTerminate(display)
display: 指定 EGL 顯示設備
- 使用 eglReleaseThread() API 釋放運作。
使用說明:
eglReleaseThread(void)
依照上述步驟就可以完成 EGL 去初始化,參考代碼如下:
eglMakeCurrent(device->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(device->display, device->context); device->context = (EGLContext)0; eglDestroySurface(device->display, device->surface); device->surface = (EGLSurface)0; fbDestroyWindow(device->window); device->window = (EGLNativeWindowType)0; eglTerminate(device->display); device->display = (EGLDisplay)0; eglReleaseThread(); |
四、 參考文獻
- 1.《OpenGL ES 3.0 Programming Guide》2ndEdition
評論