* This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
* Port by Brian Paul 23 March 2001
*
- * Command line options:
- * -info print GL implementation information
- * -stereo use stereo enabled GLX visual
- *
+ * See usage() below for command line options.
*/
#include <X11/keysym.h>
#include <GL/gl.h>
#include <GL/glx.h>
+#include <GL/glxext.h>
+
+#ifndef GLX_MESA_swap_control
+#define GLX_MESA_swap_control 1
+typedef int (*PFNGLXGETSWAPINTERVALMESAPROC)(void);
+#endif
#define BENCHMARK
}
+/**
+ * Remove window border/decorations.
+ */
+static void
+no_border( Display *dpy, Window w)
+{
+ static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
+ static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
+
+ typedef struct
+ {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+ } PropMotifWmHints;
+
+ PropMotifWmHints motif_hints;
+ Atom prop, proptype;
+ unsigned long flags = 0;
+
+ /* setup the property */
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = flags;
+
+ /* get the atom for the property */
+ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
+ if (!prop) {
+ /* something went wrong! */
+ return;
+ }
+
+ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
+ proptype = prop;
+
+ XChangeProperty( dpy, w, /* display, window */
+ prop, proptype, /* property, type */
+ 32, /* format: 32-bit datums */
+ PropModeReplace, /* mode */
+ (unsigned char *) &motif_hints, /* data */
+ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
+ );
+}
+
+
/*
* Create an RGB, double-buffered window.
* Return the window and context handles.
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;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
win = XCreateWindow( dpy, root, x, y, width, height,
0, visinfo->depth, InputOutput,
visinfo->visual, mask, &attr );
+ if (fullscreen)
+ no_border(dpy, win);
+
/* set hints and properties */
{
XSizeHints sizehints;
}
+/**
+ * Determine whether or not a GLX extension is supported.
+ */
+static int
+is_glx_extension_supported(Display *dpy, const char *query)
+{
+ const int scrnum = DefaultScreen(dpy);
+ const char *glx_extensions = NULL;
+ const size_t len = strlen(query);
+ const char *ptr;
+
+ if (glx_extensions == NULL) {
+ glx_extensions = glXQueryExtensionsString(dpy, scrnum);
+ }
+
+ ptr = strstr(glx_extensions, query);
+ return ((ptr != NULL) && ((ptr[len] == ' ') || (ptr[len] == '\0')));
+}
+
+
+/**
+ * Attempt to determine whether or not the display is synched to vblank.
+ */
+static void
+query_vsync(Display *dpy, GLXDrawable drawable)
+{
+ int interval = 0;
+
+#if defined(GLX_EXT_swap_control)
+ if (is_glx_extension_supported(dpy, "GLX_EXT_swap_control")) {
+ unsigned int tmp = -1;
+ glXQueryDrawable(dpy, drawable, GLX_SWAP_INTERVAL_EXT, &tmp);
+ interval = tmp;
+ } else
+#endif
+ if (is_glx_extension_supported(dpy, "GLX_MESA_swap_control")) {
+ PFNGLXGETSWAPINTERVALMESAPROC pglXGetSwapIntervalMESA =
+ (PFNGLXGETSWAPINTERVALMESAPROC)
+ glXGetProcAddressARB((const GLubyte *) "glXGetSwapIntervalMESA");
+
+ interval = (*pglXGetSwapIntervalMESA)();
+ } else if (is_glx_extension_supported(dpy, "GLX_SGI_swap_control")) {
+ /* The default swap interval with this extension is 1. Assume that it
+ * is set to the default.
+ *
+ * Many Mesa-based drivers default to 0, but all of these drivers also
+ * export GLX_MESA_swap_control. In that case, this branch will never
+ * be taken, and the correct result should be reported.
+ */
+ interval = 1;
+ }
+
+
+ if (interval > 0) {
+ printf("Running synchronized to the vertical refresh. The framerate should be\n");
+ if (interval == 1) {
+ printf("approximately the same as the monitor refresh rate.\n");
+ } else if (interval > 1) {
+ printf("approximately 1/%d the monitor refresh rate.\n",
+ interval);
+ }
+ }
+}
+
/**
* Handle one X event.
* \return NOP, EXIT or DRAW
static int
handle_event(Display *dpy, Window win, XEvent *event)
{
+ (void) dpy;
+ (void) win;
+
switch (event->type) {
case Expose:
return DRAW;
make_window(dpy, "glxgears", x, y, winWidth, winHeight, &win, &ctx);
XMapWindow(dpy, win);
glXMakeCurrent(dpy, win, ctx);
+ query_vsync(dpy, win);
if (printInfo) {
printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
glDeleteLists(gear1, 1);
glDeleteLists(gear2, 1);
glDeleteLists(gear3, 1);
+ glXMakeCurrent(dpy, None, NULL);
glXDestroyContext(dpy, ctx);
XDestroyWindow(dpy, win);
XCloseDisplay(dpy);