OpenGL ES 2.0学习之路--4.EGL介绍

第三章我们使用 OpenGL ES 2.0在窗口绘制了一个三角形,但我们使用自己的函数去打开和管理窗口,虽然我们的例子很简单,但是它让OpenGL ES 2.0在你的系统工作时减少你的工作量。
为发展编程上下文环境,提供了平台独立的API叫做EGL,用来管理绘制窗口,EGL提供下面的机制。

  • 你使用的系统窗口之间的通讯
  • 查询可用的类型,配置绘图窗口
  • 创建绘图窗口
  • 同步OpenGL ES 2.0渲染和其他绘图API的渲染
  • 管理渲染资源像贴图纹理
    本章介绍基本创建窗口的要求,还要其他操作,像创建贴图纹理、使用EGL命令的要求等。
    窗口系统之间通讯
    EGL提供OpenGL ES 2.0和你计算机运行的操作系统之间通讯,例如运行X视窗的GNU/Linux系统、微软系统、苹果的Mac Os系统。EGL在决定绘制什么类型的窗口前,需要打开和操作系统的通讯连接。
    每个操作系统有不同的语法,EGL提供一个基本的不透明的类——EGLDisplay——它封装了与操作系统相关的连接。使用EGL第一步是创建并初始化一个使用本操作系统EGL显示的连接。包括两步:
    1.初始化EGL
  EGLint  majorVersion;
  EGLint  minorVersion;
  EGLDisplay display;
  display=eglGetDisplay(EGL_DEFAULT_DISPLAY);
  if(display==EGL_NO_DISPLAY)
  {
     //不能打开连接本地窗口系统
}
  if(!eglInitialize(display,&majorVersion,&minorVersion))
  {
     //未能初始化EGL 处理和覆盖
}

打开一个EGL显示服务连接使用:

EGLDisplay   eglGetDisplay(EGLNativeDisplayType display_id);

EGLNativeDisplayType定义使用者的操作系统,如果连接没有建立,eglGetDisplay将返回EGL_NO_DISPLAY,这个错误指示EGL不可用,你将不能使用OpenGL ES 2.0.
检查错误
大多数情况下EGL返回EGL_TRUE或者EGL_FALSE,当然可以得到更多的信息,如果返货EGL——FALSE,我们能够查询发生错误的原因,可以使用

EGLint    eglGetError();

查询错误码
初始化EGL
当你成功的创建了一个连接,接下来需要初始化:

EGLBoolean eglInitialize(EGLDisplay display,EGLint *majorVersion,EGLint *minorVersion);

初始化EGL内部数据,返回EGL主次版本号。如果EGL不能初始化,它将返回EGL——FALSE,设定错误码如下:

  1. 如果现实指定的不是合法的EGLDisplay,返回EGL_BAD_DISPLAY
  2. 如果EGL不能初始化,返回EGL_NOT_INITIAL
    设定可用的窗口配置
    初始化EGL后,我们需要设定渲染何种类型的窗口和配置信息。这需要两步。
    1.查询窗口配置,找到最好的选择。
    2.指定要求,让EGL做出最好的匹配。
    大多数情况下第二步和第一步是类似的。或者EGL将返回一个EGLConfig结构,它标示了窗口和它特定的信息,颜色位数,深度缓冲区,可使用eglGetConfigAttribute函数查询EGLConfig的属性。
  EGLBoolean eglGetConfigs(EGLDisplay display,EGLConfig *configs,EGLint maxReturnConfigs,EGLint *numConfigs);

如果成功返回EGL_TRUE.
有两种方式调用eglGetConfigs,输入参数如果是NULL,系统将返回EGL_TRUE,并设定可用的EGLConfigs数目numConfigs,但不包含其他信息,但找到了可用的EGLConfigs数目,你就可以分配合适的内存数目来存储整个EGLConfigs.
EGLConfig是一个可供查询的属性列表,我们现在只讨论查询某个属性时使用:

EGLBoolean eglGetConfigAttrib(EGLDisplay  display,EGLConfig config,EGLint attribute,EGLint*value)

将返回你查询的属性,这将让你控制你选择的实行创建渲染窗口。
在这里插入图片描述
例-2 配置EGL属性

EGLint attribList[]=
{
   EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
   EGL_RED_SIZE,5,
   EGL_GREEN_SIZE,6,
   EGL_BLUE_SIZE,5,
   EGL_DEPTH_SIZE,1,
   EGL_NONE
};

