目录
- 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;
}