Browse Source

Support OpenGL debugging features (see gl-debug).
Also fixed the GLX code not to call reset() on the temp context but on the real context instead.

rdb 11 years ago
parent
commit
128f82863e

+ 99 - 6
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -337,6 +337,49 @@ CLP(GraphicsStateGuardian)::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::debug_callback
+//       Access: Public, Static
+//  Description: This is called by the GL if an error occurs, if
+//               gl_debug has been enabled (and the driver supports
+//               the GL_ARB_debug_output extension).
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam) {
+  // Determine how to map the severity level.
+  NotifySeverity level;
+  switch (severity) {
+  case GL_DEBUG_SEVERITY_HIGH:
+    level = NS_error;
+    break;
+
+  case GL_DEBUG_SEVERITY_MEDIUM:
+    level = NS_warning;
+    break;
+
+  case GL_DEBUG_SEVERITY_LOW:
+    level = NS_info;
+    break;
+
+  case GL_DEBUG_SEVERITY_NOTIFICATION:
+    level = NS_debug;
+    break;
+
+  default:
+    level = NS_fatal; //???
+    break;
+  }
+
+  string msg_str(message, length);
+  GLCAT.out(level) << msg_str << "\n";
+
+#ifndef NDEBUG
+  if (level >= gl_debug_abort_level.get_value()) {
+    abort();
+  }
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::reset
 //       Access: Public, Virtual
@@ -386,10 +429,65 @@ reset() {
   }
 
   // Save the extensions tokens.
+  _extensions.clear();
   save_extensions((const char *)glGetString(GL_EXTENSIONS));
   get_extra_extensions();
   report_extensions();
 
+  // Initialize OpenGL debugging output first, if enabled and supported.
+  if (gl_debug) {
+    bool supports_debug = false;
+    PFNGLDEBUGMESSAGECALLBACKPROC _glDebugMessageCallback;
+    PFNGLDEBUGMESSAGECONTROLPROC _glDebugMessageControl;
+
+    if (is_at_least_gl_version(4, 3) || has_extension("GL_KHR_debug")) {
+#ifdef OPENGLES
+      _glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)
+        get_extension_func("glDebugMessageCallbackKHR");
+      _glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)
+        get_extension_func("glDebugMessageControlKHR");
+#else
+      _glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)
+        get_extension_func("glDebugMessageCallback");
+      _glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)
+        get_extension_func("glDebugMessageControl");
+#endif
+      glEnable(GL_DEBUG_OUTPUT); // Not supported in ARB version
+      supports_debug = true;
+
+    } else if (has_extension("GL_ARB_debug_output")) {
+      _glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)
+        get_extension_func("glDebugMessageCallbackARB");
+      _glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)
+        get_extension_func("glDebugMessageControlARB");
+      supports_debug = true;
+    }
+
+    if (supports_debug) {
+      // Set the categories we want to listen to.
+      _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH,
+                             0, NULL, GLCAT.is_error());
+      _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM,
+                             0, NULL, GLCAT.is_warning());
+      _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW,
+                             0, NULL, GLCAT.is_info());
+      _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION,
+                             0, NULL, GLCAT.is_debug());
+
+      // Enable the callback.
+      _glDebugMessageCallback(&debug_callback, (void*)this);
+      if (gl_debug_synchronous) {
+        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+      }
+
+      GLCAT.error() << "gl-debug enabled.\n";
+    } else {
+      GLCAT.error() << "gl-debug enabled, but NOT supported.\n";
+    }
+  } else {
+    GLCAT.debug() << "gl-debug NOT enabled.\n";
+  }
+
   _supported_geom_rendering =
     Geom::GR_indexed_point |
     Geom::GR_point | Geom::GR_point_uniform_size |
@@ -634,7 +732,6 @@ reset() {
   }
 #endif
 
-  _cube_map_seamless = false;
 #ifdef OPENGLES_2
   _supports_cube_map = true;
 #else
