diff options
Diffstat (limited to 'progs/xdemos')
-rw-r--r-- | progs/xdemos/.gitignore | 25 | ||||
-rw-r--r-- | progs/xdemos/Makefile | 14 | ||||
-rw-r--r-- | progs/xdemos/corender.c | 400 | ||||
-rw-r--r-- | progs/xdemos/glthreads.c | 25 | ||||
-rw-r--r-- | progs/xdemos/glxgears.c | 196 | ||||
-rw-r--r-- | progs/xdemos/glxgears_pixmap.c (renamed from progs/xdemos/glxgears2.c) | 179 | ||||
-rw-r--r-- | progs/xdemos/glxinfo.c | 285 | ||||
-rw-r--r-- | progs/xdemos/glxsnoop.c | 377 | ||||
-rw-r--r-- | progs/xdemos/glxswapcontrol.c | 5 | ||||
-rw-r--r-- | progs/xdemos/ipc.c | 264 | ||||
-rw-r--r-- | progs/xdemos/ipc.h | 16 | ||||
-rw-r--r-- | progs/xdemos/offset.c | 32 | ||||
-rw-r--r-- | progs/xdemos/pbutil.c | 72 | ||||
-rw-r--r-- | progs/xdemos/pbutil.h | 3 | ||||
-rw-r--r-- | progs/xdemos/sharedtex.c | 324 | ||||
-rw-r--r-- | progs/xdemos/texture_from_pixmap.c | 396 |
16 files changed, 2375 insertions, 238 deletions
diff --git a/progs/xdemos/.gitignore b/progs/xdemos/.gitignore new file mode 100644 index 00000000000..868249db884 --- /dev/null +++ b/progs/xdemos/.gitignore @@ -0,0 +1,25 @@ +corender +glthreads +glxcontexts +glxdemo +glxgears +glxgears_fbconfig +glxgears_pixmap +glxheads +glxinfo +glxpbdemo +glxpixmap +glxsnoop +glxswapcontrol +manywin +offset +overlay +pbdemo +pbinfo +sharedtex +texture_from_pixmap +wincopy +xdemo +xfont +xrotfontdemo +yuvrect_client diff --git a/progs/xdemos/Makefile b/progs/xdemos/Makefile index 1803633ef11..c90159bd38c 100644 --- a/progs/xdemos/Makefile +++ b/progs/xdemos/Makefile @@ -11,21 +11,26 @@ LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) LIBS = -L$(TOP)/$(LIB_DIR) -l$(GL_LIB) $(APP_LIB_DEPS) PROGS = \ + corender \ glthreads \ glxdemo \ glxgears \ glxgears_fbconfig \ + glxgears_pixmap \ glxcontexts \ glxheads \ glxinfo \ glxpixmap \ glxpbdemo \ + glxsnoop \ glxswapcontrol \ manywin \ offset \ overlay \ pbinfo \ pbdemo \ + sharedtex \ + texture_from_pixmap \ wincopy \ xfont \ xrotfontdemo @@ -91,6 +96,15 @@ xuserotfont.o: xuserotfont.c xuserotfont.h xrotfontdemo.o: xrotfontdemo.c xuserotfont.h $(CC) -c -I. -I$(INCDIR) $(X11_INCLUDES) $(CFLAGS) xrotfontdemo.c +corender: corender.o ipc.o + $(CC) $(CFLAGS) corender.o ipc.o $(LIBS) -o $@ + +corender.o: corender.c ipc.h + $(CC) -c -I. -I$(INCDIR) $(X11_INCLUDES) $(CFLAGS) corender.c + +ipc.o: ipc.c ipc.h + $(CC) -c -I. -I$(INCDIR) $(X11_INCLUDES) $(CFLAGS) ipc.c + yuvrect_client: yuvrect_client.c $(CC) -I$(INCDIR) $(X11_INCLUDES) $(CFLAGS) $< $(LDFLAGS) $(LIBS) -l$(GLU_LIB) -o $@ diff --git a/progs/xdemos/corender.c b/progs/xdemos/corender.c new file mode 100644 index 00000000000..f2b8145e52b --- /dev/null +++ b/progs/xdemos/corender.c @@ -0,0 +1,400 @@ +/** + * Example of cooperative rendering into one window by two processes. + * The first instance of the program creates the GLX window. + * The second instance of the program gets the window ID from the first + * and draws into it. + * Socket IPC is used for synchronization. + * + * Usage: + * 1. run 'corender &' + * 2. run 'corender 2' (any arg will do) + * + * Brian Paul + * 11 Oct 2007 + */ + + +#include <GL/gl.h> +#include <GL/glx.h> +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <X11/keysym.h> +#include <unistd.h> +#include "ipc.h" + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +static int MyID = 0; /* 0 or 1 */ +static int WindowID = 0; +static GLXContext Context = 0; +static int Width = 700, Height = 350; +static int Rot = 0; +static int Sock = 0; + +static GLfloat Red[4] = {1.0, 0.2, 0.2, 1.0}; +static GLfloat Blue[4] = {0.2, 0.2, 1.0, 1.0}; + +static int Sync = 1; /** synchronized rendering? */ + + +static void +setup_ipc(void) +{ + int k, port = 10001; + + if (MyID == 0) { + /* I'm the first one, wait for connection from second */ + k = CreatePort(&port); + assert(k != -1); + + printf("Waiting for connection from another 'corender'\n"); + Sock = AcceptConnection(k); + + printf("Got connection, sending windowID\n"); + + /* send windowID */ + SendData(Sock, &WindowID, sizeof(WindowID)); + } + else { + /* I'm the second one, connect to first */ + char hostname[1000]; + + MyHostName(hostname, 1000); + Sock = Connect(hostname, port); + assert(Sock != -1); + + /* get windowID */ + ReceiveData(Sock, &WindowID, sizeof(WindowID)); + printf("Contacted first 'corender', getting WindowID\n"); + } +} + + + +/** from GLUT */ +static void +doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings) +{ + int i, j; + GLfloat theta, phi, theta1; + GLfloat cosTheta, sinTheta; + GLfloat cosTheta1, sinTheta1; + GLfloat ringDelta, sideDelta; + + ringDelta = 2.0 * M_PI / rings; + sideDelta = 2.0 * M_PI / nsides; + + theta = 0.0; + cosTheta = 1.0; + sinTheta = 0.0; + for (i = rings - 1; i >= 0; i--) { + theta1 = theta + ringDelta; + cosTheta1 = cos(theta1); + sinTheta1 = sin(theta1); + glBegin(GL_QUAD_STRIP); + phi = 0.0; + for (j = nsides; j >= 0; j--) { + GLfloat cosPhi, sinPhi, dist; + + phi += sideDelta; + cosPhi = cos(phi); + sinPhi = sin(phi); + dist = R + r * cosPhi; + + glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); + glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi); + glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); + glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi); + } + glEnd(); + theta = theta1; + cosTheta = cosTheta1; + sinTheta = sinTheta1; + } +} + + +static void +redraw(Display *dpy) +{ + int dbg = 0; + + glXMakeCurrent(dpy, WindowID, Context); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + glClearColor(0.5, 0.5, 0.5, 0.0); + + if (MyID == 0) { + /* First process */ + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glTranslatef(-1, 0, 0); + glRotatef(Rot, 1, 0, 0); + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red); + doughnut(0.5, 2.0, 20, 30); + glPopMatrix(); + + glFinish(); + if (!Sync) { + usleep(1000*10); + } + + /* signal second process to render */ + if (Sync) { + int code = 1; + if (dbg) printf("0: send signal\n"); + SendData(Sock, &code, sizeof(code)); + SendData(Sock, &Rot, sizeof(Rot)); + } + + /* wait for second process to finish rendering */ + if (Sync) { + int code = 0; + if (dbg) printf("0: wait signal\n"); + ReceiveData(Sock, &code, sizeof(code)); + if (dbg) printf("0: got signal\n"); + assert(code == 2); + } + + } + else { + /* Second process */ + + /* wait for first process's signal for me to render */ + if (Sync) { + int code = 0; + if (dbg) printf("1: wait signal\n"); + ReceiveData(Sock, &code, sizeof(code)); + ReceiveData(Sock, &Rot, sizeof(Rot)); + + if (dbg) printf("1: got signal\n"); + assert(code == 1); + } + + /* XXX this clear should not be here, but for some reason, it + * makes things _mostly_ work correctly w/ NVIDIA's driver. + * There's only occasional glitches. + * Without this glClear(), depth buffer for the second process + * is pretty much broken. + */ + //glClear(GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glTranslatef(1, 0, 0); + glRotatef(Rot + 90 , 1, 0, 0); + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue); + doughnut(0.5, 2.0, 20, 30); + glPopMatrix(); + glFinish(); + + glXSwapBuffers(dpy, WindowID); + usleep(1000*10); + + /* signal first process that I'm done rendering */ + if (Sync) { + int code = 2; + if (dbg) printf("1: send signal\n"); + SendData(Sock, &code, sizeof(code)); + } + } +} + + +static void +resize(Display *dpy, int width, int height) +{ + float ar = (float) width / height; + + glXMakeCurrent(dpy, WindowID, Context); + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-ar, ar, 1.0, -1.0, 5.0, 200.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -15); + + Width = width; + Height = height; +} + + + +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 +set_event_mask(Display *dpy, Window win) +{ + XSetWindowAttributes attr; + attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + XChangeWindowAttributes(dpy, win, CWEventMask, &attr); +} + + +static void +event_loop(Display *dpy) +{ + while (1) { + while (XPending(dpy) > 0) { + XEvent event; + XNextEvent(dpy, &event); + + switch (event.type) { + case Expose: + redraw(dpy); + break; + case ConfigureNotify: + resize(dpy, 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); + if (buffer[0] == 27) { + exit(0); + } + } + } + default: + /* nothing */ + ; + } + } + + if (MyID == 0 || !Sync) + Rot += 1; + redraw(dpy); + } +} + + +static XVisualInfo * +choose_visual(Display *dpy) +{ + int attribs[] = { GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None }; + int scrnum = DefaultScreen( dpy ); + return glXChooseVisual(dpy, scrnum, attribs); +} + + +static void +parse_opts(int argc, char *argv[]) +{ + if (argc > 1) { + MyID = 1; + } +} + + +int +main( int argc, char *argv[] ) +{ + Display *dpy; + XVisualInfo *visinfo; + + parse_opts(argc, argv); + + dpy = XOpenDisplay(NULL); + + visinfo = choose_visual(dpy); + + Context = glXCreateContext( dpy, visinfo, NULL, True ); + if (!Context) { + printf("Error: glXCreateContext failed\n"); + exit(1); + } + + if (MyID == 0) { + WindowID = make_gl_window(dpy, visinfo, Width, Height); + set_window_title(dpy, WindowID, "corender"); + XMapWindow(dpy, WindowID); + /*printf("WindowID 0x%x\n", (int) WindowID);*/ + } + + /* do ipc hand-shake here */ + setup_ipc(); + assert(Sock); + assert(WindowID); + + if (MyID == 1) { + set_event_mask(dpy, WindowID); + } + + resize(dpy, Width, Height); + + event_loop(dpy); + + return 0; +} diff --git a/progs/xdemos/glthreads.c b/progs/xdemos/glthreads.c index 6c7029b6ecf..4f87ee75d40 100644 --- a/progs/xdemos/glthreads.c +++ b/progs/xdemos/glthreads.c @@ -24,6 +24,7 @@ * This program tests GLX thread safety. * Command line options: * -p Open a display connection for each thread + * -l Enable application-side locking * -n <num threads> Number of threads to create (default is 2) * -display <display name> Specify X display (default is :0.0) * @@ -405,6 +406,19 @@ clean_up(void) } +static void +usage(void) +{ + printf("glthreads: test of GL thread safety (any key = exit)\n"); + printf("Usage:\n"); + printf(" glthreads [options]\n"); + printf("Options:\n"); + printf(" -display DISPLAYNAME Specify display string\n"); + printf(" -n NUMTHREADS Number of threads to create\n"); + printf(" -p Use a separate display connection for each thread\n"); + printf(" -l Use application-side locking\n"); +} + int main(int argc, char *argv[]) @@ -416,9 +430,7 @@ main(int argc, char *argv[]) Status threadStat; if (argc == 1) { - printf("glthreads: test of GL thread safety (any key = exit)\n"); - printf("Usage:\n"); - printf(" glthreads [-display dpyName] [-n numthreads]\n"); + usage(); } else { int i; @@ -442,13 +454,14 @@ main(int argc, char *argv[]) i++; } else { - fprintf(stderr, "glthreads: unexpected flag: %s\n", argv[i]); + usage(); + exit(1); } } } if (Locking) - printf("glthreads: Using explict locks around Xlib calls.\n"); + printf("glthreads: Using explicit locks around Xlib calls.\n"); else printf("glthreads: No explict locking.\n"); @@ -505,7 +518,7 @@ main(int argc, char *argv[]) for (i = 0; i < numThreads; i++) { pthread_create(&WinThreads[i].Thread, NULL, thread_function, (void*) &WinThreads[i]); - printf("glthreads: Created thread %p\n", WinThreads[i].Thread); + printf("glthreads: Created thread %p\n", (void *) WinThreads[i].Thread); } if (MultiDisplays) diff --git a/progs/xdemos/glxgears.c b/progs/xdemos/glxgears.c index 75d63e51a2e..c98c3157b5d 100644 --- a/progs/xdemos/glxgears.c +++ b/progs/xdemos/glxgears.c @@ -88,12 +88,18 @@ current_time(void) #endif +/** Event handler results: */ +#define NOP 0 +#define EXIT 1 +#define DRAW 2 + static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; static GLint gear1, gear2, gear3; static GLfloat angle = 0.0; static GLboolean fullscreen = GL_FALSE; /* Create a single fullscreen window */ static GLboolean stereo = GL_FALSE; /* Enable stereo. */ +static GLboolean animate = GL_TRUE; /* Animation */ static GLfloat eyesep = 5.0; /* Eye separation. */ static GLfloat fix_point = 40.0; /* Fixation point distance. */ static GLfloat left, right, asp; /* Stereo frustum params. */ @@ -239,7 +245,7 @@ gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, static void -do_draw(void) +draw(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -269,8 +275,9 @@ do_draw(void) glPopMatrix(); } + static void -draw(void) +draw_gears(void) { if (stereo) { /* First left eye. */ @@ -284,7 +291,7 @@ draw(void) glPushMatrix(); glTranslated(+0.5 * eyesep, 0.0, 0.0); - do_draw(); + draw(); glPopMatrix(); /* Then right eye. */ @@ -298,10 +305,50 @@ draw(void) glPushMatrix(); glTranslated(-0.5 * eyesep, 0.0, 0.0); - do_draw(); + draw(); glPopMatrix(); - } else - do_draw(); + } + else { + draw(); + } +} + + +/** Draw single frame, do SwapBuffers, compute FPS */ +static void +draw_frame(Display *dpy, Window win) +{ + static int frames = 0; + static double tRot0 = -1.0, tRate0 = -1.0; + double dt, t = current_time(); + + if (tRot0 < 0.0) + tRot0 = t; + dt = t - tRot0; + tRot0 = t; + + if (animate) { + /* advance rotation for next frame */ + angle += 70.0 * dt; /* 70 degrees per second */ + if (angle > 3600.0) + angle -= 3600.0; + } + + draw_gears(); + glXSwapBuffers(dpy, win); + + frames++; + + if (tRate0 < 0.0) + tRate0 = t; + if (t - tRate0 >= 5.0) { + GLfloat seconds = t - tRate0; + GLfloat fps = frames / seconds; + printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds, + fps); + tRate0 = t; + frames = 0; + } } @@ -319,7 +366,8 @@ reshape(int width, int height) left = -5.0 * ((w - 0.5 * eyesep) / fix_point); right = 5.0 * ((w + 0.5 * eyesep) / fix_point); - } else { + } + else { GLfloat h = (GLfloat) height / (GLfloat) width; glMatrixMode(GL_PROJECTION); @@ -430,10 +478,11 @@ make_window( Display *dpy, const char *name, attr.border_pixel = 0; attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone); attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; + /* XXX this is a bad way to get a borderless window! */ attr.override_redirect = fullscreen; mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect; - win = XCreateWindow( dpy, root, 0, 0, width, height, + win = XCreateWindow( dpy, root, x, y, width, height, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr ); @@ -463,79 +512,70 @@ make_window( Display *dpy, const char *name, } +/** + * Handle one X event. + * \return NOP, EXIT or DRAW + */ +static int +handle_event(Display *dpy, Window win, XEvent *event) +{ + switch (event->type) { + case Expose: + return DRAW; + case ConfigureNotify: + reshape(event->xconfigure.width, event->xconfigure.height); + break; + case KeyPress: + { + char buffer[10]; + int r, code; + code = XLookupKeysym(&event->xkey, 0); + if (code == XK_Left) { + view_roty += 5.0; + } + else if (code == XK_Right) { + view_roty -= 5.0; + } + else if (code == XK_Up) { + view_rotx += 5.0; + } + else if (code == XK_Down) { + view_rotx -= 5.0; + } + else { + r = XLookupString(&event->xkey, buffer, sizeof(buffer), + NULL, NULL); + if (buffer[0] == 27) { + /* escape */ + return EXIT; + } + else if (buffer[0] == 'a' || buffer[0] == 'A') { + animate = !animate; + } + } + return DRAW; + } + } + return NOP; +} + + static void event_loop(Display *dpy, Window win) { while (1) { - while (XPending(dpy) > 0) { + int op; + while (!animate || XPending(dpy) > 0) { XEvent event; XNextEvent(dpy, &event); - switch (event.type) { - case Expose: - /* we'll redraw below */ - break; - case ConfigureNotify: - reshape(event.xconfigure.width, event.xconfigure.height); - break; - case KeyPress: - { - char buffer[10]; - int r, code; - code = XLookupKeysym(&event.xkey, 0); - if (code == XK_Left) { - view_roty += 5.0; - } - else if (code == XK_Right) { - view_roty -= 5.0; - } - else if (code == XK_Up) { - view_rotx += 5.0; - } - else if (code == XK_Down) { - view_rotx -= 5.0; - } - else { - r = XLookupString(&event.xkey, buffer, sizeof(buffer), - NULL, NULL); - if (buffer[0] == 27) { - /* escape */ - return; - } - } - } - } + op = handle_event(dpy, win, &event); + if (op == EXIT) + return; + else if (op == DRAW) + break; } - { - static int frames = 0; - static double tRot0 = -1.0, tRate0 = -1.0; - double dt, t = current_time(); - if (tRot0 < 0.0) - tRot0 = t; - dt = t - tRot0; - tRot0 = t; - - /* advance rotation for next frame */ - angle += 70.0 * dt; /* 70 degrees per second */ - if (angle > 3600.0) - angle -= 3600.0; - - draw(); - glXSwapBuffers(dpy, win); - - frames++; - - if (tRate0 < 0.0) - tRate0 = t; - if (t - tRate0 >= 5.0) { - GLfloat seconds = t - tRate0; - GLfloat fps = frames / seconds; - printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds, - fps); - tRate0 = t; - frames = 0; - } - } + draw_frame(dpy, win); } } @@ -548,13 +588,15 @@ usage(void) printf(" -stereo run in stereo mode\n"); printf(" -fullscreen run in fullscreen mode\n"); printf(" -info display OpenGL renderer info\n"); + printf(" -geometry WxH+X+Y window geometry\n"); } int main(int argc, char *argv[]) { - const int winWidth = 300, winHeight = 300; + unsigned int winWidth = 300, winHeight = 300; + int x = 0, y = 0; Display *dpy; Window win; GLXContext ctx; @@ -576,6 +618,10 @@ main(int argc, char *argv[]) else if (strcmp(argv[i], "-fullscreen") == 0) { fullscreen = GL_TRUE; } + else if (i < argc-1 && strcmp(argv[i], "-geometry") == 0) { + XParseGeometry(argv[i+1], &x, &y, &winWidth, &winHeight); + i++; + } else { usage(); return -1; @@ -589,7 +635,7 @@ main(int argc, char *argv[]) return -1; } - make_window(dpy, "glxgears", 0, 0, winWidth, winHeight, &win, &ctx); + make_window(dpy, "glxgears", x, y, winWidth, winHeight, &win, &ctx); XMapWindow(dpy, win); glXMakeCurrent(dpy, win, ctx); diff --git a/progs/xdemos/glxgears2.c b/progs/xdemos/glxgears_pixmap.c index 5de5601240e..661d130e41c 100644 --- a/progs/xdemos/glxgears2.c +++ b/progs/xdemos/glxgears_pixmap.c @@ -1,6 +1,7 @@ /* * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. - * + * Copyright (C) 2008 Red Hat, Inc All Rights Reserved. + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation @@ -19,16 +20,22 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* - * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT) - * Port by Brian Paul 23 March 2001 +/** + * \file glxgears_pixmap.c + * Yet-another-version of gears. Originally ported to GLX by Brian Paul on + * 23 March 2001. Modified to use fbconfigs by Ian Romanick on 10 Feb 2004. * * Command line options: * -info print GL implementation information * + * \author Brian Paul + * \author Ian Romanick <[email protected]> + * \author Kristian Hoegsberg <[email protected]> */ +#define GLX_GLXEXT_PROTOTYPES + #include <math.h> #include <stdlib.h> #include <stdio.h> @@ -37,7 +44,9 @@ #include <X11/keysym.h> #include <GL/gl.h> #include <GL/glx.h> - +#include <GL/glxext.h> +#include <assert.h> +#include "pbutil.h" #define BENCHMARK @@ -83,7 +92,7 @@ current_time(void) static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; static GLint gear1, gear2, gear3; static GLfloat angle = 0.0; -static GLint WinWidth = 300, WinHeight = 300; + /* * @@ -256,33 +265,33 @@ draw(void) } +struct gears { + Window win; + GLXContext ctx; + Pixmap pixmap; + GLXPixmap glxpixmap; + GC gc; + int width, height; +}; + + /* new window size or exposure */ static void -reshape(int width, int height) +reshape(struct gears *gears, int width, int height) { - GLfloat h = (GLfloat) height / (GLfloat) width; - - glViewport(0, 0, (GLint) width, (GLint) height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0, 0.0, -40.0); - WinWidth = width; - WinHeight = height; + gears->width = width; + gears->height = height; } static void -init(void) +init(int width, int height) { static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 }; static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 }; static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 }; - - glClearColor(1, 0, 0, 0); + GLfloat h = (GLfloat) height / (GLfloat) width; glLightfv(GL_LIGHT0, GL_POSITION, pos); glEnable(GL_CULL_FACE); @@ -310,8 +319,15 @@ init(void) glEndList(); glEnable(GL_NORMALIZE); -} + glViewport(0, 0, (GLint) width, (GLint) height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -40.0); +} /* * Create an RGB, double-buffered window. @@ -319,43 +335,48 @@ init(void) */ static void make_window( Display *dpy, const char *name, - int x, int y, int width, int height, - Window *winRet, GLXContext *ctxRet) + int x, int y, int width, int height, struct gears *gears) { - int attrib[] = { GLX_RGBA, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 1, + int attrib[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, GL_FALSE, + GLX_DEPTH_SIZE, 1, None }; + GLXFBConfig * fbconfig; + int num_configs; int scrnum; XSetWindowAttributes attr; unsigned long mask; Window root; - Window win; - GLXContext ctx; XVisualInfo *visinfo; + gears->width = width; + gears->height = height; + scrnum = DefaultScreen( dpy ); root = RootWindow( dpy, scrnum ); - visinfo = glXChooseVisual( dpy, scrnum, attrib ); - if (!visinfo) { + fbconfig = glXChooseFBConfig(dpy, scrnum, attrib, & num_configs); + if (fbconfig == NULL) { printf("Error: couldn't get an RGB, Double-buffered visual\n"); exit(1); } /* window attributes */ + visinfo = glXGetVisualFromFBConfig(dpy, fbconfig[0]); + assert(visinfo != NULL); 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, 0, 0, width, height, - 0, visinfo->depth, InputOutput, - visinfo->visual, mask, &attr ); + gears->win = XCreateWindow( dpy, root, 0, 0, width, height, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr ); /* set hints and properties */ { @@ -365,27 +386,42 @@ make_window( Display *dpy, const char *name, sizehints.width = width; sizehints.height = height; sizehints.flags = USSize | USPosition; - XSetNormalHints(dpy, win, &sizehints); - XSetStandardProperties(dpy, win, name, name, + XSetNormalHints(dpy, gears->win, &sizehints); + XSetStandardProperties(dpy, gears->win, name, name, None, (char **)NULL, 0, &sizehints); } - ctx = glXCreateContext( dpy, visinfo, NULL, True ); - if (!ctx) { - printf("Error: glXCreateContext failed\n"); - exit(1); + gears->gc = XCreateGC(dpy, gears->win, 0, NULL); + + gears->pixmap = XCreatePixmap(dpy, gears->win, + width, height, visinfo->depth); + if (!gears->pixmap) { + printf("Error: XCreatePixmap failed\n"); + exit(-1); + } + + gears->glxpixmap = glXCreatePixmap(dpy, fbconfig[0], gears->pixmap, NULL); + if (!gears->glxpixmap) { + printf("Error: glXCreatePixmap failed\n"); + exit(-1); } - XFree(visinfo); + gears->ctx = glXCreateNewContext(dpy, fbconfig[0], + GLX_RGBA_TYPE, NULL, GL_TRUE); + if (!gears->ctx) { + printf("Error: glXCreateNewContext failed\n"); + exit(1); + } - *winRet = win; - *ctxRet = ctx; + XFree(fbconfig); } static void -event_loop(Display *dpy, Window win) +event_loop(Display *dpy, struct gears *gears) { + int x, y; + while (1) { while (XPending(dpy) > 0) { XEvent event; @@ -395,7 +431,7 @@ event_loop(Display *dpy, Window win) /* we'll redraw below */ break; case ConfigureNotify: - reshape(event.xconfigure.width, event.xconfigure.height); + reshape(gears, event.xconfigure.width, event.xconfigure.height); break; case KeyPress: { @@ -430,24 +466,12 @@ event_loop(Display *dpy, Window win) angle += 2.0; draw(); + glFinish(); -#if 0 - glXSwapBuffers(dpy, win); -#else - { - GLfloat c[4]; - - glReadBuffer(GL_BACK); - - glReadPixels(WinWidth-1, 0, 1, 1, GL_RGB, GL_FLOAT, c); - printf("Bottom right pixel color: %g, %g, %g\n", c[0], c[1], c[2]); - - glDrawBuffer(GL_FRONT); - glWindowPos2iARB(0,0); - glCopyPixels(WinWidth/2, 0, WinWidth/2, WinHeight, GL_COLOR); - glDrawBuffer(GL_BACK); - } -#endif + for (x = 0; x < gears->width; x += 100) + for (y = 0; y < gears->width; y += 100) + XCopyArea(dpy, gears->pixmap, gears->win, gears->gc, + 50, 50, 100, 100, x, y); /* calc framerate */ { @@ -477,11 +501,10 @@ int main(int argc, char *argv[]) { Display *dpy; - Window win; - GLXContext ctx; - char *dpyName = ":0"; + const char *dpyName = NULL; GLboolean printInfo = GL_FALSE; - int i; + struct gears gears; + int i, width = 200, height = 200; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-display") == 0) { @@ -495,13 +518,13 @@ main(int argc, char *argv[]) dpy = XOpenDisplay(dpyName); if (!dpy) { - printf("Error: couldn't open display %s\n", dpyName); + printf("Error: couldn't open display %s\n", XDisplayName(dpyName)); return -1; } - make_window(dpy, "glxgears", 0, 0, WinWidth, WinHeight, &win, &ctx); - XMapWindow(dpy, win); - glXMakeCurrent(dpy, win, ctx); + make_window(dpy, "glxgears", 0, 0, width, height, &gears); + XMapWindow(dpy, gears.win); + glXMakeCurrent(dpy, gears.glxpixmap, gears.ctx); if (printInfo) { printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); @@ -510,12 +533,14 @@ main(int argc, char *argv[]) printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); } - init(); + init(width, height); - event_loop(dpy, win); + event_loop(dpy, &gears); - glXDestroyContext(dpy, ctx); - XDestroyWindow(dpy, win); + glXDestroyContext(dpy, gears.ctx); + XDestroyWindow(dpy, gears.win); + glXDestroyPixmap(dpy, gears.pixmap); + XFreePixmap(dpy, gears.pixmap); XCloseDisplay(dpy); return 0; diff --git a/progs/xdemos/glxinfo.c b/progs/xdemos/glxinfo.c index e33cddff047..35b6ed16b09 100644 --- a/progs/xdemos/glxinfo.c +++ b/progs/xdemos/glxinfo.c @@ -52,6 +52,13 @@ #define GLX_TRANSPARENT_RGB 0x8008 #endif +#ifndef GLX_RGBA_BIT +#define GLX_RGBA_BIT 0x00000001 +#endif + +#ifndef GLX_COLOR_INDEX_BIT +#define GLX_COLOR_INDEX_BIT 0x00000002 +#endif typedef enum { @@ -81,7 +88,7 @@ struct visual_attribs int transparentIndexValue; int bufferSize; int level; - int rgba; + int render_type; int doubleBuffer; int stereo; int auxBuffers; @@ -388,20 +395,61 @@ print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits) XSetWindowAttributes attr; unsigned long mask; Window root; - GLXContext ctx; + GLXContext ctx = NULL; XVisualInfo *visinfo; int width = 100, height = 100; root = RootWindow(dpy, scrnum); visinfo = glXChooseVisual(dpy, scrnum, attribSingle); - if (!visinfo) { + if (!visinfo) visinfo = glXChooseVisual(dpy, scrnum, attribDouble); - if (!visinfo) { - fprintf(stderr, "Error: couldn't find RGB GLX visual\n"); - return; + + if (visinfo) + ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect ); + +#ifdef GLX_VERSION_1_3 + { + int fbAttribSingle[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, GL_TRUE, + None }; + int fbAttribDouble[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + None }; + GLXFBConfig *configs = NULL; + int nConfigs; + + if (!visinfo) + configs = glXChooseFBConfig(dpy, scrnum, fbAttribSingle, &nConfigs); + if (!visinfo) + configs = glXChooseFBConfig(dpy, scrnum, fbAttribDouble, &nConfigs); + + if (configs) { + visinfo = glXGetVisualFromFBConfig(dpy, configs[0]); + ctx = glXCreateNewContext(dpy, configs[0], GLX_RGBA_TYPE, NULL, allowDirect); + XFree(configs); } } +#endif + + if (!visinfo) { + fprintf(stderr, "Error: couldn't find RGB GLX visual or fbconfig\n"); + return; + } + + if (!ctx) { + fprintf(stderr, "Error: glXCreateContext failed\n"); + XFree(visinfo); + XDestroyWindow(dpy, win); + return; + } attr.background_pixel = 0; attr.border_pixel = 0; @@ -412,14 +460,6 @@ print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits) 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr); - ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect ); - if (!ctx) { - fprintf(stderr, "Error: glXCreateContext failed\n"); - XFree(visinfo); - XDestroyWindow(dpy, win); - return; - } - if (glXMakeCurrent(dpy, win, ctx)) { const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR); const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION); @@ -541,12 +581,27 @@ visual_class_abbrev(int cls) } } +static const char * +visual_render_type_name(int type) +{ + switch (type) { + case GLX_RGBA_BIT: + return "rgba"; + case GLX_COLOR_INDEX_BIT: + return "ci"; + case GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT: + return "rgba|ci"; + default: + return ""; + } +} -static void +static GLboolean get_visual_attribs(Display *dpy, XVisualInfo *vInfo, struct visual_attribs *attribs) { const char *ext = glXQueryExtensionsString(dpy, vInfo->screen); + int rgba; memset(attribs, 0, sizeof(struct visual_attribs)); @@ -563,11 +618,17 @@ get_visual_attribs(Display *dpy, XVisualInfo *vInfo, attribs->colormapSize = vInfo->colormap_size; attribs->bitsPerRGB = vInfo->bits_per_rgb; - if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0) - return; + if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 || + !attribs->supportsGL) + return GL_FALSE; glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize); glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level); - glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba); + glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba); + if (rgba) + attribs->render_type = GLX_RGBA_BIT; + else + attribs->render_type = GLX_COLOR_INDEX_BIT; + glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer); glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo); glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers); @@ -616,8 +677,97 @@ get_visual_attribs(Display *dpy, XVisualInfo *vInfo, #else attribs->visualCaveat = 0; #endif + + return GL_TRUE; } +#ifdef GLX_VERSION_1_3 + +static int +glx_token_to_visual_class(int visual_type) +{ + switch (visual_type) { + case GLX_TRUE_COLOR: + return TrueColor; + case GLX_DIRECT_COLOR: + return DirectColor; + case GLX_PSEUDO_COLOR: + return PseudoColor; + case GLX_STATIC_COLOR: + return StaticColor; + case GLX_GRAY_SCALE: + return GrayScale; + case GLX_STATIC_GRAY: + return StaticGray; + case GLX_NONE: + default: + return None; + } +} + +static GLboolean +get_fbconfig_attribs(Display *dpy, GLXFBConfig fbconfig, + struct visual_attribs *attribs) +{ + int visual_type; + + memset(attribs, 0, sizeof(struct visual_attribs)); + + glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &attribs->id); + +#if 0 + attribs->depth = vInfo->depth; + attribs->redMask = vInfo->red_mask; + attribs->greenMask = vInfo->green_mask; + attribs->blueMask = vInfo->blue_mask; + attribs->colormapSize = vInfo->colormap_size; + attribs->bitsPerRGB = vInfo->bits_per_rgb; +#endif + + glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type); + attribs->klass = glx_token_to_visual_class(visual_type); + + glXGetFBConfigAttrib(dpy, fbconfig, GLX_BUFFER_SIZE, &attribs->bufferSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_LEVEL, &attribs->level); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &attribs->render_type); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &attribs->doubleBuffer); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers); + + glXGetFBConfigAttrib(dpy, fbconfig, GLX_RED_SIZE, &attribs->redSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_GREEN_SIZE, &attribs->greenSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_BLUE_SIZE, &attribs->blueSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_ALPHA_SIZE, &attribs->alphaSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_DEPTH_SIZE, &attribs->depthSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_STENCIL_SIZE, &attribs->stencilSize); + + glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize); + + /* get transparent pixel stuff */ + glXGetFBConfigAttrib(dpy, fbconfig,GLX_TRANSPARENT_TYPE, &attribs->transparentType); + if (attribs->transparentType == GLX_TRANSPARENT_RGB) { + glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue); + } + else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) { + glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue); + } + + glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples); + glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat); + + return GL_TRUE; +} + +#endif + + static void print_visual_attribs_verbose(const struct visual_attribs *attribs) @@ -625,7 +775,8 @@ print_visual_attribs_verbose(const struct visual_attribs *attribs) printf("Visual ID: %x depth=%d class=%s\n", attribs->id, attribs->depth, visual_class_name(attribs->klass)); printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n", - attribs->bufferSize, attribs->level, attribs->rgba ? "rgba" : "ci", + attribs->bufferSize, attribs->level, + visual_render_type_name(attribs->render_type), attribs->doubleBuffer, attribs->stereo); printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n", attribs->redSize, attribs->greenSize, @@ -683,16 +834,17 @@ print_visual_attribs_short(const struct visual_attribs *attribs) caveat = "None"; #endif - printf("0x%2x %2d %2s %2d %2d %2d %1s %2s %2s %2d %2d %2d %2d %2d %2d %2d", + printf("0x%02x %2d %2s %2d %2d %2d %c%c %c %c %2d %2d %2d %2d %2d %2d %2d", attribs->id, attribs->depth, visual_class_abbrev(attribs->klass), attribs->transparentType != GLX_NONE, attribs->bufferSize, attribs->level, - attribs->rgba ? "r" : "c", - attribs->doubleBuffer ? "y" : ".", - attribs->stereo ? "y" : ".", + (attribs->render_type & GLX_RGBA_BIT) ? 'r' : ' ', + (attribs->render_type & GLX_COLOR_INDEX_BIT) ? 'c' : ' ', + attribs->doubleBuffer ? 'y' : '.', + attribs->stereo ? 'y' : '.', attribs->redSize, attribs->greenSize, attribs->blueSize, attribs->alphaSize, attribs->auxBuffers, @@ -728,7 +880,7 @@ print_visual_attribs_long(const struct visual_attribs *attribs) attribs->transparentType != GLX_NONE, attribs->bufferSize, attribs->level, - attribs->rgba ? "rgba" : "ci ", + visual_render_type_name(attribs->render_type), attribs->doubleBuffer, attribs->stereo, attribs->redSize, attribs->greenSize, @@ -751,42 +903,86 @@ print_visual_info(Display *dpy, int scrnum, InfoMode mode) { XVisualInfo theTemplate; XVisualInfo *visuals; - int numVisuals; + int numVisuals, numGlxVisuals; long mask; int i; + struct visual_attribs attribs; /* get list of all visuals on this screen */ theTemplate.screen = scrnum; mask = VisualScreenMask; visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals); - if (mode == Verbose) { - for (i = 0; i < numVisuals; i++) { - struct visual_attribs attribs; - get_visual_attribs(dpy, &visuals[i], &attribs); - print_visual_attribs_verbose(&attribs); - } + numGlxVisuals = 0; + for (i = 0; i < numVisuals; i++) { + if (get_visual_attribs(dpy, &visuals[i], &attribs)) + numGlxVisuals++; } - else if (mode == Normal) { + + if (numGlxVisuals == 0) + return; + + printf("%d GLX Visuals\n", numGlxVisuals); + + if (mode == Normal) print_visual_attribs_short_header(); - for (i = 0; i < numVisuals; i++) { - struct visual_attribs attribs; - get_visual_attribs(dpy, &visuals[i], &attribs); + else if (mode == Wide) + print_visual_attribs_long_header(); + + for (i = 0; i < numVisuals; i++) { + if (!get_visual_attribs(dpy, &visuals[i], &attribs)) + continue; + + if (mode == Verbose) + print_visual_attribs_verbose(&attribs); + else if (mode == Normal) print_visual_attribs_short(&attribs); - } + else if (mode == Wide) + print_visual_attribs_long(&attribs); } - else if (mode == Wide) { + printf("\n"); + + XFree(visuals); +} + +#ifdef GLX_VERSION_1_3 + +static void +print_fbconfig_info(Display *dpy, int scrnum, InfoMode mode) +{ + int numFBConfigs; + struct visual_attribs attribs; + GLXFBConfig *fbconfigs; + int i; + + /* get list of all fbconfigs on this screen */ + fbconfigs = glXGetFBConfigs(dpy, scrnum, &numFBConfigs); + + if (numFBConfigs == 0) + return; + + printf("%d GLXFBConfigs:\n", numFBConfigs); + if (mode == Normal) + print_visual_attribs_short_header(); + else if (mode == Wide) print_visual_attribs_long_header(); - for (i = 0; i < numVisuals; i++) { - struct visual_attribs attribs; - get_visual_attribs(dpy, &visuals[i], &attribs); + + for (i = 0; i < numFBConfigs; i++) { + get_fbconfig_attribs(dpy, fbconfigs[i], &attribs); + + if (mode == Verbose) + print_visual_attribs_verbose(&attribs); + else if (mode == Normal) + print_visual_attribs_short(&attribs); + else if (mode == Wide) print_visual_attribs_long(&attribs); - } } + printf("\n"); - XFree(visuals); + XFree(fbconfigs); } +#endif /* * Stand-alone Mesa doesn't really implement the GLX protocol so it @@ -860,7 +1056,7 @@ find_best_visual(Display *dpy, int scrnum) /* see if this vis is better than bestVis */ if ((!bestVis.supportsGL && vis.supportsGL) || (bestVis.visualCaveat != GLX_NONE_EXT) || - (!bestVis.rgba && vis.rgba) || + (!(bestVis.render_type & GLX_RGBA_BIT) && (vis.render_type & GLX_RGBA_BIT)) || (!bestVis.doubleBuffer && vis.doubleBuffer) || (bestVis.redSize < vis.redSize) || (bestVis.greenSize < vis.greenSize) || @@ -957,6 +1153,9 @@ main(int argc, char *argv[]) print_screen_info(dpy, scrnum, allowDirect, limits); printf("\n"); print_visual_info(dpy, scrnum, mode); +#ifdef GLX_VERSION_1_3 + print_fbconfig_info(dpy, scrnum, mode); +#endif if (scrnum + 1 < numScreens) printf("\n\n"); } 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 <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; +} diff --git a/progs/xdemos/glxswapcontrol.c b/progs/xdemos/glxswapcontrol.c index d9be984be57..e429d58ecc4 100644 --- a/progs/xdemos/glxswapcontrol.c +++ b/progs/xdemos/glxswapcontrol.c @@ -814,6 +814,11 @@ main(int argc, char *argv[]) init(); + /* Set initial projection/viewing transformation. + * same as glxgears.c + */ + reshape(300, 300); + event_loop(dpy, win); glXDestroyContext(dpy, ctx); diff --git a/progs/xdemos/ipc.c b/progs/xdemos/ipc.c new file mode 100644 index 00000000000..c872d1641ab --- /dev/null +++ b/progs/xdemos/ipc.c @@ -0,0 +1,264 @@ +/* Copyright (c) 2003 Tungsten Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files ("the + * Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: The above copyright notice, the Tungsten + * Graphics splash screen, and this permission notice shall be included + * in all copies or substantial portions of the Software. THE SOFTWARE + * IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Simple IPC API + * Brian Paul + */ + + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <unistd.h> +#include <sys/socket.h> +#include "ipc.h" + +#if defined(IRIX) || defined(irix) +typedef int socklen_t; +#endif + +#define NO_DELAY 1 + +#define DEFAULT_MASTER_PORT 7011 + + +/* + * Return my hostname in <nameOut>. + * Return 1 for success, 0 for error. + */ +int +MyHostName(char *nameOut, int maxNameLength) +{ + int k = gethostname(nameOut, maxNameLength); + return k==0; +} + + +/* + * Create a socket attached to a port. Later, we can call AcceptConnection + * on the socket returned from this function. + * Return the new socket number or -1 if error. + */ +int +CreatePort(int *port) +{ + char hostname[1000]; + struct sockaddr_in servaddr; + struct hostent *hp; + int so_reuseaddr = 1; + int tcp_nodelay = 1; + int sock, k; + + /* create socket */ + sock = socket(AF_INET, SOCK_STREAM, 0); + assert(sock > 2); + + /* get my host name */ + k = gethostname(hostname, 1000); + assert(k == 0); + + /* get hostent info */ + hp = gethostbyname(hostname); + assert(hp); + + /* initialize the servaddr struct */ + memset(&servaddr, 0, sizeof(servaddr) ); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons((unsigned short) (*port)); + memcpy((char *) &servaddr.sin_addr, hp->h_addr, + sizeof(servaddr.sin_addr)); + + /* deallocate when we exit */ + k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *) &so_reuseaddr, sizeof(so_reuseaddr)); + assert(k==0); + + /* send packets immediately */ +#if NO_DELAY + k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &tcp_nodelay, sizeof(tcp_nodelay)); + assert(k==0); +#endif + + if (*port == 0) + *port = DEFAULT_MASTER_PORT; + + k = 1; + while (k && (*port < 65534)) { + /* bind our address to the socket */ + servaddr.sin_port = htons((unsigned short) (*port)); + k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (k) + *port = *port + 1; + } + +#if 0 + printf("###### Real Port: %d\n", *port); +#endif + + /* listen for connections */ + k = listen(sock, 100); + assert(k == 0); + + return sock; +} + + +/* + * Accept a connection on the named socket. + * Return a new socket for the new connection, or -1 if error. + */ +int +AcceptConnection(int socket) +{ + struct sockaddr addr; + socklen_t addrLen; + int newSock; + + addrLen = sizeof(addr); + newSock = accept(socket, &addr, &addrLen); + if (newSock == 1) + return -1; + else + return newSock; +} + + +/* + * Contact the server running on the given host on the named port. + * Return socket number or -1 if error. + */ +int +Connect(const char *hostname, int port) +{ + struct sockaddr_in servaddr; + struct hostent *hp; + int sock, k; + int tcp_nodelay = 1; + + assert(port); + + sock = socket(AF_INET, SOCK_STREAM, 0); + assert(sock >= 0); + + hp = gethostbyname(hostname); + assert(hp); + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons((unsigned short) port); + memcpy((char *) &servaddr.sin_addr, hp->h_addr, sizeof(servaddr.sin_addr)); + + k = connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (k != 0) { + perror("Connect:"); + return -1; + } + +#if NO_DELAY + /* send packets immediately */ + k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (char *) &tcp_nodelay, sizeof(tcp_nodelay)); + assert(k==0); +#endif + + return sock; +} + + +void +CloseSocket(int socket) +{ + close(socket); +} + + +int +SendData(int socket, const void *data, int bytes) +{ + int sent = 0; + int b; + + while (sent < bytes) { + b = write(socket, (char *) data + sent, bytes - sent); + if (b <= 0) + return -1; /* something broke */ + sent += b; + } + return sent; +} + + +int +ReceiveData(int socket, void *data, int bytes) +{ + int received = 0, b; + + while (received < bytes) { + b = read(socket, (char *) data + received, bytes - received); + if (b <= 0) + return -1; + received += b; + } + return received; +} + + +int +SendString(int socket, const char *str) +{ + const int len = strlen(str); + int sent, b; + + /* first, send a 4-byte length indicator */ + b = write(socket, &len, sizeof(len)); + if (b <= 0) + return -1; + + sent = SendData(socket, str, len); + assert(sent == len); + return sent; +} + + +int +ReceiveString(int socket, char *str, int maxLen) +{ + int len, received, b; + + /* first, read 4 bytes to see how long of string to receive */ + b = read(socket, &len, sizeof(len)); + if (b <= 0) + return -1; + + assert(len <= maxLen); /* XXX fix someday */ + assert(len >= 0); + received = ReceiveData(socket, str, len); + assert(received != -1); + assert(received == len); + str[len] = 0; + return received; +} diff --git a/progs/xdemos/ipc.h b/progs/xdemos/ipc.h new file mode 100644 index 00000000000..3f434457c6f --- /dev/null +++ b/progs/xdemos/ipc.h @@ -0,0 +1,16 @@ +#ifndef IPC_H +#define IPC_H + + +extern int MyHostName(char *nameOut, int maxNameLength); +extern int CreatePort(int *port); +extern int AcceptConnection(int socket); +extern int Connect(const char *hostname, int port); +extern void CloseSocket(int socket); +extern int SendData(int socket, const void *data, int bytes); +extern int ReceiveData(int socket, void *data, int bytes); +extern int SendString(int socket, const char *str); +extern int ReceiveString(int socket, char *str, int maxLen); + + +#endif /* IPC_H */ diff --git a/progs/xdemos/offset.c b/progs/xdemos/offset.c index 97170f5c8de..6c5abf383be 100644 --- a/progs/xdemos/offset.c +++ b/progs/xdemos/offset.c @@ -70,12 +70,12 @@ typedef Vertex Quad[4]; /* data to define the six faces of a unit cube */ Quad quads[MAXQUAD] = { - { {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0} }, - { {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1} }, - { {0,0,0}, {1,0,0}, {1,0,1}, {0,0,1} }, - { {0,1,0}, {1,1,0}, {1,1,1}, {0,1,1} }, - { {0,0,0}, {0,0,1}, {0,1,1}, {0,1,0} }, - { {1,0,0}, {1,0,1}, {1,1,1}, {1,1,0} } + { {0,0,0}, {0,0,1}, {0,1,1}, {0,1,0} }, /* x = 0 */ + { {0,0,0}, {1,0,0}, {1,0,1}, {0,0,1} }, /* y = 0 */ + { {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0} }, /* z = 0 */ + { {1,0,0}, {1,0,1}, {1,1,1}, {1,1,0} }, /* x = 1 */ + { {0,1,0}, {1,1,0}, {1,1,1}, {0,1,1} }, /* y = 1 */ + { {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1} } /* z = 1 */ }; #define WIREFRAME 0 @@ -85,7 +85,7 @@ static void error(const char* prog, const char* msg); static void cubes(int mx, int my, int mode); static void fill(Quad quad); static void outline(Quad quad); -static void draw_hidden(Quad quad, int mode); +static void draw_hidden(Quad quad, int mode, int face); static void process_input(Display *dpy, Window win); static int query_extension(char* extName); @@ -100,6 +100,7 @@ int main(int argc, char** argv) { XSetWindowAttributes swa; Window win; GLXContext cx; + GLint z; dpy = XOpenDisplay(0); if (!dpy) error(argv[0], "can't open display"); @@ -140,6 +141,9 @@ int main(int argc, char** argv) { /* set other relevant state information */ glEnable(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_BITS, &z); + printf("GL_DEPTH_BITS = %d\n", z); + #ifdef GL_EXT_polygon_offset printf("using 1.0 offset extension\n"); glPolygonOffsetEXT( 1.0, 0.00001 ); @@ -159,6 +163,7 @@ int main(int argc, char** argv) { static void draw_scene(int mx, int my) { + glClearColor(0.25, 0.25, 0.25, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); @@ -205,7 +210,7 @@ cubes(int mx, int my, int mode) { glTranslatef(x, y, z); glScalef(0.8, 0.8, 0.8); for (i = 0; i < MAXQUAD; i++) - draw_hidden(quads[i], mode); + draw_hidden(quads[i], mode, i); glPopMatrix(); } } @@ -235,13 +240,18 @@ outline(Quad quad) { } static void -draw_hidden(Quad quad, int mode) { +draw_hidden(Quad quad, int mode, int face) { + static const GLfloat colors[3][3] = { + {0.5, 0.5, 0.0}, + {0.8, 0.5, 0.0}, + {0.0, 0.5, 0.8} + }; if (mode == HIDDEN_LINE) { - glColor3f(0, 0, 0); + glColor3fv(colors[face % 3]); fill(quad); } - /* draw the outline using white, optionally fill the interior with black */ + /* draw the outline using white */ glColor3f(1, 1, 1); outline(quad); } diff --git a/progs/xdemos/pbutil.c b/progs/xdemos/pbutil.c index d0bbd1b0fce..ce133d012dc 100644 --- a/progs/xdemos/pbutil.c +++ b/progs/xdemos/pbutil.c @@ -18,12 +18,12 @@ * Test if we pixel buffers are available for a particular X screen. * Input: dpy - the X display * screen - screen number - * Return: 0 = pixel buffers not available. - * 1 = pixel buffers are available via GLX 1.3. - * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer. + * Return: 0 = fbconfigs not available. + * 1 = fbconfigs are available via GLX 1.3. + * 2 = fbconfigs and pbuffers are available via GLX_SGIX_fbconfig */ int -QueryPbuffers(Display *dpy, int screen) +QueryFBConfig(Display *dpy, int screen) { #if defined(GLX_VERSION_1_3) { @@ -40,36 +40,55 @@ QueryPbuffers(Display *dpy, int screen) } #endif -#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) /* Try the SGIX extensions */ { char *extensions; extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS); - if (!extensions || - !strstr(extensions,"GLX_SGIX_fbconfig") || - !strstr(extensions,"GLX_SGIX_pbuffer")) { - return 0; + if (extensions && strstr(extensions,"GLX_SGIX_fbconfig")) { + return 2; } - return 2; } -#endif return 0; } +/** + * Test if we pixel buffers are available for a particular X screen. + * Input: dpy - the X display + * screen - screen number + * Return: 0 = pixel buffers not available. + * 1 = pixel buffers are available via GLX 1.3. + * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer. + */ +int +QueryPbuffers(Display *dpy, int screen) +{ + int ret; + ret = QueryFBConfig(dpy, screen); + if (ret == 2) { + char *extensions; + extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS); + if (extensions && strstr(extensions, "GLX_SGIX_pbuffer")) + return 2; + else + return 0; + } + else + return ret; +} FBCONFIG * ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs) { - int pbSupport = QueryPbuffers(dpy, screen); + int fbcSupport = QueryPbuffers(dpy, screen); #if defined(GLX_VERSION_1_3) - if (pbSupport == 1) { + if (fbcSupport == 1) { return glXChooseFBConfig(dpy, screen, attribs, nConfigs); } #endif #if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) - if (pbSupport == 2) { + if (fbcSupport == 2) { return glXChooseFBConfigSGIX(dpy, screen, (int *) attribs, nConfigs); } #endif @@ -80,14 +99,14 @@ ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs) FBCONFIG * GetAllFBConfigs(Display *dpy, int screen, int *nConfigs) { - int pbSupport = QueryPbuffers(dpy, screen); + int fbcSupport = QueryFBConfig(dpy, screen); #if defined(GLX_VERSION_1_3) - if (pbSupport == 1) { + if (fbcSupport == 1) { return glXGetFBConfigs(dpy, screen, nConfigs); } #endif #if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) - if (pbSupport == 2) { + if (fbcSupport == 2) { /* The GLX_SGIX_fbconfig extensions says to pass NULL to get list * of all available configurations. */ @@ -101,14 +120,14 @@ GetAllFBConfigs(Display *dpy, int screen, int *nConfigs) XVisualInfo * GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config) { - int pbSupport = QueryPbuffers(dpy, screen); + int fbcSupport = QueryFBConfig(dpy, screen); #if defined(GLX_VERSION_1_3) - if (pbSupport == 1) { + if (fbcSupport == 1) { return glXGetVisualFromFBConfig(dpy, config); } #endif #if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) - if (pbSupport == 2) { + if (fbcSupport == 2) { return glXGetVisualFromFBConfigSGIX(dpy, config); } #endif @@ -130,11 +149,11 @@ GetFBConfigAttrib(Display *dpy, int screen, int attrib ) { - int pbSupport = QueryPbuffers(dpy, screen); + int fbcSupport = QueryFBConfig(dpy, screen); int value = 0; #if defined(GLX_VERSION_1_3) - if (pbSupport == 1) { + if (fbcSupport == 1) { /* ok */ if (glXGetFBConfigAttrib(dpy, config, attrib, &value) != 0) { value = 0; @@ -145,7 +164,7 @@ GetFBConfigAttrib(Display *dpy, int screen, #endif #if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) - if (pbSupport == 2) { + if (fbcSupport == 2) { if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) { value = 0; } @@ -295,9 +314,9 @@ PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat) GLXContext CreateContext(Display *dpy, int screen, FBCONFIG config) { - int pbSupport = QueryPbuffers(dpy, screen); + int fbcSupport = QueryFBConfig(dpy, screen); #if defined(GLX_VERSION_1_3) - if (pbSupport == 1) { + if (fbcSupport == 1) { /* GLX 1.3 */ GLXContext c; c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, True); @@ -309,7 +328,7 @@ CreateContext(Display *dpy, int screen, FBCONFIG config) } #endif #if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer) - if (pbSupport == 2) { + if (fbcSupport == 2) { GLXContext c; c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, True); if (!c) { @@ -393,6 +412,7 @@ CreatePbuffer(Display *dpy, int screen, FBCONFIG config, pBuffer = None; } + XSync(dpy, False); /* Restore original X error handler */ (void) XSetErrorHandler(oldHandler); diff --git a/progs/xdemos/pbutil.h b/progs/xdemos/pbutil.h index e95b2565a23..d420522ff01 100644 --- a/progs/xdemos/pbutil.h +++ b/progs/xdemos/pbutil.h @@ -27,6 +27,9 @@ extern int +QueryFBConfig(Display *dpy, int screen); + +extern int QueryPbuffers(Display *dpy, int screen); diff --git a/progs/xdemos/sharedtex.c b/progs/xdemos/sharedtex.c new file mode 100644 index 00000000000..81703fe0e7d --- /dev/null +++ b/progs/xdemos/sharedtex.c @@ -0,0 +1,324 @@ +/* + * Test sharing of texture objects by two rendering contexts. + * In particular, test that changing a texture object in one context + * effects the texture in the second context. + * + * Brian Paul + * 30 Apr 2008 + * + * Copyright (C) 2008 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include <GL/gl.h> +#include <GL/glx.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <X11/keysym.h> + + +#define MAX_CONTEXTS 2 + +#define TEX_SIZE 32 + +static const char *DisplayName = NULL; +static Display *Dpy; +static XVisualInfo *VisInfo; +static Window Win; +static GLXContext Contexts[MAX_CONTEXTS]; +static int WinWidth = 300, WinHeight = 300; + +static int DrawContext = 0, TexContext = 1; + +static GLuint TexObj = 0; +static GLboolean NewTexture = GL_FALSE; + + +static void +Error(const char *msg) +{ + fprintf(stderr, "sharedtex error: %s\n", msg); + exit(1); +} + + +static void +CreateWindow(const char *name) +{ + int attrib[] = { GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + None }; + int scrnum; + XSetWindowAttributes attr; + unsigned long mask; + Window root; + int xpos = 0, ypos = 0; + static int n = 0; + + scrnum = DefaultScreen(Dpy); + root = RootWindow(Dpy, scrnum); + + VisInfo = glXChooseVisual(Dpy, scrnum, attrib); + if (!VisInfo) { + Error("Unable to find RGB, double-buffered visual"); + } + + /* window attributes */ + xpos = (n % 10) * 100; + ypos = (n / 10) * 100; + n++; + + 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, xpos, ypos, WinWidth, WinHeight, + 0, VisInfo->depth, InputOutput, + VisInfo->visual, mask, &attr); + if (!Win) { + Error("Couldn't create window"); + } + + { + XSizeHints sizehints; + sizehints.x = xpos; + sizehints.y = ypos; + sizehints.width = WinWidth; + sizehints.height = WinHeight; + sizehints.flags = USSize | USPosition; + XSetNormalHints(Dpy, Win, &sizehints); + XSetStandardProperties(Dpy, Win, name, name, + None, (char **)NULL, 0, &sizehints); + } + + XMapWindow(Dpy, Win); +} + + +/** + * Change texture image, using TexContext + */ +static void +ModifyTexture(void) +{ + GLuint tex[TEX_SIZE][TEX_SIZE]; + GLuint c0, c1; + int i, j; + + if (Win && !glXMakeCurrent(Dpy, Win, Contexts[TexContext])) { + Error("glXMakeCurrent failed"); + } + + /* choose two random colors */ + c0 = rand() & 0xffffffff; + c1 = rand() & 0xffffffff; + + for (i = 0; i < TEX_SIZE; i++) { + for (j = 0; j < TEX_SIZE; j++) { + if (((i / 4) ^ (j / 4)) & 1) { + tex[i][j] = c0; + } + else { + tex[i][j] = c1; + } + } + } + + glBindTexture(GL_TEXTURE_2D, TexObj); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, + GL_RGBA, GL_UNSIGNED_BYTE, tex); + + NewTexture = GL_TRUE; +} + + +static void +InitContext(void) +{ + glGenTextures(1, &TexObj); + assert(TexObj); + glBindTexture(GL_TEXTURE_2D, TexObj); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glEnable(GL_TEXTURE_2D); + + printf("GL_RENDERER = %s\n", (char*) glGetString(GL_RENDERER)); +} + + +static void +Setup(void) +{ + int i; + + Dpy = XOpenDisplay(DisplayName); + if (!Dpy) { + Error("Unable to open display"); + } + + CreateWindow("sharedtex"); + + for (i = 0; i < MAX_CONTEXTS; i++) { + GLXContext share = i > 0 ? Contexts[0] : 0; + + Contexts[i] = glXCreateContext(Dpy, VisInfo, share, True); + if (!Contexts[i]) { + Error("Unable to create GLX context"); + } + + if (!glXMakeCurrent(Dpy, Win, Contexts[i])) { + Error("glXMakeCurrent failed"); + } + + InitContext(); + } + + ModifyTexture(); +} + + +/** + * Redraw window, using DrawContext + */ +static void +Redraw(void) +{ + static float rot = 0.0; + float ar; + + rot += 1.0; + + if (Win && !glXMakeCurrent(Dpy, Win, Contexts[DrawContext])) { + Error("glXMakeCurrent failed"); + } + + glViewport(0, 0, WinWidth, WinHeight); + ar = (float) WinWidth / (float) WinHeight; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-ar, ar, -1.0, 1.0, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + + glShadeModel(GL_FLAT); + glClearColor(0.5, 0.5, 0.5, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glPushMatrix(); + glRotatef(rot, 0, 0, 1); + glScalef(0.7, 0.7, 0.7); + + if (NewTexture) { + /* rebind to get new contents */ + glBindTexture(GL_TEXTURE_2D, TexObj); + NewTexture = GL_FALSE; + } + + /* draw textured quad */ + glBegin(GL_POLYGON); + glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, -1.0 ); + glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, -1.0 ); + glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, 1.0 ); + glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, 1.0 ); + glEnd(); + + glPopMatrix(); + + if (Win) + glXSwapBuffers(Dpy, Win); +} + + +static void +EventLoop(void) +{ + while (1) { + while (XPending(Dpy) > 0) { + XEvent event; + XNextEvent(Dpy, &event); + + switch (event.type) { + case Expose: + Redraw(); + break; + case ConfigureNotify: + WinWidth = event.xconfigure.width; + WinHeight = event.xconfigure.height; + break; + case KeyPress: + { + char buf[100]; + KeySym keySym; + XComposeStatus stat; + XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat); + switch (keySym) { + case XK_Escape: + exit(0); + break; + case XK_t: + case XK_T: + ModifyTexture(); + break; + default: + ; + } + } + Redraw(); + break; + default: + /*no-op*/ ; + } + } + + Redraw(); + usleep(10000); + } +} + + + + +int +main(int argc, char *argv[]) +{ + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-display") == 0 && i < argc) { + DisplayName = argv[i+1]; + i++; + } + } + + Setup(); + + printf("Press 't' to change texture image/colors\n"); + + EventLoop(); + + return 0; +} diff --git a/progs/xdemos/texture_from_pixmap.c b/progs/xdemos/texture_from_pixmap.c new file mode 100644 index 00000000000..ab215b0ac30 --- /dev/null +++ b/progs/xdemos/texture_from_pixmap.c @@ -0,0 +1,396 @@ +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* + * Test the GLX_EXT_texture_from_pixmap extension + * Brian Paul + * 19 May 2007 + */ + + +#define GL_GLEXT_PROTOTYPES +#define GLX_GLXEXT_PROTOTYPES +#include <GL/gl.h> +#include <GL/glx.h> +#include <X11/keysym.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static float top, bottom; + +static PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT_func = NULL; +static PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT_func = NULL; + + +static Display * +OpenDisplay(void) +{ + int screen; + Display *dpy; + const char *ext; + + dpy = XOpenDisplay(NULL); + if (!dpy) { + printf("Couldn't open default display!\n"); + exit(1); + } + + screen = DefaultScreen(dpy); + ext = glXQueryExtensionsString(dpy, screen); + if (!strstr(ext, "GLX_EXT_texture_from_pixmap")) { + fprintf(stderr, "GLX_EXT_texture_from_pixmap not supported.\n"); + exit(1); + } + + glXBindTexImageEXT_func = (PFNGLXBINDTEXIMAGEEXTPROC) + glXGetProcAddress((GLubyte *) "glXBindTexImageEXT"); + glXReleaseTexImageEXT_func = (PFNGLXRELEASETEXIMAGEEXTPROC) + glXGetProcAddress((GLubyte*) "glXReleaseTexImageEXT"); + + if (!glXBindTexImageEXT_func || !glXReleaseTexImageEXT_func) { + fprintf(stderr, "glXGetProcAddress failed!\n"); + exit(1); + } + + return dpy; +} + + +static GLXFBConfig +ChoosePixmapFBConfig(Display *display) +{ + int screen = DefaultScreen(display); + GLXFBConfig *fbconfigs; + int i, nfbconfigs, value; + + fbconfigs = glXGetFBConfigs(display, screen, &nfbconfigs); + for (i = 0; i < nfbconfigs; i++) { + + glXGetFBConfigAttrib(display, fbconfigs[i], GLX_DRAWABLE_TYPE, &value); + if (!(value & GLX_PIXMAP_BIT)) + continue; + + glXGetFBConfigAttrib(display, fbconfigs[i], + GLX_BIND_TO_TEXTURE_TARGETS_EXT, &value); + if (!(value & GLX_TEXTURE_2D_BIT_EXT)) + continue; + + glXGetFBConfigAttrib(display, fbconfigs[i], + GLX_BIND_TO_TEXTURE_RGBA_EXT, &value); + if (value == False) { + glXGetFBConfigAttrib(display, fbconfigs[i], + GLX_BIND_TO_TEXTURE_RGB_EXT, &value); + if (value == False) + continue; + } + + glXGetFBConfigAttrib(display, fbconfigs[i], + GLX_Y_INVERTED_EXT, &value); + if (value == True) { + top = 0.0f; + bottom = 1.0f; + } + else { + top = 1.0f; + bottom = 0.0f; + } + + break; + } + + if (i == nfbconfigs) { + printf("Unable to find FBconfig for texturing\n"); + exit(1); + } + + return fbconfigs[i]; +} + + +static GLXPixmap +CreatePixmap(Display *dpy, GLXFBConfig config, int w, int h, Pixmap *p) +{ + GLXPixmap gp; + const int pixmapAttribs[] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, + None + }; + Window root = RootWindow(dpy, 0); + + *p = XCreatePixmap(dpy, root, w, h, 24); + XSync(dpy, 0); + gp = glXCreatePixmap(dpy, config, *p, pixmapAttribs); + XSync(dpy, 0); + + return gp; +} + + +static void +DrawPixmapImage(Display *dpy, Pixmap pm, int w, int h) +{ + XGCValues gcvals; + GC gc; + + gcvals.background = 0; + gc = XCreateGC(dpy, pm, GCBackground, &gcvals); + + XSetForeground(dpy, gc, 0x0); + XFillRectangle(dpy, pm, gc, 0, 0, w, h); + + XSetForeground(dpy, gc, 0xff0000); + XFillRectangle(dpy, pm, gc, 0, 0, 50, 50); + + XSetForeground(dpy, gc, 0x00ff00); + XFillRectangle(dpy, pm, gc, w - 50, 0, 50, 50); + + XSetForeground(dpy, gc, 0x0000ff); + XFillRectangle(dpy, pm, gc, 0, h - 50, 50, 50); + + XSetForeground(dpy, gc, 0xffffff); + XFillRectangle(dpy, pm, gc, h - 50, h - 50, 50, 50); + + XSetForeground(dpy, gc, 0xffff00); + XSetLineAttributes(dpy, gc, 3, LineSolid, CapButt, JoinBevel); + XDrawLine(dpy, pm, gc, 0, 0, w, h); + XDrawLine(dpy, pm, gc, 0, h, w, 0); + + XFreeGC(dpy, gc); +} + + +static XVisualInfo * +ChooseWindowVisual(Display *dpy) +{ + int screen = DefaultScreen(dpy); + XVisualInfo *visinfo; + int attribs[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + None + }; + + visinfo = glXChooseVisual(dpy, screen, attribs); + if (!visinfo) { + printf("Unable to find RGB, double-buffered visual\n"); + exit(1); + } + + return visinfo; +} + + +static Window +CreateWindow(Display *dpy, XVisualInfo *visinfo, + int width, int height, const char *name) +{ + int screen = DefaultScreen(dpy); + Window win; + XSetWindowAttributes attr; + unsigned long mask; + Window root; + + root = RootWindow(dpy, screen); + + /* 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, 0, 0, width, height, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr); + if (win) { + XSizeHints sizehints; + sizehints.width = width; + sizehints.height = height; + sizehints.flags = USSize; + XSetNormalHints(dpy, win, &sizehints); + XSetStandardProperties(dpy, win, name, name, + None, (char **)NULL, 0, &sizehints); + + XMapWindow(dpy, win); + } + return win; +} + + +static void +BindPixmapTexture(Display *dpy, GLXPixmap gp) +{ + GLuint texture; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + glXBindTexImageEXT_func(dpy, gp, GLX_FRONT_LEFT_EXT, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glEnable(GL_TEXTURE_2D); + /* + glXReleaseTexImageEXT_func(display, glxpixmap, GLX_FRONT_LEFT_EXT); + */ +} + + +static void +Resize(Window win, unsigned int width, unsigned int height) +{ + float sz = 1.5; + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-sz, sz, -sz, sz, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); +} + + +static void +Redraw(Display *dpy, Window win, float rot) +{ + glClearColor(0.25, 0.25, 0.25, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + glPushMatrix(); + glRotatef(rot, 0, 0, 1); + glRotatef(2.0 * rot, 1, 0, 0); + + glBegin(GL_QUADS); + glTexCoord2d(0.0, bottom); + glVertex2f(-1, -1); + glTexCoord2d(1.0, bottom); + glVertex2f( 1, -1); + glTexCoord2d(1.0, top); + glVertex2d(1.0, 1.0); + glTexCoord2d(0.0, top); + glVertex2f(-1.0, 1.0); + glEnd(); + + glPopMatrix(); + + glXSwapBuffers(dpy, win); +} + + +static void +EventLoop(Display *dpy, Window win) +{ + GLfloat rot = 0.0; + int anim = 0; + + while (1) { + if (!anim || XPending(dpy) > 0) { + XEvent event; + XNextEvent(dpy, &event); + + switch (event.type) { + case Expose: + Redraw(dpy, win, rot); + break; + case ConfigureNotify: + Resize(event.xany.window, + event.xconfigure.width, + event.xconfigure.height); + break; + case KeyPress: + { + char buf[100]; + KeySym keySym; + XComposeStatus stat; + XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat); + if (keySym == XK_Escape) { + return; /* exit */ + } + else if (keySym == XK_r) { + rot += 1.0; + Redraw(dpy, win, rot); + } + else if (keySym == XK_a) { + anim = !anim; + } + else if (keySym == XK_R) { + rot -= 1.0; + Redraw(dpy, win, rot); + } + } + break; + default: + ; /*no-op*/ + } + } + else { + /* animate */ + rot += 1.0; + Redraw(dpy, win, rot); + } + } +} + + + +int +main(int argc, char *argv[]) +{ + Display *dpy; + GLXFBConfig pixmapConfig; + XVisualInfo *windowVis; + GLXPixmap gp; + Window win; + GLXContext ctx; + Pixmap p; + + dpy = OpenDisplay(); + + pixmapConfig = ChoosePixmapFBConfig(dpy); + windowVis = ChooseWindowVisual(dpy); + win = CreateWindow(dpy, windowVis, 500, 500, "Texture From Pixmap"); + + gp = CreatePixmap(dpy, pixmapConfig, 512, 512, &p); + DrawPixmapImage(dpy, p, 512, 512); + + ctx = glXCreateContext(dpy, windowVis, NULL, True); + if (!ctx) { + printf("Couldn't create GLX context\n"); + exit(1); + } + + glXMakeCurrent(dpy, win, ctx); + + BindPixmapTexture(dpy, gp); + + EventLoop(dpy, win); + + return 0; +} |