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.
5 * Hint: use 'xwininfo' to get a window's ID.
11 #define GL_GLEXT_PROTOTYPES
18 #include <X11/keysym.h>
22 #define STENCIL_BUFFER 2
24 #define FRONT_BUFFER 4
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
;
35 * Grab the z/stencil/back/front image from the srcWin and display it
36 * (possibly converted to grayscale) in the dstWin.
39 redraw(Display
*dpy
, Window srcWin
, Window dstWin
)
41 GLubyte
*image
= malloc(Width
* Height
* 4);
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
);
49 else if (Buffer
== FRONT_BUFFER
) {
50 glReadBuffer(GL_FRONT
);
51 glReadPixels(0, 0, Width
, Height
, GL_RGBA
, GL_UNSIGNED_BYTE
, image
);
53 else if (Buffer
== Z_BUFFER
) {
54 GLfloat
*z
= malloc(Width
* Height
* sizeof(GLfloat
));
56 glReadPixels(0, 0, Width
, Height
, GL_DEPTH_COMPONENT
, GL_FLOAT
, z
);
57 for (i
= 0; i
< Width
* Height
; i
++) {
60 image
[i
*4+2] = (GLint
) (255.0 * z
[i
]);
65 else if (Buffer
== STENCIL_BUFFER
) {
66 GLubyte
*sten
= malloc(Width
* Height
* sizeof(GLubyte
));
67 int i
, min
= 100, max
= -1;
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
++) {
83 step
= 255.0 / (float) (max
- min
);
84 for (i
= 0; i
< Width
* Height
; i
++) {
87 image
[i
*4+2] = (GLint
) ((sten
[i
] - min
) * step
);
93 glXMakeCurrent(dpy
, dstWin
, Context
);
94 glWindowPos2iARB(0, 0);
95 glDrawBuffer(GL_FRONT
);
96 glDrawPixels(Width
, Height
, GL_RGBA
, GL_UNSIGNED_BYTE
, image
);
104 set_window_title(Display
*dpy
, Window win
, const char *title
)
106 XSizeHints sizehints
;
108 XSetStandardProperties(dpy
, win
, title
, title
,
109 None
, (char **)NULL
, 0, &sizehints
);
114 make_gl_window(Display
*dpy
, XVisualInfo
*visinfo
, int width
, int height
)
117 XSetWindowAttributes attr
;
124 scrnum
= DefaultScreen( dpy
);
125 root
= RootWindow( dpy
, scrnum
);
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
;
134 win
= XCreateWindow( dpy
, root
, x
, y
, width
, height
,
135 0, visinfo
->depth
, InputOutput
,
136 visinfo
->visual
, mask
, &attr
);
138 /* set hints and properties */
140 XSizeHints sizehints
;
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
);
156 update_window_title(Display
*dpy
, Window win
)
158 char title
[1000], *buf
;
177 sprintf(title
, "glxsnoop window 0x%x (%s buffer)", (int) WindowID
, buf
);
179 set_window_title(dpy
, win
, title
);
184 keypress(Display
*dpy
, Window win
, char key
)
192 Buffer
= STENCIL_BUFFER
;
198 Buffer
= FRONT_BUFFER
;
201 Buffer
= BACK_BUFFER
;
207 update_window_title(dpy
, win
);
208 redraw(dpy
, WindowID
, win
);
213 event_loop(Display
*dpy
, Window win
)
218 XNextEvent( dpy
, &event
);
220 switch (event
.type
) {
222 redraw(dpy
, WindowID
, win
);
224 case ConfigureNotify
:
225 /*resize( event.xconfigure.width, event.xconfigure.height );*/
231 code
= XLookupKeysym(&event
.xkey
, 0);
232 if (code
== XK_Left
) {
235 r
= XLookupString(&event
.xkey
, buffer
, sizeof(buffer
),
237 keypress(dpy
, win
, buffer
[0]);
249 get_window_visualid(Display
*dpy
, Window win
)
251 XWindowAttributes attr
;
253 if (XGetWindowAttributes(dpy
, win
, &attr
)) {
254 return attr
.visual
->visualid
;
263 get_window_size(Display
*dpy
, Window win
, int *w
, int *h
)
265 XWindowAttributes attr
;
267 if (XGetWindowAttributes(dpy
, win
, &attr
)) {
278 visualid_to_visualinfo(Display
*dpy
, VisualID vid
)
280 XVisualInfo
*vinfo
, templ
;
284 templ
.visualid
= vid
;
287 vinfo
= XGetVisualInfo(dpy
, mask
, &templ
, &n
);
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");
306 printf("Usage: glxsnoop [-display dpy] windowID\n");
312 parse_opts(int argc
, char *argv
[])
316 for (i
= 1; i
< argc
; i
++) {
317 if (strcmp(argv
[i
], "-h") == 0) {
321 else if (strcmp(argv
[i
], "-display") == 0) {
322 DisplayName
= argv
[i
+ 1];
326 if (argv
[i
][0] == '0' && argv
[i
][1] == 'x') {
328 WindowID
= strtol(argv
[i
], NULL
, 16);
331 WindowID
= atoi(argv
[i
]);
345 main( int argc
, char *argv
[] )
349 XVisualInfo
*visinfo
;
352 parse_opts(argc
, argv
);
356 dpy
= XOpenDisplay(DisplayName
);
358 /* find the VisualID for the named window */
359 vid
= get_window_visualid(dpy
, WindowID
);
360 get_window_size(dpy
, WindowID
, &Width
, &Height
);
362 visinfo
= visualid_to_visualinfo(dpy
, vid
);
364 Context
= glXCreateContext( dpy
, visinfo
, NULL
, True
);
366 printf("Error: glXCreateContext failed\n");
370 win
= make_gl_window(dpy
, visinfo
, Width
, Height
);
371 XMapWindow(dpy
, win
);
372 update_window_title(dpy
, win
);
374 event_loop( dpy
, win
);