@@ -644,7 +741,7 @@ reset() {
 
   if (_supports_cube_map && gl_cube_map_seamless) {
     if (is_at_least_gl_version(3, 2) || has_extension("GL_ARB_seamless_cube_map")) {
-      _cube_map_seamless = true;
+      glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
     }
   }
 #endif
@@ -2235,10 +2332,6 @@ begin_frame(Thread *current_thread) {
   }
 #endif  // NDEBUG
 
-  if (_cube_map_seamless) {
-    glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
-  }
-
   if (_current_properties->get_srgb_color()) {
     glEnable(GL_FRAMEBUFFER_SRGB);
   }

+ 6 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -55,6 +55,9 @@ typedef double GLdouble;
 // functions are defined, and the system gl.h sometimes doesn't
 // declare these typedefs.
 #if !defined( __EDG__ ) || defined( __INTEL_COMPILER )  // Protect the following from the Tau instrumentor and expose it for the intel compiler.
+typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
 typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img);
 typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
 typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
@@ -196,6 +199,8 @@ public:
   virtual int get_driver_shader_version_major();
   virtual int get_driver_shader_version_minor();
   
+  static void debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam);
+
   virtual void reset();
 
   virtual void prepare_display_region(DisplayRegionPipelineReader *dr);
@@ -543,6 +548,7 @@ protected:
   int _gl_version_major, _gl_version_minor;
   //#--- Zhao Nov/2011
   int _gl_shadlang_ver_major, _gl_shadlang_ver_minor;
+
   pset<string> _extensions;
 
 public:
@@ -582,7 +588,6 @@ public:
   PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC _glCompressedTexSubImage3D;
   PFNGLGETCOMPRESSEDTEXIMAGEPROC _glGetCompressedTexImage;
 
-  bool _cube_map_seamless;
   bool _supports_bgr;
   bool _supports_rescale_normal;
 

+ 25 - 0
panda/src/glstuff/glmisc_src.cxx

@@ -126,6 +126,31 @@ ConfigVariableEnum<GeomEnums::UsageHint> gl_min_buffer_usage_hint
             "of reusing the same buffers.  Consider increasing "
             "released-vbuffer-cache-size instead."));
 
