EGL-入门

EGL

通过Surface对象创建一个EGLSurface,将其连接到Surface的BufferQueue上,EGLSurface将会作为一个生产方,会将OpenGL-ES生产的缓冲区加入到该BufferQueue中,然后由该Surface的消费方进行处理。

Surface是一个生产方,EGLSurface也是一个独立的生产方。

一个Surface一次只能和一个EGLSurface进行连接,可以通过断开,然后重新连接另一个EGLSurface。

eglGetDisplay

1
2
3
4
5
6
// 获取当前设备中默认屏幕的handle,display对象可以认为就是一块物理的屏幕,如果没有对应的display,则返回EGL_NO_DISPLAY。

if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) {
LOGE("witgao", "eglGetDisplay");
return;
}

eglInitialize

1
2
3
4
5
6
7
// 针对获取的屏幕对egl进行初始化(display,返回的主版本号,返回的次版本号)
EGLint major, minor;
if (!eglInitialize(display, &major, &minor) || major == NULL || minor == NULL) {
LOGE("witgao", "eglInitialize");
return;
}

eglChooseConfig

surface类型有三种,window_surface、pbuffer_surface、pixmap_surface,只有window_surface和window有关联,可以在window上显示。

绘制模式有两种,back buffer、single buffer,window_surface使用的是back buffer,back buffer是一块GPU中的buffer,可以通过EGL显示在屏幕上;而single buffer 是保存在内存中的位图,不支持显示在屏幕上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const EGLint attribs[] = {
// 设置surface类型
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
// 指定opengl-es版本为2.0
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
EGLConfig config;
EGLint numConfigs;

// 获取设备中支持指定属性的配置集合(display,指定的属性,输出的配置,输出配置的个数,所有支持指定属性的配置的个数)
if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs)) {
LOGE("witgao", "eglChooseConfig");
return;
}

eglCreateWindowSurface

1
2
3
4
5
6
7
8
9
// 创建一个提供给opengl-es绘制的surface(display,配置,原生window,指定属性)
if (!(eglSurface = eglCreateWindowSurface(display, config, aNativeWindow, 0))) {
LOGE("witgao", "eglCreateWindowSurface");
return;
}

// android中创建NativeWindow
ANativeWindow *pNativeWindow = ANativeWindow_fromSurface(jenv, surface);

eglCreateContext

1
2
3
4
5
6
7
8
9
10
11
12
const EGLint context_attribs[] = {
// 设置context针对的opengl-es的版本,(EGL_NONE设置的是默认值,为1)
// 此处的版本需要和上面的EGL_RENDERABLE_TYPE 对应
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
};

// 创建context,在context中保存了opengl-es的状态信息 (display,配置,共享context的handle 一般设为null,属性)
// 一个display可以创建多个context
if (!(context = eglCreateContext(display, config, 0, context_attribs))) {
LOGE("witgao", "eglCreateContext");
return;
}

eglMakeCurrent

1
2
3
4
5
6
7
8
9
// 将上面创建的context绑定到当前线程上,并将context与surface进行关联。当makeCurrent执行后,就可以调用opengl-es的api对context中的状态集进行设定,
// 然后进而向surface中绘制内容,再把surface中的内容读取出来。
// 一个线程中enable状态的context只能有一个,如果当前线程已经有了一个enable状态的context,那么会先执行其flush操作,将没有执行完成的命令全部执行完成,然后将其改为disable状态,将新传入的context改为enable状态。
// 如果想要释放当前的context,也就是将当前的context disable,那么将第二个和第三个参数设置为 EGL_NO_SURFACE,第四个参数设置为 EGL_NO_CONTEXT即可。
// context enable后,视口大小和裁剪大小都会被设置为surface的尺寸
if (!eglMakeCurrent(display, eglSurface, eglSurface, context)) {
LOGE("witgao", "eglMakeCurrent");
return;
}

eglSwapBuffers

1
2
3
4
5
// 当opengl-es将内容绘制完成,调用该方法将该缓冲区加入到Surface的BufferQueue中
if (!eglSwapBuffers(display, eglSurface)) {
LOGE("witgao", "eglSwapBuffers");
return;
}