OpenGL egl_pgc历届冠军

OpenGL egl_pgc历届冠军【参考-khronos-egl】https://www.khronos.org/egl【参考-khronos-egl-api(目前共34个API)】https://www.khronos.org/registry/EGL/sdk/docs/man/【参考-khronos-egl-intro】https://www.khronos.org/registry/EGL/sdk/docs/man/h

【参考-khronos-egl(最新版本1.5)】https://www.khronos.org/egl
【参考-khronos-egl-api(目前共34个API,不包括Khronos扩展)】https://www.khronos.org/registry/EGL/sdk/docs/man/
【参考-khronos-egl-intro】https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglIntro.xhtml

0、概述

EGL,它是图形渲染API(如OpenGL ES)与本地平台窗口系统的一层接口,保证了OpenGL ES的平台独立性。EGL提供了若干功能:创建rendering surface、创建graphics context、同步应用程序和本地平台渲染API、提供对显示设备的访问、提供对渲染配置的管理等。

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 <stdlib.h>
#include <unistd.h>
#include <GLES/egl.h>
#include <GLES/gl.h>
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;
}
只听到从架构师办公室传来架构君的声音:
小小杯柈翠袖擎。有谁来对上联或下联?

1、基本类型

使用EGL时,需要链接libEGL库文件,最新版本为EGL 1.5,相关头文件有以下几个:

此代码由Java架构师必看网-架构君整理
#include <EGL/egl.h> #include <EGL/eglext.h> #include <EGL/eglplatform.h> #include <KHR/khrplatform.h>

EGL的API名字基本以egl关键字开头,格式固定。egl.h声明了EGL API,eglext.h是对EGL的扩展,eglplatform.h保证了EGL的平台独立性。

EGL定义了如下基本类型:

// EGL 1.0
typedef unsigned int EGLBoolean;
typedef void *EGLDisplay;
typedef void *EGLConfig;
typedef void *EGLSurface;
typedef void *EGLContext;
typedef void (*__eglMustCastToProperFunctionPointerType)(void);

// EGL 1.2
typedef unsigned int EGLenum;
typedef void *EGLClientBuffer;

// EGL 1.5
typedef void *EGLSync;
typedef intptr_t EGLAttrib; // for void*
typedef khronos_utime_nanoseconds_t EGLTime; // uint64_t
typedef void *EGLImage;

typedef khronos_int32_t EGLint; // int32_t

// Native Type: X Window in Linux
typedef Display *EGLNativeDisplayType;
typedef Pixmap   EGLNativePixmapType;
typedef Window   EGLNativeWindowType;

EGL定义了如下默认/魔术值:

此代码由Java架构师必看网-架构君整理
// EGL 1.0 #define EGL_DONT_CARE ((EGLint)-1) #define EGL_FALSE 0 #define EGL_NO_CONTEXT ((EGLContext)0) #define EGL_NO_DISPLAY ((EGLDisplay)0) #define EGL_NO_SURFACE ((EGLSurface)0) #define EGL_TRUE 1 // EGL 1.2 #define EGL_UNKNOWN ((EGLint)-1) // EGL 1.4 #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) // EGL 1.5 #define EGL_NO_SYNC ((EGLSync)0) #define EGL_NO_IMAGE ((EGLImage)0)

2、初始化Display

EGL提供了图形API如OpenGL ES和原生窗口系统如Linux的X Window之间的一个结合层次,在EGL能够确定可用的Surface类型之前,它必须打开和窗口系统的通信渠道,因为是跨平台的,每个窗口系统都有不同的语义,所以EGL提供基本的不透明类型EGLDisplay(类型为void*),该类型封装了所有系统相关属性,用于原生窗口系统接口,不同的窗口系统定义了不同的Display属性,最终都会Native化,定义为EGLNativeDisplayType。任何使用EGL的应用程序必须执行的第一个操作是创建和初始化与本地EGL Display的连接,涉及如下两个函数。

EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)

eglGetDisplay用于获取EGL Display连接,display_id指定需要连接的Display,一般取默认值EGL_DEFAULT_DISPLAY,其实就是对0进行了类型转换,无法获取Display时返回EGL_NO_DISPLAY而不产生错误。eglInitialize用于对Display进行初始化,初始化已经初始化了的Display对这个Display没有影响,dpy为eglGetDisplay的返回值,major和minor获取当前的EGL版本号,可以为NULL,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_DISPLAY(dpy不是EGL Display)、EGL_NOT_INITIALIZED(dpy不能被初始化)。

另外,与eglInitialize对应的还有个eglTerminate,用于终止EGL Display连接,释放相关的所有资源,如Surface和Context,如果还有其它线程使用这些资源时,会等到它们通过eglMakeCurrent声明不再使用后再释放,终止以及终止过的Display对这个Display没有影响,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_DISPLAY(dpy不是EGL Display),函数原型如下。

EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);

3、检查错误

EGL中的大多数API成功时返回EGL_TRUE,失败时返回EGL_FALSE,但是失败的具体原因并不直接返回,而是通过eglGetError获取,每个EGL操作都会记录一个状态码,初始值为EGL_SUCCESS,eglGetError的结果也为eglGetError,eglGetError返回当前线程中最近一个EGL操作的状态,为什么这样做而不直接返回呢?因为,检查函数的返回值是一个好的编程习惯,而对于已经验证正确的代码忽略错误检查则可以减少程序中的多余代码。eglGetError的函数原型及可能的返回值如下:

EGLAPI EGLint EGLAPIENTRY eglGetError(void);

#define EGL_SUCCESS 0x3000 // 最近一个函数成功执行
#define EGL_NOT_INITIALIZED 0x3001 // 对于指定的Display来说EGL未初始化或不能进行初始化
#define EGL_BAD_ACCESS 0x3002 // EGL不能获取资源(如被其它线程绑定的Context)
#define EGL_BAD_ALLOC 0x3003 // EGL不能分配资源
#define EGL_BAD_ATTRIBUTE 0x3004 // 属性列表的属性或属性值无效
#define EGL_BAD_CONFIG 0x3005 // EGLConfig不是有效的frame buffer配置
#define EGL_BAD_CONTEXT 0x3006 // EGLContext不是有效的渲染上下文
#define EGL_BAD_CURRENT_SURFACE 0x3007 // 当前线程的Surface是window则pixel buffer和pixmap无效
#define EGL_BAD_DISPLAY 0x3008 // EGLDisplay不是有效的显示连接
#define EGL_BAD_MATCH 0x3009 // 参数不兼容(如Context需要的buffer不能由Surface提供)
#define EGL_BAD_NATIVE_PIXMAP 0x300A // EGLNativePixmapType无效
#define EGL_BAD_NATIVE_WINDOW 0x300B // EGLNativeWindowType无效
#define EGL_BAD_PARAMETER 0x300C // 参数无效
#define EGL_BAD_SURFACE 0x300D // 用于GL渲染的EGLSurface不是有效的window、pixel buffer或pixmap
#define EGL_CONTEXT_LOST 0x300E // 触发了电源管理事件,程序必须销毁所有上下文并重新安装OpenGL ES状态和对象再进行渲染。

4、配置Surface

EGL初始化Display完成后,就可以对Surface进行配置了,有两种方法,一种是查询每个Surface配置,找出最好的选择,另一种是指定一组需求,让EGL推荐最佳匹配,两者都返回一个EGLConfig,包括Surface相关的所有属性。在许多情况下,使用第二种方法更简单,而且很有可能得到用第一种方法找到的匹配,涉及以下三个函数。

EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
             EGLint config_size, EGLint *num_config);
EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
                  EGLint attribute, EGLint *value);
EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
               EGLConfig *configs, EGLint config_size,
               EGLint *num_config);

