
from http://lyodev.appspot.com
第二章
EGL
接口
EGL
是
OpenGL ES
和底层
Native
平台视窗系统之间的接口。本章主要讲述
OpenGL ES
的
EGL API
,以及怎样用它创建
Context
和绘制
Surface
等,并对用于
OpenGL
的其它视窗
API
做了比較分析,比方
WGL
和
GLX
。本章中将涵盖例如以下几个方面:
l
EGL
综述
l
EGL
主要构成(
Display
,
Context
,
Configuration
)
l
在
Brew
和
Windows CE
上使用
EGL
l
EGL
和其它
OpenGL
视窗系统的比較
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
系统的头文件里。一旦你了解这些数据类型之间的不同,使用它们将变得非常easy。多数情况下,为保证可移植性,开发者将尽可能使用抽象数据类型而避免直接使用系统数据类型。通过使用定义在
EGL
中
Native
类型,能够让你写的
EGL
代码执行在随意的
EGL
的实现上。
Native EGL
类型说明例如以下:
l
NativeDisplayType
平台显示数据类型,标识你所开发设备的物理屏幕
l
NativeWindowType
平台窗体数据类型,标识系统窗体
l
NativePixmapType
能够作为
Framebuffer
的系统图像(内存)数据类型,该类型仅仅用于离屏渲染
以下的代码是一个
NativeWindowType
定义的样例。这仅仅是一个样例,不同平台之间的实现千差万别。使用
native
类型的关键作用在于为开发人员抽象化这些细节。
QUALCOMM
使用
IDIB
结构定义
native
类型,例如以下:
struct IDIB {
AEEVTBL(IBitmap) *pvt; // virtual table pointer
IQueryInterface * pPaletteMap; // cache for computed palette mapping info
byte * pBmp; // pointer to top row
uint32 * pRGB; // palette
NativeColor ncTransparent; // 32-bit native color value
uint16 cx; // number of pixels in width
uint16 cy; // number of pixels in height
int16 nPitch; // offset from one row to the next
uint16 cntRGB; // number of palette entries
uint8 nDepth; // size of pixel in bits
uint8 nColorScheme; // IDIB_COLORSCHEME_...(ie. 5-6-5)
uint8 reserved[6];
};
接下来的小节中,我们将深入很多其它
EGL
数据类型细节。标准
EGL
数据类型如表
2.1
所看到的。
表
2.1 EGL
数据类型
数据类型 |
值 |
EGLBoolean |
EGL_TRUE =1, EGL_FALSE=0 |
EGLint |
int |
EGLDisplay |
系统显示 |
EGLConfig |
Surface |
EGLSurface |
系统窗体或 |
EGLContext |
OpenGL ES |
NativeDisplayType |
Native |
NativeWindowType |
Native |
NativePixmapType |
Native |
EGL Displays
EGLDisplay
是一个关联系统物理屏幕的通用数据类型。对于
PC
来说,
Display
就是显示器的句柄。无论是嵌入式系统或
PC
,都可能有多个物理显示设备。为了使用系统的显示设备,
EGL
提供了
EGLDisplay
数据类型,以及一组操作设备显示的
API
。
以下的函数原型用于获取
Native Display
:
EGLDisplay eglGetDisplay (NativeDisplayType display);
当中
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
的函数原型:
EGLBoolean eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
当中
dpy
应该是一个有效的
EGLDisplay
。函数返回时,
major
和
minor
将被赋予当前
EGL
版本。比方
EGL1.0
,
major
返回
1
,
minor
则返回
0
。给
major
和
minor
传
NULL
是有效的,假设你不关心版本。
eglQueryString()
函数是另外一个获取版本号信息和其它信息的途径。通过
eglQueryString()
获取版本号信息须要解析版本号字符串,所以通过传递一个指针给
eglInitializ()
函数比較easy获得这个信息。注意在调用
eglQueryString()
必须先使用
eglInitialize()
初始化
EGLDisplay
,否则将得到
EGL_NOT_INITIALIZED
错误信息。
以下是获取
EGL
版本号字符串信息的函数原型:
const char * eglQueryString (EGLDisplay dpy, EGLint name);
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
配置信息的函数原型:
EGLBoolean eglGetConfigs (EGLDisplay dpy, EGLConfig *configs,EGLint config_size, EGLint *num_config);
參数
configs
将包括在你的平台上有效的全部
EGL framebuffer
配置列表。支持的配置总数将通过
num_config
返回。实际返回的
configs
的配置个数依赖于程序传入的
config_size
。假设
config_size < num_config
,则不是全部的配置信息都将被返回。假设想获取系统支持的全部配置信息,最好的办法就是先给
eglGetConfig
传一个
NULL
的
configs
參数,
num_config
将得到系统所支持的配置总数,然后用它来给
configs
分配合适的内存大小,再用得到的
configs
来调用
eglGetConfig
。
以下是假设使用
eglGetConfig()
函数的样例:
EGLConfig *configs_list;
EGLint num_configs;
// Main Display
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if( m_eglDisplay == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS )
return FALSE;
if( eglInitialize( m_eglDisplay, NULL, NULL ) == EGL_FALSE || eglGetError() != EGL_SUCCESS )
return FALSE;
// find out how many configurations are supported
if ( eglGetConfigs( m_eglDisplay, NULL, 0, &num_configs)
== EGL_FALSE || eglGetError() != EGL_SUCCESS )
return FALSE;
configs_list = malloc(num_configs * sizeof(EGLConfig));
if (configs_list == (EGLConfig *)0)
return FALSE;
// Get Configurations
if( eglGetConfigs( m_eglDisplay, configs_list, num_configs, &num_configs)
== EGL_FALSE || eglGetError() != EGL_SUCCESS )
return FALSE;
因为当前平台的限制,通常仅仅有非常少的配置可用。系统支持的配置一般是利用系统硬件提供最好的性能。当你移植游戏到多个平台,它们的
EGL
配置可能会有细微的区别,我们希望作为通用的移植问题来直接处理这些问题。
选择一个
EGL Configuration
基于
EGL
的属性,你能够定义一个希望从系统获得的配置,它将返回一个最接近你的需求的配置。选择一个你特有的配置是有点不合适的,由于仅仅是在你的平台上使用有效。
eglChooseConfig()
函数将适配一个你所期望的配置,而且尽可能接近一个有效的系统配置。
以下是选择一个
EGL
配置的函数原型:
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size, EGLint * num_config);
參数
attrib_list
指定了选择配置时须要參照的属性。參数
configs
将返回一个依照
attrib_list
排序的平台有效的全部
EGL framebuffer
配置列表。參数
config_size
指定了能够返回到
configs
的总配置个数。參数
num_config
返回了实际匹配的配置总数。
以下是假设使用
eglChoosetConfig()
函数的样例:
EGLint attrs[3] = { EGL_DEPTH_SIZE, 16, EGL_NONE };
EGLint num_configs;
EGLConfigs *configs_list;
// Get the display device
if ((eglDisplay = eglGetDisplay(EGL_NO_DISPLAY)) == EGL_NO_DISPLAY)
{
return eglGetError();
}
// Initialize the display
if (eglInitialize(eglDisplay, NULL, NULL) == EGL_FALSE)
{
return eglGetError();
}
// Obtain the total number of configurations that match
if (eglChooseConfig(eglDisplay, attrs, NULL, 0, &num_configs) == EGL_FALSE)
{
return eglGetError();
}
configs_list = malloc(num_configs * sizeof(EGLConfig));
if (configs_list == (EGLConfig *)0)
return eglGetError();
// Obtain the first configuration with a depth buffer of 16 bits
if (!eglChooseConfig(eglDisplay, attrs, &configs_list, num_configs, &num_configs))
{
return eglGetError();
}
假设找到多个合适的配置,有一个简单的排序算法用来匹配最接近你所查询的配置。表
2-2
显示了基于属性值的用来选择和排序的顺序,也包含了
EGL
规范中全部
EGL
配置属性及其默认值。
表
2.1 EGL
配置属性默认值和匹配法则
属性 |
数据类型 |
默认值 |
排序优先级 |
选择顺序 |
EGL_BUFFER_SIZE |
int |
0 |
3 |
Smaller value |
EGL_RED_SIZE |
int |
0 |
2 |
Larger value |
EGL_GREEN_SIZE |
int |
0 |
2 |
Larger value |
EGL_BLUE_SIZE |
int |
0 |
2 |
Larger value |
EGL_ALPHA_SIZE |
int |
0 |
2 |
Larger value |
EGL_CONFIG_CAVET |
enum |
EGL_DONT_CARE |
1(first) |
Exact value |
EGL_CONFIG_ID |
int |
EGL_DONT_CARE |
9 |
Exact value |
EGL_DEPTH_SIZE |
int |
0 |
6 |
Smaller value |
EGL_LEVEL |
int |
0 |
- |
Equal value |
EGL_NATIVE_RENDERABLE |
Boolean |
EGL_DONT_CARE |
- |
Exact value |
EGL_NATIVE_VISUAL_TYPE |
int |
EGL_DONT_CARE |
8 |
Exact value |
EGL_SAMPLE_BUFFERS |
int |
0 |
4 |
Smaller value |
EGL_SAMPLES |
int |
0 |
5 |
Smaller value |
EGL_STENCIL_SIZE |
int |
0 |
7 |
Smaller value |
EGL_SURFACE_TYPE |
bitmask |
EGL_WINDOW_BIT |
- |
Mask value |
EGL_TRANSPARENT_TYPE |
enum |
EGL_NONE |
- |
Exact value |
EGL_TRANSPARENT_RED_VALUE |
int |
EGL_DONT_CARE |
- |
Exact value |
EGL_TRANSPARENT_GREEN_VALUE |
int |
EGL_DONT_CARE |
- |
Exact value |
EGL_TRANSPARENT_BLUE_VALUE |
int |
EGL_DONT_CARE |
- |
Exact value |