blob: 2e951345b5899dbdb58c556819adc152c570afc7 [file] [log] [blame]
/**
* 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 <GL/gl.h>
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/keysym.h>
#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;
}