Android EGL接口解析

来源:互联网 发布:win10软件找不到了 编辑:程序博客网 时间:2024/05/20 13:37

  • 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 介绍
      • EGL 数据类型
      • EGL Displays
      • Initialization 初始化
      • EGL Configurations
      • 选择一个 EGL Configuration
    • 初始化EGL 的具体步骤
      • 1获取Display
      • 2初始化egl
      • 3选择Config
      • 4构造Surface
      • 5创建Context
      • 6绘制

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 类型说明如下:

  1. NativeDisplayType 平台显示数据类型,标识你所开发设备的物理屏幕
  2. NativeWindowType 平台窗口数据类型,标识系统窗口
  3. 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]; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

接下来的小节中,我们将深入更多 EGL 数据类型细节。标准 EGL 数据类型如表 2.1 所示。

表 2.1 EGL 数据类型

数据类型值EGLBooleanEGL_TRUE =1, EGL_FALSE=0EGLintint 数据类型EGLDisplay系统显示 ID 或句柄EGLConfigSurface 的 EGL 配置EGLSurface系统窗口或 frame buffer 句柄EGLContextOpenGL ES 图形上下文NativeDisplayTypeNative 系统显示类型NativeWindowTypeNative 系统窗口缓存类型NativePixmapTypeNative 系统 frame buffer

EGL Displays

EGLDisplay 是一个关联系统物理屏幕的通用数据类型。对于 PC 来说, Display 就是显示器的句柄。不管是嵌入式系统或 PC ,都可能有多个物理显示设备。为了使用系统的显示设备, EGL 提供了 EGLDisplay 数据类型,以及一组操作设备显示的 API 。 
下面的函数原型用于获取 Native Display :

EGLDisplay eglGetDisplay (NativeDisplayType 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 的函数原型:

EGLBoolean eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
  • 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 版本字符串信息的函数原型:

const char * eglQueryString (EGLDisplay dpy, EGLint name);
  • 1
  • 2

参数 name 可以是 EGL_VENDOREGL_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);
  • 1
  • 2

参数 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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

由于当前平台的限制,通常只有很少的配置可用。系统支持的配置通常是利用系统硬件提供最好的性能。当你移植游戏到多个平台,它们的 EGL 配置可能会有细微的差别,我们希望作为通用的移植问题来直接处理这些问题。

选择一个 EGL Configuration

基 于 EGL 的属性,你可以定义一个希望从系统获得的配置,它将返回一个最接近你的需求的配置。选择一个你特有的配置是有点不合适的,因为只是在你的平台上使用有效。 eglChooseConfig() 函数将适配一个你所期望的配置,并且尽可能接近一个有效的系统配置。

下面是选择一个 EGL 配置的函数原型:

EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,EGLConfig *configs, EGLint config_size, EGLint * num_config);
  • 1
  • 2
  • 3
  • 4

参数 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(); }
  • 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 配置属性默认值和匹配法则

属性 数据类型 默认值 排序优先级 选择顺序 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
  • 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的初始化过程如下图所示意:

Display → Config → Surface                            ↑                          Context                            ↑   Application → OpenGL Command   
  • 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。一般用

EGLboolean eglChooseConfig(EGLDisplay dpy, const EGLint * attr_list, EGLConfig * config, EGLint config_size, EGLint *num_config),
  • 1
  • 2

其中attr_list是以EGL_NONE结束的参数数组,通常以id,value依次存放,对于个别标识性的属性可以只有 id,没有value。另一个办法是用

EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config) 
  • 1
  • 2

来获得所有config。这两个函数都会返回不多于config_size个Config,结果保存在config[]中,系统的总Config个数保存 在num_config中。可以利用eglGetConfig()中间两个参数为0来查询系统支持的Config总个数。 
Config有众多的Attribute,这些Attribute决定FrameBuffer的格式和能力,通过eglGetConfigAttrib ()来读取,但不能修改。

4构造Surface。

Surface 实际上就是一个FrameBuffer,通过

EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr) 
  • 1
  • 2

来创建一个可实际显示的Surface。系统通常还支持另外两种Surface:PixmapSurface和PBufferSurface,这两种都不 是可显示的Surface,PixmapSurface是保存在系统内存中的位图,PBuffer则是保存在显存中的帧 。 
Surface 也有一些attribute,基本上都可以故名思意,

EGL_HEIGHT EGL_WIDTH EGL_LARGEST_PBUFFER EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET EGL_MIPMAP_TEXTURE EGL_MIPMAP_LEVEL
  • 1
  • 2

通过eglSurfaceAttrib()设置、eglQuerySurface()读取。

5创建Context。

OpenGL 的pipeline从程序的角度看就是一个状态机,有当前的颜色、纹理坐标、变换矩阵、绚染模式等一大堆状态,这些状态作用于程序提交的顶点 坐标等图元从而形成帧缓冲内的像素。在OpenGL的编程接口中,Context就代表这个状态机,程序的主要工作就是向Context提供图元、设置状 态,偶尔也从Context里获取一些信息。 

EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface read, EGLContext * share_list)
  • 1
  • 2

来创建一个Context。

6绘制。

应用程序通过OpenGL API进行绘制,一帧完成之后,调用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx) 来显示。


原创粉丝点击