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