eglGetConfigs用于获取Display的frame buffer配置列表,dpy为对应的Display,configs返回配置列表(可以为NULL而只是通过num_config获取配置列表可用的配置条目),size指定配置列表的大小(size大于1时configs需要有足够的存储空间),num_config返回配置列表获取的配置条目,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_DISPLAY(非EGL Display连接)、EGL_NOT_INITIALIZED(Display未初始化)或EGL_BAD_PARAMETER(num_config为NULL)。

eglGetConfigAttrib用于获取EGL的frame buffer配置列表中某个具体属性的值,dpy为对应的Display,config为待查询的配置列表,attribute为待查询的具体属性,value返回查询的属性值,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_DISPLAY(非EGL Display连接)、EGL_NOT_INITIALIZED(Display未初始化)、EGL_BAD_CONFIG(config无效)、EGL_BAD_ATTRIBUTE(attribute无效),attribute取值如下:

#define EGL_BUFFER_SIZE 0x3020 // 颜色缓冲区深度(包括RGBA)
#define EGL_ALPHA_SIZE 0x3021 // 颜色缓冲区中alpha位数
#define EGL_BLUE_SIZE 0x3022 // 颜色缓冲区中blue位数
#define EGL_GREEN_SIZE 0x3023 // 颜色缓冲区green位数
#define EGL_RED_SIZE 0x3024 // 颜色缓冲区red位数
#define EGL_DEPTH_SIZE 0x3025 // 深度缓冲区位数
#define EGL_STENCIL_SIZE 0x3026 // stencil缓冲区位数
#define EGL_CONFIG_CAVEAT 0x3027 // 配置说明(EGL_NONE、EGL_SLOW_CONFIG、EGL_NON_CONFORMANT_CONFIG)
#define EGL_CONFIG_ID 0x3028 // 配置ID
#define EGL_LEVEL 0x3029 // frame buffer级别(默认为0或表示overlay的整数和underlay的负数)
#define EGL_MAX_PBUFFER_HEIGHT 0x302A // Surface为pixel buffer时的最大高度(像素)
#define EGL_MAX_PBUFFER_PIXELS 0x302B // Surface为pixel buffer时的最大尺寸(像素)
#define EGL_MAX_PBUFFER_WIDTH 0x302C // Surface为pixel buffer时的最大宽度(像素)
#define EGL_NATIVE_RENDERABLE 0x302D // 本地渲染API是否可以渲染Surface
#define EGL_NATIVE_VISUAL_ID 0x302E // 本地可视ID
#define EGL_NATIVE_VISUAL_TYPE 0x302F // 本地可视类型
#define EGL_SAMPLES 0x3031 // 每个像素采样个数
#define EGL_SAMPLE_BUFFERS 0x3032 // 多重采样缓冲区位数
#define EGL_SURFACE_TYPE 0x3033 // 支持的EGL Surface的掩码
#define EGL_TRANSPARENT_TYPE 0x3034 // 透明类型(EGL_NONE、EGL_TRANSPARENT_RGB)
#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 // 透明的blue值
#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 // 透明的green值
#define EGL_TRANSPARENT_RED_VALUE 0x3037 // 透明的red值
#define EGL_NONE 0x3038 // 固定用于属性列表结尾
#define EGL_BIND_TO_TEXTURE_RGB 0x3039 // 颜色缓冲区是否可以绑定RGB纹理
#define EGL_BIND_TO_TEXTURE_RGBA 0x303A // 颜色缓冲区是否可以绑定RGBA纹理
#define EGL_MIN_SWAP_INTERVAL 0x303B // eglSwapInterval参数的最小值
#define EGL_MAX_SWAP_INTERVAL 0x303C // eglSwapInterval参数的最大值
#define EGL_LUMINANCE_SIZE 0x303D // luminance缓冲区中luminance位数
#define EGL_ALPHA_MASK_SIZE 0x303E // alpha屏蔽缓冲区位数
#define EGL_COLOR_BUFFER_TYPE 0x303F // 颜色缓冲区类型(EGL_RGB_BUFFER、EGL_LUMINANCE_BUFFER)
#define EGL_RENDERABLE_TYPE 0x3040 // 支持的客户API上下文的掩码
#define EGL_MATCH_NATIVE_PIXMAP 0x3041
#define EGL_CONFORMANT 0x3042 // 客户API上下文与配置的一致性的掩码