例-3 演示怎么使用选择的属性值,查询窗口配置

const EGLint MaxConfigs=10;
EGLConfig configs[MaxConfigs];    //只接受10个配置
EGLint numConfigs;
if(!eglChooseConfig(dpy,attribList,configs,MaxConfigs,&numConfigs))
{
    //一些没有运行处理错误情况
}
else
{
   //一切正常,继续创建一个渲染界面
}

如果eglChooseConfig返回成功,一系列的符合要求的EGLConfigs将返回。
创建在屏显示渲染区:EGL窗口
一旦我们有一个合适的EGLConfig,可以调用下面函数创建窗口:

  EGLSurface eglCreateWindowSurface(EGLDisplay display,EGLConfig  config,EGLNativeWindowType window,const EGLint*attribList)

这个函数让程序联系到操作系统的窗口管理,窗口参数为EGLConfig,要求操作系统先前已经创建一个窗口,EGL是操作系统和OpenGL ES 2.0之间的软件层 。
在这里插入图片描述
由于某些原因调用eglCreateWindowSurface会失败,这时函数调用返回EGL_NO_SURFACE,我们可以使用eglGetError查询错误发生的原因。
在这里插入图片描述
例-4 创建EGL窗口

  EGLRenderSurface window;
  EGLint attribList[]=
  {
    EGL_RENFER_BIFFER,EGL_BACK_BUFFER,EGL_NONE
};
window=eglCreateWindowSurface(dpy,window,config,attrbList);
if(window==EGL_NO_SURFACE)
{
    switch(eglGetError())
    {
       case EGL_BAD_MATCH:
       break;
       case EGL_BAD_CONFIG:
       break;
       case EGL_BAD_NATIVE_WINDOW:
       break;
       case EGL_BAd_ALLOC:
       break;
       }
}

可见窗口不是我们唯一能够绘制图形的地方,还可以绘制不能显示的窗口平面,称为pbuffers(像素缓冲区)。Pbuffeers能充分利用硬件,加速OpenGL ES 2.0.pbuffers常用来产生贴图纹理,如果你想使用贴图,你可以使用帧缓冲区来代替pbuffers,这时效率会更高。
创建pbuffers非常简单,有一点不同,也是使用EGLConfig,但修改EGL_SURFACE_TYPE值包括EGL_PBUFFEER_BIT,有了合适的EGLConfig后。使用下面的函数创建pbuffers.

EGLSurface eglCreatePbufferSurface(EGLDisplay display,EGLConfig config,const EGLint*attribList);

窗口创建后,我们注意力放到我们选择的EGLConfig属性,操作系统显示管理。
在这里插入图片描述
如果创建eglCreatePbufferSurface失败,这是函数调用返回EGL_NO_SURFACE,
在这里插入图片描述在这里插入图片描述
例-5 创建EGL pbuffer

EGLint  attribList[]=
{
   EGL_SURFACE_TYPE,EGL_PBUFFER_BIT,
   EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
   EGL_RED_SIZE,5,
   EGL_GREEN_SIZE,6,
   EGL_BLUE_SIZE,5,
   EGL_DEPTH_SIZE,1,
   EGL_NONE
};
const EGLint MaxConfig=10;
EGLConfig  configs[MaxConfigs];
EGLint numConfigs;
if(!eglChooseConfig(dpy,attribList,configs,MaxConfigs,&numConfigs))
{
       //出现错误不工作
}
else
{
//已经创建了一个pbuffer可用的EGLConfig
}
//继续创建一个512*512的pbuffer
EGLRenderSurface  pbuffer;
EGLint attribList[]=
{
   EGL_WIDTH,512,
   EGL_HEIGHT,512,
   EGL_LARGEST_PBUFFER,EGL_TRUE,
   EGL_NONE
   };
   pbuffer=eglCreatePbufferSurface(dpy,config,attribList);
pbuffer=eglCreatePbufferSurface(dpy,config,attribList);
if(pbuffer==EGL_NO_SURFACE)
{
    switch(eglGetError())
    {
       case EGL_BAD_ALLOC:
       break;
       case EGL_BAD_CONFIG:
       break;
       case EGL_BAD_PARAMETER:
       break;
       case EGL_BAD_MATCH:
       break;
       }
}
//检查我们分配的pbuffer是多大的
EGLint width;
EGLnt  height;
if(!eglQuerySurface(dpy,pbuffer,EGL_WIDTH,&width)||
   !eglQuerySurface(dpy,pbuffer,EGL_LENGTH,&height))
   {
     //不能询问窗口信息
}

