EGL提供了opengl es和运行于计算机上的原生窗口系统之间的一个结合层次,如下为调用EGL的一般流程:
1.与窗口系统通信
调用如下函数打开与EGL显示服务器的连接:
EGLDisplaye glGetDisPlay(EGLNativeDisplayType displayId)
displayId为了匹配原生窗口系统的显示类型,默认为EGL_DEFAULT_DISPLAY
(一般都选择默认值)
eg: EGLDisplay display=eglGetDisplay(EGL_DEFAULT_DISPLAY)//打开与EGL的连接
If(display==EGL_NO_DISPLAY) //表示EGL不可用
{
return EGL_FALSE;
}
检查错误:
EGLint eglGetError() 可返回错误代码,如返回EGL_SUCCESS表示没有错误。
2.初始化EGL
EGLboolean eglInitialize(EGLDisplay display,
EGLint *majorVersion,
EGLint *minorVersion)
display 指定EGL显示连接
majorVersion 指定EGL实现返回的主版本号
minorVersion 指定EGL实现返回的次版本号
eg: EGLint major,minor;
if(!eglInitialize(display,&major,&minor)) //如果不能初始化EGL
{
return EGL_FALSE;
}
3.让EGL选择配置(确定可用表面)
一旦初始化了EGL,就可以确定可用渲染表面的类型和配置,有2中方法:
(1)查询每个表面配置,找出最好的选择。
(2)指定一组需求,让EGL推荐最佳匹配
不管哪一种,EGL都返回一个EGLConfig(包含有关特定表面及其特性的EGL内部数据结构的标识符)
这里是第二种方法:
EGLBoolean eglChooseConfig(EGLDisplay display,
Const EGLint *attribList,
EGLConfig *configs,
EGLint maxReturnConfigs,
EGLint *numConfigs)
attribList 指定configs匹配的属性列表
configs 指定配置列表
maxReturnConfigs 指定配置大小
numConfigs 指定返回的配置大小
eg: const EGLint configAttibs[]= //属性列表
{
EGL_RENDER_TYPE,EGL_WINDOW_BIT, //属性的相关首选值
EGL_RED_SIZE,8,
EGL_GREEN_SIZE,8
EGL_BLUE_SIZE,8
EGL_DEPTH_SIZE,24
EGL_NONE
}
EGLConfig config;
EGLint numConfigs;
if(!eglChooseConfig(display,configAttribs,&config,1,&numConfigs))
{ //如果成功返回则返回一组匹配你的标准的EGLConfig
Return EGL_FALSE;
}
4.创建屏幕上的渲染区域:EGL窗口
一旦我们有了符合渲染需求的EGLConfig就为创建窗口做好了准备。调用创建窗口:
EGLSurface eglCreateWindowSurface(EGLDisplay display,
EGLConfig config,
EGLNativeWindowType window,
Const EGLint *attribList)
display 指定EGL显示连接
config 指定配置
window 指定原生窗口
attribList 指定窗口属性列表;可能为NULL(所有相关属性设置为默认值)
eg: EGLint attribList[]{
EGL_RENDER_BUFFER,EGL_BACK_BUFFER,//后台缓冲区
EGL_NONE
};
EGLSurface window=eglCreateWindowSurface(display,config,nativeWindow,
attribList或直接用NULL);
If(window==EGL_NO_SURFACE)
{
return EGL_FALSE;
}
或者你可以选择创建屏幕外渲染区域:EGL Pbuffer(不详细介绍了)
5.创建一个渲染上下文
如果把渲染引擎看做一个画家,那么画家开始作画之前需要做一系列的准备工作,譬如:布置好场景,摆好画架,钉好画布,调整好灯光,准备号画笔油彩,站好位置,然后才能开始下笔作画。
前期的这一系列准备过程在D3D和Ogl这样的渲染Api中对应了一系列的接口函数,这些函数初看起来又多又乱,有时调用顺序还有一定的耦合性,因此需要精心的组织这些接口,一种比较好的方法是将这些接口组织成一个叫做渲染上下文(Rendering Context)的类。
渲染上下文是opengl es的内部数据结构,包含操作所需的所有状态信息。Opengl es必须有一个可用的上下文才能绘图。
EGLContext eglCreateContext(EGLDisplay display,
EGLConfig config,
EGLContext shareContext
Const EGLint *attribList)
display 指定EGL显示连接
config 指定配置
shareContext 允许多个EGL上下文共享特定类型的数据,
使用EGL_NO_CONTEXT表示没有共享
attribList 指定创建上下文使用的属性列表;只有一个可接受的属性
EGL_CONTEXT_CLIENT_VERSION(即opengl es的具体版本eg:3)
eg: const EGLint contextAttribs[]=
{
EGL_CONTEXT_CLIENT_VERSION,3,
EGL_NONE
};
EGLContext context=eglCreateContext(display,config,EGL_NO_CONTEXT,
contextAttribs);
if(context==EGL_NO_CONTEXT){
return EGL_FALSE;
}
6.指定某个EGLContext为当前上下文
因为一个应用程序可能创建多个EGLContext用于不同的用途,所以我们需要关联特定的EGLContext和渲染表面---这一过程常常被称作“指定当前上下文”。
EGLBoolean eglMakeCurrent(EGLDisplay display,
EGLSurface draw,
EGLSurface read,
EGLContext context)
draw 指定EGL绘图表面
read 指定EGL读取表面
context 指定连接到该表面的渲染上下文
eg: if(!eglMakeCurrent(display,window,window,context))
{
return EGL_FALSE;
}
创建EGL窗口的完整例程:
EGLboolean initializeWindow(EGLNativewindow nativeWindow)
{
const EGLint configAttribs[]=
{
EGL_RENDER_TYPE,EGL_WINDOW_BIT,
EGL_RED_SIZE,8
EGL_GREEN_SIZE,8
EGL_BLUE_SIZE,8
EGL_DEPTH_SIZE,24
EGL_NONE
};
const EGLint contextAttribs[]=
{
EGL_CONTEXT_CLIENT_VERSION,3,
EGL_NONE
};
//打开与EGL显示服务器的连接
EGLDisplay display=eglGetDisplay(EGL_DEFAULT_DISPLAY)
if(display==EGL_NO_DISPLAY)
{
return EGL_FALSE;
}
//初始化EGL
EGLint major,minor;
if(!eglInitialize(display,&major,&minor))
{
return EGL_FALSE;
}
//EGL选择表面配置
EGLConfig config;
EGLint numConfigs;
if(!eglChooseConfig(display,configAttribs,&config,1,&numConfigs))
{
return EGL_FALSE;
}
//渲染屏幕上的渲染区域(EGL窗口)
EGLSurface window=eglCeateWindowSurface(display,config,nativeWindow,NULL)
if(window==EGL_NO_SURFACE)
{
return EGL_FALSE;
}
//创建一个渲染上下文
EGLContext context=eglCreateContext(display,config,EGL_NO_CONTEXT,contextAttribs);
if(context==EGL_NO_CONTEXT)
{
return EGL_FALSE;
}
//指定context为当前上下文
if(!eglMakeCurrent(display,window,window,context))
{
return EGL_FALSE;
}
return EGL_TRUE;
}
题外(缓冲区):
首先颜色缓冲区就是帧缓冲区,你需要渲染的场景最终每一个像素都要写入该缓冲区,然后由它在渲染到屏幕上显示.
深度缓冲区与帧缓冲区对应,用于记录上面每个像素的深度值,通过深度缓冲区,我们可以进行深度测试,从而确定像素的遮挡关系,保证渲染正确.
模版缓冲与深度缓冲大小相同,通过设置模版缓冲每个像素的值,我们可以指定在渲染的时候只渲染某些像素,从而可以达到一些特殊的效果.
具体的使用可以多看看相关的例子.