Fluxo de uma Aplicação Gráfica com X11, EGL e OpenGL ES

Para construir uma aplicação gráfica mínima no Linux usando X11, EGL e OpenGL ES, é necessário criar uma janela nativa, configurar uma superfície EGL e inicializar um contexto de renderização. O fluxo pode ser dividido em duas etapas principais: inicialização do X11 e setup do EGL.

  1. Inicialização do X11

A primeiar tarefa é abrir uma conexão com o servidor X, obter a janela raiz e criar a janela da aplicação. O conjunto de eventos deve ser escolhido de acordo com a interação desejada.

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

#define LARGURA  800
#define ALTURA   600

Display *dpy = XOpenDisplay(NULL);
if (!dpy) {
    fprintf(stderr, "Não foi possível abrir o display X11\n");
    return -1;
}

Window root = DefaultRootWindow(dpy);

XSetWindowAttributes swa;
swa.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask;

Window win = XCreateWindow(
    dpy, root,
    0, 0, LARGURA, ALTURA, 0,
    CopyFromParent, InputOutput, CopyFromParent,
    CWEventMask, &swa);

Após criar a janela, é importante registrar o protocolo de fechamento WM_DELETE_WINDOW, mapear a janela na tela e definir um título.

Atom wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
XSetWMProtocols(dpy, win, &wm_delete, 1);

XMapWindow(dpy, win);
XStoreName(dpy, win, "Exemplo X11 + EGL + GLES");

  1. Configuração do EGL

O EGL atua como ponte entre o sistema de janelas X11 e a API de renderização OpenGL ES. Primeiro obtém-se uma referência ao display EGL a partir do display X11, depois inicializa-se a biblioteca e escolhe-se uma configuração compatível.

#include <EGL/egl.h>

EGLDisplay egl_dpy = eglGetDisplay(dpy);
if (egl_dpy == EGL_NO_DISPLAY) {
    fprintf(stderr, "Display EGL inválido\n");
    return -1;
}

EGLint major, minor;
if (!eglInitialize(egl_dpy, &major, &minor)) {
    fprintf(stderr, "Falha ao inicializar EGL\n");
    return -1;
}

EGLint attribs[] = {
    EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
    EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES3_BIT,
    EGL_RED_SIZE,           8,
    EGL_GREEN_SIZE,         8,
    EGL_BLUE_SIZE,          8,
    EGL_ALPHA_SIZE,         8,
    EGL_DEPTH_SIZE,         24,
    EGL_STENCIL_SIZE,       8,
    EGL_NONE
};

EGLConfig cfg;
EGLint num_configs;
if (!eglChooseConfig(egl_dpy, attribs, &cfg, 1, &num_configs) || num_configs < 1) {
    fprintf(stderr, "Nenhuma configuração EGL disponível\n");
    return -1;
}

Com a configuração escolhida, cria-se a superfície de janela, o contexto e ativa-se o contexto para a thread atual.

EGLSurface surf = eglCreateWindowSurface(egl_dpy, cfg, win, NULL);
if (surf == EGL_NO_SURFACE) {
    fprintf(stderr, "Falha ao criar a superfície EGL\n");
    return -1;
}

EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
EGLContext ctx = eglCreateContext(egl_dpy, cfg, EGL_NO_CONTEXT, ctx_attribs);
if (ctx == EGL_NO_CONTEXT) {
    fprintf(stderr, "Falha ao criar o contexto EGL\n");
    return -1;
}

eglMakeCurrent(egl_dpy, surf, surf, ctx);

  1. Loop de Eventos e Renderização

Uma vez configurado o contexto, o programa entra em um loop que processa eventos do X11, atualiza a cena e apresenta o resultado na tela.

#include <GLES3/gl3.h>

int executando = 1;
XEvent ev;

while (executando) {
    while (XPending(dpy) > 0) {
        XNextEvent(dpy, &ev);

        if (ev.type == ClientMessage &&
            (Atom)ev.xclient.data.l[0] == wm_delete) {
            executando = 0;
        }
    }

    glClearColor(0.1f, 0.15f, 0.25f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    eglSwapBuffers(egl_dpy, surf);
}

  1. Liberação de Recursos

Antes de encerrar, o contexto e as superfícies devem ser desvinculados e destruídos, seguidos do fechamento da conexão com o X.

eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(egl_dpy, ctx);
eglDestroySurface(egl_dpy, surf);
eglTerminate(egl_dpy);

XDestroyWindow(dpy, win);
XCloseDisplay(dpy);

  1. Compilação

Para compilar o exemplo em um sistema Linux com o Mesa e X11, utilize um comando semelhante a:

gcc main.c -o app -lX11 -lEGL -lGLESv2

Tags: X11 EGL OpenGL-ES Xlib Mesa

Publicado em 6-28 04:37