To test things, I've been using a modified version of our favorite glxgears (patch attached) that uses two windows.
Eh-hem. The summer heat must have melted my brain. The patch is actually attached this time. :)
Index: glxgears.c
===================================================================
RCS file: /cvsroot/mesa3d/Mesa/xdemos/glxgears.c,v
retrieving revision 1.7
diff -u -d -r1.7 glxgears.c
--- glxgears.c 30 May 2003 18:41:38 -0000 1.7
+++ glxgears.c 2 Jul 2003 16:26:42 -0000
@@ -48,6 +48,8 @@
#include <GL/gl.h>
#include <GL/glx.h>
+#include <assert.h>
+
#ifndef GLX_MESA_swap_control
typedef GLint ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
typedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC) ( void );
@@ -112,7 +114,9 @@
static GLint gear1, gear2, gear3;
static GLfloat angle = 0.0;
+static GLboolean has_GLX_1_3 = GL_FALSE;
static GLboolean has_OML_sync_control = GL_FALSE;
+static GLboolean has_SGI_make_current_read = GL_FALSE;
static GLboolean has_SGI_swap_control = GL_FALSE;
static GLboolean has_MESA_swap_control = GL_FALSE;
static GLboolean has_MESA_swap_frame_usage = GL_FALSE;
@@ -266,6 +270,7 @@
draw(void)
{
if ( use_ztrick ) {
+ unsigned i;
static GLboolean flip = GL_FALSE;
static const GLfloat vert[4][3] = {
{ -1, -1, -0.999 },
@@ -352,9 +357,74 @@
}
+static void
+draw2( Display * dpy, Window * win, GLXContext ctx )
+{
+ GLboolean result;
+
+ if ( has_GLX_1_3 ) {
+ result = glXMakeContextCurrent(dpy, win[1], win[0], ctx);
+ }
+ else if ( has_SGI_make_current_read ) {
+ result = glXMakeCurrentReadSGI(dpy, win[1], win[0], ctx);
+ }
+ else {
+ result = glXMakeCurrent(dpy, win[0], ctx);
+ }
+
+ /* FIXME: If this fails, how can the app determine why it failed? */
+ assert( result );
+
+ glBindTexture( GL_TEXTURE_2D, 1 );
+ glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, 300, 300 );
+
+ if ( ! (has_GLX_1_3 || has_SGI_make_current_read) ) {
+ result = glXMakeCurrent(dpy, win[1], ctx);
+ assert( result );
+ }
+
+ glBindTexture( GL_TEXTURE_2D, 1 );
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_LIGHT0);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glTranslatef(0.5, 0.5, 0.0);
+ glRotatef(angle, 0, 0, 1);
+ glTranslatef(-0.5, -0.5, 0.0);
+ glMatrixMode(GL_MODELVIEW);
+
+ glBegin(GL_POLYGON);
+
+ glTexCoord2f( 0.0, 0.0 );
+ glVertex2f( -5.0, -5.0 );
+
+ glTexCoord2f( 0.0, 0.0 );
+ glVertex2f( 5.0, -5.0 );
+
+ glTexCoord2f( 1.0, 1.0 );
+ glVertex2f( 5.0, 5.0 );
+
+ glTexCoord2f( 0.0, 1.0 );
+ glVertex2f( -5.0, 5.0 );
+
+ glEnd();
+
+ glDisable(GL_TEXTURE_2D);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+}
+
+
/* new window size or exposure */
static void
-reshape(int width, int height)
+reshape(Window win, int width, int height)
{
aspect = (GLfloat) height / (GLfloat) width;
@@ -371,7 +441,7 @@
static void
-init(void)
+init(GLboolean create_texture_object)
{
static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
@@ -404,6 +474,21 @@
glEndList();
glEnable(GL_NORMALIZE);
+
+
+ /* Initialize the texture object so that glCopyTexSubImage2D can be used
+ * to update its contents.
+ */
+
+ if ( create_texture_object ) {
+ glBindTexture(GL_TEXTURE_2D, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 512, 512, 0, GL_RGB, GL_BYTE,
+ NULL);
+ }
}
@@ -414,7 +499,8 @@
static void
make_window( Display *dpy, const char *name,
int x, int y, int width, int height,
- Window *winRet, GLXContext *ctxRet)
+ Window *winRet, GLXContext *ctxRet,
+ GLboolean two_windows )
{
int attrib[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
@@ -427,9 +513,8 @@
XSetWindowAttributes attr;
unsigned long mask;
Window root;
- Window win;
- GLXContext ctx;
XVisualInfo *visinfo;
+ XSizeHints sizehints;
scrnum = DefaultScreen( dpy );
root = RootWindow( dpy, scrnum );
@@ -447,51 +532,72 @@
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 );
+ winRet[0] = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
/* set hints and properties */
- {
- XSizeHints sizehints;
- sizehints.x = x;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, winRet[0], &sizehints);
+ XSetStandardProperties(dpy, winRet[0], name, name,
+ None, (char **)NULL, 0, &sizehints);
+
+ if ( two_windows ) {
+ /* 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;
+
+ winRet[1] = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ sizehints.x = x + width + 10;
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);
+ XSetNormalHints(dpy, winRet[1], &sizehints);
+ XSetStandardProperties(dpy, winRet[1], "second window", "2nd win",
+ None, (char **)NULL, 0, &sizehints);
+ }
+ else {
+ winRet[1] = None;
}
- ctx = glXCreateContext( dpy, visinfo, NULL, True );
- if (!ctx) {
+ ctxRet[0] = glXCreateContext( dpy, visinfo, NULL, True );
+ if (! ctxRet[0] ) {
printf("Error: glXCreateContext failed\n");
exit(1);
}
XFree(visinfo);
-
- *winRet = win;
- *ctxRet = ctx;
}
static void
-event_loop(Display *dpy, Window win)
+event_loop(Display *dpy, Window *win, GLXContext ctx)
{
float frame_usage = 0.0;
while (1) {
while (XPending(dpy) > 0) {
- XEvent event;
- XNextEvent(dpy, &event);
+ XEvent event;
+ XNextEvent(dpy, &event);
switch (event.type) {
case Expose:
/* we'll redraw below */
break;
case ConfigureNotify:
- reshape(event.xconfigure.width, event.xconfigure.height);
+ reshape(event.xany.window,
+ event.xconfigure.width, event.xconfigure.height);
break;
case KeyPress:
{
@@ -525,15 +631,21 @@
/* next frame */
angle += 2.0;
+ glXMakeCurrent(dpy, win[0], ctx);
draw();
if ( get_frame_usage != NULL ) {
GLfloat temp;
- (*get_frame_usage)( dpy, win, & temp );
+ (*get_frame_usage)( dpy, win[0], & temp );
frame_usage += temp;
}
- glXSwapBuffers(dpy, win);
+ if ( win[1] != None ) {
+ draw2( dpy, win, ctx );
+ glXSwapBuffers(dpy, win[1]);
+ }
+
+ glXSwapBuffers(dpy, win[0]);
/* calc framerate */
{
@@ -699,16 +811,19 @@
main(int argc, char *argv[])
{
Display *dpy;
- Window win;
+ Window win[2];
GLXContext ctx;
char *dpyName = ":0";
int swap_interval = 1;
GLboolean do_swap_interval = GL_FALSE;
GLboolean force_get_rate = GL_FALSE;
GLboolean printInfo = GL_FALSE;
+ GLboolean use_two_windows = GL_FALSE;
int i;
PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL;
PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL;
+ GLint major;
+ GLint minor;
for (i = 1; i < argc; i++) {
@@ -734,6 +849,9 @@
else if (strcmp(argv[i], "-ztrick") == 0) {
use_ztrick = GL_TRUE;
}
+ else if (strcmp(argv[i], "-twowindow") == 0) {
+ use_two_windows = GL_TRUE;
+ }
else if (strcmp(argv[i], "-help") == 0) {
printf("Usage:\n");
printf(" gears [options]\n");
@@ -743,6 +861,12 @@
printf(" -info Display GL information\n");
printf(" -swap N Swap no more than once per N vertical
refreshes\n");
printf(" -forcegetrate Try to use glXGetMscRateOML function\n");
+ printf(" -ztrick Use the Quake 2 / Half-Life style
\"Z-trick\" to\n"
+ " avoid calling glClear. For testing only.
Does not\n"
+ " speed-up gears!\n" );
+ printf(" -twowindow Use two windows to test using one window as
a texture\n"
+ " for the other window. Tests GLX 1.3 and /
or\n"
+ " SGI_make_current_read.\n" );
return 0;
}
}
@@ -753,16 +877,19 @@
return -1;
}
- make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &ctx);
- XMapWindow(dpy, win);
- glXMakeCurrent(dpy, win, ctx);
+ make_window(dpy, "glxgears", 0, 0, 300, 300, win, &ctx, use_two_windows);
+ glXMakeCurrent( dpy, win[0], ctx );
make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) );
has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" );
+ has_SGI_make_current_read = is_extension_supported( "GLX_SGI_make_current_read" );
has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" );
has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" );
has_MESA_swap_frame_usage = is_extension_supported( "GLX_MESA_swap_frame_usage" );
+ glXQueryVersion( dpy, & major, & minor );
+ has_GLX_1_3 = (major > 1) || ((major == 1) && (minor >= 3));
+
if ( has_MESA_swap_control ) {
set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const
GLubyte *) "glXSwapIntervalMESA" );
get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB(
(const GLubyte *) "glXGetSwapIntervalMESA" );
@@ -786,6 +913,16 @@
show_refresh_rate( dpy );
}
+ if ( has_GLX_1_3 ) {
+ printf( "Using glXMakeContextCurrent.\n" );
+ }
+ else if ( has_SGI_make_current_read ) {
+ printf( "Using glXMakeCurrentReadSGI.\n" );
+ }
+ else {
+ printf( "Using glXMakeCurrent.\n" );
+ }
+
if ( get_swap_interval != NULL ) {
printf("Default swap interval = %d\n", (*get_swap_interval)() );
}
@@ -812,12 +949,21 @@
}
}
- init();
+ if ( win[1] != None ) {
+ XMapWindow(dpy, win[1]);
+ }
- event_loop(dpy, win);
+ XMapWindow(dpy, win[0]);
+ glXMakeCurrent(dpy, win[0], ctx);
+ init( use_two_windows );
+
+ event_loop(dpy, win, ctx);
glXDestroyContext(dpy, ctx);
- XDestroyWindow(dpy, win);
+ XDestroyWindow(dpy, win[0]);
+ if ( win[1] != None ) {
+ XDestroyWindow(dpy, win[1]);
+ }
XCloseDisplay(dpy);
return 0;
