Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / progs / xdemos / glxsnoop.c
1 /**
2 * Display/snoop the z/stencil/back/front buffers of another app's window.
3 * Also, an example of the need for shared ancillary renderbuffers.
4 *
5 * Hint: use 'xwininfo' to get a window's ID.
6 *
7 * Brian Paul
8 * 11 Oct 2007
9 */
10
11 #define GL_GLEXT_PROTOTYPES
12
13 #include <GL/gl.h>
14 #include <GL/glx.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <X11/keysym.h>
19
20
21 #define Z_BUFFER 1
22 #define STENCIL_BUFFER 2
23 #define BACK_BUFFER 3
24 #define FRONT_BUFFER 4
25
26
27 static int Buffer = BACK_BUFFER;
28 static int WindowID = 0;
29 static const char *DisplayName = NULL;
30 static GLXContext Context = 0;
31 static int Width, Height;
32
33
34 /**
35 * Grab the z/stencil/back/front image from the srcWin and display it
36 * (possibly converted to grayscale) in the dstWin.
37 */
38 static void
39 redraw(Display *dpy, Window srcWin, Window dstWin )
40 {
41 GLubyte *image = malloc(Width * Height * 4);
42
43 glXMakeCurrent(dpy, srcWin, Context);
44 glPixelStorei(GL_PACK_ALIGNMENT, 1);
45 if (Buffer == BACK_BUFFER) {
46 glReadBuffer(GL_BACK);
47 glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
48 }
49 else if (Buffer == FRONT_BUFFER) {
50 glReadBuffer(GL_FRONT);
51 glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
52 }
53 else if (Buffer == Z_BUFFER) {
54 GLfloat *z = malloc(Width * Height * sizeof(GLfloat));
55 int i;
56 glReadPixels(0, 0, Width, Height, GL_DEPTH_COMPONENT, GL_FLOAT, z);
57 for (i = 0; i < Width * Height; i++) {
58 image[i*4+0] =
59 image[i*4+1] =
60 image[i*4+2] = (GLint) (255.0 * z[i]);
61 image[i*4+3] = 255;
62 }
63 free(z);
64 }
65 else if (Buffer == STENCIL_BUFFER) {
66 GLubyte *sten = malloc(Width * Height * sizeof(GLubyte));
67 int i, min = 100, max = -1;
68 float step;
69 int sz;
70 glGetIntegerv(GL_STENCIL_BITS, &sz);
71 glReadPixels(0, 0, Width, Height,
72 GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, sten);
73 /* find min/max for converting stencil to grayscale */
74 for (i = 0; i < Width * Height; i++) {
75 if (sten[i] < min)
76 min = sten[i];
77 if (sten[i] > max)
78 max = sten[i];
79 }
80 if (min == max)
81 step = 0;
82 else
83 step = 255.0 / (float) (max - min);
84 for (i = 0; i < Width * Height; i++) {
85 image[i*4+0] =
86 image[i*4+1] =
87 image[i*4+2] = (GLint) ((sten[i] - min) * step);
88 image[i*4+3] = 255;
89 }
90 free(sten);
91 }
92
93 glXMakeCurrent(dpy, dstWin, Context);
94 glWindowPos2iARB(0, 0);
95 glDrawBuffer(GL_FRONT);
96 glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
97 glFlush();
98
99 free(image);
100 }
101
102
103 static void
104 set_window_title(Display *dpy, Window win, const char *title)
105 {
106 XSizeHints sizehints;
107 sizehints.flags = 0;
108 XSetStandardProperties(dpy, win, title, title,
109 None, (char **)NULL, 0, &sizehints);
110 }
111
112
113 static Window
114 make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
115 {
116 int scrnum;
117 XSetWindowAttributes attr;
118 unsigned long mask;
119 Window root;
120 Window win;
121 int x = 0, y = 0;
122 char *name = NULL;
123
124 scrnum = DefaultScreen( dpy );
125 root = RootWindow( dpy, scrnum );
126
127 /* window attributes */
128 attr.background_pixel = 0;
129 attr.border_pixel = 0;
130 attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
131 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
132 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
133
134 win = XCreateWindow( dpy, root, x, y, width, height,
135 0, visinfo->depth, InputOutput,
136 visinfo->visual, mask, &attr );
137
138 /* set hints and properties */
139 {
140 XSizeHints sizehints;
141 sizehints.x = x;
142 sizehints.y = y;
143 sizehints.width = width;
144 sizehints.height = height;
145 sizehints.flags = USSize | USPosition;
146 XSetNormalHints(dpy, win, &sizehints);
147 XSetStandardProperties(dpy, win, name, name,
148 None, (char **)NULL, 0, &sizehints);
149 }
150
151 return win;
152 }
153
154
155 static void
156 update_window_title(Display *dpy, Window win)
157 {
158 char title[1000], *buf;
159
160 switch (Buffer) {
161 case Z_BUFFER:
162 buf = "Z";
163 break;
164 case STENCIL_BUFFER:
165 buf = "Stencil";
166 break;
167 case BACK_BUFFER:
168 buf = "Back";
169 break;
170 case FRONT_BUFFER:
171 buf = "Front";
172 break;
173 default:
174 buf = "";
175 }
176
177 sprintf(title, "glxsnoop window 0x%x (%s buffer)", (int) WindowID, buf);
178
179 set_window_title(dpy, win, title);
180 }
181
182
183 static void
184 keypress(Display *dpy, Window win, char key)
185 {
186 switch (key) {
187 case 27:
188 /* escape */
189 exit(0);
190 break;
191 case 's':
192 Buffer = STENCIL_BUFFER;
193 break;
194 case 'z':
195 Buffer = Z_BUFFER;
196 break;
197 case 'f':
198 Buffer = FRONT_BUFFER;
199 break;
200 case 'b':
201 Buffer = BACK_BUFFER;
202 break;
203 default:
204 return;
205 }
206
207 update_window_title(dpy, win);
208 redraw(dpy, WindowID, win);
209 }
210
211
212 static void
213 event_loop(Display *dpy, Window win)
214 {
215 XEvent event;
216
217 while (1) {
218 XNextEvent( dpy, &event );
219
220 switch (event.type) {
221 case Expose:
222 redraw(dpy, WindowID, win);
223 break;
224 case ConfigureNotify:
225 /*resize( event.xconfigure.width, event.xconfigure.height );*/
226 break;
227 case KeyPress:
228 {
229 char buffer[10];
230 int r, code;
231 code = XLookupKeysym(&event.xkey, 0);
232 if (code == XK_Left) {
233 }
234 else {
235 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
236 NULL, NULL);
237 keypress(dpy, win, buffer[0]);
238 }
239 }
240 default:
241 /* nothing */
242 ;
243 }
244 }
245 }
246
247
248 static VisualID
249 get_window_visualid(Display *dpy, Window win)
250 {
251 XWindowAttributes attr;
252
253 if (XGetWindowAttributes(dpy, win, &attr)) {
254 return attr.visual->visualid;
255 }
256 else {
257 return 0;
258 }
259 }
260
261
262 static void
263 get_window_size(Display *dpy, Window win, int *w, int *h)
264 {
265 XWindowAttributes attr;
266
267 if (XGetWindowAttributes(dpy, win, &attr)) {
268 *w = attr.width;
269 *h = attr.height;
270 }
271 else {
272 *w = *h = 0;
273 }
274 }
275
276
277 static XVisualInfo *
278 visualid_to_visualinfo(Display *dpy, VisualID vid)
279 {
280 XVisualInfo *vinfo, templ;
281 long mask;
282 int n;
283
284 templ.visualid = vid;
285 mask = VisualIDMask;
286
287 vinfo = XGetVisualInfo(dpy, mask, &templ, &n);
288 return vinfo;
289 }
290
291
292 static void
293 key_usage(void)
294 {
295 printf("Keyboard:\n");
296 printf(" z - display Z buffer\n");
297 printf(" s - display stencil buffer\n");
298 printf(" f - display front color buffer\n");
299 printf(" b - display back buffer\n");
300 }
301
302
303 static void
304 usage(void)
305 {
306 printf("Usage: glxsnoop [-display dpy] windowID\n");
307 key_usage();
308 }
309
310
311 static void
312 parse_opts(int argc, char *argv[])
313 {
314 int i;
315
316 for (i = 1; i < argc; i++) {
317 if (strcmp(argv[i], "-h") == 0) {
318 usage();
319 exit(0);
320 }
321 else if (strcmp(argv[i], "-display") == 0) {
322 DisplayName = argv[i + 1];
323 i++;
324 }
325 else {
326 if (argv[i][0] == '0' && argv[i][1] == 'x') {
327 /* hex */
328 WindowID = strtol(argv[i], NULL, 16);
329 }
330 else {
331 WindowID = atoi(argv[i]);
332 }
333 break;
334 }
335 }
336
337 if (!WindowID) {
338 usage();
339 exit(0);
340 }
341 }
342
343
344 int
345 main( int argc, char *argv[] )
346 {
347 Display *dpy;
348 VisualID vid;
349 XVisualInfo *visinfo;
350 Window win;
351
352 parse_opts(argc, argv);
353
354 key_usage();
355
356 dpy = XOpenDisplay(DisplayName);
357
358 /* find the VisualID for the named window */
359 vid = get_window_visualid(dpy, WindowID);
360 get_window_size(dpy, WindowID, &Width, &Height);
361
362 visinfo = visualid_to_visualinfo(dpy, vid);
363
364 Context = glXCreateContext( dpy, visinfo, NULL, True );
365 if (!Context) {
366 printf("Error: glXCreateContext failed\n");
367 exit(1);
368 }
369
370 win = make_gl_window(dpy, visinfo, Width, Height);
371 XMapWindow(dpy, win);
372 update_window_title(dpy, win);
373
374 event_loop( dpy, win );
375
376 return 0;
377 }