glxsnoop.c revision 32001f49
132001f49Smrg/**
232001f49Smrg * Display/snoop the z/stencil/back/front buffers of another app's window.
332001f49Smrg * Also, an example of the need for shared ancillary renderbuffers.
432001f49Smrg *
532001f49Smrg * Hint: use 'xwininfo' to get a window's ID.
632001f49Smrg *
732001f49Smrg * Brian Paul
832001f49Smrg * 11 Oct 2007
932001f49Smrg */
1032001f49Smrg
1132001f49Smrg#define GL_GLEXT_PROTOTYPES
1232001f49Smrg
1332001f49Smrg#include <GL/gl.h>
1432001f49Smrg#include <GL/glx.h>
1532001f49Smrg#include <stdio.h>
1632001f49Smrg#include <stdlib.h>
1732001f49Smrg#include <string.h>
1832001f49Smrg#include <X11/keysym.h>
1932001f49Smrg
2032001f49Smrg
2132001f49Smrg#define Z_BUFFER 1
2232001f49Smrg#define STENCIL_BUFFER 2
2332001f49Smrg#define BACK_BUFFER 3
2432001f49Smrg#define FRONT_BUFFER 4
2532001f49Smrg
2632001f49Smrg
2732001f49Smrgstatic int Buffer = BACK_BUFFER;
2832001f49Smrgstatic int WindowID = 0;
2932001f49Smrgstatic const char *DisplayName = NULL;
3032001f49Smrgstatic GLXContext Context = 0;
3132001f49Smrgstatic int Width, Height;
3232001f49Smrg
3332001f49Smrg
3432001f49Smrg/**
3532001f49Smrg * Grab the z/stencil/back/front image from the srcWin and display it
3632001f49Smrg * (possibly converted to grayscale) in the dstWin.
3732001f49Smrg */
3832001f49Smrgstatic void
3932001f49Smrgredraw(Display *dpy, Window srcWin, Window dstWin )
4032001f49Smrg{
4132001f49Smrg   GLubyte *image = malloc(Width * Height * 4);
4232001f49Smrg
4332001f49Smrg   glXMakeCurrent(dpy, srcWin, Context);
4432001f49Smrg   glPixelStorei(GL_PACK_ALIGNMENT, 1);
4532001f49Smrg   if (Buffer == BACK_BUFFER) {
4632001f49Smrg      glReadBuffer(GL_BACK);
4732001f49Smrg      glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
4832001f49Smrg   }
4932001f49Smrg   else if (Buffer == FRONT_BUFFER) {
5032001f49Smrg      glReadBuffer(GL_FRONT);
5132001f49Smrg      glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
5232001f49Smrg   }
5332001f49Smrg   else if (Buffer == Z_BUFFER) {
5432001f49Smrg      GLfloat *z = malloc(Width * Height * sizeof(GLfloat));
5532001f49Smrg      int i;
5632001f49Smrg      glReadPixels(0, 0, Width, Height, GL_DEPTH_COMPONENT, GL_FLOAT, z);
5732001f49Smrg      for (i = 0; i < Width * Height; i++) {
5832001f49Smrg         image[i*4+0] =
5932001f49Smrg         image[i*4+1] =
6032001f49Smrg         image[i*4+2] = (GLint) (255.0 * z[i]);
6132001f49Smrg         image[i*4+3] = 255;
6232001f49Smrg      }
6332001f49Smrg      free(z);
6432001f49Smrg   }
6532001f49Smrg   else if (Buffer == STENCIL_BUFFER) {
6632001f49Smrg      GLubyte *sten = malloc(Width * Height * sizeof(GLubyte));
6732001f49Smrg      int i, min = 100, max = -1;
6832001f49Smrg      float step;
6932001f49Smrg      int sz;
7032001f49Smrg      glGetIntegerv(GL_STENCIL_BITS, &sz);
7132001f49Smrg      glReadPixels(0, 0, Width, Height,
7232001f49Smrg                   GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, sten);
7332001f49Smrg      /* find min/max for converting stencil to grayscale */
7432001f49Smrg      for (i = 0; i < Width * Height; i++) {
7532001f49Smrg         if (sten[i] < min)
7632001f49Smrg            min = sten[i];
7732001f49Smrg         if (sten[i] > max)
7832001f49Smrg            max = sten[i];
7932001f49Smrg      }
8032001f49Smrg      if (min == max)
8132001f49Smrg         step = 0;
8232001f49Smrg      else
8332001f49Smrg         step = 255.0 / (float) (max - min);
8432001f49Smrg      for (i = 0; i < Width * Height; i++) {
8532001f49Smrg         image[i*4+0] =
8632001f49Smrg         image[i*4+1] =
8732001f49Smrg         image[i*4+2] = (GLint) ((sten[i] - min) * step);
8832001f49Smrg         image[i*4+3] = 255;
8932001f49Smrg      }
9032001f49Smrg      free(sten);
9132001f49Smrg   }
9232001f49Smrg
9332001f49Smrg   glXMakeCurrent(dpy, dstWin, Context);
9432001f49Smrg   glWindowPos2iARB(0, 0);
9532001f49Smrg   glDrawBuffer(GL_FRONT);
9632001f49Smrg   glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
9732001f49Smrg   glFlush();
9832001f49Smrg
9932001f49Smrg   free(image);
10032001f49Smrg}
10132001f49Smrg
10232001f49Smrg
10332001f49Smrgstatic void
10432001f49Smrgset_window_title(Display *dpy, Window win, const char *title)
10532001f49Smrg{
10632001f49Smrg   XSizeHints sizehints;
10732001f49Smrg   sizehints.flags = 0;
10832001f49Smrg   XSetStandardProperties(dpy, win, title, title,
10932001f49Smrg                          None, (char **)NULL, 0, &sizehints);
11032001f49Smrg}
11132001f49Smrg
11232001f49Smrg
11332001f49Smrgstatic Window
11432001f49Smrgmake_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
11532001f49Smrg{
11632001f49Smrg   int scrnum;
11732001f49Smrg   XSetWindowAttributes attr;
11832001f49Smrg   unsigned long mask;
11932001f49Smrg   Window root;
12032001f49Smrg   Window win;
12132001f49Smrg   int x = 0, y = 0;
12232001f49Smrg   char *name = NULL;
12332001f49Smrg
12432001f49Smrg   scrnum = DefaultScreen( dpy );
12532001f49Smrg   root = RootWindow( dpy, scrnum );
12632001f49Smrg
12732001f49Smrg   /* window attributes */
12832001f49Smrg   attr.background_pixel = 0;
12932001f49Smrg   attr.border_pixel = 0;
13032001f49Smrg   attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
13132001f49Smrg   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
13232001f49Smrg   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
13332001f49Smrg
13432001f49Smrg   win = XCreateWindow( dpy, root, x, y, width, height,
13532001f49Smrg		        0, visinfo->depth, InputOutput,
13632001f49Smrg		        visinfo->visual, mask, &attr );
13732001f49Smrg
13832001f49Smrg   /* set hints and properties */
13932001f49Smrg   {
14032001f49Smrg      XSizeHints sizehints;
14132001f49Smrg      sizehints.x = x;
14232001f49Smrg      sizehints.y = y;
14332001f49Smrg      sizehints.width  = width;
14432001f49Smrg      sizehints.height = height;
14532001f49Smrg      sizehints.flags = USSize | USPosition;
14632001f49Smrg      XSetNormalHints(dpy, win, &sizehints);
14732001f49Smrg      XSetStandardProperties(dpy, win, name, name,
14832001f49Smrg                              None, (char **)NULL, 0, &sizehints);
14932001f49Smrg   }
15032001f49Smrg
15132001f49Smrg   return win;
15232001f49Smrg}
15332001f49Smrg
15432001f49Smrg
15532001f49Smrgstatic void
15632001f49Smrgupdate_window_title(Display *dpy, Window win)
15732001f49Smrg{
15832001f49Smrg   char title[1000], *buf;
15932001f49Smrg
16032001f49Smrg   switch (Buffer) {
16132001f49Smrg   case Z_BUFFER:
16232001f49Smrg      buf = "Z";
16332001f49Smrg      break;
16432001f49Smrg   case STENCIL_BUFFER:
16532001f49Smrg      buf = "Stencil";
16632001f49Smrg      break;
16732001f49Smrg   case BACK_BUFFER:
16832001f49Smrg      buf = "Back";
16932001f49Smrg      break;
17032001f49Smrg   case FRONT_BUFFER:
17132001f49Smrg      buf = "Front";
17232001f49Smrg      break;
17332001f49Smrg   default:
17432001f49Smrg      buf = "";
17532001f49Smrg   }
17632001f49Smrg
17732001f49Smrg   sprintf(title, "glxsnoop window 0x%x (%s buffer)", (int) WindowID, buf);
17832001f49Smrg
17932001f49Smrg   set_window_title(dpy, win, title);
18032001f49Smrg}
18132001f49Smrg
18232001f49Smrg
18332001f49Smrgstatic void
18432001f49Smrgkeypress(Display *dpy, Window win, char key)
18532001f49Smrg{
18632001f49Smrg   switch (key) {
18732001f49Smrg   case 27:
18832001f49Smrg      /* escape */
18932001f49Smrg      exit(0);
19032001f49Smrg      break;
19132001f49Smrg   case 's':
19232001f49Smrg      Buffer = STENCIL_BUFFER;
19332001f49Smrg      break;
19432001f49Smrg   case 'z':
19532001f49Smrg      Buffer = Z_BUFFER;
19632001f49Smrg      break;
19732001f49Smrg   case 'f':
19832001f49Smrg      Buffer = FRONT_BUFFER;
19932001f49Smrg      break;
20032001f49Smrg   case 'b':
20132001f49Smrg      Buffer = BACK_BUFFER;
20232001f49Smrg      break;
20332001f49Smrg   default:
20432001f49Smrg      return;
20532001f49Smrg   }
20632001f49Smrg
20732001f49Smrg   update_window_title(dpy, win);
20832001f49Smrg   redraw(dpy, WindowID, win);
20932001f49Smrg}
21032001f49Smrg
21132001f49Smrg
21232001f49Smrgstatic void
21332001f49Smrgevent_loop(Display *dpy, Window win)
21432001f49Smrg{
21532001f49Smrg   XEvent event;
21632001f49Smrg
21732001f49Smrg   while (1) {
21832001f49Smrg      XNextEvent( dpy, &event );
21932001f49Smrg
22032001f49Smrg      switch (event.type) {
22132001f49Smrg      case Expose:
22232001f49Smrg         redraw(dpy, WindowID, win);
22332001f49Smrg         break;
22432001f49Smrg      case ConfigureNotify:
22532001f49Smrg         /*resize( event.xconfigure.width, event.xconfigure.height );*/
22632001f49Smrg         break;
22732001f49Smrg      case KeyPress:
22832001f49Smrg         {
22932001f49Smrg            char buffer[10];
23032001f49Smrg            int code;
23132001f49Smrg            code = XLookupKeysym(&event.xkey, 0);
23232001f49Smrg            if (code == XK_Left) {
23332001f49Smrg            }
23432001f49Smrg            else {
23532001f49Smrg               XLookupString(&event.xkey, buffer, sizeof(buffer),
23632001f49Smrg                             NULL, NULL);
23732001f49Smrg               keypress(dpy, win, buffer[0]);
23832001f49Smrg            }
23932001f49Smrg         }
24032001f49Smrg      default:
24132001f49Smrg         /* nothing */
24232001f49Smrg         ;
24332001f49Smrg      }
24432001f49Smrg   }
24532001f49Smrg}
24632001f49Smrg
24732001f49Smrg
24832001f49Smrgstatic VisualID
24932001f49Smrgget_window_visualid(Display *dpy, Window win)
25032001f49Smrg{
25132001f49Smrg   XWindowAttributes attr;
25232001f49Smrg
25332001f49Smrg   if (XGetWindowAttributes(dpy, win, &attr)) {
25432001f49Smrg      return attr.visual->visualid;
25532001f49Smrg   }
25632001f49Smrg   else {
25732001f49Smrg      return 0;
25832001f49Smrg   }
25932001f49Smrg}
26032001f49Smrg
26132001f49Smrg
26232001f49Smrgstatic void
26332001f49Smrgget_window_size(Display *dpy, Window win, int *w, int *h)
26432001f49Smrg{
26532001f49Smrg   XWindowAttributes attr;
26632001f49Smrg
26732001f49Smrg   if (XGetWindowAttributes(dpy, win, &attr)) {
26832001f49Smrg      *w = attr.width;
26932001f49Smrg      *h = attr.height;
27032001f49Smrg   }
27132001f49Smrg   else {
27232001f49Smrg      *w = *h = 0;
27332001f49Smrg   }
27432001f49Smrg}
27532001f49Smrg
27632001f49Smrg
27732001f49Smrgstatic XVisualInfo *
27832001f49Smrgvisualid_to_visualinfo(Display *dpy, VisualID vid)
27932001f49Smrg{
28032001f49Smrg   XVisualInfo *vinfo, templ;
28132001f49Smrg   long mask;
28232001f49Smrg   int n;
28332001f49Smrg
28432001f49Smrg   templ.visualid = vid;
28532001f49Smrg   mask = VisualIDMask;
28632001f49Smrg
28732001f49Smrg   vinfo = XGetVisualInfo(dpy, mask, &templ, &n);
28832001f49Smrg   return vinfo;
28932001f49Smrg}
29032001f49Smrg
29132001f49Smrg
29232001f49Smrgstatic void
29332001f49Smrgkey_usage(void)
29432001f49Smrg{
29532001f49Smrg   printf("Keyboard:\n");
29632001f49Smrg   printf("  z - display Z buffer\n");
29732001f49Smrg   printf("  s - display stencil buffer\n");
29832001f49Smrg   printf("  f - display front color buffer\n");
29932001f49Smrg   printf("  b - display back buffer\n");
30032001f49Smrg}
30132001f49Smrg
30232001f49Smrg
30332001f49Smrgstatic void
30432001f49Smrgusage(void)
30532001f49Smrg{
30632001f49Smrg   printf("Usage: glxsnoop [-display dpy] windowID\n");
30732001f49Smrg   key_usage();
30832001f49Smrg}
30932001f49Smrg
31032001f49Smrg
31132001f49Smrgstatic void
31232001f49Smrgparse_opts(int argc, char *argv[])
31332001f49Smrg{
31432001f49Smrg   int i;
31532001f49Smrg
31632001f49Smrg   for (i = 1; i < argc; i++) {
31732001f49Smrg      if (strcmp(argv[i], "-h") == 0) {
31832001f49Smrg         usage();
31932001f49Smrg         exit(0);
32032001f49Smrg      }
32132001f49Smrg      else if (strcmp(argv[i], "-display") == 0) {
32232001f49Smrg         DisplayName = argv[i + 1];
32332001f49Smrg         i++;
32432001f49Smrg      }
32532001f49Smrg      else {
32632001f49Smrg         if (argv[i][0] == '0' && argv[i][1] == 'x') {
32732001f49Smrg            /* hex */
32832001f49Smrg            WindowID = strtol(argv[i], NULL, 16);
32932001f49Smrg         }
33032001f49Smrg         else {
33132001f49Smrg            WindowID = atoi(argv[i]);
33232001f49Smrg         }
33332001f49Smrg         break;
33432001f49Smrg      }
33532001f49Smrg   }
33632001f49Smrg
33732001f49Smrg   if (!WindowID) {
33832001f49Smrg      usage();
33932001f49Smrg      exit(0);
34032001f49Smrg   }
34132001f49Smrg}
34232001f49Smrg
34332001f49Smrg
34432001f49Smrgint
34532001f49Smrgmain( int argc, char *argv[] )
34632001f49Smrg{
34732001f49Smrg   Display *dpy;
34832001f49Smrg   VisualID vid;
34932001f49Smrg   XVisualInfo *visinfo;
35032001f49Smrg   Window win;
35132001f49Smrg
35232001f49Smrg   parse_opts(argc, argv);
35332001f49Smrg
35432001f49Smrg   key_usage();
35532001f49Smrg
35632001f49Smrg   dpy = XOpenDisplay(DisplayName);
35732001f49Smrg
35832001f49Smrg   /* find the VisualID for the named window */
35932001f49Smrg   vid = get_window_visualid(dpy, WindowID);
36032001f49Smrg   get_window_size(dpy, WindowID, &Width, &Height);
36132001f49Smrg
36232001f49Smrg   visinfo = visualid_to_visualinfo(dpy, vid);
36332001f49Smrg
36432001f49Smrg   Context = glXCreateContext( dpy, visinfo, NULL, True );
36532001f49Smrg   if (!Context) {
36632001f49Smrg      printf("Error: glXCreateContext failed\n");
36732001f49Smrg      exit(1);
36832001f49Smrg   }
36932001f49Smrg
37032001f49Smrg   win = make_gl_window(dpy, visinfo, Width, Height);
37132001f49Smrg   XMapWindow(dpy, win);
37232001f49Smrg   update_window_title(dpy, win);
37332001f49Smrg
37432001f49Smrg   event_loop( dpy, win );
37532001f49Smrg
37632001f49Smrg   return 0;
37732001f49Smrg}
378