- 1获取Display//获取显示设备引用
- 2初始化egl//初始化egl这个工具
- 3选择Config//选择egl这个工具的目标,frambuffer的初始化参数
- 4构造Surface//根据参数构造一个frambuffer,也就是surface
- 5创建Context//创建context
- 6绘制//opengl 的eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)作为参数传到opengl里面,两者产生联系
http://blog.csdn.net/u012515661/article/details/55213460
Android EGL接口解析
EGL 是 OpenGL ES 和底层 Native 平台视窗系统之间的接口。本章主要讲述 OpenGL ES 的 EGL API ,以及如何用它创建 Context 和绘制 Surface 等,并对用于 OpenGL 的其他视窗 API 做了比较分析,比如 WGL 和 GLX 。
EGL 介绍
EGL 是为 OpenGL ES 提供平台独立性而设计。在本章中,你将详细地学习每个 EGL API ,并了解使用 EGL 时候需要注意的平台特性和限制。 OpenGL ES 为附加功能和可能的平台特性开发提供了扩展机制,但仍然需要一个可以让 OpenGL ES 和本地视窗系统交互且平台无关的层。 OpenGL ES 本质上是一个图形渲染管线的状态机,而 EGL 则是用于监控这些状态以及维护 Frame buffer 和其他渲染 Surface 的外部层。
图 2-1 是一个典型的 EGL 系统布局图。
EGL 视窗设计是基于人们熟悉的用于 Microsoft Windows ( WGL )和 UNIX ( GLX )上的 OpenGL 的 Native 接口,与后者比较接近。 OpenGL ES 图形管线的状态被存储于 EGL 管理的一个 Context 中。 Frame Buffers 和其他绘制 Surfaces 通过 EGL API 创建、管理和销毁。 EGL 同时也控制和提供了对设备显示和可能的设备渲染配置的访问。
EGL 数据类型
EGL 包含了自己的一组数据类型,同时也提供了对一组平台相关的本地数据类型的支持。这些 Native 数据类型定义在 EGL 系统的头文件中。一旦你了解这些数据类型之间的不同,使用它们将变得很简单。多数情况下,为保证可移植性,开发人员将尽可能使用抽象数据类型而避免直接使 用系统数据类型。通过使用定义在 EGL 中 Native 类型,可以让你写的 EGL 代码运行在任意的 EGL 的实现上。 Native EGL 类型说明如下:
- NativeDisplayType 平台显示数据类型,标识你所开发设备的物理屏幕
- NativeWindowType 平台窗口数据类型,标识系统窗口
- NativePixmapType 可以作为 Framebuffer 的系统图像(内存)数据类型,该类型只用于离屏渲染
下面的代码是一个 NativeWindowType 定义的例子。这只是一个例子,不同平台之间的实现千差万别。使用 native 类型的关键作用在于为开发者抽象化这些细节。 QUALCOMM 使用 IDIB 结构定义 native 类型,如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
接下来的小节中,我们将深入更多 EGL 数据类型细节。标准 EGL 数据类型如表 2.1 所示。
表 2.1 EGL 数据类型
数据类型 | 值 |
---|---|
EGLBoolean | EGL_TRUE =1, EGL_FALSE=0 |
EGLint | int 数据类型 |
EGLDisplay | 系统显示 ID 或句柄 |
EGLConfig | Surface 的 EGL 配置 |
EGLSurface | 系统窗口或 frame buffer 句柄 |
EGLContext | OpenGL ES 图形上下文 |
NativeDisplayType | Native 系统显示类型 |
NativeWindowType | Native 系统窗口缓存类型 |
NativePixmapType | Native 系统 frame buffer |
EGL Displays
EGLDisplay 是一个关联系统物理屏幕的通用数据类型。对于 PC 来说, Display 就是显示器的句柄。不管是嵌入式系统或 PC ,都可能有多个物理显示设备。为了使用系统的显示设备, EGL 提供了 EGLDisplay 数据类型,以及一组操作设备显示的 API 。
下面的函数原型用于获取 Native Display :
- 1
- 2
其 中 display 参数是 native 系统的窗口显示 ID 值。如果你只是想得到一个系统默认的 Display ,你可以使用 EGL_DEFAULT_DISPLAY 参数。如果系统中没有一个可用的 native display ID 与给定的 display 参数匹配,函数将返回 EGL_NO_DISPLAY ,而没有任何 Error 状态被设置。
由于设置无效的 display 值不会有任何错误状态,在你继续操作前请检测返回值。
下面是一个使用 EGL API 获取系统 Display 的例子:
m_eglDisplay = eglGetDisplay( system.display);
if (m_eglDisplay == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS))
throw error_egl_display;
Initialization 初始化
和很多视窗 API 类似, EGL 在使用前需要初始化,因此每个 EGLDisplay 在使用前都需要初始化。初始化 EGLDisplay 的同时,你可以得到系统中 EGL 的实现版本号。了解当前的版本号在向后兼容性方面是非常有价值的。嵌入式和移动设备通常是持续的投放到市场上,所以你需要考虑到你的代码将被运行在形形色 色的实现上。通过动态查询 EGL 版本号,你可以为新旧版本的 EGL 附加额外的特性或运行环境。基于平台配置,软件开发可用清楚知道哪些 API 可用访问,这将会为你的代码提供最大限度的可移植性。
下面是初始化 EGL 的函数原型:
- 1
- 2
其中 dpy 应该是一个有效的 EGLDisplay 。函数返回时, major 和 minor 将被赋予当前 EGL 版本号。比如 EGL1.0 , major 返回 1 , minor 则返回 0 。给 major 和 minor 传 NULL 是有效的,如果你不关心版本号。
eglQueryString() 函数是另外一个获取版本信息和其他信息的途径。通过 eglQueryString() 获取版本信息需要解析版本字符串,所以通过传递一个指针给 eglInitializ() 函数比较容易获得这个信息。注意在调用 eglQueryString() 必须先使用 eglInitialize() 初始化 EGLDisplay ,否则将得到 EGL_NOT_INITIALIZED 错误信息。
下面是获取 EGL 版本字符串信息的函数原型:
- 1
- 2
参数 name 可以是 EGL_VENDOR
, EGL_VERSION
, 或者EGL_EXTENSIONS
。这个函数最常用来查询有哪些 EGL 扩展被实现。所有 EGL 扩展都是可选的,如果你想使用某个扩展特性,请检查该扩展是否被实现了,而不要想当然假定已经实现了。如果没有扩展被实现,将返回一个 Null 字符串,如果给定的 name 参数无效,则会得到 EGL_BAD_PARAMETER
. 错误信息。
EGL Configurations
EGLConfigs 是一个用来描述 EGL surface 配置信息的数据类型。要获取正确的渲染结果, Surface 的格式是非常重要的。根据平台的不同, surface 配置可能会有限制,比如某个设备只支持 16 位色深显示,或是不支持 stencil buffer ,还有其他的功能限制或精度的差异。
下面是获取系统可用的 EGL 配置信息的函数原型:
- 1
- 2
参数 configs 将包含在你的平台上有效的所有 EGL framebuffer 配置列表。支持的配置总数将通过 num_config 返回。实际返回的 configs 的配置个数依赖于程序传入的 config_size 。如果 config_size < num_config ,则不是所有的配置信息都将被返回。如果想获取系统支持的所有配置信息,最好的办法就是先给 eglGetConfig 传一个 NULL 的 configs 参数, num_config 将得到系统所支持的配置总数,然后用它来给 configs 分配合适的内存大小,再用得到的 configs 来调用 eglGetConfig 。
下面是如果使用 eglGetConfig() 函数的例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
由于当前平台的限制,通常只有很少的配置可用。系统支持的配置通常是利用系统硬件提供最好的性能。当你移植游戏到多个平台,它们的 EGL 配置可能会有细微的差别,我们希望作为通用的移植问题来直接处理这些问题。
选择一个 EGL Configuration
基 于 EGL 的属性,你可以定义一个希望从系统获得的配置,它将返回一个最接近你的需求的配置。选择一个你特有的配置是有点不合适的,因为只是在你的平台上使用有效。 eglChooseConfig() 函数将适配一个你所期望的配置,并且尽可能接近一个有效的系统配置。
下面是选择一个 EGL 配置的函数原型:
- 1
- 2
- 3
- 4
参数 attrib_list
指定了选择配置时需要参照的属性。参数 configs 将返回一个按照 attrib_list 排序的平台有效的所有 EGL framebuffer 配置列表。参数 config_size 指定了可以返回到 configs 的总配置个数。参数 num_config 返回了实际匹配的配置总数。
下面是如果使用 eglChoosetConfig() 函数的例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
如果找到多个合适的配置,有一个简单的排序算法用来匹配最接近你所查询的配置。表 2-2 显示了基于属性值的用来选择和排序的顺序,也包括了 EGL 规范中所有 EGL 配置属性及其默认值。
表 2.1 EGL 配置属性默认值和匹配法则
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
初始化EGL 的具体步骤
OpenGL ES是一个平台中立的图形库,在它能够工作之前,需要与一个实际的窗口系统关联起来,这与OpenGL是一样的。但不一样的是,这部份工作有标准,这个标 准就是EGL。而OpenGL时代在不同平台上有不同的机制以关联窗口系统,在Windows上是wgl,在X-Window上是xgl,在Apple OS上是agl等。EGL的工作方式和部份术语都接近于xgl。
OpenGL ES的初始化过程如下图所示意:
- 1
- 2
- 3
- 4
- 5
1获取Display。
Display 代表显示器,在有些系统上可以有多个显示器,也就会有多个Display。获得Display要调用EGLboolean eglGetDisplay(NativeDisplay dpy),参数一般为 EGL_DEFAULT_DISPLAY 。该参数实际的意义是平台实现相关的,在X-Window下是XDisplay ID,在MS Windows下是Window DC。
2初始化egl。
调用 EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor),该函数会进行一些内部初始化工作,并传回EGL版本号(major.minor)。
3选择Config。
所 为Config实际指的是FrameBuffer的参数,在MS Windows下对应于PixelFormat,在X-Window下对应Visual。一般用
- 1
- 2
其中attr_list
是以EGL_NONE
结束的参数数组,通常以id,value依次存放,对于个别标识性的属性可以只有 id,没有value。另一个办法是用
- 1
- 2
来获得所有config。这两个函数都会返回不多于config_size
个Config,结果保存在config[]
中,系统的总Config个数保存 在num_config
中。可以利用eglGetConfig()
中间两个参数为0来查询系统支持的Config总个数。
Config有众多的Attribute,这些Attribute决定FrameBuffer的格式和能力,通过eglGetConfigAttrib ()
来读取,但不能修改。
4构造Surface。
Surface 实际上就是一个FrameBuffer,通过
- 1
- 2
来创建一个可实际显示的Surface。系统通常还支持另外两种Surface:PixmapSurface和PBufferSurface,这两种都不 是可显示的Surface,PixmapSurface是保存在系统内存中的位图,PBuffer则是保存在显存中的帧 。
Surface 也有一些attribute,基本上都可以故名思意,
- 1
- 2
通过eglSurfaceAttrib()设置、eglQuerySurface()读取。
5创建Context。
OpenGL 的pipeline从程序的角度看就是一个状态机,有当前的颜色、纹理坐标、变换矩阵、绚染模式等一大堆状态,这些状态作用于程序提交的顶点 坐标等图元从而形成帧缓冲内的像素。在OpenGL的编程接口中,Context就代表这个状态机,程序的主要工作就是向Context提供图元、设置状 态,偶尔也从Context里获取一些信息。
用
- 1
- 2
来创建一个Context。
6绘制。
应用程序通过OpenGL API进行绘制,一帧完成之后,调用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)
来显示。