Tutorial: OpenGL 3.0 Context Creation (GLX)
Overview
This tutorial illustrates (with a working program) how to create an OpenGL 3.0 context using the new glXCreateContextAttribsARB()
API. In the event that this API is unsupported or fails, we fall back and create a standard (old-style) GL 2.1 context.
The Code
#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <unistd.h>
- define GL_GLEXT_PROTOTYPES 1
- define GLX_GLXEXT_PROTOTYPES 1
- include <X11/Xlib.h>
- include <X11/Xutil.h>
- include <GL/gl.h>
- include <GL/glx.h>
- define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
- define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
int main (int argc, char ** argv)
{
Display *display = XOpenDisplay(0);
if ( !display )
{
printf( "Failed to open X display\n" );
exit(1);
}
// // Query/print GLX version
// int major, minor;
//
// if ( !glXQueryVersion( display, &major, &minor ) )
// {
// printf( "glXQueryVersion failed\n" );
// exit(1);
// }
// printf( "GLX version = %d.%d\n", major, minor );
//
// if ( major < 1 || major == 1 && minor < 3 )
// {
// printf( "GLX version is too old; must be > 1.3\n" );
// exit(1);
// }
// // Print GLX extensions
// const char *extensions = glXQueryExtensionsString( display,
// DefaultScreen( display ) );
// printf( "%s\n", extensions );
// Get a matching FB config
static int visual_attribs[] =
{
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_ALPHA_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , True,
//GLX_SAMPLE_BUFFERS , 1,
//GLX_SAMPLES , 4,
None
};
printf( "Getting matching framebuffer configs\n" );
int fbcount;
GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ),
visual_attribs, &fbcount );
if ( !fbc )
{
printf( "Failed to retrieve a framebuffer config\n" );
exit(1);
}
printf( "Found %d matching FB configs.\n", fbcount );
// Pick the FB config/visual with the most samples per pixel
printf( "Getting XVisualInfos\n" );
int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
for ( int i = 0; i < fbcount; i++ )
{
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
if ( vi )
{
int samp_buf, samples;
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
" SAMPLES = %d\n",
i, vi -> visualid, samp_buf, samples );
if ( best_fbc < 0 || samp_buf && samples > best_num_samp )
best_fbc = i, best_num_samp = samples;
if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp )
worst_fbc = i, worst_num_samp = samples;
}
XFree( vi );
}
// Get a visual
int fbc_id = best_fbc;
//int fbc_id = worst_fbc;
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[ fbc_id ] );
printf( "Chosen visual ID = 0x%x\n", vi->visualid );
printf( "Creating colormap\n" );
XSetWindowAttributes swa;
swa.colormap = XCreateColormap( display, RootWindow( display, vi->screen ),
vi->visual, AllocNone );
swa.background_pixmap = None ;
swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
printf( "Creating window\n" );
Window win = XCreateWindow( display, RootWindow( display, vi->screen ),
0, 0, 100, 100, 0, vi->depth, InputOutput,
vi->visual,
CWBorderPixel|CWColormap|CWEventMask, &swa );
if ( !win )
{
printf( "Failed to create window.\n" );
exit(1);
}
XStoreName( display, win, "GL 3.0 Window");
printf( "Mapping window\n" );
XMapWindow( display, win );
// See if GL driver supports glXCreateContextAttribsARB()
// Create an old-style GLX context first, to get the correct function ptr.
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
GLXContext ctx_old = glXCreateContext( display, vi, 0, True );
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddress( (const GLubyte *) "glXCreateContextAttribsARB" );
GLXContext ctx = 0;
// If it doesn't, just use the old-style 2.x GLX context
if ( !glXCreateContextAttribsARB )
{
printf( "glXCreateContextAttribsARB() not found"
" ... using old-style GLX context\n" );
ctx = ctx_old;
}
// If it "does", try to get a GL 3.0 context!
else
{
glXMakeCurrent( display, 0, 0 );
glXDestroyContext( display, ctx_old );
static int context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
printf( "Creating context\n" );
ctx = glXCreateContextAttribsARB( display, fbc[ fbc_id ], 0,
True, context_attribs );
if ( ctx )
printf( "Created GL 3.0 context\n" );
else
{
// Couldn't create GL 3.0 context. Fall back to old-style 2.x context.
printf( "Failed to create GL 3.0 context"
" ... using old-style GLX context\n" );
ctx = glXCreateContext( display, vi, 0, True );
}
}
XFree( fbc );
// Verifying that context is a direct context
printf( "Verifying that context is direct\n" );
if ( ! glXIsDirect ( display, ctx ) )
{
printf( "Indirect GLX rendering context obtained" );
exit(1);
}
printf( "Making context current\n" );
glXMakeCurrent( display, win, ctx );
glClearColor ( 0, 0.5, 1, 1 );
glClear ( GL_COLOR_BUFFER_BIT );
glXSwapBuffers ( display, win );
sleep( 1 );
glClearColor ( 1, 0.5, 0, 1 );
glClear ( GL_COLOR_BUFFER_BIT );
glXSwapBuffers ( display, win );
sleep( 1 );
ctx = glXGetCurrentContext( );
glXMakeCurrent( display, 0, 0 );
glXDestroyContext( display, ctx );
}
Compilation
g++ -o gl3 gl3.cxx -lGL
Execution
> gl3 GLX version = 1.3 Getting matching framebuffer configs Found 3 matching FB configs. Getting XVisualInfos Matching fbconfig 0, visual ID 0x23: SAMPLE_BUFFERS = 0, SAMPLES = 0 Matching fbconfig 1, visual ID 0x37: SAMPLE_BUFFERS = 1, SAMPLES = 2 Matching fbconfig 2, visual ID 0x39: SAMPLE_BUFFERS = 1, SAMPLES = 4 Chosen visual ID = 0x39 Creating colormap Creating window Mapping window Creating context Created GL 3.0 context Verifying that context is direct Making context current