Pbuffers和视窗一样支持所有的OpenGL ES 2.0渲染设备,最主要的区别——除了在你的屏幕上不能显示Pbuffers内容,当你完成渲染后,不是交换缓冲区,而是从Pbuffers中拷贝值到你的应用程序中或者绑定Pbuffers作为贴图。

创建渲染环境(上下文)
渲染环境指OpenGL ES 2.0的包含所有项目运行需要的设置的数据结构。例如着色点、片段着色器、顶点数据矩阵。OpenGL ES 2.0绘图前需要一个可用的context。
创建context,使用

 EGLContext  eglCreateContext(EGLDisplay display,EGLConfig config,EGLContext shareContext,const EGLint* attribList);

之后用EGLConfig建立显示连接你的应用程序,参数shareContext允许建立EGLContexts到各种类型数据的链接,像着色器、贴图。输入EGL_NO_CONTEXT作为shareContext的值,说明不和其他contexts分享资源。
最后像其他EGL函数一样eglCreateContext指定一系列的属性,如下表:
在这里插入图片描述
在这里插入图片描述
创建eglCreateContext成功后,它返回一个新创建的context的句柄。如果context不能被创建,eglCreateContext返回 EGL_NO_CONTEXT.可用eglGetError查询失败原因,唯一原因是EGLConfig不是有效的,返回的错误码是EGL_BAD_CONFIG.
例-6 显示怎样使用一个合适的EGLConfig创建context

  const EGLint  attrbList[]={
     EGL_CONTEXT_CLIENT_VERSION,2,
     EGL_NONE
     };
     EGLContext   context;
     context=eglCreateContext(dpy,config,EGL_NO_CONTEXT,attribList);
     if(context==EGL_NO_CONTEXT)
     {
         EGLError error=eglGetError();
         if(error==EGL_BAD_CONFIG)
         {
             //处理错误并重新运行
         }
}

别的错误也可能被eglCreateContext产生,但目前我们只检查EGLConfig错误。成功创建EGLContext后,渲染前还需最后一步。
确定当前的EGLContext
一个应用可能创建多种EGLContext,我们需要确定联系到一个特殊的EGLContext,渲染使用的EGLContext,也叫作make current.
使用:

EGLBoolean eglmakeCurrent(EGLDisplay  display,EGLSurface  draw,EGLSurface  read,EGLContext  context);

函数使用了两个EGLSurface,这也是允许的,但是我们设定这两个值为相同的值,即先前创建的窗口。
本章流程:

  1. 初始化EGL
  2. 绑定一个EGLContext到EGLRenderSurface
  3. 如果窗口被创建,没有任何错误,应用结束了。
    例-7 完整的创建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,8,
    EGL_NONE
    };
    const EGLint  contextAttribs[]=
    {
       EGL_CONTEXT_CLIENT_VERSION,2,
       EGL_NONE
       };
       EGLDisplay  dpy;
       dpy=eglGetNativeDisplay(EGL_DEFAULT_DISPLAY);
       if(dpy==EGL_NO_DISPLAY)
       {
          return  EGL_FALSE;
      }
      EGLint  major,minor;
      if(!eglInitialize(dpy,&major,&minor))
      {
          return   EGL_FALSE;
      }
      EGLConfig  config;
      EGLint  numConfigs;
      if(!eglChooseConfig(dpy,configAttribs,&config,1,&numConfigs)){
      return   EGL_FALSE;
      }
      EGLSurface  window;
      window=eglCreateWindowSurface(dpy,config,nativeWindow,NULL);
      if(window==EGL_NO_SURFACE)
      {
         return  EGL_FALSE;
         }
EGLContext  context;
context=eglCreateContext(dpy,config,EGL_NO_CONTEXT,contextAttribs);
if(context==EGL_NO_CONTEXT)
{
   return  EGL_FALSE;
   }
 if(!eglMakeCurrent(dpy,window,window,context))
 {
     return  EGL_FALSE;
}
return  EGL_TRUE;
}

例-8 显示打开一个512*512的窗口

ESContext   esContext;
const  char* title="OpenGL  ES Application Window Title";
if(esCreateWindow(&esContext,title,512,512,ES_WINDOW_RGB|ES_WINDOW_DEPTH))
{
   //窗口创建失败
}

在这里插入图片描述
这些窗口属性值将用来填充EGLConfig的属性列表。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值