From 226b64e9bdae9383aeaa6735d28ce0470b190b83 Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Thu, 6 Sep 2018 16:51:31 +0000 Subject: [PATCH] X11 + OpenGL: new procedure to create OpenGL3+ contexts giving access to the highest OpenGL version supported by GLX. The ABI compatibility was checked with the abi-compliance-checker tool. The same code has already been committed in the 1.4 branch. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@13043 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- FL/Fl_Gl_Window.H | 15 ++--- documentation/src/opengl.dox | 23 ++++--- src/Fl_Gl_Choice.H | 12 ++-- src/Fl_Gl_Choice.cxx | 123 +++++++++++++++++++++++++++++++++-- 4 files changed, 146 insertions(+), 27 deletions(-) diff --git a/FL/Fl_Gl_Window.H b/FL/Fl_Gl_Window.H index 6881c1806..ceb710469 100644 --- a/FL/Fl_Gl_Window.H +++ b/FL/Fl_Gl_Window.H @@ -149,7 +149,7 @@ public: - \c FL_DEPTH - depth buffer - \c FL_STENCIL - stencil buffer - \c FL_MULTISAMPLE - multisample antialiasing - - \c FL_OPENGL3 - use OpenGL version 3.0 or more when running Mac OS. + - \c FL_OPENGL3 - use OpenGL version 3.0 or more. FL_RGB and FL_SINGLE have a value of zero, so they are "on" unless you give FL_INDEX or FL_DOUBLE. @@ -169,16 +169,9 @@ public: mode() must not be called within draw() since it changes the current context. - \note On the MSWindows and Unix/Linux platforms, FLTK produces - contexts for the highest OpenGL version supported by the hardware. Such contexts - are also compatible with lower OpenGL versions. On the Apple OS X - platform, it is necessary to decide whether the source code targets - OpenGL versions higher or lower than 3.0. By default, FLTK - creates contexts adequate for OpenGL versions 1 and 2. To get contexts - for OpenGL 3.0 or higher, the FL_OPENGL3 flag and Mac OS - version 10.7 or higher are required (in that case the context is NOT - compatible with OpenGL versions 1 or 2). The FL_OPENGL3 flag has no - effect on non-Apple platforms. + The FL_OPENGL3 flag is required to access OpenGL version 3 or more + under the X11 and MacOS platforms; it's optional under Windows. + See more details in \ref opengl3. \version the FL_OPENGL3 flag appeared in version 1.3.4 */ diff --git a/documentation/src/opengl.dox b/documentation/src/opengl.dox index 00bcf19bc..de1c79224 100644 --- a/documentation/src/opengl.dox +++ b/documentation/src/opengl.dox @@ -456,14 +456,21 @@ showing how to use OpenGL 3.0 (or higher versions) with FLTK in a cross-platform It contains also OpenGL3-glut-test.cxx which shows how to use FLTK's GLUT compatibility and OpenGL 3. -On the MSWindows and Unix/Linux platforms, FLTK creates contexts implementing -the highest OpenGL version supported by the hardware, -which are also compatible with lower OpenGL versions. Thus, FLTK allows -source code targeting any version of OpenGL. Access to functions from OpenGL versions above 1.1 requires to load function pointers at runtime on these platforms. FLTK recommends to use the GLEW library to perform this. It is therefore -necessary to install the GLEW library (see below). On the Mac OS X platform, -FLTK creates by default contexts implementing OpenGL versions 1 or 2. -To access OpenGL 3.0 (or higher versions), use the FL_OPENGL3 flag (see below). -Mac OS 10.7 or above is required; GLEW is possible but not necessary. +To access OpenGL 3.0 (or higher versions), use the FL_OPENGL3 flag +when calling Fl_Gl_Window::mode(int a) or glutInitDisplayMode(). + +On the Windows and Unix/Linux platforms, FLTK creates contexts +implementing the highest OpenGL version supported by the hardware. +Such contexts may also be compatible with lower OpenGL versions. +Access to functions from OpenGL +versions above 1.1 requires to load function pointers at runtime on these platforms. +FLTK recommends to use the GLEW library to perform this. It is therefore +necessary to install the GLEW library (see below). + +On the macOS platform, MacOS 10.7 or above is required; +GLEW is possible but not necessary. FLTK creates contexts for OpenGL +versions 1 and 2 without the FL_OPENGL3 +flag and for OpenGL versions 3.2 and above with it. \par GLEW installation (Unix/Linux and MSWindows platforms) GLEW is available as a package for most Linux distributions and in source form at http://glew.sourceforge.net/. diff --git a/src/Fl_Gl_Choice.H b/src/Fl_Gl_Choice.H index 2d5e2fcb9..790c6372d 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-2010 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 @@ -64,6 +64,9 @@ typedef NSOpenGLContext* FLOpenGLContextPtr; #else # include # define GLContext GLXContext +# if ! defined(GLX_VERSION_1_3) +# typedef void *GLXFBConfig; +# endif #endif // Describes crap needed to create a GLContext. @@ -80,6 +83,7 @@ public: #else XVisualInfo *vis; // the visual to use Colormap colormap; // a colormap for that visual + GLXFBConfig best_fb; #endif // Return one of these structures for a given gl mode. // The second argument is a glX attribute list, and is used if mode is @@ -101,10 +105,10 @@ GLContext fl_create_gl_context(Fl_Window*, const Fl_Gl_Choice*, int layer=0); GLContext fl_create_gl_context(XVisualInfo* vis); -static inline -GLContext fl_create_gl_context(Fl_Window*, const Fl_Gl_Choice* g) { +//static inline + GLContext fl_create_gl_context(Fl_Window*, const Fl_Gl_Choice* g);/* { return fl_create_gl_context(g->vis); -} +}*/ #endif diff --git a/src/Fl_Gl_Choice.cxx b/src/Fl_Gl_Choice.cxx index edb0843f2..6e270f60c 100644 --- a/src/Fl_Gl_Choice.cxx +++ b/src/Fl_Gl_Choice.cxx @@ -3,7 +3,7 @@ // // OpenGL visual selection code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2010 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 @@ -33,6 +33,63 @@ void fl_save_dc(HWND, HDC); extern void gl_texture_reset(); #endif +#if defined(USE_X11) +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 ) ) + { + //printf("Invalid GLX version"); + 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; + + int i; + for (i=0; i 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; +} +#endif + static Fl_Gl_Choice *first; // this assumes one of the two arguments is zero: @@ -96,12 +153,19 @@ Fl_Gl_Choice *Fl_Gl_Choice::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) { + 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); + if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE,0); # endif - return 0; + return 0; + } } #elif defined(__APPLE_QUARTZ__) @@ -155,6 +219,7 @@ Fl_Gl_Choice *Fl_Gl_Choice::find(int m, const int *alistp) { #if defined(USE_X11) g->vis = visp; + g->best_fb = best_fb; if (/*MaxCmapsOfScreen(ScreenOfDisplay(fl_display,fl_screen))==1 && */ visp->visualid == fl_visual->visualid && @@ -204,6 +269,56 @@ static void del_context(GLContext ctx) { #if defined(USE_X11) +static bool ctxErrorOccurred = false; +static int ctxErrorHandler( Display *dpy, XErrorEvent *ev ) +{ + ctxErrorOccurred = true; + return 0; +} + + +GLContext fl_create_gl_context(Fl_Window *window, const Fl_Gl_Choice* g) { + 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 ); + // Sync to ensure any errors generated are processed. + XSync( fl_display, False ); + 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_create_gl_context(XVisualInfo* vis) { GLContext shared_ctx = 0; if (context_list && nContext) shared_ctx = context_list[0];