Merge branch '7.8'
[mesa.git] / progs / xdemos / corender.c
1 /**
2 * Example of cooperative rendering into one window by two processes.
3 * The first instance of the program creates the GLX window.
4 * The second instance of the program gets the window ID from the first
5 * and draws into it.
6 * Socket IPC is used for synchronization.
7 *
8 * Usage:
9 * 1. run 'corender &'
10 * 2. run 'corender 2' (any arg will do)
11 *
12 * Brian Paul
13 * 11 Oct 2007
14 */
15
16
17 #include <GL/gl.h>
18 #include <GL/glx.h>
19 #include <assert.h>
20 #include <math.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <X11/keysym.h>
24 #include <unistd.h>
25 #include "ipc.h"
26
27
28 #ifndef M_PI
29 #define M_PI 3.14159265358979323846
30 #endif
31
32 static int MyID = 0; /* 0 or 1 */
33 static int WindowID = 0;
34 static GLXContext Context = 0;
35 static int Width = 700, Height = 350;
36 static int Rot = 0;
37 static int Sock = 0;
38
39 static GLfloat Red[4] = {1.0, 0.2, 0.2, 1.0};
40 static GLfloat Blue[4] = {0.2, 0.2, 1.0, 1.0};
41
42 static int Sync = 1; /** synchronized rendering? */
43
44
45 static void
46 setup_ipc(void)
47 {
48 int k, port = 10001;
49
50 if (MyID == 0) {
51 /* I'm the first one, wait for connection from second */
52 k = CreatePort(&port);
53 assert(k != -1);
54
55 printf("Waiting for connection from another 'corender'\n");
56 Sock = AcceptConnection(k);
57 assert(Sock != -1);
58
59 printf("Got connection, sending windowID\n");
60
61 /* send windowID */
62 SendData(Sock, &WindowID, sizeof(WindowID));
63 }
64 else {
65 /* I'm the second one, connect to first */
66 char hostname[1000];
67
68 MyHostName(hostname, 1000);
69 Sock = Connect(hostname, port);
70 assert(Sock != -1);
71
72 /* get windowID */
73 ReceiveData(Sock, &WindowID, sizeof(WindowID));
74 printf("Contacted first 'corender', getting WindowID\n");
75 }
76 }
77
78
79
80 /** from GLUT */
81 static void
82 doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
83 {
84 int i, j;
85 GLfloat theta, phi, theta1;
86 GLfloat cosTheta, sinTheta;
87 GLfloat cosTheta1, sinTheta1;
88 GLfloat ringDelta, sideDelta;
89
90 ringDelta = 2.0 * M_PI / rings;
91 sideDelta = 2.0 * M_PI / nsides;
92
93 theta = 0.0;
94 cosTheta = 1.0;
95 sinTheta = 0.0;
96 for (i = rings - 1; i >= 0; i--) {
97 theta1 = theta + ringDelta;
98 cosTheta1 = cos(theta1);
99 sinTheta1 = sin(theta1);
100 glBegin(GL_QUAD_STRIP);
101 phi = 0.0;
102 for (j = nsides; j >= 0; j--) {
103 GLfloat cosPhi, sinPhi, dist;
104
105 phi += sideDelta;
106 cosPhi = cos(phi);
107 sinPhi = sin(phi);
108 dist = R + r * cosPhi;
109
110 glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
111 glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
112 glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
113 glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi);
114 }
115 glEnd();
116 theta = theta1;
117 cosTheta = cosTheta1;
118 sinTheta = sinTheta1;
119 }
120 }
121
122
123 static void
124 redraw(Display *dpy)
125 {
126 int dbg = 0;
127
128 glXMakeCurrent(dpy, WindowID, Context);
129 glEnable(GL_LIGHTING);
130 glEnable(GL_LIGHT0);
131 glEnable(GL_DEPTH_TEST);
132 glClearColor(0.5, 0.5, 0.5, 0.0);
133
134 if (MyID == 0) {
135 /* First process */
136
137 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
138
139 glPushMatrix();
140 glTranslatef(-1, 0, 0);
141 glRotatef(Rot, 1, 0, 0);
142 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
143 doughnut(0.5, 2.0, 20, 30);
144 glPopMatrix();
145
146 glFinish();
147 if (!Sync) {
148 usleep(1000*10);
149 }
150
151 /* signal second process to render */
152 if (Sync) {
153 int code = 1;
154 if (dbg) printf("0: send signal\n");
155 SendData(Sock, &code, sizeof(code));
156 SendData(Sock, &Rot, sizeof(Rot));
157 }
158
159 /* wait for second process to finish rendering */
160 if (Sync) {
161 int code = 0;
162 if (dbg) printf("0: wait signal\n");
163 ReceiveData(Sock, &code, sizeof(code));
164 if (dbg) printf("0: got signal\n");
165 assert(code == 2);
166 }
167
168 }
169 else {
170 /* Second process */
171
172 /* wait for first process's signal for me to render */
173 if (Sync) {
174 int code = 0;
175 if (dbg) printf("1: wait signal\n");
176 ReceiveData(Sock, &code, sizeof(code));
177 ReceiveData(Sock, &Rot, sizeof(Rot));
178
179 if (dbg) printf("1: got signal\n");
180 assert(code == 1);
181 }
182
183 /* XXX this clear should not be here, but for some reason, it
184 * makes things _mostly_ work correctly w/ NVIDIA's driver.
185 * There's only occasional glitches.
186 * Without this glClear(), depth buffer for the second process
187 * is pretty much broken.
188 */
189 /* glClear(GL_DEPTH_BUFFER_BIT); */
190
191 glPushMatrix();
192 glTranslatef(1, 0, 0);
193 glRotatef(Rot + 90 , 1, 0, 0);
194 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
195 doughnut(0.5, 2.0, 20, 30);
196 glPopMatrix();
197 glFinish();
198
199 glXSwapBuffers(dpy, WindowID);
200 usleep(1000*10);
201
202 /* signal first process that I'm done rendering */
203 if (Sync) {
204 int code = 2;
205 if (dbg) printf("1: send signal\n");
206 SendData(Sock, &code, sizeof(code));
207 }
208 }
209 }
210
211
212 static void
213 resize(Display *dpy, int width, int height)
214 {
215 float ar = (float) width / height;
216
217 glXMakeCurrent(dpy, WindowID, Context);
218
219 glViewport(0, 0, width, height);
220 glMatrixMode(GL_PROJECTION);
221 glLoadIdentity();
222 glFrustum(-ar, ar, 1.0, -1.0, 5.0, 200.0);
223 glMatrixMode(GL_MODELVIEW);
224 glLoadIdentity();
225 glTranslatef(0, 0, -15);
226
227 Width = width;
228 Height = height;
229 }
230
231
232
233 static void
234 set_window_title(Display *dpy, Window win, const char *title)
235 {
236 XSizeHints sizehints;
237 sizehints.flags = 0;
238 XSetStandardProperties(dpy, win, title, title,
239 None, (char **)NULL, 0, &sizehints);
240 }
241
242
243 static Window
244 make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
245 {
246 int scrnum;
247 XSetWindowAttributes attr;
248 unsigned long mask;
249 Window root;
250 Window win;
251 int x = 0, y = 0;
252 char *name = NULL;
253
254 scrnum = DefaultScreen( dpy );
255 root = RootWindow( dpy, scrnum );
256
257 /* window attributes */
258 attr.background_pixel = 0;
259 attr.border_pixel = 0;
260 attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
261 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
262 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
263
264 win = XCreateWindow( dpy, root, x, y, width, height,
265 0, visinfo->depth, InputOutput,
266 visinfo->visual, mask, &attr );
267
268 /* set hints and properties */
269 {
270 XSizeHints sizehints;
271 sizehints.x = x;
272 sizehints.y = y;
273 sizehints.width = width;
274 sizehints.height = height;
275 sizehints.flags = USSize | USPosition;
276 XSetNormalHints(dpy, win, &sizehints);
277 XSetStandardProperties(dpy, win, name, name,
278 None, (char **)NULL, 0, &sizehints);
279 }
280
281 return win;
282 }
283
284
285 static void
286 set_event_mask(Display *dpy, Window win)
287 {
288 XSetWindowAttributes attr;
289 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
290 XChangeWindowAttributes(dpy, win, CWEventMask, &attr);
291 }
292
293
294 static void
295 event_loop(Display *dpy)
296 {
297 while (1) {
298 while (XPending(dpy) > 0) {
299 XEvent event;
300 XNextEvent(dpy, &event);
301
302 switch (event.type) {
303 case Expose:
304 redraw(dpy);
305 break;
306 case ConfigureNotify:
307 resize(dpy, event.xconfigure.width, event.xconfigure.height);
308 break;
309 case KeyPress:
310 {
311 char buffer[10];
312 int r, code;
313 code = XLookupKeysym(&event.xkey, 0);
314 if (code == XK_Left) {
315 }
316 else {
317 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
318 NULL, NULL);
319 if (buffer[0] == 27) {
320 exit(0);
321 }
322 }
323 }
324 default:
325 /* nothing */
326 ;
327 }
328 }
329
330 if (MyID == 0 || !Sync)
331 Rot += 1;
332 redraw(dpy);
333 }
334 }
335
336
337 static XVisualInfo *
338 choose_visual(Display *dpy)
339 {
340 int attribs[] = { GLX_RGBA,
341 GLX_RED_SIZE, 1,
342 GLX_GREEN_SIZE, 1,
343 GLX_BLUE_SIZE, 1,
344 GLX_DOUBLEBUFFER,
345 GLX_DEPTH_SIZE, 1,
346 None };
347 int scrnum = DefaultScreen( dpy );
348 return glXChooseVisual(dpy, scrnum, attribs);
349 }
350
351
352 static void
353 parse_opts(int argc, char *argv[])
354 {
355 if (argc > 1) {
356 MyID = 1;
357 }
358 }
359
360
361 int
362 main( int argc, char *argv[] )
363 {
364 Display *dpy;
365 XVisualInfo *visinfo;
366
367 parse_opts(argc, argv);
368
369 dpy = XOpenDisplay(NULL);
370
371 visinfo = choose_visual(dpy);
372
373 Context = glXCreateContext( dpy, visinfo, NULL, True );
374 if (!Context) {
375 printf("Error: glXCreateContext failed\n");
376 exit(1);
377 }
378
379 if (MyID == 0) {
380 WindowID = make_gl_window(dpy, visinfo, Width, Height);
381 set_window_title(dpy, WindowID, "corender");
382 XMapWindow(dpy, WindowID);
383 /*printf("WindowID 0x%x\n", (int) WindowID);*/
384 }
385
386 /* do ipc hand-shake here */
387 setup_ipc();
388 assert(Sock);
389 assert(WindowID);
390
391 if (MyID == 1) {
392 set_event_mask(dpy, WindowID);
393 }
394
395 resize(dpy, Width, Height);
396
397 event_loop(dpy);
398
399 return 0;
400 }