#include #include #include #include int main (int argc, char ** argv) { pid_t pid = fork(); // Sleep so that the child can create all GLX resources if (pid != 0) sleep(2); Display *dpy = XOpenDisplay(NULL); int nelements; GLXFBConfig *fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), 0, &nelements); static int attributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None }; XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList); XSetWindowAttributes swa; swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); swa.border_pixel = 0; swa.event_mask = StructureNotifyMask; // It is crucial that the context is created before the window GLXContext ctx = glXCreateContext(dpy, vi, 0, GL_FALSE); Window win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, 100, 100, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); XMapWindow (dpy, win); glXMakeCurrent(dpy, win, ctx); if (pid == 0) { // The child needs to wait for the parent to take over // the current context in the X server sleep(3); } else { // Wait for the child to terminate, which will trigger the // cleanup routines in the X server. int status; wait(&status); // This call will crash the X server as it believes that // this parent process is holding the active context, but // the cleanup from the child cleared the dispatch table. glGetString(GL_VENDOR); } glXDestroyContext(dpy, ctx); }