另外,EGL_MATCH_NATIVE_PIXMAP只支持eglChooseConfig,而不支持eglGetConfigAttrib。

eglChooseConfig用于获取Display的frame buffer配置列表,不过这个配置列表要与指定的属性列表attrib_list匹配,dpy为对应的Display,attrib_list为config需要匹配的属性列表,configs返回配置列表(非NULL时,size为最大值,num_configs为实际值,为NULL时,忽略size),size指定配置列表的大小(size大于1时configs需要有足够的存储空间),num_config返回配置列表获取的配置条目,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_DISPLAY(非EGL Display连接)、EGL_BAD_ATTRIBUTE(属性列表的属性或属性值错误)EGL_NOT_INITIALIZED(Display未初始化)或EGL_BAD_PARAMETER(num_config为NULL)。attrib_list有固定的格式,属性及属性值成对出现,每个属性的属性值也都有一定的要求,最后以EGL_NONE结尾。如果某个属性在attrib_list中没有指定,则使用默认值,如EGL_DEPTH_SIZE的默认值为0,有些属性的默认值为EGL_DONT_CARE,意思是可以为任何值,这些属性将不作检查。属性匹配有不同的方式,如EGL_LEVEL为设定值,而EGL_RED_SIZE设置的实际上是个最小值。如果有多个配置匹配属性时,将返回一个根据匹配标准进行排序的配置列表。有三个掩码类型的属性,EGL_CONFORMANT、EGL_RENDERABLE_TYPE和EGL_SURFACE_TYPE,只有掩码非0时才进行匹配。attrib_list支持的属性基本同上面介绍的eglGetConfigAttrib的属性,下面再作个简单介绍

