mesa: added new linux-gallium and linux-gallium-debug configs
[mesa.git] / progs / xdemos / manywin.c
1 /*
2 * Create N GLX windows/contexts and render to them in round-robin order.
3 * Also, have the contexts share all texture objects.
4 * Press 'd' to delete a texture, 'u' to unbind it.
5 *
6 * Copyright (C) 2000 Brian Paul All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 #include <GL/gl.h>
28 #include <GL/glx.h>
29 #include <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <X11/keysym.h>
35
36
37 /*
38 * Each display/window/context:
39 */
40 struct head {
41 char DisplayName[1000];
42 Display *Dpy;
43 Window Win;
44 GLXContext Context;
45 float Angle;
46 char Renderer[1000];
47 char Vendor[1000];
48 char Version[1000];
49 };
50
51
52 #define MAX_HEADS 200
53 static struct head Heads[MAX_HEADS];
54 static int NumHeads = 0;
55 static GLboolean SwapSeparate = GL_TRUE;
56 static GLuint TexObj = 0;
57
58
59 static void
60 Error(const char *display, const char *msg)
61 {
62 fprintf(stderr, "Error on display %s - %s\n", XDisplayName(display), msg);
63 exit(1);
64 }
65
66
67 static struct head *
68 AddHead(const char *displayName, const char *name)
69 {
70 Display *dpy;
71 Window win;
72 GLXContext ctx;
73 int attrib[] = { GLX_RGBA,
74 GLX_RED_SIZE, 1,
75 GLX_GREEN_SIZE, 1,
76 GLX_BLUE_SIZE, 1,
77 GLX_DOUBLEBUFFER,
78 None };
79 int scrnum;
80 XSetWindowAttributes attr;
81 unsigned long mask;
82 Window root;
83 XVisualInfo *visinfo;
84 int width = 90, height = 90;
85 int xpos = 0, ypos = 0;
86
87 if (NumHeads >= MAX_HEADS)
88 return NULL;
89
90 dpy = XOpenDisplay(displayName);
91 if (!dpy) {
92 Error(displayName, "Unable to open display");
93 return NULL;
94 }
95
96 scrnum = DefaultScreen(dpy);
97 root = RootWindow(dpy, scrnum);
98
99 visinfo = glXChooseVisual(dpy, scrnum, attrib);
100 if (!visinfo) {
101 Error(displayName, "Unable to find RGB, double-buffered visual");
102 return NULL;
103 }
104
105 /* window attributes */
106 xpos = (NumHeads % 10) * 100;
107 ypos = (NumHeads / 10) * 100;
108 printf("%d, %d\n", xpos, ypos);
109 attr.background_pixel = 0;
110 attr.border_pixel = 0;
111 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
112 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
113 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
114
115 win = XCreateWindow(dpy, root, xpos, ypos, width, height,
116 0, visinfo->depth, InputOutput,
117 visinfo->visual, mask, &attr);
118 if (!win) {
119 Error(displayName, "Couldn't create window");
120 return NULL;
121 }
122
123 {
124 XSizeHints sizehints;
125 sizehints.x = xpos;
126 sizehints.y = ypos;
127 sizehints.width = width;
128 sizehints.height = height;
129 sizehints.flags = USSize | USPosition;
130 XSetNormalHints(dpy, win, &sizehints);
131 XSetStandardProperties(dpy, win, name, name,
132 None, (char **)NULL, 0, &sizehints);
133 }
134
135 if (NumHeads == 0) {
136 ctx = glXCreateContext(dpy, visinfo, NULL, True);
137 }
138 else {
139 /* share textures & dlists with 0th context */
140 printf("sharing\n");
141 ctx = glXCreateContext(dpy, visinfo, Heads[0].Context, True);
142 }
143 if (!ctx) {
144 Error(displayName, "Couldn't create GLX context");
145 return NULL;
146 }
147
148 XMapWindow(dpy, win);
149
150 if (!glXMakeCurrent(dpy, win, ctx)) {
151 Error(displayName, "glXMakeCurrent failed");
152 printf("glXMakeCurrent failed in Redraw()\n");
153 return NULL;
154 }
155
156 if (NumHeads == 0) {
157 /* create texture object now */
158 static const GLubyte checker[2][2][4] = {
159 { {255, 255, 255, 255}, { 0, 0, 0, 255} },
160 { { 0, 0, 0, 0}, {255, 255, 255, 255} }
161 };
162 glGenTextures(1, &TexObj);
163 assert(TexObj);
164 glBindTexture(GL_TEXTURE_2D, TexObj);
165 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGB,
166 GL_UNSIGNED_BYTE, checker);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
169 }
170 else {
171 /* bind 0th context's texture in this context too */
172 assert(TexObj);
173 glBindTexture(GL_TEXTURE_2D, TexObj);
174 }
175 glEnable(GL_TEXTURE_2D);
176
177 /* save the info for this head */
178 {
179 struct head *h = &Heads[NumHeads];
180 strcpy(h->DisplayName, name);
181 h->Dpy = dpy;
182 h->Win = win;
183 h->Context = ctx;
184 h->Angle = 0.0;
185 strcpy(h->Version, (char *) glGetString(GL_VERSION));
186 strcpy(h->Vendor, (char *) glGetString(GL_VENDOR));
187 strcpy(h->Renderer, (char *) glGetString(GL_RENDERER));
188 NumHeads++;
189 return &Heads[NumHeads-1];
190 }
191
192 }
193
194
195 static void
196 DestroyHeads(void)
197 {
198 int i;
199 for (i = 0; i < NumHeads; i++) {
200 XDestroyWindow(Heads[i].Dpy, Heads[i].Win);
201 glXDestroyContext(Heads[i].Dpy, Heads[i].Context);
202 XCloseDisplay(Heads[i].Dpy);
203 }
204 }
205
206
207 static void
208 Redraw(struct head *h)
209 {
210 if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
211 Error(h->DisplayName, "glXMakeCurrent failed");
212 printf("glXMakeCurrent failed in Redraw()\n");
213 return;
214 }
215
216 h->Angle += 1.0;
217
218 glShadeModel(GL_FLAT);
219 glClearColor(0.5, 0.5, 0.5, 1.0);
220 glClear(GL_COLOR_BUFFER_BIT);
221
222 /* draw green triangle */
223 glColor3f(0.0, 1.0, 0.0);
224 glPushMatrix();
225 glRotatef(h->Angle, 0, 0, 1);
226 glBegin(GL_TRIANGLES);
227 glTexCoord2f(0.5, 1.0); glVertex2f(0, 0.8);
228 glTexCoord2f(0.0, 0.0); glVertex2f(-0.8, -0.7);
229 glTexCoord2f(1.0, 0.0); glVertex2f(0.8, -0.7);
230 glEnd();
231 glPopMatrix();
232
233 if (!SwapSeparate)
234 glXSwapBuffers(h->Dpy, h->Win);
235 }
236
237
238 static void
239 Swap(struct head *h)
240 {
241 glXSwapBuffers(h->Dpy, h->Win);
242 }
243
244
245 static void
246 Resize(const struct head *h, unsigned int width, unsigned int height)
247 {
248 if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
249 Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
250 return;
251 }
252 glFlush();
253 glViewport(0, 0, width, height);
254 glMatrixMode(GL_PROJECTION);
255 glLoadIdentity();
256 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
257 }
258
259
260
261 static void
262 EventLoop(void)
263 {
264 while (1) {
265 int i;
266 for (i = 0; i < NumHeads; i++) {
267 struct head *h = &Heads[i];
268 while (XPending(h->Dpy) > 0) {
269 XEvent event;
270 XNextEvent(h->Dpy, &event);
271 if (event.xany.window == h->Win) {
272 switch (event.type) {
273 case Expose:
274 Redraw(h);
275 if (SwapSeparate)
276 Swap(h);
277 break;
278 case ConfigureNotify:
279 Resize(h, event.xconfigure.width, event.xconfigure.height);
280 break;
281 case KeyPress:
282 {
283 char buf[100];
284 KeySym keySym;
285 XComposeStatus stat;
286 XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
287 switch (keySym) {
288 case XK_Escape:
289 exit(0);
290 break;
291 case XK_d:
292 case XK_D:
293 printf("Delete Texture in window %d\n", i);
294 glXMakeCurrent(h->Dpy, h->Win, h->Context);
295 glDeleteTextures(1, &TexObj);
296 break;
297 case XK_u:
298 case XK_U:
299 printf("Unbind Texture in window %d\n", i);
300 glXMakeCurrent(h->Dpy, h->Win, h->Context);
301 glBindTexture(GL_TEXTURE_2D, 0);
302 break;
303 }
304 }
305 break;
306 default:
307 /*no-op*/ ;
308 }
309 }
310 else {
311 printf("window mismatch\n");
312 }
313 }
314 }
315
316 /* redraw all windows */
317 for (i = 0; i < NumHeads; i++) {
318 Redraw(&Heads[i]);
319 }
320 /* swapbuffers on all windows, if not already done */
321 if (SwapSeparate) {
322 for (i = 0; i < NumHeads; i++) {
323 Swap(&Heads[i]);
324 }
325 }
326 usleep(1);
327 }
328 }
329
330
331
332 static void
333 PrintInfo(const struct head *h)
334 {
335 printf("Name: %s\n", h->DisplayName);
336 printf(" Display: %p\n", (void *) h->Dpy);
337 printf(" Window: 0x%x\n", (int) h->Win);
338 printf(" Context: 0x%lx\n", (long) h->Context);
339 printf(" GL_VERSION: %s\n", h->Version);
340 printf(" GL_VENDOR: %s\n", h->Vendor);
341 printf(" GL_RENDERER: %s\n", h->Renderer);
342 }
343
344
345 int
346 main(int argc, char *argv[])
347 {
348 char *dpyName = NULL;
349 int i;
350
351 if (argc == 1) {
352 printf("manywin: open N simultaneous glx windows\n");
353 printf("Usage:\n");
354 printf(" manywin [-s] numWindows\n");
355 printf("Options:\n");
356 printf(" -s = swap immediately after drawing (see src code)\n");
357 printf("Example:\n");
358 printf(" manywin 10\n");
359 return 0;
360 }
361 else {
362 int n = 3;
363 for (i = 1; i < argc; i++) {
364 if (strcmp(argv[i], "-s") == 0) {
365 SwapSeparate = GL_FALSE;
366 }
367 else if (strcmp(argv[i], "-display") == 0 && i < argc) {
368 dpyName = argv[i+1];
369 i++;
370 }
371 else {
372 n = atoi(argv[i]);
373 }
374 }
375 if (n < 1)
376 n = 1;
377
378 printf("%d windows\n", n);
379 for (i = 0; i < n; i++) {
380 char name[100];
381 struct head *h;
382 sprintf(name, "%d", i);
383 h = AddHead(dpyName, name);
384 if (h) {
385 PrintInfo(h);
386 }
387 }
388 }
389
390 EventLoop();
391 DestroyHeads();
392 return 0;
393 }