目錄
- EGL 介紹
- EGL 類型和初始化
- EGL初始化方法
- 獲取 eglDisplay
- 初始化 EGL
- 選擇 Config
- 構造 Surface
- 構造 Context
- 開始繪制
- EGL Demo
EGL 介紹
OpenGL-ES
是一個操作GPU
的圖像API
標準,它通過驅動向 GPU
發送相關圖形指令,控制圖形渲染管線狀態機的運行狀態,但OpenGL
需要本地視窗系統進行交互,這就需要一個中間控制層,最好與平臺無關
EGL ---- 因此被獨立的設計出來,它作為 OpenGL-ES
和本地窗口的橋梁
EGL
是 OpenGL ES
和底層 Native
平臺視窗系統之間的接口層,EGL API
是獨立于OpenGL ES
各版本標準的獨立 API
,EGL
提供下面的機制:
- 和設備的原生窗口系統進行通信
- 查詢繪圖表面的可用類型和配置
- 創建繪圖表面
- 在
OpenGL-ES
和其他渲染API
之間同步渲染 - 管理紋理貼圖等繪圖資源
比如 egl
可以和 opencl
進行同步,主要通過下面幾種方式:
- 通過
eglCreateContext
創建共享的上下文 - 通過
eglCreateImageKHR
創建可以被OpenGL ES
和OpenCL0
共同訪問的圖像資源 eglCreateSyncKHR
/eglDestroySyncKHR
等函數可以創建跨API
的同步點
總結:對接窗口系統,保存繪圖狀態,管理繪圖資源,提供繪圖表面配置,和其他 API
進行同步
為 OpenGL-ES
指令創建 Context
、繪制目標Surface
、配置Framebuffer
屬性、Swap
提交繪制結果等都是EGL
實現的功能
EGL
的作用如下圖所示:
EGL 類型和初始化
EGL
包含了自己的一組數據類型,同時也提供了對一組平臺相關的本地數據類型的支持,這些 Native
數據類型定義在 EGL
系統的頭文件中
下面表格中列舉了常見的幾種 EGL
類型:
數據類型 | 說明 |
---|---|
EGLBoolean | EGL_TRUE =1,EGL_FALSE=0 |
EGLint | windows上是int32類型 |
EGLDisplay | Handle 概念 typedef void *EGLDisplay; |
EGLConfig | Handle 概念 typedef void *EGLConfig; |
EGLSurface | Handle 概念 typedef void *EGLSurface |
EGLContext | Handle 概念 typedef void *EGLContext; OpenGL-ES 圖形上下文,它代表了OpenGL狀態機) |
EGL初始化方法
EGL 初始化流程如下圖所示:
獲取 eglDisplay
獲得 Display
要調用 EGLboolean eglGetDisplay(NativeDisplay dpy) 參數一般為 EGL_DEFAULT_DISPLAY
初始化 EGL
調用 EGLboolean eglInitialize**(EGLDisplay dpy, EGLint *major, EGLint *minor)
,該函數會進行一些內部初始化工作,并傳回 EGL
版本號(major,minor)
選擇 Config
一般用EGLboolean eglChooseConfig**(EGLDisplay dpy, const EGLint * attr_list, EGLConfig * config, EGLint config_size, EGLint *num_config)
其中 attr_list
是以 EGL_NONE 結束的參數數組,通常以id
,value
依次存放,對于個別標識性的屬性可以只有 id,沒有value
另一個辦法是用 EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config)
來獲得所有config
,這兩個函數都會返回不多于 config_size
個 config
,結果保存在 config[]
中,系統的總 Config
個數保存 在num_config
中
可以利用 eglGetConfig() 中間兩個參數為0來查詢系統支持的 Config
總個數,Config
有眾多的Attribute
,這些Attribute
決定FrameBuffer
的格式和能力,通過 eglGetConfigAttrib
來讀取,但不能修改
構造 Surface
通過 EGLSurface eglCreateWindowSurface**(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr)
來創建一個可實際顯示的 Surface
系統通常還支持另外兩種 Surface
:PixmapSurface和PBufferSurface,這兩種都不是可顯示的Surface,PixmapSurface
是保存在系統內存中的位圖,PBuffer
則是保存在顯存中的幀
對于這兩種 Surface
,Android
系統中,支持 PBufferSurface
Surface
也有一些 attribute
,基本上都可以顧名思義
EGL_HEIGHT
EGL_WIDTH
EGL_LARGEST_PBUFFER
EGL_TEXTURE_FORMAT
EGL_TEXTURE_TARGET
EGL_MIPMAP_TEXTURE
EGL_MIPMAP_LEVEL
通過 eglSurfaceAttrib
設置、eglQuerySurface
讀取
構造 Context
OpenGL ES
的 Pipeline
從程序的角度看就是一個狀態機,有當前的顏色、紋理坐標、變換矩陣、絢染模式等一大堆狀態,這些狀態作用于 OpenGL API
程序提交的頂點坐標等圖元從而形成幀緩沖內的像素;在 OpenGL
的編程接口中,Context
就代表這個狀態機,OpenGL API
程序的主要工作就是向 Context
提供圖元、設置狀態,偶爾也從 Context
里獲取一些信息。
可以用
EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface read, EGLContext * share_list)
EGL變量之間的綁定
boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context)
//該接口將申請到的display,draw(surface)和 context進行了綁定。也就是說,在context下的 OpenGLAPI 指令將draw
//(surface)作為其渲染最終目的地。而display作為draw(surface)的前端顯示。調用后,當前線程使用的EGLContex為context
開始繪制
應用程序通過 OpenGL API
進行繪制,一幀完成之后,調用 eglSwapBuffers(EGLDisplay dpy, EGLContext ctx) 來顯示
EGL Demo
#include "esUtil.h"static GLboolean ESUTIL_API esCreateWindow(ESContext *esContext, \const char *title, GLint width, GLint height, GLuint flags) {EGLConfig config;EGLint majorVersion;EGLint minorVersion;EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };if (esContext == NULL) {return GL_FALSE;}esContext->width = width;esContext->height = height;if (!WinCreate(esContext, title)) {return GL_FALSE;}// 獲取 eglDisplayesContext->eglDisplay = eglGetDisplay(esContext->eglNativeDisplay);// Initialize EGLif (!eglInitialize(esContext->eglDisplay, &majorVersion, &minorVersion)) {return GL_FALSE;}#if (TDEBUG == 1)printf("opengl version major:%d minor:%d\n", majorVersion, minorVersion);EGLint numsConfig = 0;eglGetConfigs(esContext->eglDisplay, NULL, 0, &numsConfig);printf("get numsConfig: %d \n", numsConfig);
#endif{EGLint numConfigs = 0;EGLint attribList[] ={EGL_RED_SIZE, 5,EGL_GREEN_SIZE, 6,EGL_BLUE_SIZE, 5,EGL_ALPHA_SIZE, (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,EGL_DEPTH_SIZE, (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,EGL_STENCIL_SIZE, (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,EGL_SAMPLE_BUFFERS, (flags & ES_WINDOW_MULTISAMPLE) ? 1 : 0,// if EGL_KHR_create_context extension is supported, then we will use// EGL_OPENGL_ES3_BIT_KHR instead of EGL_OPENGL_ES2_BIT in the attribute listEGL_RENDERABLE_TYPE, GetContextRenderableType(esContext->eglDisplay),EGL_NONE};// Choose configif (!eglChooseConfig(esContext->eglDisplay, attribList, &config, 1, &numConfigs)) {return GL_FALSE;}}// Create a surfaceesContext->eglSurface = eglCreateWindowSurface(esContext->eglDisplay, config,esContext->eglNativeWindow, NULL);// Create a GL context contextAttribs 指定openGL ES 版本esContext->eglContext = eglCreateContext(esContext->eglDisplay, config,EGL_NO_CONTEXT, contextAttribs);// Make the context currentif (!eglMakeCurrent(esContext->eglDisplay, esContext->eglSurface,esContext->eglSurface, esContext->eglContext)) {return GL_FALSE;}return GL_TRUE;
}