EGL_ALPHA_MASK_SIZE:非负整数,指定最小值,默认为0,用于OpenGL和OpenGL ES。
EGL_ALPHA_SIZE:非负整数,为0时使用最小值,否则为最大值,默认为0。
EGL_BIND_TO_TEXTURE_RGB:EGL_DONT_CARE、EGL_TRUE或EGL_FALSE,默认为EGL_DONT_CARE,目前仅支持pbuffer。
EGL_BIND_TO_TEXTURE_RGBA:EGL_DONT_CARE、EGL_TRUE或EGL_FALSE,默认为EGL_DONT_CARE,目前仅支持pbuffer。
EGL_BLUE_SIZE:非负整数,为0时使用最小值,否则为最大值,默认为0。
EGL_BUFFER_SIZE:非负整数,指定最小值,默认为0。
EGL_COLOR_BUFFER_TYPE:EGL_RGB_BUFFER、EGL_LUMINANCE_BUFFER。
EGL_CONFIG_CAVEAT:EGL_DONT_CARE、EGL_NONE、EGL_SLOW_CONFIG、EGL_NON_CONFORMANT_CONFIG,默认为EGL_DONT_CARE。
EGL_CONFIG_ID:默认为EGL_DONT_CARE。
EGL_CONFORMANT:EGL_OPENGL_BIT、EGL_OPENGL_ES_BIT、EGL_OPENGL_ES2_BIT、EGL_OPENGL_ES3_BIT、EGL_OPENVG_BIT,默认为0。
EGL_DEPTH_SIZE:非负整数,非0时指定最小值,默认为0,用于OpenGL和OpenGL ES。
EGL_GREEN_SIZE:非负整数,为0时使用最小值,否则为最大值,默认为0。
EGL_LEVEL:默认为0。
EGL_LUMINANCE_SIZE:非负整数,为0时使用最小值,否则为最大值,默认为0。
EGL_MATCH_NATIVE_PIXMAP:默认为0。
EGL_NATIVE_RENDERABLE:EGL_DONT_CARE、EGL_TRUE、EGL_FALSE,默认为EGL_DONT_CARE。
EGL_MAX_SWAP_INTERVAL:默认为EGL_DONT_CARE。
EGL_MIN_SWAP_INTERVAL:默认为EGL_DONT_CARE。
EGL_RED_SIZE:非负整数,为0时使用最小值,否则为最大值,默认为0。
EGL_SAMPLE_BUFFERS:指定最小值,仅支持0和1,默认为0。
EGL_SAMPLES:指定最小值。
EGL_STENCIL_SIZE:非负整数,为0时使用最小值,否则为最大值,默认为0,用于OpenGL和OpenGL ES。
EGL_RENDERABLE_TYPE:可选值同EGL_CONFORMANT,默认为EGL_OPENGL_ES_BIT。
EGL_SURFACE_TYPE:EGL_MULTISAMPLE_RESOLVE_BOX_BIT、EGL_PBUFFER_BIT、EGL_PIXMAP_BIT、EGL_SWAP_BEHAVIOR_PRESERVED_BIT、EGL_VG_ALPHA_FORMAT_PRE_BIT、EGL_VG_COLORSPACE_LINEAR_BIT、EGL_WINDOW_BIT,默认为EGL_WINDOW_BIT。
EGL_TRANSPARENT_TYPE:EGL_NONE、EGL_TRANSPARENT_RGB,默认为EGL_NONE。
EGL_TRANSPARENT_RED_VALUE:在0到颜色缓冲区的red分量之间,默认为EGL_DONT_CARE。
EGL_TRANSPARENT_GREEN_VALUE:在0到颜色缓冲区的red分量之间,默认为EGL_DONT_CARE。
EGL_TRANSPARENT_BLUE_VALUE:在0到颜色缓冲区的red分量之间,默认为EGL_DONT_CARE。

下面说明上面提到的有多个配置匹配属性时的排序原则,优先级从高到底。
(1)EGL_CONFIG_CAVEAT:优先级从高到低是EGL_NONE、EGL_SLOW_CONFIG、EGL_NON_CONFORMANT_CONFIG。
(2)EGL_COLOR_BUFFER_TYPE:优先级从高到低是EGL_RGB_BUFFER、EGL_LUMINANCE_BUFFER。
(3)颜色缓冲区取颜色位数总和的较大值,如RGB的EGL_RED_SIZE、EGL_GREEN_SIZE、EGL_BLUE_SIZE和EGL_ALPHA_SIZE,或者luminance的EGL_LUMINANCE_SIZE和EGL_ALPHA_SIZE。
(4)EGL_BUFFER_SIZE:取较小值。
(5)EGL_SAMPLE_BUFFERS:取较小值。
(6)EGL_SAMPLES:取较小值。
(7)EGL_DEPTH_SIZE:取较小值。
(8)EGL_STENCIL_SIZE:取较小值。
(9)EGL_ALPHA_MASK_SIZE:取较小值。
(10)EGL_NATIVE_VISUAL_TYPE:由实现而定。
(11)EGL_CONFIG_ID:取较小值。
(12)其它属性不作排序。
上面提到的颜色缓冲区包括RGB和luminance,如果OpenGL或OpenGL ES支持luminance颜色缓冲区,可以理解为GL_RED_BITS同EGL_LUMINANCE_SIZE,而忽略了GL_GREEN_BITS和GL_BLUE_BITS。因为第三条排序规则,所以为了匹配指定属性的最佳格式,必须添加额外的逻辑来检查返回的结果,例如,如果要求565的RGB格式,那么888格式将先出现在返回的结果中。

