Reputation: 33
How does one create a native X11 window that works in EGL? Going through the eglIntro
there is little documentation on the matter. Alternatively, is there a way to create native windows through EGL itself? There is an EGLNativeWindowType
that I assume can be used instead of whatever X11's native window types are.
Upvotes: 2
Views: 5404
Reputation: 14467
No, EGL itself does not provide an Xlib wrapper. You have to create the window by yourself.
Here is a minimal sample to get you started. It refers to GLES2, but it should work with GLES1 also.
First, you declare the Xlib objects(display and 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;
}
From the main
function you will call the X event handler procedure. I have left commented printf
calls to show how the event values are named, so there's no need to lookup the documentation. If the concept of "Event loop" is not clear, then I recommend reading about general UI event processing.
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;
}
}
Finally, in the main() routine you create and open 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;
}
The window is created and shown once you have the Display opened.
Finally, in the main() routine you create and open 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" );
When you have the window, intialise the EGL.
egl_error = init_egl();
if (!egl_error) {
return 1;
}
Once you have the EGL & Xlib objects, you can start the event processing loop.
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
}
This should get you started. The code is extracted from a larger project, so there might have be typos introduced while removing irrelevant things.
To conclude the answer and to be more precise, here EGLNativeWindowType
is specialized to Window
from X11/Xlib.h
header and EGLNativeDisplayType
is Display*
.
An easier way might be to use libxcb
, but I do not have any tested sample code. The GLFW library can be a useful source of OS-dependant OpenGL context creation routines.
Upvotes: 3