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.
6 * Copyright (C) 2000 Brian Paul All Rights Reserved.
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:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
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.
34 #include <X11/keysym.h>
38 * Each display/window/context:
41 char DisplayName
[1000];
53 static struct head Heads
[MAX_HEADS
];
54 static int NumHeads
= 0;
55 static GLboolean SwapSeparate
= GL_TRUE
;
56 static GLuint TexObj
= 0;
60 Error(const char *display
, const char *msg
)
62 fprintf(stderr
, "Error on display %s - %s\n", XDisplayName(display
), msg
);
68 AddHead(const char *displayName
, const char *name
)
73 int attrib
[] = { GLX_RGBA
,
80 XSetWindowAttributes attr
;
84 int width
= 90, height
= 90;
85 int xpos
= 0, ypos
= 0;
87 if (NumHeads
>= MAX_HEADS
)
90 dpy
= XOpenDisplay(displayName
);
92 Error(displayName
, "Unable to open display");
96 scrnum
= DefaultScreen(dpy
);
97 root
= RootWindow(dpy
, scrnum
);
99 visinfo
= glXChooseVisual(dpy
, scrnum
, attrib
);
101 Error(displayName
, "Unable to find RGB, double-buffered visual");
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
;
115 win
= XCreateWindow(dpy
, root
, xpos
, ypos
, width
, height
,
116 0, visinfo
->depth
, InputOutput
,
117 visinfo
->visual
, mask
, &attr
);
119 Error(displayName
, "Couldn't create window");
124 XSizeHints sizehints
;
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
);
136 ctx
= glXCreateContext(dpy
, visinfo
, NULL
, True
);
139 /* share textures & dlists with 0th context */
141 ctx
= glXCreateContext(dpy
, visinfo
, Heads
[0].Context
, True
);
144 Error(displayName
, "Couldn't create GLX context");
148 XMapWindow(dpy
, win
);
150 if (!glXMakeCurrent(dpy
, win
, ctx
)) {
151 Error(displayName
, "glXMakeCurrent failed");
152 printf("glXMakeCurrent failed in Redraw()\n");
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} }
162 glGenTextures(1, &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
);
171 /* bind 0th context's texture in this context too */
173 glBindTexture(GL_TEXTURE_2D
, TexObj
);
175 glEnable(GL_TEXTURE_2D
);
177 /* save the info for this head */
179 struct head
*h
= &Heads
[NumHeads
];
182 if (strlen(name
) + 1 > sizeof(h
->DisplayName
)) {
183 Error(displayName
, "name string overflow");
186 strcpy(h
->DisplayName
, name
);
193 tmp
= (char *) glGetString(GL_VERSION
);
194 if (strlen(tmp
) + 1 > sizeof(h
->Version
)) {
195 Error(displayName
, "GL_VERSION string overflow");
198 strcpy(h
->Version
, tmp
);
200 tmp
= (char *) glGetString(GL_VENDOR
);
201 if (strlen(tmp
) + 1 > sizeof(h
->Vendor
)) {
202 Error(displayName
, "GL_VENDOR string overflow");
205 strcpy(h
->Vendor
, tmp
);
207 tmp
= (char *) glGetString(GL_RENDERER
);
208 if (strlen(tmp
) + 1 > sizeof(h
->Renderer
)) {
209 Error(displayName
, "GL_RENDERER string overflow");
212 strcpy(h
->Renderer
, tmp
);
215 return &Heads
[NumHeads
-1];
225 for (i
= 0; i
< NumHeads
; i
++) {
226 XDestroyWindow(Heads
[i
].Dpy
, Heads
[i
].Win
);
227 glXDestroyContext(Heads
[i
].Dpy
, Heads
[i
].Context
);
228 XCloseDisplay(Heads
[i
].Dpy
);
234 Redraw(struct head
*h
)
236 if (!glXMakeCurrent(h
->Dpy
, h
->Win
, h
->Context
)) {
237 Error(h
->DisplayName
, "glXMakeCurrent failed");
238 printf("glXMakeCurrent failed in Redraw()\n");
244 glShadeModel(GL_FLAT
);
245 glClearColor(0.5, 0.5, 0.5, 1.0);
246 glClear(GL_COLOR_BUFFER_BIT
);
248 /* draw green triangle */
249 glColor3f(0.0, 1.0, 0.0);
251 glRotatef(h
->Angle
, 0, 0, 1);
252 glBegin(GL_TRIANGLES
);
253 glTexCoord2f(0.5, 1.0); glVertex2f(0, 0.8);
254 glTexCoord2f(0.0, 0.0); glVertex2f(-0.8, -0.7);
255 glTexCoord2f(1.0, 0.0); glVertex2f(0.8, -0.7);
260 glXSwapBuffers(h
->Dpy
, h
->Win
);
267 glXSwapBuffers(h
->Dpy
, h
->Win
);
272 Resize(const struct head
*h
, unsigned int width
, unsigned int height
)
274 if (!glXMakeCurrent(h
->Dpy
, h
->Win
, h
->Context
)) {
275 Error(h
->DisplayName
, "glXMakeCurrent failed in Resize()");
279 glViewport(0, 0, width
, height
);
280 glMatrixMode(GL_PROJECTION
);
282 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
292 for (i
= 0; i
< NumHeads
; i
++) {
293 struct head
*h
= &Heads
[i
];
294 while (XPending(h
->Dpy
) > 0) {
296 XNextEvent(h
->Dpy
, &event
);
297 if (event
.xany
.window
== h
->Win
) {
298 switch (event
.type
) {
304 case ConfigureNotify
:
305 Resize(h
, event
.xconfigure
.width
, event
.xconfigure
.height
);
312 XLookupString(&event
.xkey
, buf
, sizeof(buf
), &keySym
, &stat
);
319 printf("Delete Texture in window %d\n", i
);
320 glXMakeCurrent(h
->Dpy
, h
->Win
, h
->Context
);
321 glDeleteTextures(1, &TexObj
);
325 printf("Unbind Texture in window %d\n", i
);
326 glXMakeCurrent(h
->Dpy
, h
->Win
, h
->Context
);
327 glBindTexture(GL_TEXTURE_2D
, 0);
337 printf("window mismatch\n");
342 /* redraw all windows */
343 for (i
= 0; i
< NumHeads
; i
++) {
346 /* swapbuffers on all windows, if not already done */
348 for (i
= 0; i
< NumHeads
; i
++) {
359 PrintInfo(const struct head
*h
)
361 printf("Name: %s\n", h
->DisplayName
);
362 printf(" Display: %p\n", (void *) h
->Dpy
);
363 printf(" Window: 0x%x\n", (int) h
->Win
);
364 printf(" Context: 0x%lx\n", (long) h
->Context
);
365 printf(" GL_VERSION: %s\n", h
->Version
);
366 printf(" GL_VENDOR: %s\n", h
->Vendor
);
367 printf(" GL_RENDERER: %s\n", h
->Renderer
);
372 main(int argc
, char *argv
[])
374 char *dpyName
= NULL
;
378 printf("manywin: open N simultaneous glx windows\n");
380 printf(" manywin [-s] numWindows\n");
381 printf("Options:\n");
382 printf(" -s = swap immediately after drawing (see src code)\n");
383 printf("Example:\n");
384 printf(" manywin 10\n");
389 for (i
= 1; i
< argc
; i
++) {
390 if (strcmp(argv
[i
], "-s") == 0) {
391 SwapSeparate
= GL_FALSE
;
393 else if (strcmp(argv
[i
], "-display") == 0 && i
< argc
) {
406 printf("%d windows\n", n
);
407 for (i
= 0; i
< n
; i
++) {
410 sprintf(name
, "%d", i
);
411 h
= AddHead(dpyName
, name
);