如何创建用于EGL的本机X11窗口

z0qdvdin  于 2022-10-18  发布在  其他
关注(0)|答案(1)|浏览(260)

如何创建在EGL中工作的本机X11窗口?在eglIntro中,几乎没有关于这个问题的文档。或者,有没有办法通过EGL本身来创建本机窗口?我假设有一个EGLNativeWindowType可以用来代替X11的本机窗口类型。

niknxzdl

niknxzdl1#

不,EGL本身不提供Xlib Package 器。您必须自己创建窗口。
这里有一个最小的示例,可以让您开始使用。它引用GLES2,但它也应该与GLES1一起工作。
首先,声明Xlib对象(Display和Window)。


# 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,      8,
        EGL_BLUE_SIZE,       8,
        // 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_conf, EGL_NO_CONTEXT, ctxattr );
    if ( egl_context == EGL_NO_CONTEXT ) {
        printf("CreateContext, EGL eglError: %d\n", 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", XLookupKeysym (&xev.xkey, 0));
            break;
        case ButtonPress:
            // printf("BPress: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y);
            // printf("Type=%d\n", (int)xev.xbutton.type);
            break;
        case ButtonRelease:
            // printf("BRelease: state = %d, button = %d, x = %d, y = %d\n", xev.xbutton.state, xev.xbutton.button, xev.xbutton.x, xev.xbutton.y);
            // printf("Type=%d\n", (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, 0, 0, 640, 480,   0,
        CopyFromParent, InputOutput, CopyFromParent, CWEventMask,
       &swa );

    XMapWindow ( xdisplay , win );         // make window visible
    XStoreName ( xdisplay , win , "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_surface, egl_context );

       /* Call OpenGL as you see fit */

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

   // deinitialize
}

这应该是你开始的第一步。代码是从一个较大的项目中提取的,因此在删除不相关的内容时可能会出现打字错误。
为了总结答案,更准确地说,这里EGLNativeWindowType专门用于X11/Xlib.h报头中的WindowEGLNativeDisplayTypeDisplay*
一种更简单的方法可能是使用libxcb,但我没有任何经过测试的样例代码。GLFW library可以作为依赖于操作系统的OpenGL上下文创建例程的有用来源。

相关问题