Browse Source

fall back to older XVisualInfo interface if GLXFBConfig doesn't return any available options

David Rose 21 years ago
parent
commit
3d2f33e10e

+ 360 - 21
panda/src/glxdisplay/glxGraphicsPipe.cxx

@@ -185,25 +185,44 @@ make_gsg(const FrameBufferProperties &properties,
   }
   }
 
 
   FrameBufferProperties new_properties = properties;
   FrameBufferProperties new_properties = properties;
+  GLXContext context = NULL;
+
   GLXFBConfig fbconfig = choose_fbconfig(new_properties);
   GLXFBConfig fbconfig = choose_fbconfig(new_properties);
-  if (fbconfig == None) {
-    return NULL;
+  XVisualInfo *visual = NULL;
+
+  if (fbconfig != None) {
+    context = 
+      glXCreateNewContext(_display, fbconfig, GLX_RGBA_TYPE, share_context,
+                          GL_TRUE);
+  }
+  if (context == NULL) {
+    // If we couldn't create a context with the fbconfig interface,
+    // try falling back to the older XVisual interface.
+    visual = choose_visual(new_properties);
+
+    if (visual != (XVisualInfo *)NULL) {
+      context = glXCreateContext(_display, visual, None, GL_TRUE);
+      fbconfig = None;
+    }
   }
   }
 
 
-  // Attempt to create a GL context.
-  GLXContext context = 
-    glXCreateNewContext(_display, fbconfig, GLX_RGBA_TYPE, share_context,
-                        GL_TRUE);
   if (context == NULL) {
   if (context == NULL) {
     glxdisplay_cat.error()
     glxdisplay_cat.error()
       << "Could not create GL context.\n";
       << "Could not create GL context.\n";
     return NULL;
     return NULL;
   }
   }
 
 
+  if (visual == (XVisualInfo *)NULL) {
+    // If we used the fbconfig to open the context, we still need to
+    // get the associated XVisual.
+    nassertr(fbconfig != None, NULL);
+    visual = glXGetVisualFromFBConfig(_display, fbconfig);
+  }
+
   // Now we can make a GSG.
   // Now we can make a GSG.
   PT(glxGraphicsStateGuardian) gsg = 
   PT(glxGraphicsStateGuardian) gsg = 
-    new glxGraphicsStateGuardian(new_properties, share_gsg, context, fbconfig,
-                                 _display, _screen);
+    new glxGraphicsStateGuardian(new_properties, share_gsg, context, 
+                                 fbconfig, visual, _display, _screen);
   return gsg.p();
   return gsg.p();
 }
 }
 
 
@@ -282,7 +301,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
   // information: we don't care about that much detail.
   // information: we don't care about that much detail.
   NotifySeverity show_fbconfig_severity = NS_debug;
   NotifySeverity show_fbconfig_severity = NS_debug;
 
 
-  if (fbconfig == NULL) {
+  if (fbconfig == None) {
     glxdisplay_cat.info()
     glxdisplay_cat.info()
       << "glxGraphicsWindow::choose_fbconfig() - fbconfig with requested "
       << "glxGraphicsWindow::choose_fbconfig() - fbconfig with requested "
       << "capabilities not found; trying for lesser fbconfig.\n";
       << "capabilities not found; trying for lesser fbconfig.\n";
@@ -308,7 +327,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
       fbconfig = try_for_fbconfig(frame_buffer_mode, 1, 1);
       fbconfig = try_for_fbconfig(frame_buffer_mode, 1, 1);
     }
     }
 
 