+ConfigVariableBool gl_debug
+  ("gl-debug", false,
+   PRC_DESC("Setting this to true will cause OpenGL to emit more useful "
+            "error and debug messages, at a slight runtime performance cost.  "
+            "notify-level-glgsg controls which severity levels are shown."));
+
+ConfigVariableBool gl_debug_synchronous
+  ("gl-debug-synchronous", false,
+   PRC_DESC("Set this true to make sure that the errors generated by "
+            "gl-debug are reported as soon as they happen.  This is "
+            "highly recommended if you want to attach a debugger since "
+            "the call stack may otherwise not point to the GL call "
+            "where the error originated."));
+
+ConfigVariableEnum<NotifySeverity> gl_debug_abort_level
+  ("gl-debug-abort-level", NS_fatal,
+   PRC_DESC("Set this to a setting other than 'fatal' to cause an "
+            "abort to be triggered when an error of the indicated "
+            "severity level (or a more severe one) occurs.  This is "
+            "useful if you want to attach a debugger.  If you set this, "
+            "it is highly recommended to also set gl-debug-synchronous, "
+            "since the call stack will otherwise not point to the GL call "
+            "that triggered the error message.  "
+            "This feature is not available when NDEBUG has been defined."));
+
 ConfigVariableBool gl_debug_buffers
   ("gl-debug-buffers", false,
    PRC_DESC("Set this true, in addition to enabling debug notify for "

+ 3 - 0
panda/src/glstuff/glmisc_src.h

@@ -55,6 +55,9 @@ extern ConfigVariableBool gl_interleaved_arrays;
 extern ConfigVariableBool gl_parallel_arrays;
 extern ConfigVariableInt gl_max_errors;
 extern ConfigVariableEnum<GeomEnums::UsageHint> gl_min_buffer_usage_hint;
+extern ConfigVariableBool gl_debug;
+extern ConfigVariableBool gl_debug_synchronous;
+extern ConfigVariableEnum<NotifySeverity> gl_debug_abort_level;
 extern ConfigVariableBool gl_debug_buffers;
 extern ConfigVariableBool gl_finish;
 extern ConfigVariableBool gl_force_depth_stencil;

+ 74 - 0
panda/src/glstuff/panda_glext.h

@@ -2398,6 +2398,50 @@ extern "C" {
 #define GL_TEXTURE_IMMUTABLE_FORMAT       0x912F
 #endif
 
+#ifndef GL_KHR_debug
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS       0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION        0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM      0x8245
+#define GL_DEBUG_SOURCE_API               0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM     0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER   0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY       0x8249
+#define GL_DEBUG_SOURCE_APPLICATION       0x824A
+#define GL_DEBUG_SOURCE_OTHER             0x824B
+#define GL_DEBUG_TYPE_ERROR               0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR  0x824E
+#define GL_DEBUG_TYPE_PORTABILITY         0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE         0x8250
+#define GL_DEBUG_TYPE_OTHER               0x8251
+#define GL_DEBUG_TYPE_MARKER              0x8268
+#define GL_DEBUG_TYPE_PUSH_GROUP          0x8269
+#define GL_DEBUG_TYPE_POP_GROUP           0x826A
+#define GL_DEBUG_SEVERITY_NOTIFICATION    0x826B
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH    0x826C
+#define GL_DEBUG_GROUP_STACK_DEPTH        0x826D
+#define GL_BUFFER                         0x82E0
+#define GL_SHADER                         0x82E1
+#define GL_PROGRAM                        0x82E2
+#define GL_QUERY                          0x82E3
+#define GL_PROGRAM_PIPELINE               0x82E4
+#define GL_SAMPLER                        0x82E6
+#define GL_DISPLAY_LIST                   0x82E7
+/* DISPLAY_LIST used in compatibility profile only */
+#define GL_MAX_LABEL_LENGTH               0x82E8
+#define GL_MAX_DEBUG_MESSAGE_LENGTH       0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES      0x9144
+#define GL_DEBUG_LOGGED_MESSAGES          0x9145
+#define GL_DEBUG_SEVERITY_HIGH            0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM          0x9147
+#define GL_DEBUG_SEVERITY_LOW             0x9148
+#define GL_DEBUG_OUTPUT                   0x92E0
+#define GL_CONTEXT_FLAG_DEBUG_BIT         0x00000002
+/* reuse GL_STACK_UNDERFLOW */
+/* reuse GL_STACK_OVERFLOW */
+#endif
+
 #ifndef GL_ARB_compute_shader
 #define GL_COMPUTE_SHADER                 0x91B9
 #define GL_MAX_COMPUTE_UNIFORM_BLOCKS     0x91BB
@@ -5597,6 +5641,10 @@ typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLen
 typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
 #endif
 
+#ifndef GL_KHR_debug
+typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
+#endif
+
 #ifndef GL_NV_vdpau_interop
 typedef GLintptr GLvdpauSurfaceNV;
 #endif
@@ -7903,6 +7951,32 @@ typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum ta
 typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 #endif
 
+#ifndef GL_KHR_debug
+#define GL_KHR_debug 1
+#ifdef GL_GLEXT_PROTOTYPES
+GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam);
+GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+GLAPI void APIENTRY glPopDebugGroup (void);
+GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label);
+GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
+typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void);
+typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+
 #ifndef GL_ARB_compute_shader
 #define GL_ARB_compute_shader 1
 #ifdef GL_GLEXT_PROTOTYPES

+ 180 - 149
panda/src/glxdisplay/glxGraphicsStateGuardian.cxx

