Tutorial: OpenGL 3.0 Context Creation (GLX): Difference between revisions
Jump to navigation
Jump to search
Geometrian (talk | contribs) Improved some compile/portability errors in code |
|||
(4 intermediate revisions by 2 users not shown) | |||
Line 7: | Line 7: | ||
== The Code == | == The Code == | ||
< | <source lang="cpp"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
Line 24: | Line 24: | ||
// http://www.opengl.org/resources/features/OGLextensions/ | // http://www.opengl.org/resources/features/OGLextensions/ | ||
static bool isExtensionSupported(const char *extList, const char *extension) | static bool isExtensionSupported(const char *extList, const char *extension) | ||
{ | { | ||
const char *start; | const char *start; | ||
const char *where, *terminator; | const char *where, *terminator; | ||
Line 32: | Line 30: | ||
/* Extension names should not have spaces. */ | /* Extension names should not have spaces. */ | ||
where = strchr(extension, ' '); | where = strchr(extension, ' '); | ||
if ( where || *extension == '\0' ) | if (where || *extension == '\0') | ||
return false; | return false; | ||
Line 38: | Line 36: | ||
OpenGL extensions string. Don't be fooled by sub-strings, | OpenGL extensions string. Don't be fooled by sub-strings, | ||
etc. */ | etc. */ | ||
for ( start = extList; ; ) { | for (start=extList;;) { | ||
where = strstr( start, extension ); | where = strstr(start, extension); | ||
if ( !where ) | if (!where) | ||
break; | break; | ||
terminator = where + strlen( extension ); | terminator = where + strlen(extension); | ||
if ( where == start || *(where - 1) == ' ' ) | if ( where == start || *(where - 1) == ' ' ) | ||
Line 63: | Line 61: | ||
} | } | ||
int main (int argc, char | int main(int argc, char* argv[]) | ||
{ | { | ||
Display *display = XOpenDisplay( | Display *display = XOpenDisplay(NULL); | ||
if ( !display ) | if (!display) | ||
{ | { | ||
printf( "Failed to open X display\n" ); | printf("Failed to open X display\n"); | ||
exit(1); | exit(1); | ||
} | } | ||
Line 98: | Line 96: | ||
( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) | ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) | ||
{ | { | ||
printf( "Invalid GLX version" ); | printf("Invalid GLX version"); | ||
exit(1); | exit(1); | ||
} | } | ||
Line 104: | Line 102: | ||
printf( "Getting matching framebuffer configs\n" ); | printf( "Getting matching framebuffer configs\n" ); | ||
int fbcount; | int fbcount; | ||
GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ), | GLXFBConfig* fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount); | ||
if (!fbc) | |||
if ( !fbc ) | |||
{ | { | ||
printf( "Failed to retrieve a framebuffer config\n" ); | printf( "Failed to retrieve a framebuffer config\n" ); | ||
Line 118: | Line 115: | ||
int i; | int i; | ||
for ( i = 0; i < fbcount; | for (i=0; i<fbcount; ++i) | ||
{ | { | ||
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] ); | XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] ); | ||
Line 273: | Line 270: | ||
glXMakeCurrent( display, win, ctx ); | glXMakeCurrent( display, win, ctx ); | ||
glClearColor ( 0, 0.5, 1, 1 ); | glClearColor( 0, 0.5, 1, 1 ); | ||
glClear ( GL_COLOR_BUFFER_BIT ); | glClear( GL_COLOR_BUFFER_BIT ); | ||
glXSwapBuffers ( display, win ); | glXSwapBuffers ( display, win ); | ||
Line 291: | Line 288: | ||
XFreeColormap( display, cmap ); | XFreeColormap( display, cmap ); | ||
XCloseDisplay( display ); | XCloseDisplay( display ); | ||
return 0; | |||
} | } | ||
</ | </source> | ||
== Compilation == | == Compilation == | ||
cc -o gl3 gl3.cxx -lGL | cc -o gl3 gl3.cxx -lGL -lX11 | ||
== Execution == | == Execution == |
Latest revision as of 01:53, 27 December 2013
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.
It also shows how to choose the X visual / framebuffer format that has the highest number of multisample subsamples in it.
The Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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*);
// Helper to check for extension string presence. Adapted from:
// http://www.opengl.org/resources/features/OGLextensions/
static bool isExtensionSupported(const char *extList, const char *extension)
{
const char *start;
const char *where, *terminator;
/* Extension names should not have spaces. */
where = strchr(extension, ' ');
if (where || *extension == '\0')
return false;
/* It takes a bit of care to be fool-proof about parsing the
OpenGL extensions string. Don't be fooled by sub-strings,
etc. */
for (start=extList;;) {
where = strstr(start, extension);
if (!where)
break;
terminator = where + strlen(extension);
if ( where == start || *(where - 1) == ' ' )
if ( *terminator == ' ' || *terminator == '\0' )
return true;
start = terminator;
}
return false;
}
static bool ctxErrorOccurred = false;
static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
{
ctxErrorOccurred = true;
return 0;
}
int main(int argc, char* argv[])
{
Display *display = XOpenDisplay(NULL);
if (!display)
{
printf("Failed to open X display\n");
exit(1);
}
// 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
};
int glx_major, glx_minor;
// FBConfigs were added in GLX version 1.3.
if ( !glXQueryVersion( display, &glx_major, &glx_minor ) ||
( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) )
{
printf("Invalid GLX version");
exit(1);
}
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;
int i;
for (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 );
}
GLXFBConfig bestFbc = fbc[ best_fbc ];
// Be sure to free the FBConfig list allocated by glXChooseFBConfig()
XFree( fbc );
// Get a visual
XVisualInfo *vi = glXGetVisualFromFBConfig( display, bestFbc );
printf( "Chosen visual ID = 0x%x\n", vi->visualid );
printf( "Creating colormap\n" );
XSetWindowAttributes swa;
Colormap cmap;
swa.colormap = cmap = 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);
}
// Done with the visual info data
XFree( vi );
XStoreName( display, win, "GL 3.0 Window" );
printf( "Mapping window\n" );
XMapWindow( display, win );
// Get the default screen's GLX extension list
const char *glxExts = glXQueryExtensionsString( display,
DefaultScreen( display ) );
// NOTE: It is not necessary to create or make current to a context before
// calling glXGetProcAddressARB
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
GLXContext ctx = 0;
// Install an X error handler so the application won't exit if GL 3.0
// context allocation fails.
//
// Note this error handler is global. All display connections in all threads
// of a process use the same error handler, so be sure to guard against other
// threads issuing X commands while this code is running.
ctxErrorOccurred = false;
int (*oldHandler)(Display*, XErrorEvent*) =
XSetErrorHandler(&ctxErrorHandler);
// Check for the GLX_ARB_create_context extension string and the function.
// If either is not present, use GLX 1.3 context creation method.
if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) ||
!glXCreateContextAttribsARB )
{
printf( "glXCreateContextAttribsARB() not found"
" ... using old-style GLX context\n" );
ctx = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True );
}
// If it does, try to get a GL 3.0 context!
else
{
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, bestFbc, 0,
True, context_attribs );
// Sync to ensure any errors generated are processed.
XSync( display, False );
if ( !ctxErrorOccurred && ctx )
printf( "Created GL 3.0 context\n" );
else
{
// Couldn't create GL 3.0 context. Fall back to old-style 2.x context.
// When a context version below 3.0 is requested, implementations will
// return the newest context version compatible with OpenGL versions less
// than version 3.0.
// GLX_CONTEXT_MAJOR_VERSION_ARB = 1
context_attribs[1] = 1;
// GLX_CONTEXT_MINOR_VERSION_ARB = 0
context_attribs[3] = 0;
ctxErrorOccurred = false;
printf( "Failed to create GL 3.0 context"
" ... using old-style GLX context\n" );
ctx = glXCreateContextAttribsARB( display, bestFbc, 0,
True, context_attribs );
}
}
// Sync to ensure any errors generated are processed.
XSync( display, False );
// Restore the original error handler
XSetErrorHandler( oldHandler );
if ( ctxErrorOccurred || !ctx )
{
printf( "Failed to create an OpenGL context\n" );
exit(1);
}
// Verifying that context is a direct context
if ( ! glXIsDirect ( display, ctx ) )
{
printf( "Indirect GLX rendering context obtained\n" );
}
else
{
printf( "Direct GLX rendering context obtained\n" );
}
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 );
glXMakeCurrent( display, 0, 0 );
glXDestroyContext( display, ctx );
XDestroyWindow( display, win );
XFreeColormap( display, cmap );
XCloseDisplay( display );
return 0;
}
Compilation
cc -o gl3 gl3.cxx -lGL -lX11
Execution
> gl3 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 Direct GLX rendering context obtained Making context current