1 与窗口系统通信
EGL在OpenGL ES 和 本地窗口系统之间 提供了一个 "glue"层。 在EGL 决定那种类型的绘制surface可以用之前,它先开启了与窗口系统通信的通道。
1.1 EGLDisplay 因为,每个窗口系统都有其不同的实现机制,因此EGL提供了一种封装了与本地窗口系统交互的系统库的 类型: EGLDisplay。 使用EGL的应用程序所做的第一步就是创建和初始化与本地EGL display的连接。
EGLDisplay eglGetDisplay(EGLNativeDisplayType displayId) 参数:
displayId: 定义了 display的连接, 默认为 EGL_DEFAULT_DISPLAY 它用来匹配本地窗口系统display的类
返回值: 如果失败, 它会返回EGL_NO_DISPLAY
1.2 初始化EGL 一旦获取了正确的链接, EGL 需要初始化 EGLBoolean eglInitialize(EGLDisplay display, EGLint *majorVersion, EGLint *minorVersion)
参数: display: majorVersion: 定义了实现EGL的最大版本 minorVersion: 定义了实现EGL的最小版本
功能: 该函数初始化了EGL内部的数据结构,并返回其最大最小版本号。
返回值: 如果EGL初始化失败,会返回EGL_FALSE,并返回EGL_BAD_DISPLAY,提示一个无效的EGLDisplay, 和返回 EGL_NOT_INITIALIZED 提示EGL没有初始化
2 确定可用的Surfae配置 一旦初始化了EGL, 我们就可以决定渲染Surface的类型和配置。 有两种方式: 确定每个Surface的配置,并找出最佳选择 自己定义一组配置,然后让EGL推荐最佳配置
在多数情况下,第二种比较简单实现, 而且基本与第一种效果一样。 不管哪种方法,EGL都会返回一个 EGLConfig。 EGLConfig是 EGL内部数据结构的标识, 该数据结构包含了特定Surface的信息和特性: 颜色分量的量化程度(bit数), 深度buffer。
2.1 让EGL 选择配置 EGLBoolean eglChooseConfig(EGLDisplay display, const EGLint *attribList, EGLConfig *configs, EGLint maxReturnConfigs, EGLint *numConfigs)
参数: display: attribList: 定义了与 configs匹配的一组属性 configs: 返回的一组符合要求的配置 maxReturnConfigs: 返回最大的配置数目 numConfigs: 返回返回配置的数目 返回值: EGL_TRUE EGL_FALSE: EGL_BAD_ATTRIBUTE: 如果attribList里有不符合要求的。
功能:一旦eglChooseConfig返回成功, 会返回一组符合要求的配置
2.2 确定配置 EGLConfig 包含了关于 EGL获得的Surface的所有信息。 可获取的颜色表示范围, depth buffers, stencil buffers, multisample buffers等。 在选择可用的Surface配置后,需要确定配置 EGLBoolean eglGetConfigAttrib(EGLDisplay display, EGLConfig config, EGLint attribute, EGLint *value)
参数: display: 定义EGL display连接 config: 定义了确认的配置 attribute: 返回的特定属性 value: 返回的特定的值 返回值: EGL_TRUE EGL_FALSE EGL_BAD_ATTRIBUTE: 如果attribute不是有效属性
3 创建渲染区域: EGL Window 一旦我们确定了与渲染相合适的 EGLConfig 后,我们就可以创建窗口了。 EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, EGLNativeWindowType window, const EGLint *attribList)
参数: display: config: window: 指定一个 本地窗口 attribuList, 指定一组窗口属性, 也许是NULL. 是Surface的属性,以EGL_RENDER_BUFFER开头, 以 EGL_NONE 结尾 中间设置的参数有: EGL_SIGLE_BUFFER, EGL_BACK_BUFFER, 默认是 EGL_BACK_BUFFER
说明: 它的第三个参数 就是上一节中 我们创建的Android窗口 EGL_SIGLE_BUFFER 和 EGL_BACK_BUFFER代表了两种渲染的方式。 前者是直接渲染到显示的buffer里, 后者是 先渲染到BACK_BUFFER,然后前后buffer交换。
返回值: EGL_BAD_MATCH: EGLConfig 与 native window不匹配 EGL_BAD_CONFIG:EGLConfig不被系统支持 EGL_BAD_NATIVE_WINDOW: 当创建native window 无效 EGL_BAD_ALLOCAT: eglCreateWindowSurface 不能为EGL window分配资源
4 创建渲染的 Context 一个渲染的Context是 OpenGL ES3.0的一个数据结构,包含了所有要操作的 状态信息。 如, 它包含了 vertex/fragment shader以及顶点数据的所有引用。 EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext shareContext, const EGLint *attribList)
参数: display: config, sharedContext: 运行多个 EGL Context共享某种类型的数据,如shader program和 texture map。 如果没有共享的:EGL_NO_CONTEXT attribList: 指定EGL Context的版本
5 使EGLContext 称为当前Context 这很重要。 我们可能会创建多个 Context, 因此需要当前渲染的Surface绑定一个 Context。 EGLBoolean eglMakeCurrent(EGLDisplay display , EGLSurface draw, EGLSurface read, EGLContext context) 参数: display: draw: 指定现实的Surface read: 指定渲染到的Surface context: 指定了Surface 依附的Context
______________________________________________________________________________实现EGL 创建窗口 按照上一帖,
void android_main(strut android_app *app)不仅是 我们程序的入口,而且app 还为我们提供了 本地的window。
struct android_app中 有一个 用于 处理app命令的回掉函数: static void onAppCmd(struct android_app *app, int32_t cmd) 其中,cmd有几种类型: APP_CMD_SAVE_STATE, APP_CMD_INIT_WINDOW, APP_CMD_TERM_WINDOW, APP_CMD_GAINED_FOCUS, APP_CMD_LOST_FOCUS。 这几种类型 代表了 窗口的生命周期。 当窗口启动时 会执行 APP_CAM_INIT_WINDOW, APP_CMD_GAINED_FOCUS; 当窗口销毁时会有 APP_CMD_LOST_FOCUS, APP_CMD_TERM_WINDOW
在本地窗口处于 APP_CMD_INIT_WINDOW的时候,我们可以创建EGL窗口 由于,android_app 有一个userData,可以用来接受 用户自己定义的对象,如
void android_main(struct android_app *app)这样 ,我们在 生命周期方法里,就能够对 我们定义的窗口上下文进行初始化,并创建窗口,如
{
....
winContext wContext; // 自己定义的窗口上下文结构体,里面包含了创建窗口的所有信息
app->userData = &wContext;
....
}
void onAppCmd(struct android_app *app, int_32 md)
{
winContext *wContext = (winContext) app->userData;
switch(cmd)
{
...
case APP_CMD_INIT_WINDOW:
wContext->eglNativeDisplay = EGL_DEFAULT_DISPLAY;
wContext->eglNativeWindow = app->window;
....
//创建窗口
}
}
在上面1-5 的分析中,可以看出,创建一个 EGL窗口, 首先需要 EGLDisplay去获取本地系统的一个连接 其次,要选择Surface的配置,并确定该配置 然后,根据 android_app 提供的本地window,以及EGLDisplay 去创建一个Surface,并制定Surface的渲染模式。 最后, 指定Surface的 Context。
在上面1-5 的分析中,可以看出,创建一个 EGL窗口, 首先需要 EGLDisplay去获取本地系统的一个连接 其次,要选择Surface的配置,并确定该配置 然后,根据 android_app 提供的本地window,以及EGLDisplay 去创建一个Surface,并制定Surface的渲染模式。 最后, 指定Surface的 Context。