-    if (fbconfig == NULL) {
+    if (fbconfig == None) {
       // Ok, not good enough.  Now try to eliminate options, but keep
       // Ok, not good enough.  Now try to eliminate options, but keep
       // as many bits as we asked for.
       // as many bits as we asked for.
 
 
@@ -348,7 +367,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
       tried_masks.insert(frame_buffer_mode);
       tried_masks.insert(frame_buffer_mode);
 
 
       int i;
       int i;
-      for (i = 0; fbconfig == NULL && strip_properties[i] != 0; i++) {
+      for (i = 0; fbconfig == None && strip_properties[i] != 0; i++) {
         int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
         int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
         if (tried_masks.insert(new_frame_buffer_mode).second) {
         if (tried_masks.insert(new_frame_buffer_mode).second) {
           fbconfig = try_for_fbconfig(new_frame_buffer_mode, want_depth_bits,
           fbconfig = try_for_fbconfig(new_frame_buffer_mode, want_depth_bits,
@@ -360,10 +379,10 @@ choose_fbconfig(FrameBufferProperties &properties) const {
         tried_masks.clear();
         tried_masks.clear();
         tried_masks.insert(frame_buffer_mode);
         tried_masks.insert(frame_buffer_mode);
 
 
-        if (fbconfig == NULL) {
+        if (fbconfig == None) {
           // Try once more, this time eliminating all of the size
           // Try once more, this time eliminating all of the size
           // requests.
           // requests.
-          for (i = 0; fbconfig == NULL && strip_properties[i] != 0; i++) {
+          for (i = 0; fbconfig == None && strip_properties[i] != 0; i++) {
             int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
             int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
             if (tried_masks.insert(new_frame_buffer_mode).second) {
             if (tried_masks.insert(new_frame_buffer_mode).second) {
               fbconfig = try_for_fbconfig(new_frame_buffer_mode, 1, 1);
               fbconfig = try_for_fbconfig(new_frame_buffer_mode, 1, 1);
@@ -372,16 +391,16 @@ choose_fbconfig(FrameBufferProperties &properties) const {
         }
         }
       }
       }
 
 
-      if (fbconfig == NULL) {
+      if (fbconfig == None) {
         // Here's our last-ditch desparation attempt: give us any GLX
         // Here's our last-ditch desparation attempt: give us any GLX
         // fbconfig at all!
         // fbconfig at all!
         fbconfig = try_for_fbconfig(0, 1, 1);
         fbconfig = try_for_fbconfig(0, 1, 1);
       }
       }
 
 
-      if (fbconfig == NULL) {
+      if (fbconfig == None) {
         glxdisplay_cat.error()
         glxdisplay_cat.error()
           << "Could not get any GLX fbconfig.\n";
           << "Could not get any GLX fbconfig.\n";
-        return NULL;
+        return None;
       }
       }
     }
     }
   }
   }
@@ -389,7 +408,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
   glxdisplay_cat.info()
   glxdisplay_cat.info()
     << "Selected suitable GLX fbconfig.\n";
     << "Selected suitable GLX fbconfig.\n";
 
 
-  // Now update our frambuffer_mode and bit depth appropriately.
+  // Now update our framebuffer_mode and bit depth appropriately.
   int render_mode, double_buffer, stereo, red_size, green_size, blue_size,
   int render_mode, double_buffer, stereo, red_size, green_size, blue_size,
     alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
     alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
     depth_size, stencil_size;
     depth_size, stencil_size;
@@ -457,7 +476,7 @@ choose_fbconfig(FrameBufferProperties &properties) const {
 //  Description: Attempt to get the requested fbconfig, if it is
 //  Description: Attempt to get the requested fbconfig, if it is
 //               available.  It's just a wrapper around
 //               available.  It's just a wrapper around
 //               glXChooseFBConfig().  It returns the fbconfig
 //               glXChooseFBConfig().  It returns the fbconfig
-//               information if possible, or NULL if it is not.
+//               information if possible, or None if it is not.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GLXFBConfig glxGraphicsPipe::
 GLXFBConfig glxGraphicsPipe::
 try_for_fbconfig(int framebuffer_mode,
 try_for_fbconfig(int framebuffer_mode,
@@ -538,17 +557,17 @@ try_for_fbconfig(int framebuffer_mode,
       attrib_list[n++] = want_color_component_bits;
       attrib_list[n++] = want_color_component_bits;
     }
     }
   }
   }
-#if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
+  /*
   if (framebuffer_mode & FrameBufferProperties::FM_multisample) {
   if (framebuffer_mode & FrameBufferProperties::FM_multisample) {
     glxdisplay_cat.debug(false) << " MULTISAMPLE";
     glxdisplay_cat.debug(false) << " MULTISAMPLE";
     attrib_list[n++] = GLX_SAMPLES_SGIS;
     attrib_list[n++] = GLX_SAMPLES_SGIS;
     // We decide 4 is minimum number of samples
     // We decide 4 is minimum number of samples
     attrib_list[n++] = 4;
     attrib_list[n++] = 4;
   }
   }
-#endif
+  */
 
 
   // Terminate the list
   // Terminate the list
-  nassertr(n < max_attrib_list, NULL);
+  nassertr(n < max_attrib_list, None);
   attrib_list[n] = (int)None;
   attrib_list[n] = (int)None;
 
 
   int num_configs = 0;
   int num_configs = 0;
@@ -576,6 +595,326 @@ try_for_fbconfig(int framebuffer_mode,
   return fbconfig;
   return fbconfig;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: glxGraphicsPipe::choose visual
+//       Access: Private
+//  Description: Selects an appropriate X visual for the given frame
+//               buffer properties.  Returns the visual pointer if
+//               successful, or NULL otherwise.
+//
+//               If successful, this may modify properties to reflect
+//               the actual visual chosen.
+//
+//               This is an older GLX interface, replaced by the new
+//               fbconfig interface.  However, some implementations of
+//               GLX may not support fbconfig, so we have to have this
+//               code as a fallback.
+////////////////////////////////////////////////////////////////////
+XVisualInfo *glxGraphicsPipe::
+choose_visual(FrameBufferProperties &properties) const {
+  int frame_buffer_mode = 0;
+  int want_depth_bits = 0;
+  int want_color_bits = 0;
+
+  if (properties.has_frame_buffer_mode()) {
+    frame_buffer_mode = properties.get_frame_buffer_mode();
+  }
+
+  if (properties.has_depth_bits()) {
+    want_depth_bits = properties.get_depth_bits();
+  }
+
+  if (properties.has_color_bits()) {
+    want_color_bits = properties.get_color_bits();
+  }
+
+  /*
+  if (frame_buffer_mode & FrameBufferProperties::FM_multisample) {
+    if (!glx_supports("GLX_SGIS_multisample")) {
+      glxdisplay_cat.info()
+        << "multisample not supported by this glx implementation.\n";
+      frame_buffer_mode &= ~FrameBufferProperties::FM_multisample;
+    }
+  }
+  */
+
+  XVisualInfo *visual = 
+    try_for_visual(frame_buffer_mode, want_depth_bits, want_color_bits);
+
+  // This is the severity level at which we'll report the details of
+  // the visual we actually do find.  Normally, it's debug-level
+  // information: we don't care about that much detail.
+  NotifySeverity show_visual_severity = NS_debug;
+
+  if (visual == NULL) {
+    glxdisplay_cat.info()
+      << "glxGraphicsWindow::choose_visual() - visual with requested\n"
+      << "   capabilities not found; trying for lesser visual.\n";
+
+    // If we're unable to get the visual we asked for, however, we
+    // probably *do* care to know the details about what we actually
+    // got, even if we don't have debug mode set.  So we'll report the
+    // visual at a higher level.
+    show_visual_severity = NS_info;
+
+    bool special_size_request =
+      (want_depth_bits != 1 || want_color_bits != 1);
+
+    // We try to be smart about choosing a close match for the visual.
+    // First, we'll eliminate some of the more esoteric options one at
+    // a time, then two at a time, and finally we'll try just the bare
+    // minimum.
+
+    if (special_size_request) {
+      // Actually, first we'll eliminate all of the minimum sizes, to
+      // try to open a window with all of the requested options, but
+      // maybe not as many bits in some options as we'd like.
+      visual = try_for_visual(frame_buffer_mode, 1, 1);
+    }
+
+    if (visual == NULL) {
+      // Ok, not good enough.  Now try to eliminate options, but keep
+      // as many bits as we asked for.
+
+      // This array keeps the bitmasks of options that we pull out of
+      // the requested frame_buffer_mode, in order.
+
+      static const int strip_properties[] = {
+        // One esoteric option removed.
+        FrameBufferProperties::FM_multisample,
+        FrameBufferProperties::FM_stencil,
+        FrameBufferProperties::FM_accum,
+        FrameBufferProperties::FM_alpha,
+        FrameBufferProperties::FM_stereo,
+
+        // Two esoteric options removed.
+        FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_multisample,
+        FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
+        FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_multisample,
+        FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
+        FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum,
+        FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo,
+        FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
+        FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
+
+        // All esoteric options removed.
+        FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
+
+        // All esoteric options, plus some we'd really really prefer,
+        // removed.
+        FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample | FrameBufferProperties::FM_double_buffer,
+
+        // A zero marks the end of the array.
+        0
+      };
+
+      pset<int> tried_masks;
+      tried_masks.insert(frame_buffer_mode);
+
+      int i;
+      for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
+        int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
+        if (tried_masks.insert(new_frame_buffer_mode).second) {
+          visual = try_for_visual(new_frame_buffer_mode, want_depth_bits,
+                                  want_color_bits);
+        }
+      }
+
+      if (special_size_request) {
+        tried_masks.clear();
+        tried_masks.insert(frame_buffer_mode);
+
+        if (visual == NULL) {
+          // Try once more, this time eliminating all of the size
+          // requests.
+          for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
+            int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
+            if (tried_masks.insert(new_frame_buffer_mode).second) {
+              visual = try_for_visual(new_frame_buffer_mode, 1, 1);
+            }
+          }
+        }
+      }
+
+      if (visual == NULL) {
+        // Here's our last-ditch desparation attempt: give us any GLX
+        // visual at all!
+        visual = try_for_visual(0, 1, 1);
+      }
+
+      if (visual == NULL) {
+        glxdisplay_cat.error()
+          << "Could not get any GLX visual.\n";
+        return NULL;
+      }
+    }
+  }
+
+  glxdisplay_cat.info()
+    << "Got visual 0x" << hex << (int)visual->visualid << dec << ".\n";
+
+  // Now update our framebuffer_mode and bit depth appropriately.
+  int render_mode, double_buffer, stereo, red_size, green_size, blue_size,
+    alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
+    depth_size, stencil_size;
+  
+  glXGetConfig(_display, visual, GLX_RGBA, &render_mode);
+  glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &double_buffer);
+  glXGetConfig(_display, visual, GLX_STEREO, &stereo);
+  glXGetConfig(_display, visual, GLX_RED_SIZE, &red_size);
+  glXGetConfig(_display, visual, GLX_GREEN_SIZE, &green_size);
+  glXGetConfig(_display, visual, GLX_BLUE_SIZE, &blue_size);
+  glXGetConfig(_display, visual, GLX_ALPHA_SIZE, &alpha_size);
+  glXGetConfig(_display, visual, GLX_ACCUM_RED_SIZE, &ared_size);
+  glXGetConfig(_display, visual, GLX_ACCUM_GREEN_SIZE, &agreen_size);
+  glXGetConfig(_display, visual, GLX_ACCUM_BLUE_SIZE, &ablue_size);
+  glXGetConfig(_display, visual, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
+  glXGetConfig(_display, visual, GLX_DEPTH_SIZE, &depth_size);
+  glXGetConfig(_display, visual, GLX_STENCIL_SIZE, &stencil_size);
+
+  frame_buffer_mode = 0;
+  if (double_buffer) {
+    frame_buffer_mode |= FrameBufferProperties::FM_double_buffer;
+  }
+  if (stereo) {
+    frame_buffer_mode |= FrameBufferProperties::FM_stereo;
+  }
+  if (!render_mode) {
+    frame_buffer_mode |= FrameBufferProperties::FM_index;
+  }
+  if (stencil_size != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_stencil;
+  }
+  if (depth_size != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_depth;
+  }
+  if (alpha_size != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_alpha;
+  }
+  if (ared_size + agreen_size + ablue_size != 0) {
+    frame_buffer_mode |= FrameBufferProperties::FM_accum;
+  }
+
+  properties.set_frame_buffer_mode(frame_buffer_mode);
+  properties.set_color_bits(red_size + green_size + blue_size + alpha_size);
+  properties.set_depth_bits(depth_size);
+
+  if (glxdisplay_cat.is_on(show_visual_severity)) {
+    glxdisplay_cat.out(show_visual_severity)
+      << "GLX Visual Info (# bits of each):" << endl
+      << " RGBA: " << red_size << " " << green_size << " " << blue_size
+      << " " << alpha_size << endl
+      << " Accum RGBA: " << ared_size << " " << agreen_size << " "
+      << ablue_size << " " << aalpha_size << endl
+      << " Depth: " << depth_size << endl
+      << " Stencil: " << stencil_size << endl
+      << " DoubleBuffer? " << double_buffer << endl
+      << " Stereo? " << stereo << endl;
+  }
+
+  return visual;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: glxGraphicsPipe::try_for_visual
+//       Access: Private
+//  Description: Attempt to get the requested visual, if it is
+//               available.  It's just a wrapper around
+//               glXChooseVisual().  It returns the visual information
+//               if possible, or NULL if it is not.
+//
+//               This is an older GLX interface, replaced by the new
+//               fbconfig interface.  However, some implementations of
+//               GLX may not support fbconfig, so we have to have this
+//               code as a fallback.
+////////////////////////////////////////////////////////////////////
+XVisualInfo *glxGraphicsPipe::
+try_for_visual(int framebuffer_mode,
+               int want_depth_bits, int want_color_bits) const {
+  static const int max_attrib_list = 32;
+  int attrib_list[max_attrib_list];
+  int n=0;
+
+  glxdisplay_cat.debug()
+    << "Trying for visual with: RGB(" << want_color_bits << ")";
+
+  int want_color_component_bits;
+  if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
+    want_color_component_bits = max(want_color_bits / 4, 1);
+  } else {
+    want_color_component_bits = max(want_color_bits / 3, 1);
+  }
+
+  attrib_list[n++] = GLX_RGBA;
+  attrib_list[n++] = GLX_RED_SIZE;
+  attrib_list[n++] = want_color_component_bits;
+  attrib_list[n++] = GLX_GREEN_SIZE;
+  attrib_list[n++] = want_color_component_bits;
+  attrib_list[n++] = GLX_BLUE_SIZE;
+  attrib_list[n++] = want_color_component_bits;
+
+  if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
+    glxdisplay_cat.debug(false) << " ALPHA";
+    attrib_list[n++] = GLX_ALPHA_SIZE;
+    attrib_list[n++] = want_color_component_bits;
+  }
+  if (framebuffer_mode & FrameBufferProperties::FM_double_buffer) {
+    glxdisplay_cat.debug(false) << " DOUBLEBUFFER";
+    attrib_list[n++] = GLX_DOUBLEBUFFER;
+  }
+  if (framebuffer_mode & FrameBufferProperties::FM_stereo) {
+    glxdisplay_cat.debug(false) << " STEREO";
+    attrib_list[n++] = GLX_STEREO;
+  }
+  if (framebuffer_mode & FrameBufferProperties::FM_depth) {
+    glxdisplay_cat.debug(false) << " DEPTH(" << want_depth_bits << ")";
+    attrib_list[n++] = GLX_DEPTH_SIZE;
+    attrib_list[n++] = want_depth_bits;
+  }
+  if (framebuffer_mode & FrameBufferProperties::FM_stencil) {
+    glxdisplay_cat.debug(false) << " STENCIL";
+    attrib_list[n++] = GLX_STENCIL_SIZE;
+    attrib_list[n++] = 1;
+  }
+  if (framebuffer_mode & FrameBufferProperties::FM_accum) {
+    glxdisplay_cat.debug(false) << " ACCUM";
+    attrib_list[n++] = GLX_ACCUM_RED_SIZE;
+    attrib_list[n++] = want_color_component_bits;
+    attrib_list[n++] = GLX_ACCUM_GREEN_SIZE;
+    attrib_list[n++] = want_color_component_bits;
+    attrib_list[n++] = GLX_ACCUM_BLUE_SIZE;
+    attrib_list[n++] = want_color_component_bits;
+    if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
+      attrib_list[n++] = GLX_ACCUM_ALPHA_SIZE;
+      attrib_list[n++] = want_color_component_bits;
+    }
+  }
+  /*
+  if (framebuffer_mode & FrameBufferProperties::FM_multisample) {
+    glxdisplay_cat.debug(false) << " MULTISAMPLE";
+    attrib_list[n++] = GLX_SAMPLES_SGIS;
+    // We decide 4 is minimum number of samples
+    attrib_list[n++] = 4;
+  }
+  */
+
+  // Terminate the list
+  nassertr(n < max_attrib_list, NULL);
+  attrib_list[n] = (int)None;
+
+  XVisualInfo *vinfo = glXChooseVisual(_display, _screen, attrib_list);
+
+  if (glxdisplay_cat.is_debug()) {
+    if (vinfo != NULL) {
+      glxdisplay_cat.debug(false) << ", match found!\n";
+    } else {
+      glxdisplay_cat.debug(false) << ", no match.\n";
+    }
+  }
+
+  return vinfo;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: glxGraphicsPipe::make_hidden_cursor
 //     Function: glxGraphicsPipe::make_hidden_cursor
 //       Access: Private
 //       Access: Private

+ 5 - 0
panda/src/glxdisplay/glxGraphicsPipe.h

@@ -93,6 +93,11 @@ private:
   GLXFBConfig choose_fbconfig(FrameBufferProperties &properties) const;
   GLXFBConfig choose_fbconfig(FrameBufferProperties &properties) const;
   GLXFBConfig try_for_fbconfig(int framebuffer_mode,
   GLXFBConfig try_for_fbconfig(int framebuffer_mode,
                                int want_depth_bits, int want_color_bits) const;
                                int want_depth_bits, int want_color_bits) const;
+
+  XVisualInfo *choose_visual(FrameBufferProperties &properties) const;
+  XVisualInfo *try_for_visual(int framebuffer_mode,
+                              int want_depth_bits, int want_color_bits) const;
+
   void make_hidden_cursor();
   void make_hidden_cursor();
   void release_hidden_cursor();
   void release_hidden_cursor();
 
 

+ 5 - 1
panda/src/glxdisplay/glxGraphicsStateGuardian.cxx

@@ -30,10 +30,11 @@ glxGraphicsStateGuardian::
 glxGraphicsStateGuardian(const FrameBufferProperties &properties,
 glxGraphicsStateGuardian(const FrameBufferProperties &properties,
                          glxGraphicsStateGuardian *share_with,
                          glxGraphicsStateGuardian *share_with,
                          GLXContext context, GLXFBConfig fbconfig,
                          GLXContext context, GLXFBConfig fbconfig,
-                         Display *display, int screen) :
+                         XVisualInfo *visual, Display *display, int screen) :
   GLGraphicsStateGuardian(properties),
   GLGraphicsStateGuardian(properties),
   _context(context),
   _context(context),
   _fbconfig(fbconfig),
   _fbconfig(fbconfig),
+  _visual(visual),
   _display(display),
   _display(display),
   _screen(screen)
   _screen(screen)
 {
 {
@@ -49,6 +50,9 @@ glxGraphicsStateGuardian(const FrameBufferProperties &properties,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 glxGraphicsStateGuardian::
 glxGraphicsStateGuardian::
 ~glxGraphicsStateGuardian() {
 ~glxGraphicsStateGuardian() {
+  if (_visual != (XVisualInfo *)NULL) {
+    XFree(_visual);
+  }
   if (_context != (GLXContext)NULL) {
   if (_context != (GLXContext)NULL) {
     glXDestroyContext(_display, _context);
     glXDestroyContext(_display, _context);
     _context = (GLXContext)NULL;
     _context = (GLXContext)NULL;

+ 2 - 1
panda/src/glxdisplay/glxGraphicsStateGuardian.h

@@ -34,11 +34,12 @@ public:
   glxGraphicsStateGuardian(const FrameBufferProperties &properties,
   glxGraphicsStateGuardian(const FrameBufferProperties &properties,
                            glxGraphicsStateGuardian *share_with,
                            glxGraphicsStateGuardian *share_with,
                            GLXContext context, GLXFBConfig fbconfig,
                            GLXContext context, GLXFBConfig fbconfig,
-                           Display *display, int screen);
+                           XVisualInfo *visual, Display *display, int screen);
   virtual ~glxGraphicsStateGuardian();
   virtual ~glxGraphicsStateGuardian();
 
 
   GLXContext _context;
   GLXContext _context;
   GLXFBConfig _fbconfig;
   GLXFBConfig _fbconfig;
+  XVisualInfo *_visual;
   Display *_display;
   Display *_display;
   int _screen;
   int _screen;
 
 

+ 54 - 5
panda/src/glxdisplay/glxGraphicsWindow.cxx

@@ -505,9 +505,7 @@ open_window() {
   glxGraphicsStateGuardian *glxgsg;
   glxGraphicsStateGuardian *glxgsg;
   DCAST_INTO_R(glxgsg, _gsg, false);
   DCAST_INTO_R(glxgsg, _gsg, false);
 
 
-  XVisualInfo *visual_info = 
-    glXGetVisualFromFBConfig(_display, glxgsg->_fbconfig);
-
+  XVisualInfo *visual_info = glxgsg->_visual;
   if (visual_info == NULL) {
   if (visual_info == NULL) {
     // No X visual for this fbconfig; how can we open the window?
     // No X visual for this fbconfig; how can we open the window?
     glxdisplay_cat.error()
     glxdisplay_cat.error()
@@ -516,7 +514,6 @@ open_window() {
   }
   }
   Visual *visual = visual_info->visual;
   Visual *visual = visual_info->visual;
   int depth = visual_info->depth;
   int depth = visual_info->depth;
-  XFree(visual_info);
 
 
 
 
   if (!_properties.has_origin()) {
   if (!_properties.has_origin()) {
@@ -528,7 +525,11 @@ open_window() {
 
 
   Window root_window = glx_pipe->get_root();
   Window root_window = glx_pipe->get_root();
 
 
-  setup_colormap(glxgsg->_fbconfig);
+  if (glxgsg->_fbconfig != None) {
+    setup_colormap(glxgsg->_fbconfig);
+  } else {
+    setup_colormap(visual_info);
+  }
 
 
   _event_mask =
   _event_mask =
     ButtonPressMask | ButtonReleaseMask |
     ButtonPressMask | ButtonReleaseMask |
@@ -736,6 +737,54 @@ setup_colormap(GLXFBConfig fbconfig) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: glxGraphicsWindow::setup_colormap
+//       Access: Private
+//  Description: Allocates a colormap appropriate to the visual and
+//               stores in in the _colormap method.
+////////////////////////////////////////////////////////////////////
+void glxGraphicsWindow::
+setup_colormap(XVisualInfo *visual) {
+  glxGraphicsPipe *glx_pipe;
+  DCAST_INTO_V(glx_pipe, _pipe);
+  Window root_window = glx_pipe->get_root();
+
+  int visual_class = visual->c_class;
+  int rc, is_rgb;
+
+  switch (visual_class) {
+    case PseudoColor:
+      rc = glXGetConfig(_display, visual, GLX_RGBA, &is_rgb);
+      if (rc == 0 && is_rgb) {
+        glxdisplay_cat.warning()
+          << "mesa pseudocolor not supported.\n";
+        // this is a terrible terrible hack, but it seems to work
+        _colormap = (Colormap)0;
+
+      } else {
+        _colormap = XCreateColormap(_display, root_window,
+                                    visual->visual, AllocAll);
+      }
+      break;
+    case TrueColor:
+    case DirectColor:
+      _colormap = XCreateColormap(_display, root_window,
+                                  visual->visual, AllocNone);
+      break;
+    case StaticColor:
+    case StaticGray:
+    case GrayScale:
+      _colormap = XCreateColormap(_display, root_window,
+                                  visual->visual, AllocNone);
+      break;
+    default:
+      glxdisplay_cat.error()
+        << "Could not allocate a colormap for visual class "
+        << visual_class << ".\n";
+      break;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: glxGraphicsWindow::handle_keystroke
 //     Function: glxGraphicsWindow::handle_keystroke
 //       Access: Private
 //       Access: Private

+ 1 - 0
panda/src/glxdisplay/glxGraphicsWindow.h

@@ -56,6 +56,7 @@ private:
   void set_wm_properties(const WindowProperties &properties);
   void set_wm_properties(const WindowProperties &properties);
 
 
   void setup_colormap(GLXFBConfig fbconfig);
   void setup_colormap(GLXFBConfig fbconfig);
+  void setup_colormap(XVisualInfo *visual);
   void handle_keystroke(XKeyEvent &event);
   void handle_keystroke(XKeyEvent &event);
   void handle_keypress(XKeyEvent &event);
   void handle_keypress(XKeyEvent &event);
   void handle_keyrelease(XKeyEvent &event);
   void handle_keyrelease(XKeyEvent &event);