EGL介绍
EGL是Khronos Group定义的一组API,用来管理drawing surfaces。它提供了下面的功能:
- 和native windows system建立联系
- 查询可用来做drawing surface的类型和配置
- 创建drawing surface
- 同步opengl es的渲染和其他graphics-render相关的渲染
- 管理渲染的资源,如texture maps
和Native windows system建立联系
EGL在OpenGL ES和native windows system(如X Window Sysmte, Microsoft Windows或者Mac OSXs Quartz)提供一个胶水层。EGL通过EGLDisplay来封装和Native Window相关的依赖。如果要使用EGL,需要先创建和初始化一个本地的EGLDisplay.
EGLint majorVersion;
EGLint minorVersion;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY)
{
// Unable to open connection to local windowing system
}
if (!eglInitialize(display, &majorVersion, &minorVersion))
{
// Unable to initialize EGL; handle and recover
}
决定可用的Surface Configurations
初始化EGL之后,就可以来决定可以用哪些类型和配置的rendering surface来做渲染。有两种办法来做:
- 查询每种surface的配置然后自己来找一个最佳的选择。可使用
eglGetConfigs
函数 - 指定一组要求,让EGL来做一个推荐。可使用
eglChooseConfig
函数
无论哪种情况,EGL都会返回一个EGLConfig,指定EGL内部的数据结构。你可以通过eglGetConfigAttrib
查询下EGLConfig的属性.
const EGLint MaxConfigs = 10;
EGLConfig configs[MaxConfigs]; // We'll accept only 10 configs
EGLint numConfigs;
if (!eglChooseConfig(display, attribList, configs, MaxConfigs, &numConfigs))
{
// Something did not work ... handle error situation
}
else
{
// Everything is okay; continue to create a rendering surface
}
创建一个显示区域: EGL Window
一旦有一个合适的EGLConfig,下一步就要通过eglCreateWindowSurface
创建下window。
EGLint attribList[] =
{
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
EGL_NONE
);
EGLSurface window = eglCreateWindowSurface(display, config, nativeWindow, attribList);
if (window == EGL_NO_SURFACE)
{
switch (eglGetError())
{
case EGL_BAD_MATCH:
// Check window and EGLConfig attributes to determine
// compatibility, or verify that the EGLConfig
// supports rendering to a window
break;
case EGL_BAD_CONFIG:
// Verify that provided EGLConfig is valid
break;
case EGL_BAD_NATIVE_WINDOW:
// Verify that provided EGLNativeWindow is valid
break;
case EGL_BAD_ALLOC:
// Not enough resources available; handle and recover
break;
}
}
创建一个离屏显示区域: EGL Pbuffers
除了在一个显式的窗口做渲染外,还可以渲染到一个off-screen surface,成为pixel buffer,简称pbuffers. Pbuffers 通常用来生成texture map. 如果你只是想渲染到一个texture,推荐使用framebuffer objects. 但是pbuffer在其他地方还有用,譬如说用OpenGLES 渲染到一个离屏surface,然后再使用OpenVG的api去使用这个texture. 创建离屏Buffer需要使用eglCreatePbufferSurface
函数,具体如下:
EGLint attribList[] = {EGL_SURFACE_TYPE,
EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES3_BIT_KHR,
EGL_RED_SIZE,
5,
EGL_GREEN_SIZE,
6,
EGL_BLUE_SIZE,
5,
EGL_DEPTH_SIZE,
1,
EGL_NONE};
const EGLint MaxConfigs = 10;
EGLConfig configs[MaxConfigs]; // We'll accept only 10 configs
EGLint numConfigs;
if (!eglChooseConfig(display, attribList, configs, MaxConfigs, &numConfigs))
{
// Something did not work ... handle error situation
}
else
{
// We have found a pbuffer-capable EGLConfig
}
// Proceed to create a 512 x 512 pbuffer
// (or the largest available)
EGLSurface pbuffer;
EGLint attribList[] =
{
EGL_WIDTH, 512,
EGL_HEIGHT, 512,
EGL_LARGEST_PBUFFER, EGL_TRUE,
EGL_NONE
);
pbuffer = eglCreatePbufferSurface(display, config, attribList);
if (pbuffer == EGL_NO_SURFACE)
{
switch (eglGetError())
{
case EGL_BAD_ALLOC:
// Not enough resources available; handle and recover
break;
case EGL_BAD_CONFIG:
// Verify that provided EGLConfig is valid
break;
case EGL_BAD_PARAMETER:
// Verify that EGL_WIDTH and EGL_HEIGHT are
// non-negative values
break;
case EGL_BAD_MATCH:
// Check window and EGLConfig attributes to determine
// compatibility and pbuffer-texture parameters
break;
}
}
// Check the size of pbuffer that was allocated
EGLint width;
EGLint height;
if (!eglQuerySurface(display, pbuffer, EGL_WIDTH, &width) ||
!eglQuerySurface(display, pbuffer, EGL_HEIGHT, &height))
{
// Unable to query surface information
}
创建一个rendering context
一个rendering context是一个数据结构,包含了所有的状态信息。调用eglCreateContext来创建,需要display connection和EGLConfig信息。
const EGLint attribList[] = {
// EGL_KHR_create_context is required
EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, attribList);
if (context == EGL_NO_CONTEXT)
{
EGLError error = eglGetError();
if (error == EGL_BAD_CONFIG)
{
// Handle error and recover
}
}
启用EGLContext
一个应用可能会创建多个EGLContext,需要绑定一个特定的EGLContext到rendering surface,通常称为"make current"。要绑定一个EGLContext和EGLSurface,使用eglMakeCurrent
:
完整的一套流程如下:
EGLBoolean initializeWindow(EGLNativeWindow nativeWindow)
{
const EGLint configAttribs[] = {EGL_RENDER_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_NONE};
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY) if (display == EGL_NO_DISPLAY)
{
return EGL_FALSE;
}
EGLint major, minor;
if (!eglInitialize(display, &major, &minor))
{
return EGL_FALSE;
}
EGLConfig config;
EGLint numConfigs;
if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfigs))
{
return EGL_FALSE;
}
EGLSurface window = eglCreateWindowSurface(display, config, nativeWindow, NULL);
if (window == EGL_NO_SURFACE)
{
return EGL_FALSE;
}
EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT)
{
return EGL_FALSE;
}
if (!eglMakeCurrent(display, window, window, context))
{
return EGL_FALSE;
}
return EGL_TRUE;
}
渲染同步
你可能会遇到一种情况,需要协调不同的渲染API渲染到同一个window. 譬如说,使用OpenVG或者native windowing system 字体渲染函数来渲染字体到一个window。这种情况下,需要允许不同的库渲染到共同的窗口。EGL有一些函数来帮你同步任务。
在opengl es中确保所有render已完成,需要使用glFinish. 但是如果使用OpenVG等来渲染,则需要调用eglWaitClient
或者eglWaitNative
来创建。
网友评论