summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManolo Gouy <Manolo>2018-08-20 15:12:10 +0000
committerManolo Gouy <Manolo>2018-08-20 15:12:10 +0000
commitc0e04da27f29a989b65958de4deb7566d172bdbe (patch)
tree95ce7015015051e63823cccb0941a16d98bdb7c5
parentb26ace4b18be5450c4b3ba248a5c9df08652679d (diff)
Fix creation of OpenGL3+ context under X11 platform
The procedure given in https://www.khronos.org/opengl/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX) is now followed. This gives access to contexts for the highest OpenGL version supported by the hardware when flag FL_OPENGL3 is used in the call to Fl_Gl_Window::mode(int). git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@13021 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
-rw-r--r--src/Fl_Gl_Choice.H8
-rw-r--r--src/Fl_Gl_Choice.cxx108
2 files changed, 107 insertions, 9 deletions
diff --git a/src/Fl_Gl_Choice.H b/src/Fl_Gl_Choice.H
index bdee1c6c8..5c5b339ef 100644
--- a/src/Fl_Gl_Choice.H
+++ b/src/Fl_Gl_Choice.H
@@ -3,7 +3,7 @@
//
// OpenGL definitions for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2016 by Bill Spitzak and others.
+// Copyright 1998-2018 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -50,9 +50,13 @@
#ifdef FL_CFG_GFX_XLIB
# include <GL/glx.h>
+# if ! defined(GLX_VERSION_1_3)
+# typedef void *GLXFBConfig;
+# endif
# define FL_GL_CHOICE_PLATFORM_SPECIFIC_MEMBERS \
XVisualInfo *vis; /* the visual to use */ \
- Colormap colormap; // a colormap for that visual
+ Colormap colormap; /* a colormap for that visual */ \
+ GLXFBConfig best_fb;
#endif // FL_CFG_GFX_XLIB*/
diff --git a/src/Fl_Gl_Choice.cxx b/src/Fl_Gl_Choice.cxx
index 014635e14..3fbce41f7 100644
--- a/src/Fl_Gl_Choice.cxx
+++ b/src/Fl_Gl_Choice.cxx
@@ -231,6 +231,53 @@ void Fl_WinAPI_Gl_Window_Driver::delete_gl_context(GLContext context) {
#ifdef FL_CFG_GFX_XLIB
# include <FL/platform.H>
+static XVisualInfo *gl3_getvisual(const int *blist, GLXFBConfig *pbestFB)
+{
+ int glx_major, glx_minor;
+
+ // FBConfigs were added in GLX version 1.3.
+ if ( !glXQueryVersion(fl_display, &glx_major, &glx_minor) ||
+ ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) {
+ return NULL;
+ }
+
+ //printf( "Getting matching framebuffer configs\n" );
+ int fbcount;
+ GLXFBConfig* fbc = glXChooseFBConfig(fl_display, DefaultScreen(fl_display), blist, &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
+ 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( fl_display, fbc[i] );
+ if (vi) {
+ int samp_buf, samples;
+ glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
+ glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLES , &samples );
+ /*printf( " Matching fbconfig %d, visual ID 0x%2lx: 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(fl_display, bestFbc);
+ *pbestFB = bestFbc;
+ return vi;
+}
+
Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp)
{
Fl_Gl_Choice *g = Fl_Gl_Window_Driver::find_begin(m, alistp);
@@ -286,18 +333,26 @@ Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp)
}
fl_open_display();
- XVisualInfo *visp = glXChooseVisual(fl_display, fl_screen, (int *)blist);
+ XVisualInfo *visp = NULL;
+ GLXFBConfig best_fb = NULL;
+ if (m & FL_OPENGL3) {
+ visp = gl3_getvisual((const int *)blist, &best_fb);
+ }
if (!visp) {
-# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
- if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE,0);
-# endif
- return 0;
+ visp = glXChooseVisual(fl_display, fl_screen, (int *)blist);
+ if (!visp) {
+# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
+ if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE, 0);
+# endif
+ return 0;
+ }
}
g = new Fl_Gl_Choice(m, alistp, first);
first = g;
g->vis = visp;
+ g->best_fb = best_fb;
if (/*MaxCmapsOfScreen(ScreenOfDisplay(fl_display,fl_screen))==1 && */
visp->visualid == fl_visual->visualid &&
@@ -306,13 +361,52 @@ Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp)
else
g->colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen),
visp->visual, AllocNone);
-
return g;
}
+static bool ctxErrorOccurred = false;
+static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
+{
+ ctxErrorOccurred = true;
+ return 0;
+}
GLContext Fl_X11_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) {
- return create_gl_context(g->vis);
+ GLContext shared_ctx = 0;
+ if (context_list && nContext) shared_ctx = context_list[0];
+
+ typedef GLContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLContext, Bool, const int*);
+ // It is not necessary to create or make current to a context before calling glXGetProcAddressARB
+ static glXCreateContextAttribsARBProc glXCreateContextAttribsARB =
+ (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB");
+
+ GLContext ctx = 0;
+ // Check for the GLX_ARB_create_context extension string and the function.
+ // If either is not present, use GLX 1.3 context creation method.
+ const char *glxExts = glXQueryExtensionsString(fl_display, fl_screen);
+ if (g->best_fb && strstr(glxExts, "GLX_ARB_create_context") && glXCreateContextAttribsARB ) {
+ int context_attribs[] =
+ {
+ GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+ GLX_CONTEXT_MINOR_VERSION_ARB, 2,
+ //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+ //GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+ None
+ };
+ ctxErrorOccurred = false;
+ XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
+ ctx = glXCreateContextAttribsARB(fl_display, g->best_fb, shared_ctx, true, context_attribs);
+ XSync(fl_display, false); // Sync to ensure any errors generated are processed.
+ if (ctxErrorOccurred) ctx = 0;
+ XSetErrorHandler(oldHandler);
+ }
+ if (!ctx) { // use OpenGL 1-style context creation
+ ctx = glXCreateContext(fl_display, g->vis, shared_ctx, true);
+ }
+ if (ctx)
+ add_context(ctx);
+//glXMakeCurrent(fl_display, fl_xid(window), ctx);printf("%s\n", glGetString(GL_VERSION));
+ return ctx;
}
GLContext Fl_X11_Gl_Window_Driver::create_gl_context(XVisualInfo *vis) {