如下例子中frame buffer的级别为0,非overlay或underlay,颜色缓冲区的R、G、B最少4位,可能没有alpha,也可能没有深度缓冲区和stencil缓冲区。

EGLint const attrib_list[] = { EGL_RED_SIZE, 4, EGL_GREEN_SIZE, 4, EGL_BLUE_SIZE, 4, EGL_NONE };

5、创建Surface

有了EGLConfig之后,就可以创建EGLSurface了,Surface不只一种类型,下面先介绍Window Surface,可以理解为EGL窗口,是屏幕上的渲染区域,由eglCreateWindowSurface创建。

eglCreateWindowSurface——

EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
                  EGLNativeWindowType win,
                  const EGLint *attrib_list);

eglCreateWindowSurface用于创建Window Surface,dpy为对应的EGL Display连接,config为EGL frame buffer配置,定义了可用于Surface的frame buffer资源,win为Native Window,是个平台相关的类型,attrib_list为Window Surface属性列表,可以为NULL,成功时返回新创建的EGLSurface,失败时返回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_BACK_BUFFER,还可以选择EGL_SINGLE_BUFFER ,OpenGL ES 3.0只支持EGL_BACK_BUFFER。
EGL_VG_ALPHA_FORMAT:只适用于OpenVG,默认值为EGL_VG_ALPHA_FORMAT_NONPRE,还可以选择EGL_VG_ALPHA_FORMAT_PRE。
EGL_VG_COLORSPACE:只适用于OpenVG,默认值为EGL_VG_COLORSPACE_sRGB,还可以选择EGL_VG_COLORSPACE_LINEAR。

eglDestroySurface——

EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);

与eglCreateXxxSurface对应的,还有个eglDestroySurface,用于销毁surface,dpy为对应的Display,surface为将要销毁的Surface,如果任何其它线程都没有使用这个Surface时,Surface将被立即销毁,否则要等到这个Surface不被任何线程使用时才销毁,另外,对于一个PBuffer Surface来说,其资源要等到绑定到纹理对象的颜色缓冲区释放后才被销毁。成功时返回EGL_TRUE,失败时返回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信息,dpy为对应的Display,surface待查询的Surface,attribute为待查询的Surface属性,value用于返回Surface属性值,成功时返回EGL_TRUE,失败时返回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

eglSurfaceAttrib——

EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
                EGLint attribute, EGLint value);

eglSurfaceAttrib用于设置Surface属性,dpy为对应的Display,surface为要设置的Surface,attribute为要设置的Surface属性,value为要设置的Surface属性值,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_DISPLAY、EGL_BAD_MATCH、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_BAD_ATTRIBUTE。attribute取值可以是:

EGL_MIPMAP_LEVEL:默认值为0。
EGL_MULTISAMPLE_RESOLVE:EGL_MULTISAMPLE_RESOLVE_DEFAULT或EGL_MULTISAMPLE_RESOLVE_BOX,默认值为前者。
EGL_SWAP_BEHAVIOR:EGL_BUFFER_PRESERVED或EGL_BUFFER_DESTROYED,默认值由实现而定。

eglCreatePbufferSurface——

EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
                   const EGLint *attrib_list);

PBuffer Surface是不同于Window Surface的另一种EGLSurface,eglCreatePbufferSurface用于创建off-screen的pixel buffer Surface,dpy为对应的Display,config为frame buffer配置,attrib_list为PBuffer属性列表,可以为NULL,成功时返回新创建的EGLSurface,失败时返回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:默认值为0。
EGL_LARGEST_PBUFFER:默认值为EGL_FALSE。
EGL_MIPMAP_TEXTURE:默认值为EGL_FALSE。
EGL_TEXTURE_FORMAT:默认值为EGL_NO_TEXTURE,还可以选择EGL_TEXTURE_RGB或EGL_TEXTURE_RGBA。
EGL_TEXTURE_TARGET:默认值为EGL_NO_TEXTURE,还可以选择EGL_TEXTURE_2D。
EGL_VG_ALPHA_FORMAT:只适用于OpenVG,默认值为EGL_VG_ALPHA_FORMAT_NONPRE,还可以选择EGL_VG_ALPHA_FORMAT_PRE。
EGL_VG_COLORSPACE:只适用于OpenVG,默认值为EGL_VG_COLORSPACE_sRGB,还可以选择EGL_VG_COLORSPACE_LINEAR。
EGL_WIDTH:默认值为0

