EGL简介
EGL的官方定义是Khronos的渲染API(opengl、openvg)和具体的原生平台的窗口系统之间的一层接口。简单的理解就是OpenGL是图形渲染的API,提供了一套统一的接口来达到跨平台的目的,各个不同的GPU厂家(mali,adreno, PowerVR...)都可以来实现它,甚至它可以通过软件来实现(Android中就有一套OpenGL的软件实现库)。但是光有渲染的API还是不行,OpenGL还需要有画布以及它的渲染环境,而每个不同的操作系统(windows, macos, linux, android, ios)都有自己的一套窗口管理系统。假如对不同操作系统都适配一套接口,那就和OpenGL的跨平台实现相违背了。所以EGL就是定义了一套标准,来连接各个不同平台的窗口系统和OpenGL的渲染环境。这样程序员就只需要面向EGL和OpenGL编程即可,和平台相关的事情在不同平台有不同平台的EGL/OpenGL实现。下面先对EGL的API做一个简单的了解。
设备和上下文管理
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
EGLBoolean eglTerminate(EGLDisplay dpy)
const char *eglQueryString(EGLDisplay dpy, EGLint name)
EGLBoolean eglReleaseThread(void)
复制代码
eglGetDisplay是使用EGL最首先需要调用的函数,一般传入EGL_DEFAULT_DISPLAY,我们就能得到对屏幕的一个抽象对象EGLDisplay,后续的API都会依赖这个对象。 eglInitialize也是必须要调用的方法,major和minor返回EGL的版本号。eglQueryString可以得到在当前设备平台上的一些特定信息。
EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
复制代码
在不同的设备上实际上是有不同的配置实现,所以在使用EGL时,一定要先查询一下当前设备对不同配置的支持情况,然后选择某项配置。
EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx
EGLContext eglGetCurrentContext(void)
EGLSurface eglGetCurrentSurface(EGLint readdraw)
EGLDisplay eglGetCurrentDisplay(void)
EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
复制代码
创建和管理渲染的上下文环境。
渲染Surface
EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
复制代码
这一组API是创建Surface相关,包括上屏渲染的WindowSurface,离屏渲染的PbuferSurface,这个Surface是连接Native Window和OpenGL的桥梁,可以理解为EGL为OpenGL在不同的平台上抽象出来的画布。
EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
复制代码
需要在每次GL命令渲染之前调用eglMakeCurrent来绑定和选择当前的渲染上下文。调用eglSwapBuffers来使渲染的画面显示到前台,或者eglCopyBuffers把渲染的内容拷贝到一个原生的Pixemap。eglBindTexImage可以利用一个pbuffer的surface渲染到一块OpenGL的纹理上。
EGL扩展
EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image)
EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
复制代码
Android上使用EGL
Android一般需要使用Native的OpenGL来画图时,需要在程序中通过EGL来初始化OpenGL环境。在Android中,Surface就是窗口系统中的一个个窗口,EGL的作用就是需要连接OpenGL和Surface。在Native层,和Surface相对应的概念就是ANativeWindow,可以通过ANativeWindow_fromSurface来得到这个ANativeWindow对象,它和EGL的EGLNativeWindowType是同一个概念。所以可以把这个ANativeWindow作为参数传递到eglCreateWindowSurface函数中,来创建一个EGLSurface对象。这个EGLSurface和Surface的bufferqueue就建立起了连接,也就是往EGLSurface画的内容会显示在Android的Surface上。例如简单的实例如下:
// 初始化Dispaly设备
EGLDisplay display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display_, 0, 0);
// 选择合适的config,这里可以选择每个channel的bit数
EGLConfig config_;
const EGLint attribs[] =
{EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE};
EGLint num_configs;
eglChooseConfig(display_, attribs, &config_, 1, &num_configs);
if (!num_configs)
return;
// 根据ANativeWindow创建EGLSurface,这里surface实际上也可以选择相应的属性,这里为NULL
EGLSurface surface_ = eglCreateWindowSurface(display_, config_, window_, NULL);
// 可以查询surface的大小
eglQuerySurface(display_, surface_, EGL_WIDTH, &screen_width_);
eglQuerySurface(display_, surface_, EGL_HEIGHT, &screen_height_);
// 创建EGLContext
const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION,
2, // Request opengl ES2.0
EGL_NONE};
EGLContext context_ = eglCreateContext(display_, config_, NULL, context_attribs);
// 选择EGLContext
if (eglMakeCurrent(display_, surface_, surface_, context_) == EGL_FALSE) {
LOGW("Unable to eglMakeCurrent");
return false;
//至此OpenGL渲染环境就初始化完毕,可以使用OpenGL命令来渲染了
glClear(0, 0, 0, 1);
// 渲染内容上屏
glSwapBuffers(display_, surface_);
复制代码
参考
source.android.com/devices/gra…
www.khronos.org/egl
www.khronos.org/files/egl-1…
www.khronos.org/registry/EG…
www.khronos.org/registry/EG…