| /* |
| * Create several OpenGL rendering contexts, sharing textures, display |
| * lists, etc. Exercise binding, deleting, etc. |
| * |
| * Brian Paul |
| * 21 December 2004 |
| */ |
| |
| |
| #include <GL/gl.h> |
| #include <GL/glx.h> |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <X11/keysym.h> |
| |
| |
| /* |
| * Each display/window/context: |
| */ |
| struct context { |
| char DisplayName[1000]; |
| Display *Dpy; |
| Window Win; |
| GLXContext Context; |
| }; |
| |
| |
| #define MAX_CONTEXTS 200 |
| static struct context Contexts[MAX_CONTEXTS]; |
| static int NumContexts = 0; |
| |
| |
| static void |
| Error(const char *display, const char *msg) |
| { |
| fprintf(stderr, "Error on display %s - %s\n", display, msg); |
| exit(1); |
| } |
| |
| |
| static struct context * |
| CreateContext(const char *displayName, const char *name) |
| { |
| Display *dpy; |
| Window win; |
| GLXContext ctx; |
| int attrib[] = { GLX_RGBA, |
| GLX_RED_SIZE, 1, |
| GLX_GREEN_SIZE, 1, |
| GLX_BLUE_SIZE, 1, |
| GLX_DOUBLEBUFFER, |
| None }; |
| int scrnum; |
| XSetWindowAttributes attr; |
| unsigned long mask; |
| Window root; |
| XVisualInfo *visinfo; |
| int width = 90, height = 90; |
| int xpos = 0, ypos = 0; |
| |
| if (NumContexts >= MAX_CONTEXTS) |
| return NULL; |
| |
| dpy = XOpenDisplay(displayName); |
| if (!dpy) { |
| Error(displayName, "Unable to open display"); |
| return NULL; |
| } |
| |
| scrnum = DefaultScreen(dpy); |
| root = RootWindow(dpy, scrnum); |
| |
| visinfo = glXChooseVisual(dpy, scrnum, attrib); |
| if (!visinfo) { |
| Error(displayName, "Unable to find RGB, double-buffered visual"); |
| return NULL; |
| } |
| |
| /* window attributes */ |
| xpos = (NumContexts % 10) * 100; |
| ypos = (NumContexts / 10) * 100; |
| attr.background_pixel = 0; |
| attr.border_pixel = 0; |
| attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); |
| attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; |
| mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; |
| |
| win = XCreateWindow(dpy, root, xpos, ypos, width, height, |
| 0, visinfo->depth, InputOutput, |
| visinfo->visual, mask, &attr); |
| if (!win) { |
| Error(displayName, "Couldn't create window"); |
| return NULL; |
| } |
| |
| { |
| XSizeHints sizehints; |
| sizehints.x = xpos; |
| sizehints.y = ypos; |
| sizehints.width = width; |
| sizehints.height = height; |
| sizehints.flags = USSize | USPosition; |
| XSetNormalHints(dpy, win, &sizehints); |
| XSetStandardProperties(dpy, win, name, name, |
| None, (char **)NULL, 0, &sizehints); |
| } |
| |
| if (NumContexts == 0) { |
| ctx = glXCreateContext(dpy, visinfo, NULL, True); |
| } |
| else { |
| /* share textures & dlists with 0th context */ |
| ctx = glXCreateContext(dpy, visinfo, Contexts[0].Context, True); |
| } |
| if (!ctx) { |
| Error(displayName, "Couldn't create GLX context"); |
| return NULL; |
| } |
| |
| XMapWindow(dpy, win); |
| |
| if (!glXMakeCurrent(dpy, win, ctx)) { |
| Error(displayName, "glXMakeCurrent failed"); |
| return NULL; |
| } |
| |
| if (NumContexts == 0) { |
| printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); |
| } |
| |
| /* save the info for this context */ |
| { |
| struct context *h = &Contexts[NumContexts]; |
| strcpy(h->DisplayName, name); |
| h->Dpy = dpy; |
| h->Win = win; |
| h->Context = ctx; |
| NumContexts++; |
| return &Contexts[NumContexts-1]; |
| } |
| } |
| |
| |
| static void |
| MakeCurrent(int i) |
| { |
| if (!glXMakeCurrent(Contexts[i].Dpy, Contexts[i].Win, Contexts[i].Context)) { |
| fprintf(stderr, "glXMakeCurrent failed!\n"); |
| } |
| } |
| |
| |
| |
| static void |
| DestroyContext(int i) |
| { |
| XDestroyWindow(Contexts[i].Dpy, Contexts[i].Win); |
| glXDestroyContext(Contexts[i].Dpy, Contexts[i].Context); |
| XCloseDisplay(Contexts[i].Dpy); |
| } |
| |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| char *dpyName = NULL; |
| int i; |
| GLuint t; |
| GLint tb; |
| |
| for (i = 0; i < 2; i++) { |
| CreateContext(dpyName, "context"); |
| } |
| |
| /* Create texture and bind it in context 0 */ |
| MakeCurrent(0); |
| glGenTextures(1, &t); |
| printf("Generated texture ID %u\n", t); |
| assert(!glIsTexture(t)); |
| glBindTexture(GL_TEXTURE_2D, t); |
| assert(glIsTexture(t)); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb); |
| assert(tb == t); |
| |
| /* Bind texture in context 1 */ |
| MakeCurrent(1); |
| assert(glIsTexture(t)); |
| glBindTexture(GL_TEXTURE_2D, t); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb); |
| assert(tb == t); |
| |
| /* Delete texture from context 0 */ |
| MakeCurrent(0); |
| glDeleteTextures(1, &t); |
| assert(!glIsTexture(t)); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb); |
| printf("After delete, binding = %d\n", tb); |
| |
| /* Check texture state from context 1 */ |
| MakeCurrent(1); |
| assert(!glIsTexture(t)); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb); |
| printf("In second context, binding = %d\n", tb); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb); |
| assert(tb == 0); |
| |
| |
| for (i = 0; i < NumContexts; i++) { |
| DestroyContext(i); |
| } |
| |
| printf("Success!\n"); |
| |
| return 0; |
| } |