EGL介绍

2021-05-31  本文已影响0人  videoisfun

EGL介绍

EGL是Khronos Group定义的一组API,用来管理drawing surfaces。它提供了下面的功能:

  1. 和native windows system建立联系
  2. 查询可用来做drawing surface的类型和配置
  3. 创建drawing surface
  4. 同步opengl es的渲染和其他graphics-render相关的渲染
  5. 管理渲染的资源,如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来做渲染。有两种办法来做:

  1. 查询每种surface的配置然后自己来找一个最佳的选择。可使用eglGetConfigs函数
  2. 指定一组要求,让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来创建。

上一篇 下一篇

猜你喜欢

热点阅读