From f1104b079f7992f60925fc6c08544cb8ab3cade4 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 11 Oct 2007 16:39:02 -0600 Subject: [PATCH] New glxsnoop demo to display another window's z/stencil/back buffer. --- progs/xdemos/Makefile | 1 + progs/xdemos/glxsnoop.c | 377 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 378 insertions(+) create mode 100644 progs/xdemos/glxsnoop.c diff --git a/progs/xdemos/Makefile b/progs/xdemos/Makefile index c585026ad38..4c4ecac38ac 100644 --- a/progs/xdemos/Makefile +++ b/progs/xdemos/Makefile @@ -17,6 +17,7 @@ PROGS = glthreads \ glxinfo \ glxpixmap \ glxpbdemo \ + glxsnoop \ glxswapcontrol \ manywin \ offset \ diff --git a/progs/xdemos/glxsnoop.c b/progs/xdemos/glxsnoop.c new file mode 100644 index 00000000000..2e951345b58 --- /dev/null +++ b/progs/xdemos/glxsnoop.c @@ -0,0 +1,377 @@ +/** + * Display/snoop the z/stencil/back/front buffers of another app's window. + * Also, an example of the need for shared ancillary renderbuffers. + * + * Hint: use 'xwininfo' to get a window's ID. + * + * Brian Paul + * 11 Oct 2007 + */ + +#define GL_GLEXT_PROTOTYPES + +#include +#include +#include +#include +#include +#include + + +#define Z_BUFFER 1 +#define STENCIL_BUFFER 2 +#define BACK_BUFFER 3 +#define FRONT_BUFFER 4 + + +static int Buffer = BACK_BUFFER; +static int WindowID = 0; +static const char *DisplayName = NULL; +static GLXContext Context = 0; +static int Width, Height; + + +/** + * Grab the z/stencil/back/front image from the srcWin and display it + * (possibly converted to grayscale) in the dstWin. + */ +static void +redraw(Display *dpy, Window srcWin, Window dstWin ) +{ + GLubyte *image = malloc(Width * Height * 4); + + glXMakeCurrent(dpy, srcWin, Context); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + if (Buffer == BACK_BUFFER) { + glReadBuffer(GL_BACK); + glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image); + } + else if (Buffer == FRONT_BUFFER) { + glReadBuffer(GL_FRONT); + glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image); + } + else if (Buffer == Z_BUFFER) { + GLfloat *z = malloc(Width * Height * sizeof(GLfloat)); + int i; + glReadPixels(0, 0, Width, Height, GL_DEPTH_COMPONENT, GL_FLOAT, z); + for (i = 0; i < Width * Height; i++) { + image[i*4+0] = + image[i*4+1] = + image[i*4+2] = (GLint) (255.0 * z[i]); + image[i*4+3] = 255; + } + free(z); + } + else if (Buffer == STENCIL_BUFFER) { + GLubyte *sten = malloc(Width * Height * sizeof(GLubyte)); + int i, min = 100, max = -1; + float step; + int sz; + glGetIntegerv(GL_STENCIL_BITS, &sz); + glReadPixels(0, 0, Width, Height, + GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, sten); + /* find min/max for converting stencil to grayscale */ + for (i = 0; i < Width * Height; i++) { + if (sten[i] < min) + min = sten[i]; + if (sten[i] > max) + max = sten[i]; + } + if (min == max) + step = 0; + else + step = 255.0 / (float) (max - min); + for (i = 0; i < Width * Height; i++) { + image[i*4+0] = + image[i*4+1] = + image[i*4+2] = (GLint) ((sten[i] - min) * step); + image[i*4+3] = 255; + } + free(sten); + } + + glXMakeCurrent(dpy, dstWin, Context); + glWindowPos2iARB(0, 0); + glDrawBuffer(GL_FRONT); + glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image); + glFlush(); + + free(image); +} + + +static void +set_window_title(Display *dpy, Window win, const char *title) +{ + XSizeHints sizehints; + sizehints.flags = 0; + XSetStandardProperties(dpy, win, title, title, + None, (char **)NULL, 0, &sizehints); +} + + +static Window +make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height) +{ + int scrnum; + XSetWindowAttributes attr; + unsigned long mask; + Window root; + Window win; + int x = 0, y = 0; + char *name = NULL; + + scrnum = DefaultScreen( dpy ); + root = RootWindow( dpy, scrnum ); + + /* window attributes */ + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + win = XCreateWindow( dpy, root, x, y, width, height, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr ); + + /* set hints and properties */ + { + XSizeHints sizehints; + sizehints.x = x; + sizehints.y = y; + sizehints.width = width; + sizehints.height = height; + sizehints.flags = USSize | USPosition; + XSetNormalHints(dpy, win, &sizehints); + XSetStandardProperties(dpy, win, name, name, + None, (char **)NULL, 0, &sizehints); + } + + return win; +} + + +static void +update_window_title(Display *dpy, Window win) +{ + char title[1000], *buf; + + switch (Buffer) { + case Z_BUFFER: + buf = "Z"; + break; + case STENCIL_BUFFER: + buf = "Stencil"; + break; + case BACK_BUFFER: + buf = "Back"; + break; + case FRONT_BUFFER: + buf = "Front"; + break; + default: + buf = ""; + } + + sprintf(title, "glxsnoop window 0x%x (%s buffer)", (int) WindowID, buf); + + set_window_title(dpy, win, title); +} + + +static void +keypress(Display *dpy, Window win, char key) +{ + switch (key) { + case 27: + /* escape */ + exit(0); + break; + case 's': + Buffer = STENCIL_BUFFER; + break; + case 'z': + Buffer = Z_BUFFER; + break; + case 'f': + Buffer = FRONT_BUFFER; + break; + case 'b': + Buffer = BACK_BUFFER; + break; + default: + return; + } + + update_window_title(dpy, win); + redraw(dpy, WindowID, win); +} + + +static void +event_loop(Display *dpy, Window win) +{ + XEvent event; + + while (1) { + XNextEvent( dpy, &event ); + + switch (event.type) { + case Expose: + redraw(dpy, WindowID, win); + break; + case ConfigureNotify: + /*resize( event.xconfigure.width, event.xconfigure.height );*/ + break; + case KeyPress: + { + char buffer[10]; + int r, code; + code = XLookupKeysym(&event.xkey, 0); + if (code == XK_Left) { + } + else { + r = XLookupString(&event.xkey, buffer, sizeof(buffer), + NULL, NULL); + keypress(dpy, win, buffer[0]); + } + } + default: + /* nothing */ + ; + } + } +} + + +static VisualID +get_window_visualid(Display *dpy, Window win) +{ + XWindowAttributes attr; + + if (XGetWindowAttributes(dpy, win, &attr)) { + return attr.visual->visualid; + } + else { + return 0; + } +} + + +static void +get_window_size(Display *dpy, Window win, int *w, int *h) +{ + XWindowAttributes attr; + + if (XGetWindowAttributes(dpy, win, &attr)) { + *w = attr.width; + *h = attr.height; + } + else { + *w = *h = 0; + } +} + + +static XVisualInfo * +visualid_to_visualinfo(Display *dpy, VisualID vid) +{ + XVisualInfo *vinfo, templ; + long mask; + int n; + + templ.visualid = vid; + mask = VisualIDMask; + + vinfo = XGetVisualInfo(dpy, mask, &templ, &n); + return vinfo; +} + + +static void +key_usage(void) +{ + printf("Keyboard:\n"); + printf(" z - display Z buffer\n"); + printf(" s - display stencil buffer\n"); + printf(" f - display front color buffer\n"); + printf(" b - display back buffer\n"); +} + + +static void +usage(void) +{ + printf("Usage: glxsnoop [-display dpy] windowID\n"); + key_usage(); +} + + +static void +parse_opts(int argc, char *argv[]) +{ + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0) { + usage(); + exit(0); + } + else if (strcmp(argv[i], "-display") == 0) { + DisplayName = argv[i + 1]; + i++; + } + else { + if (argv[i][0] == '0' && argv[i][1] == 'x') { + /* hex */ + WindowID = strtol(argv[i], NULL, 16); + } + else { + WindowID = atoi(argv[i]); + } + break; + } + } + + if (!WindowID) { + usage(); + exit(0); + } +} + + +int +main( int argc, char *argv[] ) +{ + Display *dpy; + VisualID vid; + XVisualInfo *visinfo; + Window win; + + parse_opts(argc, argv); + + key_usage(); + + dpy = XOpenDisplay(DisplayName); + + /* find the VisualID for the named window */ + vid = get_window_visualid(dpy, WindowID); + get_window_size(dpy, WindowID, &Width, &Height); + + visinfo = visualid_to_visualinfo(dpy, vid); + + Context = glXCreateContext( dpy, visinfo, NULL, True ); + if (!Context) { + printf("Error: glXCreateContext failed\n"); + exit(1); + } + + win = make_gl_window(dpy, visinfo, Width, Height); + XMapWindow(dpy, win); + update_window_title(dpy, win); + + event_loop( dpy, win ); + + return 0; +} -- 2.30.2