PBuffer Surface与Window Surface——
除了可以用OpenGL ES 3.0在屏幕上的窗口渲染之外,还可以渲染称作PBuffer(像素缓冲区Pixel Buffer的缩写)的不可见屏幕外表面,和窗口一样,PBuffer可以利用OpenGL ES 3.0中的任何硬件加速,PBuffer最常用于生成纹理贴图,如果想要做的是渲染到一个纹理,那么建议使用帧缓冲区对象(FBO)代替PBuffer,因为帧缓冲区更高效,不过在某些FBO无法使用的情况下,PBuffer仍然有用,例如用OpenGL ES在屏幕外表面上渲染,然后将其作为其它API(如OpenVG)中的纹理。另外,EGLSurface还有个Pixmap Surface,简单总结一下三者的特点。window是on-screen的,pbuffer和pixmap是off-screen的,window绑定到了NativeWindow,pixmap绑定到了NativePixmap,pbuffer没有任何本地绑定,window是双缓冲区的,pbuffer和pixmap是单缓冲区的,window默认在back buffer渲染,通过eglSwapBuffers交换到屏幕上显示,pbuffer在显存中分配,由EGL_HEIGHT和EGL_WIDTH指定大小,常用作纹理数据,pixmap绑定到本地的像素缓冲区,这个缓冲区可以被其它API使用。创建不同的EGLSurface时,需要在EGLConfig中配置EGL_SURFACE_TYPE,window、pbuffer、pixmap分别对应于EGL_WINDOW_BIT、EGL_PBUFFER_BIT、EGL_PIXMAP_BUFFER。

eglCreatePixmapSurface——

EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
                  EGLNativePixmapType pixmap,
                  const EGLint *attrib_list);

eglCreatePixmapSurface用于创建off-screen的Pixmap Surface,dpy为对应的Display,config为frame buffer配置,pixmap为Native Pixmap,attrib_list为Pixmap属性列表,可以为NULL,成功时返回新创建的EGLSurface,失败时返回EGL_NO_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:只适用于OpenVG,默认值为EGL_VG_ALPHA_FORMAT_NONPRE,还可以选择EGL_VG_ALPHA_FORMAT_PRE。
EGL_VG_COLORSPACE:只适用于OpenVG,默认值为EGL_VG_COLORSPACE_sRGB,还可以选择EGL_VG_COLORSPACE_LINEAR。

eglSwapBuffers——
对于Window Surface或back buffer来说,还需要通过eglSwapBuffers把off-sreen的back buffer交换到screen buffer,也就是说把EGL Surface的颜色缓冲区post到Native Window,内部调用了渲染API的Flush命令,返回EGL_FALSE时可能的原因为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_SURFACE、EGL_CONTEXT_LOST。eglSwapBuffers对PBuffer Surface和Pixmap Surface无效。

EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);

另外,swap buffer时是否保存原有的buffer数据是个值得讨论的话题,详见:
https://www.khronos.org/registry/EGL/specs/EGLTechNote0001.html

6、创建Context

eglCreateContext——

EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
                EGLContext share_context,
                const EGLint *attrib_list);

