如何创建与EGL一起使用的本机X11窗口

问题描述

如何创建可在EGL中运行的本机X11窗口?遍历eglintro(https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglIntro.xhtml)时,有关此问题的文档很少。或者,是否可以通过EGL本身创建本机窗口?我假设可以使用EGLNativeWindowType来代替X11的本机窗口类型。

解决方法

否,EGL本身不提供Xlib包装器。您必须自己创建窗口。

以下是帮助您入门的最小样本。它指的是GLES2,但也应与GLES1一起使用。

首先,您声明Xlib对象(显示和窗口)。

#include <stdio.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

#include  <GLES2/gl2.h>
#include  <EGL/egl.h>

// Native handles for window and display
Window      win;
Display* xdisplay;

// EGL-related objects
EGLDisplay  egl_display;
EGLConfig   egl_conf;
EGLContext  egl_context;
EGLSurface  egl_surface;

int init_egl()
{
    EGLint attr[] = {
        EGL_SURFACE_TYPE,EGL_WINDOW_BIT,EGL_RED_SIZE,8,EGL_GREEN_SIZE,EGL_BLUE_SIZE,// EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,/* If one needs GLES2 */
        EGL_NONE
    };

    EGLint num_config;
    EGLint major,minor;

    EGLint ctxattr[] = {
       EGL_CONTEXT_CLIENT_VERSION,2,EGL_NONE
    };

    egl_display  =  eglGetDisplay( (EGLNativeDisplayType) xdisplay );
    if ( egl_display == EGL_NO_DISPLAY ) {
        printf("Error getting EGL display\n");
        return 0;
    }

    if ( !eglInitialize( egl_display,&major,&minor ) ) {
        printf("Error initializing EGL\n");
        return 0;
    }

    printf("EGL major: %d,minor %d\n",major,minor);

    /* create EGL rendering context */
    if ( !eglChooseConfig( shell->egl_display,attr,&shell->egl_conf,1,&num_config ) ) {
        printf("Failed to choose config (eglError: %x)\n",eglGetError());
        return 0;
    }

    if ( num_config != 1 ) {
        return 0;
    }

    egl_surface = eglCreateWindowSurface ( egl_display,egl_conf,win,NULL );
    if (egl_surface == EGL_NO_SURFACE ) {
        printf("CreateWindowSurface,EGL eglError: %d\n",eglGetError() );
        return 0;
    }

    egl_context = eglCreateContext ( egl_display,EGL_NO_CONTEXT,ctxattr );
    if ( egl_context == EGL_NO_CONTEXT ) {
        printf("CreateContext,eglGetError() );
        return 0;
    }

    return 1;
}

通过main函数,您将调用X事件处理程序过程。我已对printf调用进行了注释,以显示事件值的命名方式,因此无需查找文档。如果“事件循环”的概念不清楚,那么我建议阅读有关常规UI事件处理的文章。

void process_xevent(XEvent xev) {
    //    XNextEvent( xdisplay,&xev );
    switch (xev.type)
    {
        case MotionNotify:
            // printf("motion: %d %d\n",xev.xbutton.x,xev.xbutton.y);
            break;
        case KeyRelease:
            // printf("rel (%d)\n",XLookupKeysym (&xev.xkey,0));
            break;
        case KeyPress:
            // printf("keypress (%d)\n",0));
            break;
        case ButtonPress:
            // printf("BPress: state = %d,button = %d,x = %d,y = %d\n",xev.xbutton.state,xev.xbutton.button,xev.xbutton.y);
            // printf("Type=%d\n",(int)xev.xbutton.type);
            break;
        case ButtonRelease:
            // printf("BRelease: state = %d,(int)xev.xbutton.type);
            break;
    }
}

最后,在main()例程中创建并打开display / Xwindow。

int main()
{
    int egl_error;

    Window root;
    XSetWindowAttributes  swa;

    /* open standard display (primary screen) */
    xdisplay = XOpenDisplay ( NULL );   
    if ( xdisplay == NULL ) {
        printf("Error opening X display\n");
        return 0;
    }

打开显示器后,便会创建并显示该窗口。

最后,在main()例程中创建并打开display / Xwindow。

    // get the root window (usually the whole screen)
    root  =  DefaultRootWindow( shell->xdisplay );

    // list all events this window accepts
    swa.event_mask =
    StructureNotifyMask |
    ExposureMask        |
    PointerMotionMask   |
    KeyPressMask        |
    KeyReleaseMask      |
    ButtonPressMask     |
    ButtonReleaseMask;

    // Xlib's window creation
    win  =  XCreateWindow (
        xdisplay,root,640,480,CopyFromParent,InputOutput,CWEventMask,&swa );

    XMapWindow ( xdisplay,win );         // make window visible
    XStoreName ( xdisplay,"EGL" );

打开窗口后,初始化EGL。

    egl_error = init_egl();
    if (!egl_error) {
        return 1;
    }

一旦有了EGL和Xlib对象,就可以开始事件处理循环。

while (1) {
        int keycode;
        XEvent  xev;

        if ( XPending ( xdisplay ) )
            if (XCheckWindowEvent(shell->xdisplay,shell->win,global_event_mask,&xev))
                process_xevent(shell,xev);

       /* if (should_exit) { break; }   // set some global flag if you want to exit */

       eglMakeCurrent( egl_display,egl_surface,egl_context );

       /* Call OpenGL as you see fit */

       /* get rendered buffer to the screen */
       eglSwapBuffers ( egl_display,egl_surface );
   }


   // deinitialize
}

这应该使您入门。该代码是从一个较大的项目中提取的,因此在删除不相关的内容时可能会引入错别字。

为得出答案并更精确地说,这里EGLNativeWindowType专用于Window头中的X11/Xlib.h,而EGLNativeDisplayTypeDisplay*

一种更简单的方法可能是使用libxcb,但是我没有经过测试的示例代码。 GLFW library是依赖于操作系统的OpenGL上下文创建例程的有用来源。