132001f49Smrg/*
232001f49Smrg * Create several OpenGL rendering contexts, sharing textures, display
332001f49Smrg * lists, etc.  Exercise binding, deleting, etc.
432001f49Smrg *
532001f49Smrg * Brian Paul
632001f49Smrg * 21 December 2004
732001f49Smrg */
832001f49Smrg
932001f49Smrg
1032001f49Smrg#include <GL/gl.h>
1132001f49Smrg#include <GL/glx.h>
1232001f49Smrg#include <assert.h>
1332001f49Smrg#include <stdio.h>
1432001f49Smrg#include <stdlib.h>
1532001f49Smrg#include <string.h>
1632001f49Smrg#include <unistd.h>
1732001f49Smrg#include <X11/keysym.h>
1832001f49Smrg
1932001f49Smrg
2032001f49Smrg/*
2132001f49Smrg * Each display/window/context:
2232001f49Smrg */
2332001f49Smrgstruct context {
2432001f49Smrg   char DisplayName[1000];
2532001f49Smrg   Display *Dpy;
2632001f49Smrg   Window Win;
2732001f49Smrg   GLXContext Context;
2832001f49Smrg};
2932001f49Smrg
3032001f49Smrg
3132001f49Smrg#define MAX_CONTEXTS 200
3232001f49Smrgstatic struct context Contexts[MAX_CONTEXTS];
3332001f49Smrgstatic int NumContexts = 0;
3432001f49Smrg
3532001f49Smrg
3632001f49Smrgstatic void
3732001f49SmrgError(const char *display, const char *msg)
3832001f49Smrg{
3932001f49Smrg   fprintf(stderr, "Error on display %s - %s\n", display, msg);
4032001f49Smrg   exit(1);
4132001f49Smrg}
4232001f49Smrg
4332001f49Smrg
4432001f49Smrgstatic struct context *
4532001f49SmrgCreateContext(const char *displayName, const char *name)
4632001f49Smrg{
4732001f49Smrg   Display *dpy;
4832001f49Smrg   Window win;
4932001f49Smrg   GLXContext ctx;
5032001f49Smrg   int attrib[] = { GLX_RGBA,
5132001f49Smrg		    GLX_RED_SIZE, 1,
5232001f49Smrg		    GLX_GREEN_SIZE, 1,
5332001f49Smrg		    GLX_BLUE_SIZE, 1,
5432001f49Smrg		    GLX_DOUBLEBUFFER,
5532001f49Smrg		    None };
5632001f49Smrg   int scrnum;
5732001f49Smrg   XSetWindowAttributes attr;
5832001f49Smrg   unsigned long mask;
5932001f49Smrg   Window root;
6032001f49Smrg   XVisualInfo *visinfo;
6132001f49Smrg   int width = 90, height = 90;
6232001f49Smrg   int xpos = 0, ypos = 0;
6332001f49Smrg
6432001f49Smrg   if (NumContexts >= MAX_CONTEXTS)
6532001f49Smrg      return NULL;
6632001f49Smrg
6732001f49Smrg   dpy = XOpenDisplay(displayName);
6832001f49Smrg   if (!dpy) {
6932001f49Smrg      Error(displayName, "Unable to open display");
7032001f49Smrg      return NULL;
7132001f49Smrg   }
7232001f49Smrg
7332001f49Smrg   scrnum = DefaultScreen(dpy);
7432001f49Smrg   root = RootWindow(dpy, scrnum);
7532001f49Smrg
7632001f49Smrg   visinfo = glXChooseVisual(dpy, scrnum, attrib);
7732001f49Smrg   if (!visinfo) {
7832001f49Smrg      Error(displayName, "Unable to find RGB, double-buffered visual");
7932001f49Smrg      return NULL;
8032001f49Smrg   }
8132001f49Smrg
8232001f49Smrg   /* window attributes */
8332001f49Smrg   xpos = (NumContexts % 10) * 100;
8432001f49Smrg   ypos = (NumContexts / 10) * 100;
8532001f49Smrg   attr.background_pixel = 0;
8632001f49Smrg   attr.border_pixel = 0;
8732001f49Smrg   attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
8832001f49Smrg   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
8932001f49Smrg   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
9032001f49Smrg
9132001f49Smrg   win = XCreateWindow(dpy, root, xpos, ypos, width, height,
9232001f49Smrg		        0, visinfo->depth, InputOutput,
9332001f49Smrg		        visinfo->visual, mask, &attr);
9432001f49Smrg   if (!win) {
9532001f49Smrg      Error(displayName, "Couldn't create window");
9632001f49Smrg      return NULL;
9732001f49Smrg   }
9832001f49Smrg
9932001f49Smrg   {
10032001f49Smrg      XSizeHints sizehints;
10132001f49Smrg      sizehints.x = xpos;
10232001f49Smrg      sizehints.y = ypos;
10332001f49Smrg      sizehints.width  = width;
10432001f49Smrg      sizehints.height = height;
10532001f49Smrg      sizehints.flags = USSize | USPosition;
10632001f49Smrg      XSetNormalHints(dpy, win, &sizehints);
10732001f49Smrg      XSetStandardProperties(dpy, win, name, name,
10832001f49Smrg                              None, (char **)NULL, 0, &sizehints);
10932001f49Smrg   }
11032001f49Smrg
11132001f49Smrg   if (NumContexts == 0) {
11232001f49Smrg      ctx = glXCreateContext(dpy, visinfo, NULL, True);
11332001f49Smrg   }
11432001f49Smrg   else {
11532001f49Smrg      /* share textures & dlists with 0th context */
11632001f49Smrg      ctx = glXCreateContext(dpy, visinfo, Contexts[0].Context, True);
11732001f49Smrg   }
11832001f49Smrg   if (!ctx) {
11932001f49Smrg      Error(displayName, "Couldn't create GLX context");
12032001f49Smrg      return NULL;
12132001f49Smrg   }
12232001f49Smrg
12332001f49Smrg   XMapWindow(dpy, win);
12432001f49Smrg
12532001f49Smrg   if (!glXMakeCurrent(dpy, win, ctx)) {
12632001f49Smrg      Error(displayName, "glXMakeCurrent failed");
12732001f49Smrg      return NULL;
12832001f49Smrg   }
12932001f49Smrg
13032001f49Smrg   if (NumContexts == 0) {
13132001f49Smrg      printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
13232001f49Smrg   }
13332001f49Smrg
13432001f49Smrg   /* save the info for this context */
13532001f49Smrg   {
13632001f49Smrg      struct context *h = &Contexts[NumContexts];
13732001f49Smrg      strcpy(h->DisplayName, name);
13832001f49Smrg      h->Dpy = dpy;
13932001f49Smrg      h->Win = win;
14032001f49Smrg      h->Context = ctx;
14132001f49Smrg      NumContexts++;
14232001f49Smrg      return &Contexts[NumContexts-1];
14332001f49Smrg   }
14432001f49Smrg}
14532001f49Smrg
14632001f49Smrg
14732001f49Smrgstatic void
14832001f49SmrgMakeCurrent(int i)
14932001f49Smrg{
15032001f49Smrg   if (!glXMakeCurrent(Contexts[i].Dpy, Contexts[i].Win, Contexts[i].Context)) {
15132001f49Smrg      fprintf(stderr, "glXMakeCurrent failed!\n");
15232001f49Smrg   }
15332001f49Smrg}
15432001f49Smrg
15532001f49Smrg
15632001f49Smrg
15732001f49Smrgstatic void
15832001f49SmrgDestroyContext(int i)
15932001f49Smrg{
16032001f49Smrg   XDestroyWindow(Contexts[i].Dpy, Contexts[i].Win);
16132001f49Smrg   glXDestroyContext(Contexts[i].Dpy, Contexts[i].Context);
16232001f49Smrg   XCloseDisplay(Contexts[i].Dpy);
16332001f49Smrg}
16432001f49Smrg
16532001f49Smrg
16632001f49Smrgint
16732001f49Smrgmain(int argc, char *argv[])
16832001f49Smrg{
16932001f49Smrg   char *dpyName = NULL;
17032001f49Smrg   int i;
17132001f49Smrg   GLuint t;
17232001f49Smrg   GLint tb;
17332001f49Smrg
17432001f49Smrg   for (i = 0; i < 2; i++) {
17532001f49Smrg      CreateContext(dpyName, "context");
17632001f49Smrg   }
17732001f49Smrg
17832001f49Smrg   /* Create texture and bind it in context 0 */
17932001f49Smrg   MakeCurrent(0);
18032001f49Smrg   glGenTextures(1, &t);
18132001f49Smrg   printf("Generated texture ID %u\n", t);
18232001f49Smrg   assert(!glIsTexture(t));
18332001f49Smrg   glBindTexture(GL_TEXTURE_2D, t);
18432001f49Smrg   assert(glIsTexture(t));
18532001f49Smrg   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
18632001f49Smrg   assert(tb == t);
18732001f49Smrg
18832001f49Smrg   /* Bind texture in context 1 */
18932001f49Smrg   MakeCurrent(1);
19032001f49Smrg   assert(glIsTexture(t));
19132001f49Smrg   glBindTexture(GL_TEXTURE_2D, t);
19232001f49Smrg   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
19332001f49Smrg   assert(tb == t);
19432001f49Smrg
19532001f49Smrg   /* Delete texture from context 0 */
19632001f49Smrg   MakeCurrent(0);
19732001f49Smrg   glDeleteTextures(1, &t);
19832001f49Smrg   assert(!glIsTexture(t));
19932001f49Smrg   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
20032001f49Smrg   printf("After delete, binding = %d\n", tb);
20132001f49Smrg
20232001f49Smrg   /* Check texture state from context 1 */
20332001f49Smrg   MakeCurrent(1);
20432001f49Smrg   assert(!glIsTexture(t));
20532001f49Smrg   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
20632001f49Smrg   printf("In second context, binding = %d\n", tb);
20732001f49Smrg   glBindTexture(GL_TEXTURE_2D, 0);
20832001f49Smrg   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
20932001f49Smrg   assert(tb == 0);
21032001f49Smrg
21132001f49Smrg
21232001f49Smrg   for (i = 0; i < NumContexts; i++) {
21332001f49Smrg      DestroyContext(i);
21432001f49Smrg   }
21532001f49Smrg
21632001f49Smrg   printf("Success!\n");
21732001f49Smrg
21832001f49Smrg   return 0;
21932001f49Smrg}
220