@@ -295,6 +295,11 @@ choose_pixel_format(const FrameBufferProperties &properties,
   int best_result = 0;
   FrameBufferProperties best_props;
 
+  int render_type = GLX_RGBA_TYPE;
+  if (properties.get_indexed_color()) {
+    render_type = GLX_COLOR_INDEX_TYPE;
+  }
+
   static const int max_attrib_list = 32;
   int attrib_list[max_attrib_list];
   int n = 0;
@@ -324,7 +329,8 @@ choose_pixel_format(const FrameBufferProperties &properties,
         const char *pixmaptext = context_has_pixmap ? " (pixmap)" : "";
         const char *slowtext = slow ? " (slow)" : "";
         glxdisplay_cat.debug()
-          << i << ": " << fbprops << " quality=" << quality << pbuffertext << pixmaptext << slowtext << "\n";
+          << i << ": " << fbprops << " quality=" << quality << pbuffertext
+          << pixmaptext << slowtext << "\n";
       }
       if (need_pbuffer && !context_has_pbuffer) {
         continue;
@@ -343,10 +349,29 @@ choose_pixel_format(const FrameBufferProperties &properties,
 
   if (best_quality > 0) {
     _fbconfig = configs[best_result];
-    _context =
-      _glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context,
-                           GL_TRUE);
+
+    if (_glXCreateContextAttribs != NULL) {
+      // NB.  This is a wholly different type of attrib list
+      // than below, the same values are not used!
+      n = 0;
+      attrib_list[n++] = GLX_RENDER_TYPE;
+      attrib_list[n++] = render_type;
+      if (gl_debug) {
+        attrib_list[n++] = GLX_CONTEXT_FLAGS_ARB;
+        attrib_list[n++] = GLX_CONTEXT_DEBUG_BIT_ARB;
+      }
+      attrib_list[n] = None;
+      _context = _glXCreateContextAttribs(_display, _fbconfig, _share_context,
+                                          GL_TRUE, attrib_list);
+    } else {
+      _context =
+        _glXCreateNewContext(_display, _fbconfig, render_type, _share_context,
+                             GL_TRUE);
+    }
+
     if (_context) {
+      mark_new();
+
       if (_visuals != (XVisualInfo *)NULL) {
         XFree(_visuals);
         _visuals = NULL;
@@ -398,150 +423,6 @@ choose_pixel_format(const FrameBufferProperties &properties,
   _context_has_pbuffer = false;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: glxGraphicsStateGuardian::reset
-//       Access: Public, Virtual
-//  Description: Resets all internal state as if the gsg were newly
-//               created.
-////////////////////////////////////////////////////////////////////
-void glxGraphicsStateGuardian::
-reset() {
-  PosixGraphicsStateGuardian::reset();
-
-  _supports_swap_control = has_extension("GLX_SGI_swap_control");
-
-  if (_supports_swap_control) {
-    _glXSwapIntervalSGI = 
-      (PFNGLXSWAPINTERVALSGIPROC)get_extension_func("glXSwapIntervalSGI");
-    if (_glXSwapIntervalSGI == NULL) {
-      glxdisplay_cat.error()
-        << "Driver claims to support GLX_SGI_swap_control extension, but does not define all functions.\n";
-      _supports_swap_control = false;
-    }
-  }
-
-  if (_supports_swap_control) {
-    // Set the video-sync setting up front, if we have the extension
-    // that supports it.
-    _glXSwapIntervalSGI(sync_video ? 1 : 0);
-  }
-
-  if (glx_support_fbconfig) {
-    if (glx_is_at_least_version(1, 3)) {
-      // If we have glx 1.3 or better, we have the FBConfig interface.
-      _supports_fbconfig = true;
-
-      _glXChooseFBConfig =
-        (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glXChooseFBConfig");
-      _glXCreateNewContext =
-        (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glXCreateNewContext");
-      _glXGetVisualFromFBConfig =
-        (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glXGetVisualFromFBConfig");
-      _glXGetFBConfigAttrib =
-        (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glXGetFBConfigAttrib");
-      _glXCreatePixmap =
-        (PFNGLXCREATEPIXMAPPROC)get_extension_func("glXCreatePixmap");
-
-      if (_glXChooseFBConfig == NULL ||
-          _glXCreateNewContext == NULL ||
-          _glXGetVisualFromFBConfig == NULL ||
-          _glXGetFBConfigAttrib == NULL ||
-          _glXCreatePixmap == NULL) {
-        glxdisplay_cat.error()
-          << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n";
-        _supports_fbconfig = false;
-      }
-    } else if (has_extension("GLX_SGIX_fbconfig")) {
-      // Or maybe we have the old SGIX extension for FBConfig.  This is
-      // the same, but the function names are different--we just remap
-      // them to the same function pointers.
-      _supports_fbconfig = true;
-
-      _glXChooseFBConfig =
-        (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glXChooseFBConfigSGIX");
-      _glXCreateNewContext =
-        (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glXCreateContextWithConfigSGIX");
-      _glXGetVisualFromFBConfig =
-        (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glXGetVisualFromFBConfigSGIX");
-      _glXGetFBConfigAttrib =
-        (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glXGetFBConfigAttribSGIX");
-      _glXCreatePixmap =
-        (PFNGLXCREATEPIXMAPPROC)get_extension_func("glXCreateGLXPixmapWithConfigSGIX");
-
-      if (_glXChooseFBConfig == NULL ||
-          _glXCreateNewContext == NULL ||
-          _glXGetVisualFromFBConfig == NULL ||
-          _glXGetFBConfigAttrib == NULL ||
-          _glXCreatePixmap == NULL) {
-        glxdisplay_cat.error()
-          << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n";
-        _supports_fbconfig = false;
-      }
-    }
-
-    if (glx_is_at_least_version(1, 3)) {
-      // If we have glx 1.3 or better, we have the PBuffer interface.
-      _supports_pbuffer = true;
-      _uses_sgix_pbuffer = false;
-
-      _glXCreatePbuffer =
-        (PFNGLXCREATEPBUFFERPROC)get_extension_func("glXCreatePbuffer");
-      _glXCreateGLXPbufferSGIX = NULL;
-      _glXDestroyPbuffer =
-        (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glXDestroyPbuffer");
-      if (_glXCreatePbuffer == NULL ||
-          _glXDestroyPbuffer == NULL) {
-        glxdisplay_cat.error()
-          << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n";
-        _supports_pbuffer = false;
-      }
-
-    } else if (has_extension("GLX_SGIX_pbuffer")) {
-      // Or maybe we have the old SGIX extension for PBuffers.
-      _uses_sgix_pbuffer = true;
-
-      // CreatePbuffer has a different form between SGIX and 1.3,
-      // however, so we must treat it specially.  But we can use the
-      // same function pointer for DestroyPbuffer.
-      _glXCreatePbuffer = NULL;
-      _glXCreateGLXPbufferSGIX =
-        (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glXCreateGLXPbufferSGIX");
-      _glXDestroyPbuffer =
-        (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glXDestroyGLXPbufferSGIX");
-      if (_glXCreateGLXPbufferSGIX == NULL ||
-          _glXDestroyPbuffer == NULL) {
-        glxdisplay_cat.error()
-          << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n";
-        _supports_pbuffer = false;
-      }
-    }
-  }
-
-
-  if (glxdisplay_cat.is_debug()) {
-    glxdisplay_cat.debug()
-      << "supports_swap_control = " << _supports_swap_control << "\n";
-    glxdisplay_cat.debug()
-      << "supports_fbconfig = " << _supports_fbconfig << "\n";
-    glxdisplay_cat.debug()
-      << "supports_pbuffer = " << _supports_pbuffer
-      << " sgix = " << _uses_sgix_pbuffer << "\n";
-  }
-
-  // If "Mesa" is present, assume software.  However, if "Mesa DRI" is
-  // found, it's actually a Mesa-based OpenGL layer running over a
-  // hardware driver.
-  if (_gl_renderer.find("Mesa") != string::npos &&
-      _gl_renderer.find("Mesa DRI") == string::npos) {
-    // It's Mesa, therefore probably a software context.
-    _fbprops.set_force_software(1);
-    _fbprops.set_force_hardware(0);
-  } else {
-    _fbprops.set_force_hardware(1);
-    _fbprops.set_force_software(0);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: glxGraphicsStateGuardian::glx_is_at_least_version
 //       Access: Public
@@ -692,6 +573,153 @@ do_get_extension_func(const char *name) {
   return PosixGraphicsStateGuardian::do_get_extension_func(name);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: glxGraphicsStateGuardian::query_glx_extensions
+//       Access: Private
+//  Description: Queries the GLX extension pointers.
+////////////////////////////////////////////////////////////////////
+void glxGraphicsStateGuardian::
+query_glx_extensions() {
+  _supports_swap_control = has_extension("GLX_SGI_swap_control");
+
+  if (_supports_swap_control) {
+    _glXSwapIntervalSGI = 
+      (PFNGLXSWAPINTERVALSGIPROC)get_extension_func("glXSwapIntervalSGI");
+    if (_glXSwapIntervalSGI == NULL) {
+      glxdisplay_cat.error()
+        << "Driver claims to support GLX_SGI_swap_control extension, but does not define all functions.\n";
+      _supports_swap_control = false;
+    }
+  }
+
+  if (_supports_swap_control) {
+    // Set the video-sync setting up front, if we have the extension
+    // that supports it.
+    _glXSwapIntervalSGI(sync_video ? 1 : 0);
+  }
+
+  if (glx_support_fbconfig) {
+    if (glx_is_at_least_version(1, 3)) {
+      // If we have glx 1.3 or better, we have the FBConfig interface.
+      _supports_fbconfig = true;
+
+      _glXChooseFBConfig =
+        (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glXChooseFBConfig");
+      _glXCreateNewContext =
+        (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glXCreateNewContext");
+      _glXGetVisualFromFBConfig =
+        (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glXGetVisualFromFBConfig");
+      _glXGetFBConfigAttrib =
+        (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glXGetFBConfigAttrib");
+      _glXCreatePixmap =
+        (PFNGLXCREATEPIXMAPPROC)get_extension_func("glXCreatePixmap");
+
+      if (_glXChooseFBConfig == NULL ||
+          _glXCreateNewContext == NULL ||
+          _glXGetVisualFromFBConfig == NULL ||
+          _glXGetFBConfigAttrib == NULL ||
+          _glXCreatePixmap == NULL) {
+        glxdisplay_cat.error()
+          << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n";
+        _supports_fbconfig = false;
+      }
+    } else if (has_extension("GLX_SGIX_fbconfig")) {
+      // Or maybe we have the old SGIX extension for FBConfig.  This is
+      // the same, but the function names are different--we just remap
+      // them to the same function pointers.
+      _supports_fbconfig = true;
+
+      _glXChooseFBConfig =
+        (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glXChooseFBConfigSGIX");
+      _glXCreateNewContext =
+        (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glXCreateContextWithConfigSGIX");
+      _glXGetVisualFromFBConfig =
+        (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glXGetVisualFromFBConfigSGIX");
+      _glXGetFBConfigAttrib =
+        (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glXGetFBConfigAttribSGIX");
+      _glXCreatePixmap =
+        (PFNGLXCREATEPIXMAPPROC)get_extension_func("glXCreateGLXPixmapWithConfigSGIX");
+
+      if (_glXChooseFBConfig == NULL ||
+          _glXCreateNewContext == NULL ||
+          _glXGetVisualFromFBConfig == NULL ||
+          _glXGetFBConfigAttrib == NULL ||
+          _glXCreatePixmap == NULL) {
+        glxdisplay_cat.error()
+          << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n";
+        _supports_fbconfig = false;
+      }
+    }
+
+    if (glx_is_at_least_version(1, 3)) {
+      // If we have glx 1.3 or better, we have the PBuffer interface.
+      _supports_pbuffer = true;
+      _uses_sgix_pbuffer = false;
+
+      _glXCreatePbuffer =
+        (PFNGLXCREATEPBUFFERPROC)get_extension_func("glXCreatePbuffer");
+      _glXCreateGLXPbufferSGIX = NULL;
+      _glXDestroyPbuffer =
+        (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glXDestroyPbuffer");
+      if (_glXCreatePbuffer == NULL ||
+          _glXDestroyPbuffer == NULL) {
+        glxdisplay_cat.error()
+          << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n";
+        _supports_pbuffer = false;
+      }
+
+    } else if (has_extension("GLX_SGIX_pbuffer")) {
+      // Or maybe we have the old SGIX extension for PBuffers.
+      _uses_sgix_pbuffer = true;
+
+      // CreatePbuffer has a different form between SGIX and 1.3,
+      // however, so we must treat it specially.  But we can use the
+      // same function pointer for DestroyPbuffer.
+      _glXCreatePbuffer = NULL;
+      _glXCreateGLXPbufferSGIX =
+        (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glXCreateGLXPbufferSGIX");
+      _glXDestroyPbuffer =
+        (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glXDestroyGLXPbufferSGIX");
+      if (_glXCreateGLXPbufferSGIX == NULL ||
+          _glXDestroyPbuffer == NULL) {
+        glxdisplay_cat.error()
+          << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n";
+        _supports_pbuffer = false;
+      }
+    }
+
+    if (has_extension("GLX_ARB_create_context")) {
+      _glXCreateContextAttribs = 
+        (PFNGLXCREATECONTEXTATTRIBSARBPROC)get_extension_func("glXCreateContextAttribsARB");
+    } else {
+      _glXCreateContextAttribs = NULL;
+    }
+  }
+
+  if (glxdisplay_cat.is_debug()) {
+    glxdisplay_cat.debug()
+      << "supports_swap_control = " << _supports_swap_control << "\n";
+    glxdisplay_cat.debug()
+      << "supports_fbconfig = " << _supports_fbconfig << "\n";
+    glxdisplay_cat.debug()
+      << "supports_pbuffer = " << _supports_pbuffer
+      << " sgix = " << _uses_sgix_pbuffer << "\n";
+  }
+
+  // If "Mesa" is present, assume software.  However, if "Mesa DRI" is
+  // found, it's actually a Mesa-based OpenGL layer running over a
+  // hardware driver.
+  if (_gl_renderer.find("Mesa") != string::npos &&
+      _gl_renderer.find("Mesa DRI") == string::npos) {
+    // It's Mesa, therefore probably a software context.
+    _fbprops.set_force_software(1);
+    _fbprops.set_force_hardware(0);
+  } else {
+    _fbprops.set_force_hardware(1);
+    _fbprops.set_force_software(0);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: glxGraphicsStateGuardian::show_glx_client_string
 //       Access: Protected
@@ -814,8 +842,11 @@ init_temp_context() {
     return;
   }
 
+  // Now use it to query the available GLX features.
   glXMakeCurrent(_display, _temp_xwindow, _temp_context);
-  reset();
+  query_gl_version();
+  get_extra_extensions();
+  query_glx_extensions();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 3
panda/src/glxdisplay/glxGraphicsStateGuardian.h

@@ -67,7 +67,7 @@ typedef int (* PFNGLXGETFBCONFIGATTRIBPROC) (X11_Display *dpy, GLXFBConfig confi
 typedef GLXPixmap (* PFNGLXCREATEPIXMAPPROC) (X11_Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);
 typedef GLXPbuffer (* PFNGLXCREATEPBUFFERPROC) (X11_Display *dpy, GLXFBConfig config, const int *attrib_list);
 typedef void (* PFNGLXDESTROYPBUFFERPROC) (X11_Display *dpy, GLXPbuffer pbuf);
-
+typedef GLXContext ( *PFNGLXCREATECONTEXTATTRIBSARBPROC) (X11_Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
 #endif  // __EDG__
 
 ////////////////////////////////////////////////////////////////////
@@ -92,8 +92,6 @@ public:
 
   virtual ~glxGraphicsStateGuardian();
 
-  virtual void reset();
-
   bool glx_is_at_least_version(int major_version, int minor_version) const;
 
   GLXContext _share_context;
@@ -119,6 +117,7 @@ public:
   PFNGLXGETVISUALFROMFBCONFIGPROC _glXGetVisualFromFBConfig;
   PFNGLXGETFBCONFIGATTRIBPROC _glXGetFBConfigAttrib;
   PFNGLXCREATEPIXMAPPROC _glXCreatePixmap;
+  PFNGLXCREATECONTEXTATTRIBSARBPROC _glXCreateContextAttribs;
 
   bool _supports_pbuffer;  // true if the interface is available.
   bool _uses_sgix_pbuffer;
@@ -135,6 +134,7 @@ protected:
   virtual void *do_get_extension_func(const char *name);
 
 private:
+  void query_glx_extensions();
   void show_glx_client_string(const string &name, int id);
   void show_glx_server_string(const string &name, int id);
   void choose_temp_visual(const FrameBufferProperties &properties);