eglCreateContext用于创建EGL渲染Context,dpy为对应的Display,config为frame buffer配置,share_context为其它的共享Context,可以设置为EGL_NO_CONTEXT,attrib_list为Context属性列表,成功时返回新创建的EGLContext,失败时返回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,整数值,指定OpenGL ES版本,默认值为1,还可以是2、3等其它版本值,创建OpenGL ES Context时设置这个属性,也就是说渲染API为EGL_OPENGL_ES_API时才设置这个属性,为此还要设置或查询渲染API,使用如下两个函数。

EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);

eglBindAPI用于设置调用线程的渲染API,api指定渲染API类型,成功是返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_PARAMETER。api取值可以是:

EGL_OPENGL_API
EGL_OPENGL_ES_API // 支持OpenGL ES时这个为默认值,否则为EGL_NONE。
EGL_OPENVG_API

eglQueryAPI用于获取调用线程的渲染API,可能返回EGL_NONE,不产生错误。

同Surface一样,Context也有对应的Create、Destroy、Query函数。

eglDestroyContext——

EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);

eglDestroyContext用于销毁渲染Context,dpy为对应的Display,ctx为要销毁的Context,如果有其它线程使用这个Context时就要等到不使用时再销毁,否则立即销毁,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_DISPLAY、EGL_NOT_INITIALIZED、EGL_BAD_CONTEXT。

eglQueryContext——

EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
               EGLint attribute, EGLint *value);

eglQueryContext用于获取Context信息,dpy为对应的Display,ctx为要查询的Context,attribute为要查询的Context属性,value返回查询的Context属性值,成功时返回EGL_TRUE,失败时返回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

7、eglMakeCurrent

EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
              EGLSurface read, EGLContext ctx);

创建了Surface和Context之后,因为可能有多个Surface和Context,所以需要通过eglMakeCurrent绑定Context到Surface,dpy为对应的Display,draw用于绘制,read用于读,ctx为要绑定的Context,成功是返回EGL_TRUE,失败时返回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。因为EGL规范要求eglMakeCurrent实现进行一次刷新,所以这一调用对于基于图块的架构代价很高。

8、同步渲染

在一个窗口中可能不只使用了一种渲染API,如OpenGL、OpenGL ES和OpenVG,这就需要协调这些渲染API,涉及同步问题,在切换窗口系统原生渲染API之前可能不知道使用的是哪个客户端渲染API,为此可以调用eglWaitClient延迟客户端的执行,直到通过某个Khronos API的所有渲染完成,效果等同于glFinish和vgFinish,成功时返回EGL_TRUE,失败是返回EGL_FALSE,可能的错误为EGL_BAD_CURRENT_SURFACE。同样,如果需要保证原生窗口系统的渲染完成,则调用eglWaitNative,参数engine指定需要等待的渲染引擎,值为EGL_CORE_NATIVE_ENGINE,成功时返回EGL_TRUE,失败时返回EGL_FALSE,可能的错误为EGL_BAD_PARAMETER、EGL_BAD_CURRENT_SURFACE。

EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);

还有一个相关函数eglWaitGL,用于执行GL操作完毕后才继续后面的Native渲染工作,同glFinish,返回EGL_FALSE时可能的错误为EGL_BAD_CURRENT_SURFACE。

EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);

9、其它

下面简单介绍一下上面没有提到的其它EGL API。

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

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。

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交换时的最小帧数,默认为1,返回EGL_FALSE时可能的错误为EGL_BAD_CONTEXT、EGL_BAD_SURFACE。

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。

eglCopyBuffers——

EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);

eglCopyBuffers用于拷贝surface的颜色buffer到native pixmap,前者保持不变,返回前内部调用了glFlush,后续命令等到拷贝完成之后才会执行,返回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的扩展函数,可能返回NULL,非NULL时这个函数也不一定在运行时支持,需要通过eglGetString(EGL_EXTENSIONS)或eglQueryString(display, EGL_EXTENSIONS)确认。

架构君码字不易,如需转载,请注明出处:https://javajgs.com/archives/210217
0
   

发表评论