1/*
2 * Create several OpenGL rendering contexts, sharing textures, display
3 * lists, etc.  Exercise binding, deleting, etc.
4 *
5 * Brian Paul
6 * 21 December 2004
7 */
8
9
10#include <GL/gl.h>
11#include <GL/glx.h>
12#include <assert.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <X11/keysym.h>
18
19
20/*
21 * Each display/window/context:
22 */
23struct context {
24   char DisplayName[1000];
25   Display *Dpy;
26   Window Win;
27   GLXContext Context;
28};
29
30
31#define MAX_CONTEXTS 200
32static struct context Contexts[MAX_CONTEXTS];
33static int NumContexts = 0;
34
35
36static void
37Error(const char *display, const char *msg)
38{
39   fprintf(stderr, "Error on display %s - %s\n", display, msg);
40   exit(1);
41}
42
43
44static struct context *
45CreateContext(const char *displayName, const char *name)
46{
47   Display *dpy;
48   Window win;
49   GLXContext ctx;
50   int attrib[] = { GLX_RGBA,
51		    GLX_RED_SIZE, 1,
52		    GLX_GREEN_SIZE, 1,
53		    GLX_BLUE_SIZE, 1,
54		    GLX_DOUBLEBUFFER,
55		    None };
56   int scrnum;
57   XSetWindowAttributes attr;
58   unsigned long mask;
59   Window root;
60   XVisualInfo *visinfo;
61   int width = 90, height = 90;
62   int xpos = 0, ypos = 0;
63
64   if (NumContexts >= MAX_CONTEXTS)
65      return NULL;
66
67   dpy = XOpenDisplay(displayName);
68   if (!dpy) {
69      Error(displayName, "Unable to open display");
70      return NULL;
71   }
72
73   scrnum = DefaultScreen(dpy);
74   root = RootWindow(dpy, scrnum);
75
76   visinfo = glXChooseVisual(dpy, scrnum, attrib);
77   if (!visinfo) {
78      Error(displayName, "Unable to find RGB, double-buffered visual");
79      return NULL;
80   }
81
82   /* window attributes */
83   xpos = (NumContexts % 10) * 100;
84   ypos = (NumContexts / 10) * 100;
85   attr.background_pixel = 0;
86   attr.border_pixel = 0;
87   attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
88   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
89   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
90
91   win = XCreateWindow(dpy, root, xpos, ypos, width, height,
92		        0, visinfo->depth, InputOutput,
93		        visinfo->visual, mask, &attr);
94   if (!win) {
95      Error(displayName, "Couldn't create window");
96      return NULL;
97   }
98
99   {
100      XSizeHints sizehints;
101      sizehints.x = xpos;
102      sizehints.y = ypos;
103      sizehints.width  = width;
104      sizehints.height = height;
105      sizehints.flags = USSize | USPosition;
106      XSetNormalHints(dpy, win, &sizehints);
107      XSetStandardProperties(dpy, win, name, name,
108                              None, (char **)NULL, 0, &sizehints);
109   }
110
111   if (NumContexts == 0) {
112      ctx = glXCreateContext(dpy, visinfo, NULL, True);
113   }
114   else {
115      /* share textures & dlists with 0th context */
116      ctx = glXCreateContext(dpy, visinfo, Contexts[0].Context, True);
117   }
118   if (!ctx) {
119      Error(displayName, "Couldn't create GLX context");
120      return NULL;
121   }
122
123   XMapWindow(dpy, win);
124
125   if (!glXMakeCurrent(dpy, win, ctx)) {
126      Error(displayName, "glXMakeCurrent failed");
127      return NULL;
128   }
129
130   if (NumContexts == 0) {
131      printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
132   }
133
134   /* save the info for this context */
135   {
136      struct context *h = &Contexts[NumContexts];
137      strcpy(h->DisplayName, name);
138      h->Dpy = dpy;
139      h->Win = win;
140      h->Context = ctx;
141      NumContexts++;
142      return &Contexts[NumContexts-1];
143   }
144}
145
146
147static void
148MakeCurrent(int i)
149{
150   if (!glXMakeCurrent(Contexts[i].Dpy, Contexts[i].Win, Contexts[i].Context)) {
151      fprintf(stderr, "glXMakeCurrent failed!\n");
152   }
153}
154
155
156
157static void
158DestroyContext(int i)
159{
160   XDestroyWindow(Contexts[i].Dpy, Contexts[i].Win);
161   glXDestroyContext(Contexts[i].Dpy, Contexts[i].Context);
162   XCloseDisplay(Contexts[i].Dpy);
163}
164
165
166int
167main(int argc, char *argv[])
168{
169   char *dpyName = NULL;
170   int i;
171   GLuint t;
172   GLint tb;
173
174   for (i = 0; i < 2; i++) {
175      CreateContext(dpyName, "context");
176   }
177
178   /* Create texture and bind it in context 0 */
179   MakeCurrent(0);
180   glGenTextures(1, &t);
181   printf("Generated texture ID %u\n", t);
182   assert(!glIsTexture(t));
183   glBindTexture(GL_TEXTURE_2D, t);
184   assert(glIsTexture(t));
185   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
186   assert(tb == t);
187
188   /* Bind texture in context 1 */
189   MakeCurrent(1);
190   assert(glIsTexture(t));
191   glBindTexture(GL_TEXTURE_2D, t);
192   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
193   assert(tb == t);
194
195   /* Delete texture from context 0 */
196   MakeCurrent(0);
197   glDeleteTextures(1, &t);
198   assert(!glIsTexture(t));
199   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
200   printf("After delete, binding = %d\n", tb);
201
202   /* Check texture state from context 1 */
203   MakeCurrent(1);
204   assert(!glIsTexture(t));
205   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
206   printf("In second context, binding = %d\n", tb);
207   glBindTexture(GL_TEXTURE_2D, 0);
208   glGetIntegerv(GL_TEXTURE_BINDING_2D, &tb);
209   assert(tb == 0);
210
211
212   for (i = 0; i < NumContexts; i++) {
213      DestroyContext(i);
214   }
215
216   printf("Success!\n");
217
218   return 0;
219}
220