Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
360 changes: 353 additions & 7 deletions examples/pxScene2d/src/glut/pxContextUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,369 @@ limitations under the License.

#include "pxContextUtils.h"

#include <GL/gl.h>
#include <GL/glu.h>

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glx.h>
#include <X11/Xlib.h>


#include <map>
#include "rtLog.h"
#include "rtMutex.h"

bool glContextIsCurrent = false;
rtMutex eglContextMutex;
int nextInternalContextId = 1;
#define GL_MAJOR_VERSION 0x821B
#define GL_MINOR_VERSION 0x821C
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);

extern GLXContext *openGLContext;
#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;
}
std::map<int, GLXContext *> internalContexts;
static bool ctxErrorOccurred = false;
static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
{
ctxErrorOccurred = true;
return 0;
}

GLXContext* getContext()
{
Display *display = XOpenDisplay(NULL);

if (!display)
{
printf("Failed to open X display\n");
return NULL;
}

// 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");
return NULL;
}

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" );
return NULL;
}
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;

pxError createInternalContext(int &id, bool /*depthBuffer*/)
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" );
return NULL;
}

// 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.
bool 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 2.1 context!
else
{
int context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
//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 2.1 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 2.1 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" );
return NULL;
}

// 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 );

glClearColor ( 1, 0.5, 0, 1 );
glClear ( GL_COLOR_BUFFER_BIT );
glXSwapBuffers ( display, win );

glXMakeCurrent( display, 0, 0 );
glXDestroyContext( display, ctx );

XDestroyWindow( display, win );
XFreeColormap( display, cmap );
XCloseDisplay( display );

return &ctx;
}

pxError createGLContext(int id, bool depthBuffer)
{
id = nextInternalContextId++;
//TODO
GLXContext *context = NULL;
rtMutexLockGuard eglContextMutexGuard(eglContextMutex);
if ( internalContexts.find(id) != internalContexts.end() )
{
context = internalContexts.at(id);
}
if (context == NULL)
{
internalContexts[id] = getContext();
}
return PX_OK;
}

pxError createInternalContext(int &id, bool depthBuffer)
{
{
rtMutexLockGuard eglContextMutexGuard(eglContextMutex);
id = nextInternalContextId++;
}
createGLContext(id, depthBuffer);
return PX_OK;
}

pxError deleteInternalGLContext(int)
pxError deleteInternalGLContext(int id)
{
//TODO
rtMutexLockGuard eglContextMutexGuard(eglContextMutex);
if ( internalContexts.find(id) != internalContexts.end() )
{
internalContexts.erase(id);
}
return PX_OK;
}

pxError makeInternalGLContextCurrent(bool, int)
pxError makeInternalGLContextCurrent(bool current, int id)
{
//TODO
if (current)
{
GLXContext *context = NULL;
{
rtMutexLockGuard eglContextMutexGuard(eglContextMutex);
if (internalContexts.find(id) != internalContexts.end())
{
context = internalContexts.at(id);
}
}
if (context != NULL)
{
createGLContext(id, false);
{
rtMutexLockGuard eglContextMutexGuard(eglContextMutex);
context = internalContexts[id];
}
// [context makeCurrentContext];

#if 0
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
#endif
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
}
glContextIsCurrent = true;
}
else
{
glFlush();
// [openGLContext makeCurrentContext];
glContextIsCurrent = false;
}
return PX_OK;
}