在Android系统中,直接面向终端用户的便是GUI,可以说任何一款产品的UI都是至关重要的,是用户可以实实在在感受到的东西,是最直观的、最易被感知的东西。SurfaceFlinger作为Android GUI系统的核心模块,与OpenGL ES息息相关,所以在分析SurfaceFlinger之前有必要先了解一下OpenGL ES。
OpenGL即Open Graphics Library,是一款跨语言的、跨平台的开源图形库,包括2D、3D图形,不过OpenGL的运行对设备要求较高,很难被直接应用在CPU和内存资源匮乏、用电量需要严格控制甚至没有浮点数硬件协助的嵌入式设备上,于是OpenGL ES应运而生,OpenGL ES即OpenGL for Embeded System,是专门面向嵌入式系统的OpenGL API子集,可以理解为OpenGL的一个精简版。OpenGL ES现有三个版本(与OpengGL的版本不同),1.x版用于fixed function hardware,2.x版用于programmable hardware,3.x版则加入了更多新特性,如着色语言的完善、支持更多缓冲区对象、支持几何体实例化、统一的纹理压缩格式等。更多信息可查看如下khronos官网:
https://www.khronos.org/
在现实生活中,我们很容易感知到3D物体,但是在计算机屏幕上,物体实际上是2D的,只是通过一定的技术手段产生了3D效果,如3D电影的光影技术、计算机图形处理的透视效果。OpenGL ES支持三种基本的几何元素,点、线段和三角形,但通过这三种元素可以绘制任何复杂的几何体。图形渲染支持不同的pipeline,如1.x版的固定功能管线和2.x版的可编程管线,现在用的较多的是可编程管线,之所以称之为管线,是因为以3D数据作为输入后经过一系列的流水线式处理并最终输出2D光栅图形。
下面是Android中OpenGL ES的框架简图:
下面是Android源码中OpenGL ES相关的几个代码路径——
Java层SDK:frameworks/base/opengl/java
JNI层实现:frameworks/base/core/jni
C++代码实现:frameworks/native/opengl
Mesa3D引擎库:external/mesa3d
上面的OpenGL ES框架简图中有个EGL,它是图形渲染API(如OpenGL ES)与本地平台窗口系统的一层接口,保证了OpenGL ES的平台独立性。EGL提供了若干功能:创建rendering surface、创建graphics context、同步应用程序和本地平台渲染API、提供对显示设备的访问、提供对渲染配置的管理等。下面分析一下EGL的用法。
图形渲染可通过硬件或软件实现,是在系统启动后动态确定的。如果是硬件加速,首先要加载libhgl库,否则加载libagl库由CPU进行图形处理。具体哪种渲染方式,是由系统解析egl.cfg文件后决定的。若egl.cfg不存在,则说明硬件不支持图形渲染加速;若egl.cfg存在的话,一般放在源码device/[Manufacture]目录下,然后编译、烧机到设备/system/lib/egl/egl.cfg。例如,device/google/marlin/egl.cfg,可能有如下内容:
0 0 android
0 1 adreno
egl.cfg文件中,第一个数字表示显示屏编号,Android系统理论上支持多个显示设备,但到目前位置还只能支持一个,所以这个数值必须为0;第二个数字表示渲染方式,1为硬件加速,2为软件描画;第三个参数是库的名称,需要将对应的实现库放在/system/lib/egl或/vendor/lib/egl目录下,库的名称格式如下:
libEGL_<Lib_Name>.so
libGLES_<Lib_Name>.so
libGLESv1_CM_<Lib_Name>.so
libGLESv2_<Lib_Name>.so
如上device/google/marlin/egl.cfg,“0 0 android”为默认配置,“0 1 adreno”表示采用高通adreno GPU进行硬件加速。egl.cfg可以配置多个库,优先级逐行递减。
EGL的API名字基本以egl关键字开头,格式固定,头文件位置如下:
frameworks/native/opengl/include/EGL/egl.h
frameworks/native/opengl/include/EGL/eglext.h
frameworks/native/opengl/include/EGL/eglplatform.h
egl.h声明了EGL API,eglext.h是对EGL的扩展,eglplatform.h保证了EGL的平台独立性。下面是EGL常用的类型及常量,可以看出EGL的最新版本为EGL1.4。
typedef int EGLint;
typedef unsigned int EGLBoolean;
typedef unsigned int EGLenum;
typedef void *EGLConfig;
typedef void *EGLContext;
typedef void *EGLDisplay;
typedef void *EGLSurface;
typedef void *EGLClientBuffer;
#define EGL_FALSE 0
#define EGL_TRUE 1
#define EGL_VERSION_1_0 1
#define EGL_VERSION_1_1 1
#define EGL_VERSION_1_2 1
#define EGL_VERSION_1_3 1
#define EGL_VERSION_1_4 1
#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType, 0)
#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0)
#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0)
#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0)
#define EGL_DONT_CARE EGL_CAST(EGLint, -1)
下面简单介绍一下EGL API,更多信息可查看如下khronos官网
https://www.khronos.org/registry/EGL/sdk/docs/man/
eglGetError——
EGLAPI EGLint EGLAPIENTRY eglGetError(void);
eglGetError用于获取当前线程的上一个EGL操作的结果,初始值为EGL_SUCCESS,下面是可能的返回值:
#define EGL_SUCCESS 0x3000
#define EGL_NOT_INITIALIZED 0x3001
#define EGL_BAD_ACCESS 0x3002
#define EGL_BAD_ALLOC 0x3003
#define EGL_BAD_ATTRIBUTE 0x3004
#define EGL_BAD_CONFIG 0x3005
#define EGL_BAD_CONTEXT 0x3006
#define EGL_BAD_CURRENT_SURFACE 0x3007
#define EGL_BAD_DISPLAY 0x3008
#define EGL_BAD_MATCH 0x3009
#define EGL_BAD_NATIVE_PIXMAP 0x300A
#define EGL_BAD_NATIVE_WINDOW 0x300B
#define EGL_BAD_PARAMETER 0x300C
#define EGL_BAD_SURFACE 0x300D
#define EGL_CONTEXT_LOST 0x300E
eglGetDisplay——
EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
eglGetDisplay用于获取display,display_id一般取值为EGL_DEFAULT_DISPLAY,无法获取display时返回EGL_NO_DISPLAY而不产生错误。
eglInitialize——
EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
eglInitialize用于对display进行初始化,并获取当前的EGL版本号major和minor,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED。
eglTerminate——
EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
eglTerminate用于释放display资源,包括surface和context,如果还有其它线程使用这些资源时,会等到它们通过eglMakeCurrent失效后再释放,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY。
eglQueryString——
EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name);
eglQueryString用于获取display的某些信息,返回NULL时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_PARAMETER,name取值如下:
#define EGL_VENDOR 0x3053
#define EGL_VERSION 0x3054
#define EGL_EXTENSIONS 0x3055
#define EGL_CLIENT_APIS 0x308D
eglGetConfigs——
EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
EGLint config_size, EGLint *num_config);
eglGetConfigs用于获取display的frame buffer配置列表,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_PARAMETER。
eglGetConfigAttrib——
EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
EGLint attribute, EGLint *value);
eglGetConfigAttrib用于获取display的frame buffer配置列表的某个具体的属性值,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、 EGL_BAD_CONFIG、EGL_BAD_ATTRIBUTE,attribute取值如下:
#define EGL_BUFFER_SIZE 0x3020
#define EGL_ALPHA_SIZE 0x3021
#define EGL_BLUE_SIZE 0x3022
#define EGL_GREEN_SIZE 0x3023
#define EGL_RED_SIZE 0x3024
#define EGL_DEPTH_SIZE 0x3025
#define EGL_STENCIL_SIZE 0x3026
#define EGL_CONFIG_CAVEAT 0x3027
#define EGL_CONFIG_ID 0x3028
#define EGL_LEVEL 0x3029
#define EGL_MAX_PBUFFER_HEIGHT 0x302A
#define EGL_MAX_PBUFFER_PIXELS 0x302B
#define EGL_MAX_PBUFFER_WIDTH 0x302C
#define EGL_NATIVE_RENDERABLE 0x302D
#define EGL_NATIVE_VISUAL_ID 0x302E
#define EGL_NATIVE_VISUAL_TYPE 0x302F
#define EGL_SAMPLES 0x3031
#define EGL_SAMPLE_BUFFERS 0x3032
#define EGL_SURFACE_TYPE 0x3033
#define EGL_TRANSPARENT_TYPE 0x3034
#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
#define EGL_TRANSPARENT_RED_VALUE 0x3037
#define EGL_NONE 0x3038
#define EGL_BIND_TO_TEXTURE_RGB 0x3039
#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
#define EGL_MIN_SWAP_INTERVAL 0x303B
#define EGL_MAX_SWAP_INTERVAL 0x303C
#define EGL_LUMINANCE_SIZE 0x303D
#define EGL_ALPHA_MASK_SIZE 0x303E
#define EGL_COLOR_BUFFER_TYPE 0x303F
#define EGL_RENDERABLE_TYPE 0x3040
#define EGL_MATCH_NATIVE_PIXMAP 0x3041
#define EGL_CONFORMANT 0x3042
eglChooseConfig——
EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
EGLConfig *configs, EGLint config_size,
EGLint *num_config);
eglChooseConfig用于获取display的frame buffer配置列表,不过这个配置列表要与指定的属性列表attrib_list匹配,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_PARAMETER、EGL_BAD_ATTRIBUTE。attrib_list有固定的格式,属性及属性值成对出现,每个属性的属性值也都有一定的要求,最后以EGL_NONE结尾,例子如下:
EGLint const attrib_list[] = {
EGL_RED_SIZE, 4,
EGL_GREEN_SIZE, 4,
EGL_BLUE_SIZE, 4,
EGL_NONE
};
eglCreateWindowSurface——
EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
EGLNativeWindowType win,
const EGLint *attrib_list);
eglCreateWindowSurface用于创建window surface,失败时返回EGL_NO_SURFACE,可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONFIG、EGL_BAD_NATIVE_WINDOW、EGL_BAD_ATTRIBUTE、EGL_BAD_ALLOC、EGL_BAD_MATCH。attrib_list的属性可以是EGL_RENDER_BUFFER、EGL_VG_ALPHA_FORMAT、EGL_VG_COLORSPACE。
eglCreatePbufferSurface——
EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
const EGLint *attrib_list);
eglCreatePbufferSurface用于创建off-screen的pixel buffer surface,失败时返回EGL_NO_SURFACE,可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONFIG、EGL_BAD_ATTRIBUTE、EGL_BAD_ALLOC、EGL_BAD_MATCH。attrib_list的属性可以是EGL_HEIGHT、EGL_LARGEST_PBUFFER、EGL_MIPMAP_TEXTURE、EGL_TEXTURE_FORMAT、EGL_TEXTURE_TARGET、EGL_VG_ALPHA_FORMAT、EGL_VG_COLORSPACE、EGL_WIDTH。
eglCreatePixmapSurface——
EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
EGLNativePixmapType pixmap,
const EGLint *attrib_list);
eglCreatePixmapSurface用于创建off-screen的pixmap surface,失败时返回EGL_NO_SURFACE,可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONFIG、EGL_BAD_NATIVE_PIXMAP、EGL_BAD_ATTRIBUTE、EGL_BAD_ALLOC、EGL_BAD_MATCH。attrib_list的属性可以是EGL_VG_ALPHA_FORMAT、EGL_VG_COLORSPACE。
eglDestroySurface——
EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
eglDestroySurface用于销毁surface,有其它线程使用这个surface时要等到不使用时在销毁,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE。
eglQuerySurface——
EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
EGLint attribute, EGLint *value);
eglQuerySurface用于获取surface信息,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_BAD_ATTRIBUTE。attribute取值为:EGL_CONFIG_ID、EGL_HEIGHT、EGL_HORIZONTAL_RESOLUTION、EGL_LARGEST_PBUFFER、EGL_MIPMAP_LEVEL、EGL_MIPMAP_TEXTURE、EGL_MULTISAMPLE_RESOLVE、EGL_PIXEL_ASPECT_RATIO、EGL_RENDER_BUFFER、EGL_SWAP_BEHAVIOR、EGL_TEXTURE_FORMAT、EGL_TEXTURE_TARGET、EGL_VERTICAL_RESOLUTION、EGL_WIDTH。
eglBindAPI——
EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
eglBindAPI用于设置调用线程的渲染API,返回EGL_FALSE时可能的错误为EGL_BAD_PARAMETER。api取值为:EGL_OPENGL_API、EGL_OPENGL_ES_API、EGL_OPENVG_API。
eglQueryAPI——
EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
eglQueryAPI用于获取调用线程的渲染API,可能返回EGL_NONE。
eglWaitClient——
EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
eglWaitClient用于等待client API执行完毕才继续后面的渲染工作,返回EGL_FALSE时可能的错误为EGL_BAD_CURRENT_SURFACE。
eglReleaseThread——
EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void);
eglReleaseThread用于清空每个线程的状态为初始值,如错误、API、context等。
eglCreatePbufferFromClientBuffer——
EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
EGLConfig config, const EGLint *attrib_list);
eglCreatePbufferFromClientBuffer用于创建绑定到OpenVG图片的off-screen的pixel buffer surface,失败时返回EGL_NO_SURFACE,可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONFIG、EGL_BAD_PARAMETER、EGL_BAD_ACCESS、EGL_BAD_ATTRIBUTE、EGL_BAD_ALLOC、EGL_BAD_MATCH。buftype值为EGL_OPENVG_IMAGE,attrib_list的属性可以是EGL_MIPMAP_TEXTURE、EGL_TEXTURE_FORMAT、EGL_TEXTURE_TARGET。
eglSurfaceAttrib——
EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
EGLint attribute, EGLint value);
eglSurfaceAttrib用于设置surface属性,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_BAD_MATCH、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_BAD_ATTRIBUTE。attribute值为EGL_MIPMAP_LEVEL、EGL_MULTISAMPLE_RESOLVE、EGL_SWAP_BEHAVIOR。
eglBindTexImage——
EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
eglBindTexImage用于定义二维纹理图片,返回EGL_FALSE时可能的错误为EGL_BAD_ACCESS、EGL_BAD_MATCH、EGL_BAD_SURFACE。
eglReleaseTexImage——
EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
eglReleaseTexImage用于释放用作纹理的color buffer,返回EGL_FALSE时可能的错误为EGL_BAD_MATCH、EGL_BAD_SURFACE。
eglSwapInterval——
EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
eglSwapInterval用于设置buffer交换时的最小帧数,返回EGL_FALSE时可能的错误为EGL_BAD_CONTEXT、EGL_BAD_SURFACE。
eglCreateContext——
EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
EGLContext share_context,
const EGLint *attrib_list);
eglCreateContext用于创建渲染context,失败时返回EGL_NO_CONTEXT,可能的错误为EGL_BAD_MATCH、EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONFIG、EGL_BAD_CONTEXT、EGL_BAD_ATTRIBUTE、EGL_BAD_ALLOC。attrib_list属性值为EGL_CONTEXT_CLIENT_VERSION。
eglDestroyContext——
EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
eglDestroyContext用于销毁渲染context,如果有其它线程使用这个context时就等到不使用时再销毁,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONTEXT。
eglMakeCurrent——
EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext ctx);
eglMakeCurrent用于绑定渲染context和surface,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_BAD_CONTEXT、EGL_BAD_MATCH、EGL_BAD_ACCESS 、EGL_BAD_NATIVE_PIXMAP、EGL_BAD_NATIVE_WINDOW、EGL_BAD_CURRENT_SURFACE、EGL_BAD_ALLOC、EGL_CONTEXT_LOST。
eglGetCurrentContext——
EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void);
eglGetCurrentContext用于获取当前的渲染context。
eglGetCurrentSurface——
EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw);
eglGetCurrentSurface用于获取当前的surface。
eglGetCurrentDisplay——
EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void);
eglGetCurrentDisplay用于获取当前的display。
eglQueryContext——
EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
EGLint attribute, EGLint *value);
eglQueryContext用于获取context信息,返回EGL_FALSE时可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONTEXT、EGL_BAD_ATTRIBUTE。attribute值为EGL_CONFIG_ID、EGL_CONTEXT_CLIENT_TYPE、EGL_CONTEXT_CLIENT_VERSION、EGL_RENDER_BUFFER。
eglWaitGL——
EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);
eglWaitGL用于执行GL操作完毕后才继续后面的渲染工作,返回EGL_FALSE时可能的错误为EGL_BAD_CURRENT_SURFACE。
eglWaitNative——
EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
eglWaitNative用于native操作执行完毕之后才继续后面GL渲染,返回EGL_FALSE时可能的错误为EGL_BAD_CURRENT_SURFACE。engine值为EGL_CORE_NATIVE_ENGINE。
eglSwapBuffers——
EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
eglSwapBuffers用于置换surface的颜色buffer到native window,返回EGL_FALSE时可能的原因为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_CONTEXT_LOST。
eglCopyBuffers——
EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
EGLNativePixmapType target);
eglCopyBuffers用于拷贝surface的颜色buffer到native pixmap,返回EGL_FALSE时可能的原因为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_BAD_NATIVE_PIXMAP、EGL_BAD_MATCH、EGL_CONTEXT_LOST。
eglGetProcAddress——
typedef void (*__eglMustCastToProperFunctionPointerType)(void);
EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
eglGetProcAddress(const char *procname);
eglGetProcAddress用于获取GL或EGL的扩展函数。
(以下内容翻译自https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglIntro.xhtml)
EGL(The Khronos Platform Graphics Interface)提供了一种方法用于通过客户端API和本地窗口系统进行渲染,客户端API包括用于嵌入式系统的3D渲染器OpenGL ES、用于桌面系统的的OpenGL ES的超集OpenGL、2D矢量图形渲染器OpenVG,本地窗口系统包括Windows、X。
基于EGL的实现,它或多或少与本地窗口系统紧密关联,大多数EGL功能都需要一个显示连接,这可以通过函数eglGetDisplay获得,然后通过函数eglInitialize初始化显示连接并获得EGL版本号。
本地窗口系统使得EGL的一系列图形可用于客户端API的渲染,这些图形可能是pixel格式、frame buffer配置等,通过这些图形还可能通过本地窗口系统的API创建window和pixmap。
EGL的surface从本地window或pixmap扩展而来,还带有一些额外的buffer,包括color buffer、depth buffer、stencil buffer和alpha mask buffer,在EGL的frame buffer配置中包含这些额外buffer的部分或全部。
EGL支持三种类型的surface渲染,分别是window、pixmap和pixel buffer。其中,window和pixmap类型的surface与本地窗口系统对应的资源息息相关;而pixel buffer则是EGL资源独享的,不可通过本地窗口系统进行渲染。
为了能够在EGL的surface上使用客户端API进行渲染,必须使用应用程序需要的渲染特性来配置合适的EGL frame buffer,相关的三个函数为eglChooseConfig、eglGetConfigs和eglGetConfigAttrib。对于window和pixmap类型的EGL surface来说,合适的本地window或pixmap匹配了本地图形时,应该首先被创建出来;对于一个给定个EGL frame buffer配置,可以通过eglGetConfigAttrib获取本地图形的类型和ID;而对于pixpel buffer来说,则不需本地资源。
从本地窗口创建EGL的window surface时调用eglCreateWindowSurface,从本地pixmap创建EGL的pixmap surface时调用eglCreatePixmapSurface,而创建与本地buffer无关联的EGL pixel buffer surface时,则使用eglCreatePbufferSurface,通过eglCreatePbufferFromClientBuffer创建的pbuffer surface的color buffer则是由OpenVG提供的,使用eglDestroySurface可以释放之前分配的资源。
绑定客户端的渲染与EGL的surface时,需要用到EGL渲染context,context与surface的frame buffer配置必须是兼容的,通过eglCreateContext创建EGL渲染context,客户端API的类型还会被第一次调用eglBindAPI而设定。
通过eglMakeCurrent可能绑定了一个EGL渲染context到一个或多个EGL surface,这样context和surface就建立了关系,后面的客户端API渲染都使用了同样的context,直到以不同的参数来再次调用eglMakeCurrent。
在同一个surface上可能同时执行了本地和客户端API的命令,但它们不是同步的,同步需要调用eglWaitClient或eglWaitNative,或者是其它的本地窗口系统命令。
下面是一个非常简单的例子,用于创建RGBA格式的window,通过OpenGL ES进行渲染,程序运行后,window颜色为黄色。
#include
#include
#include
#include
typedef ... NativeWindowType;
extern NativeWindowType createNativeWindow(void);
static EGLint const attribute_list[] = {
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_NONE
};
int main(int argc, char ** argv)
{
EGLDisplay display;
EGLConfig config;
EGLContext context;
EGLSurface surface;
NativeWindowType native_window;
EGLint num_config;
/* get an EGL display connection */
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
/* initialize the EGL display connection */
eglInitialize(display, NULL, NULL);
/* get an appropriate EGL frame buffer configuration */
eglChooseConfig(display, attribute_list, &config, 1, &num_config);
/* create an EGL rendering context */
context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL);
/* create a native window */
native_window = createNativeWindow();
/* create an EGL window surface */
surface = eglCreateWindowSurface(display, config, native_window, NULL);
/* connect the context to the surface */
eglMakeCurrent(display, surface, surface, context);
/* clear the color buffer */
glClearColor(1.0, 1.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glFlush();
eglSwapBuffers(display, surface);
sleep(10);
return EXIT_SUCCESS;
}