Panda3D

glxGraphicsStateGuardian.cxx

00001 // Filename: glxGraphicsStateGuardian.cxx
00002 // Created by:  drose (27Jan03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "glxGraphicsStateGuardian.h"
00016 #include "config_glxdisplay.h"
00017 #include "config_glgsg.h"
00018 #include "lightReMutexHolder.h"
00019 
00020 #include <dlfcn.h>
00021 
00022 
00023 TypeHandle glxGraphicsStateGuardian::_type_handle;
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: glxGraphicsStateGuardian::Constructor
00027 //       Access: Public
00028 //  Description:
00029 ////////////////////////////////////////////////////////////////////
00030 glxGraphicsStateGuardian::
00031 glxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
00032                          glxGraphicsStateGuardian *share_with) :
00033   GLGraphicsStateGuardian(engine, pipe)
00034 {
00035   _share_context=0;
00036   _context=0;
00037   _display=0;
00038   _screen=0;
00039   _visual=0;
00040   _visuals=0;
00041   _fbconfig=0;
00042   _context_has_pbuffer = false;
00043   _context_has_pixmap = false;
00044   _slow = false;
00045 
00046   _supports_swap_control = false;
00047   _supports_fbconfig = false;
00048   _supports_pbuffer = false;
00049   _uses_sgix_pbuffer = false;
00050   
00051   if (share_with != (glxGraphicsStateGuardian *)NULL) {
00052     _prepared_objects = share_with->get_prepared_objects();
00053     _share_context = share_with->_context;
00054   }
00055   
00056   _libgl_handle = NULL;
00057   _checked_get_proc_address = false;
00058   _glXGetProcAddress = NULL;
00059   _temp_context = (GLXContext)NULL;
00060   _temp_xwindow = (Window)NULL;
00061   _temp_colormap = (Colormap)NULL;
00062 }
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: glxGraphicsStateGuardian::Destructor
00066 //       Access: Public
00067 //  Description:
00068 ////////////////////////////////////////////////////////////////////
00069 glxGraphicsStateGuardian::
00070 ~glxGraphicsStateGuardian() {
00071   destroy_temp_xwindow();
00072   if (_visuals != (XVisualInfo *)NULL) {
00073     XFree(_visuals);
00074   }
00075   if (_context != (GLXContext)NULL) {
00076     glXDestroyContext(_display, _context);
00077     _context = (GLXContext)NULL;
00078   }
00079   if (_libgl_handle != (void *)NULL) {
00080     dlclose(_libgl_handle);
00081   }
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: glxGraphicsStateGuardian::get_properties
00086 //       Access: Public
00087 //  Description: Gets the FrameBufferProperties to match the
00088 //               indicated visual.
00089 ////////////////////////////////////////////////////////////////////
00090 void glxGraphicsStateGuardian::
00091 get_properties(FrameBufferProperties &properties, XVisualInfo *visual) {
00092 
00093   int use_gl, render_mode, double_buffer, stereo,
00094     red_size, green_size, blue_size,
00095     alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
00096     depth_size, stencil_size;
00097   
00098   glXGetConfig(_display, visual, GLX_USE_GL, &use_gl);
00099   glXGetConfig(_display, visual, GLX_RGBA, &render_mode);
00100   glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &double_buffer);
00101   glXGetConfig(_display, visual, GLX_STEREO, &stereo);
00102   glXGetConfig(_display, visual, GLX_RED_SIZE, &red_size);
00103   glXGetConfig(_display, visual, GLX_GREEN_SIZE, &green_size);
00104   glXGetConfig(_display, visual, GLX_BLUE_SIZE, &blue_size);
00105   glXGetConfig(_display, visual, GLX_ALPHA_SIZE, &alpha_size);
00106   glXGetConfig(_display, visual, GLX_ACCUM_RED_SIZE, &ared_size);
00107   glXGetConfig(_display, visual, GLX_ACCUM_GREEN_SIZE, &agreen_size);
00108   glXGetConfig(_display, visual, GLX_ACCUM_BLUE_SIZE, &ablue_size);
00109   glXGetConfig(_display, visual, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
00110   glXGetConfig(_display, visual, GLX_DEPTH_SIZE, &depth_size);
00111   glXGetConfig(_display, visual, GLX_STENCIL_SIZE, &stencil_size);
00112 
00113   properties.clear();
00114 
00115   if (use_gl == 0) {
00116     // If we return a set of properties without setting either
00117     // rgb_color or indexed_color, then this indicates a visual
00118     // that's no good for any kind of rendering.
00119     return;
00120   }
00121 
00122   if (double_buffer) {
00123     properties.set_back_buffers(1);
00124   }
00125   if (stereo) {
00126     properties.set_stereo(1);
00127   }
00128   if (render_mode) {
00129     properties.set_rgb_color(1);
00130   } else {
00131     properties.set_indexed_color(1);
00132   }
00133   properties.set_color_bits(red_size+green_size+blue_size);
00134   properties.set_stencil_bits(stencil_size);
00135   properties.set_depth_bits(depth_size);
00136   properties.set_alpha_bits(alpha_size);
00137   properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size);
00138   
00139   // Set both hardware and software bits, indicating not-yet-known.
00140   properties.set_force_software(1);
00141   properties.set_force_hardware(1);
00142 }
00143 
00144 ////////////////////////////////////////////////////////////////////
00145 //     Function: glxGraphicsStateGuardian::get_properties_advanced
00146 //       Access: Public
00147 //  Description: Gets the FrameBufferProperties to match the
00148 //               indicated GLXFBConfig
00149 ////////////////////////////////////////////////////////////////////
00150 void glxGraphicsStateGuardian::
00151 get_properties_advanced(FrameBufferProperties &properties, 
00152                         bool &context_has_pbuffer, bool &context_has_pixmap,
00153                         bool &slow, GLXFBConfig config) {
00154   properties.clear();
00155 
00156   if (_supports_fbconfig) {
00157     // Now update our framebuffer_mode and bit depth appropriately.
00158     int render_type, double_buffer, stereo, red_size, green_size, blue_size,
00159       alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
00160       depth_size, stencil_size, samples, drawable_type, caveat;
00161     
00162     _glXGetFBConfigAttrib(_display, config, GLX_RENDER_TYPE, &render_type);
00163     _glXGetFBConfigAttrib(_display, config, GLX_DOUBLEBUFFER, &double_buffer);
00164     _glXGetFBConfigAttrib(_display, config, GLX_STEREO, &stereo);
00165     _glXGetFBConfigAttrib(_display, config, GLX_RED_SIZE, &red_size);
00166     _glXGetFBConfigAttrib(_display, config, GLX_GREEN_SIZE, &green_size);
00167     _glXGetFBConfigAttrib(_display, config, GLX_BLUE_SIZE, &blue_size);
00168     _glXGetFBConfigAttrib(_display, config, GLX_ALPHA_SIZE, &alpha_size);
00169     _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_RED_SIZE, &ared_size);
00170     _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_GREEN_SIZE, &agreen_size);
00171     _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_BLUE_SIZE, &ablue_size);
00172     _glXGetFBConfigAttrib(_display, config, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
00173     _glXGetFBConfigAttrib(_display, config, GLX_DEPTH_SIZE, &depth_size);
00174     _glXGetFBConfigAttrib(_display, config, GLX_STENCIL_SIZE, &stencil_size);
00175     _glXGetFBConfigAttrib(_display, config, GLX_SAMPLES, &samples);
00176     _glXGetFBConfigAttrib(_display, config, GLX_DRAWABLE_TYPE, &drawable_type);
00177     _glXGetFBConfigAttrib(_display, config, GLX_CONFIG_CAVEAT, &caveat);
00178     
00179     context_has_pbuffer = false;
00180     if ((drawable_type & GLX_PBUFFER_BIT)!=0) {
00181       context_has_pbuffer = true;
00182     }
00183     
00184     context_has_pixmap = false;
00185     if ((drawable_type & GLX_PIXMAP_BIT)!=0) {
00186       context_has_pixmap = true;
00187     }
00188     
00189     slow = false;
00190     if (caveat == GLX_SLOW_CONFIG) {
00191       slow = true;
00192     }
00193     
00194     if ((drawable_type & GLX_WINDOW_BIT)==0) {
00195       // We insist on having a context that will support an onscreen window.
00196       return;
00197     }
00198     
00199     if (double_buffer) {
00200       properties.set_back_buffers(1);
00201     }
00202     if (stereo) {
00203       properties.set_stereo(1);
00204     }
00205     
00206     if ((render_type & GLX_RGBA_BIT)!=0) {
00207       properties.set_rgb_color(1);
00208     }
00209     if ((render_type & GLX_COLOR_INDEX_BIT)!=0) {
00210       properties.set_indexed_color(1);
00211     }
00212     properties.set_color_bits(red_size+green_size+blue_size);
00213     properties.set_stencil_bits(stencil_size);
00214     properties.set_depth_bits(depth_size);
00215     properties.set_alpha_bits(alpha_size);
00216     properties.set_accum_bits(ared_size+agreen_size+ablue_size+aalpha_size);
00217     properties.set_multisamples(samples);
00218     
00219     // Set both hardware and software bits, indicating not-yet-known.
00220     properties.set_force_software(1);
00221     properties.set_force_hardware(1);
00222   }
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: glxGraphicsStateGuardian::choose_pixel_format
00227 //       Access: Public
00228 //  Description: Selects a visual or fbconfig for all the windows
00229 //               and buffers that use this gsg.  Also creates the GL
00230 //               context and obtains the visual.
00231 ////////////////////////////////////////////////////////////////////
00232 void glxGraphicsStateGuardian::
00233 choose_pixel_format(const FrameBufferProperties &properties,
00234                     Display *display,
00235                     int screen, bool need_pbuffer, bool need_pixmap) {
00236 
00237   _display = display;
00238   _screen = screen;
00239   _context = 0;
00240   _fbconfig = 0;
00241   _visual = 0;
00242   if (_visuals != (XVisualInfo *)NULL) {
00243     XFree(_visuals);
00244     _visuals = NULL;
00245   }
00246 
00247   _fbprops.clear();
00248 
00249   // First, attempt to create a context using the XVisual interface.
00250   // We need this before we can query the FBConfig interface, because
00251   // we need an OpenGL context to get the required extension function
00252   // pointers.
00253   destroy_temp_xwindow();
00254   choose_temp_visual(properties);
00255   if (_temp_context == NULL) {
00256     // No good.
00257     return;
00258   }
00259 
00260   // Now we have to initialize the context so we can query its
00261   // capabilities and extensions.  This also means creating a
00262   // temporary window, so we have something to bind the context to and
00263   // make it current.
00264   init_temp_context();
00265 
00266   if (!_supports_fbconfig) {
00267     // We have a good OpenGL context, but it doesn't support the
00268     // FBConfig interface, so we'll stop there.
00269     if (glxdisplay_cat.is_debug()) {
00270       glxdisplay_cat.debug()
00271         <<" No FBConfig supported; using XVisual only.\n";
00272 
00273       glxdisplay_cat.debug()
00274         << _fbprops << "\n";
00275 
00276       _context = _temp_context;
00277       _temp_context = (GLXContext)NULL;
00278 
00279       // By convention, every indirect XVisual that can render to a
00280       // window can also render to a GLXPixmap.  Direct visuals we're
00281       // not as sure about.
00282       _context_has_pixmap = !glXIsDirect(_display, _context);
00283 
00284       // Pbuffers aren't supported at all with the XVisual interface.
00285       _context_has_pbuffer = false;
00286     }
00287     return;
00288   }
00289 
00290   // The OpenGL context supports the FBConfig interface, so we can use
00291   // that more advanced interface to choose the actual window format
00292   // we'll use.  FBConfig provides for more options than the older
00293   // XVisual interface, so we'd much rather use it if it's available.
00294 
00295   int best_quality = 0;
00296   int best_result = 0;
00297   FrameBufferProperties best_props;
00298 
00299   static const int max_attrib_list = 32;
00300   int attrib_list[max_attrib_list];
00301   int n = 0;
00302   attrib_list[n++] = GLX_STEREO;
00303   attrib_list[n++] = GLX_DONT_CARE;
00304   attrib_list[n++] = GLX_RENDER_TYPE;
00305   attrib_list[n++] = GLX_DONT_CARE;
00306   attrib_list[n++] = GLX_DRAWABLE_TYPE;
00307   attrib_list[n++] = GLX_DONT_CARE;
00308   attrib_list[n] = (int)None;
00309   
00310   int num_configs = 0;
00311   GLXFBConfig *configs =
00312     _glXChooseFBConfig(_display, _screen, attrib_list, &num_configs);
00313   
00314   if (configs != 0) {
00315     bool context_has_pbuffer, context_has_pixmap, slow;
00316     int quality, i;
00317     for (i = 0; i < num_configs; ++i) {
00318       FrameBufferProperties fbprops;
00319       get_properties_advanced(fbprops, context_has_pbuffer, context_has_pixmap,
00320                               slow, configs[i]);
00321       quality = fbprops.get_quality(properties);
00322       if ((quality > 0)&&(slow)) quality -= 10000000;
00323       if (glxdisplay_cat.is_debug()) {
00324         const char *pbuffertext = context_has_pbuffer ? " (pbuffer)" : "";
00325         const char *pixmaptext = context_has_pixmap ? " (pixmap)" : "";
00326         const char *slowtext = slow ? " (slow)" : "";
00327         glxdisplay_cat.debug()
00328           << i << ": " << fbprops << " quality=" << quality << pbuffertext << pixmaptext << slowtext << "\n";
00329       }
00330       if (need_pbuffer && !context_has_pbuffer) {
00331         continue;
00332       }
00333       if (need_pixmap && !context_has_pixmap) {
00334         continue;
00335       }
00336       
00337       if (quality > best_quality) {
00338         best_quality = quality;
00339         best_result = i;
00340         best_props = fbprops;
00341       }
00342     }
00343   }
00344 
00345   if (best_quality > 0) {
00346     _fbconfig = configs[best_result];
00347     _context = 
00348       _glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context,
00349                            GL_TRUE);
00350     if (_context) {
00351       if (_visuals != (XVisualInfo *)NULL) {
00352         XFree(_visuals);
00353         _visuals = NULL;
00354       }
00355       _visuals = _glXGetVisualFromFBConfig(_display, _fbconfig);
00356       _visual = _visuals;
00357 
00358       if (_visual) {
00359         get_properties_advanced(_fbprops, _context_has_pbuffer, _context_has_pixmap,
00360                                 _slow, _fbconfig);
00361 
00362         if (glxdisplay_cat.is_debug()) {
00363           glxdisplay_cat.debug()
00364             << "Selected context " << best_result << ": " << _fbprops << "\n";
00365           glxdisplay_cat.debug()
00366             << "context_has_pbuffer = " << _context_has_pbuffer
00367             << ", context_has_pixmap = " << _context_has_pixmap << "\n";
00368         }
00369 
00370         return;
00371       }
00372     }
00373     // This really shouldn't happen, so I'm not too careful about cleanup.
00374     glxdisplay_cat.error()
00375       << "Could not create FBConfig context!\n";
00376     _fbconfig = 0;
00377     _context = 0;
00378     _visual = 0;
00379     _visuals = 0;
00380   }
00381 
00382   glxdisplay_cat.info()
00383     << "No suitable FBConfig contexts available.\n";
00384 }
00385 
00386 ////////////////////////////////////////////////////////////////////
00387 //     Function: glxGraphicsStateGuardian::reset
00388 //       Access: Public, Virtual
00389 //  Description: Resets all internal state as if the gsg were newly
00390 //               created.
00391 ////////////////////////////////////////////////////////////////////
00392 void glxGraphicsStateGuardian::
00393 reset() {
00394   GLGraphicsStateGuardian::reset();
00395 
00396   _supports_swap_control = has_extension("GLX_SGI_swap_control");
00397 
00398   if (_supports_swap_control) {
00399     _glXSwapIntervalSGI = 
00400       (PFNGLXSWAPINTERVALSGIPROC)get_extension_func("glX", "SwapIntervalSGI");
00401     if (_glXSwapIntervalSGI == NULL) {
00402       glxdisplay_cat.error()
00403         << "Driver claims to support GLX_SGI_swap_control extension, but does not define all functions.\n";
00404       _supports_swap_control = false;
00405     }
00406   }
00407 
00408   if (_supports_swap_control) {
00409     // Set the video-sync setting up front, if we have the extension
00410     // that supports it.
00411     _glXSwapIntervalSGI(sync_video ? 1 : 0);
00412   }
00413 
00414   if (glx_support_fbconfig) {
00415     if (glx_is_at_least_version(1, 3)) {
00416       // If we have glx 1.3 or better, we have the FBConfig interface.
00417       _supports_fbconfig = true;
00418       
00419       _glXChooseFBConfig = 
00420         (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfig");
00421       _glXCreateNewContext = 
00422         (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateNewContext");
00423       _glXGetVisualFromFBConfig = 
00424         (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfig");
00425       _glXGetFBConfigAttrib = 
00426         (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttrib");
00427       _glXCreatePixmap = 
00428         (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreatePixmap");
00429       
00430       if (_glXChooseFBConfig == NULL ||
00431           _glXCreateNewContext == NULL ||
00432           _glXGetVisualFromFBConfig == NULL ||
00433           _glXGetFBConfigAttrib == NULL ||
00434           _glXCreatePixmap == NULL) {
00435         glxdisplay_cat.error()
00436           << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n";
00437         _supports_fbconfig = false;
00438       }
00439     } else if (has_extension("GLX_SGIX_fbconfig")) {
00440       // Or maybe we have the old SGIX extension for FBConfig.  This is
00441       // the same, but the function names are different--we just remap
00442       // them to the same function pointers.
00443       _supports_fbconfig = true;
00444       
00445       _glXChooseFBConfig = 
00446         (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfigSGIX");
00447       _glXCreateNewContext = 
00448         (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateContextWithConfigSGIX");
00449       _glXGetVisualFromFBConfig = 
00450         (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfigSGIX");
00451       _glXGetFBConfigAttrib = 
00452         (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttribSGIX");
00453       _glXCreatePixmap = 
00454         (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreateGLXPixmapWithConfigSGIX");
00455       
00456       if (_glXChooseFBConfig == NULL ||
00457           _glXCreateNewContext == NULL ||
00458           _glXGetVisualFromFBConfig == NULL ||
00459           _glXGetFBConfigAttrib == NULL ||
00460           _glXCreatePixmap == NULL) {
00461         glxdisplay_cat.error()
00462           << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n";
00463         _supports_fbconfig = false;
00464       }
00465     }
00466     
00467     if (glx_is_at_least_version(1, 3)) {
00468       // If we have glx 1.3 or better, we have the PBuffer interface.
00469       _supports_pbuffer = true;
00470       _uses_sgix_pbuffer = false;
00471       
00472       _glXCreatePbuffer = 
00473         (PFNGLXCREATEPBUFFERPROC)get_extension_func("glX", "CreatePbuffer");
00474       _glXCreateGLXPbufferSGIX = NULL;
00475       _glXDestroyPbuffer = 
00476         (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyPbuffer");
00477       if (_glXCreatePbuffer == NULL ||
00478           _glXDestroyPbuffer == NULL) {
00479         glxdisplay_cat.error()
00480           << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n";
00481         _supports_pbuffer = false;
00482       }
00483       
00484     } else if (has_extension("GLX_SGIX_pbuffer")) {
00485       // Or maybe we have the old SGIX extension for PBuffers.
00486       _uses_sgix_pbuffer = true;
00487       
00488       // CreatePbuffer has a different form between SGIX and 1.3,
00489       // however, so we must treat it specially.  But we can use the
00490       // same function pointer for DestroyPbuffer.
00491       _glXCreatePbuffer = NULL;
00492       _glXCreateGLXPbufferSGIX = 
00493         (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glX", "CreateGLXPbufferSGIX");
00494       _glXDestroyPbuffer = 
00495         (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyGLXPbufferSGIX");
00496       if (_glXCreateGLXPbufferSGIX == NULL ||
00497           _glXDestroyPbuffer == NULL) {
00498         glxdisplay_cat.error()
00499           << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n";
00500         _supports_pbuffer = false;
00501       }
00502     }
00503   }
00504 
00505 
00506   if (glxdisplay_cat.is_debug()) {
00507     glxdisplay_cat.debug()
00508       << "supports_swap_control = " << _supports_swap_control << "\n";
00509     glxdisplay_cat.debug()
00510       << "supports_fbconfig = " << _supports_fbconfig << "\n";
00511     glxdisplay_cat.debug()
00512       << "supports_pbuffer = " << _supports_pbuffer
00513       << " sgix = " << _uses_sgix_pbuffer << "\n";
00514   }
00515 
00516   // If "Mesa" is present, assume software.  However, if "Mesa DRI" is
00517   // found, it's actually a Mesa-based OpenGL layer running over a
00518   // hardware driver.
00519   if (_gl_renderer.find("Mesa") != string::npos &&
00520       _gl_renderer.find("Mesa DRI") == string::npos) {
00521     // It's Mesa, therefore probably a software context.
00522     _fbprops.set_force_software(1);
00523     _fbprops.set_force_hardware(0);
00524   } else {
00525     _fbprops.set_force_hardware(1);
00526     _fbprops.set_force_software(0);
00527   }
00528 }
00529 
00530 ////////////////////////////////////////////////////////////////////
00531 //     Function: glxGraphicsStateGuardian::glx_is_at_least_version
00532 //       Access: Public
00533 //  Description: Returns true if the runtime GLX version number is at
00534 //               least the indicated value, false otherwise.
00535 ////////////////////////////////////////////////////////////////////
00536 bool glxGraphicsStateGuardian::
00537 glx_is_at_least_version(int major_version, int minor_version) const {
00538   if (_glx_version_major < major_version) {
00539     return false;
00540   }
00541   if (_glx_version_major > major_version) {
00542     return true;
00543   }
00544   if (_glx_version_minor < minor_version) {
00545     return false;
00546   }
00547   return true;
00548 }
00549 
00550 ////////////////////////////////////////////////////////////////////
00551 //     Function: glxGraphicsStateGuardian::gl_flush
00552 //       Access: Protected, Virtual
00553 //  Description: Calls glFlush().
00554 ////////////////////////////////////////////////////////////////////
00555 void glxGraphicsStateGuardian::
00556 gl_flush() const {
00557   // This call requires synchronization with X.
00558   LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
00559   GLGraphicsStateGuardian::gl_flush();
00560 }
00561 
00562 ////////////////////////////////////////////////////////////////////
00563 //     Function: glxGraphicsStateGuardian::gl_get_error
00564 //       Access: Protected, Virtual
00565 //  Description: Returns the result of glGetError().
00566 ////////////////////////////////////////////////////////////////////
00567 GLenum glxGraphicsStateGuardian::
00568 gl_get_error() const {
00569   // This call requires synchronization with X.
00570   LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
00571   return GLGraphicsStateGuardian::gl_get_error();
00572 }
00573 
00574 ////////////////////////////////////////////////////////////////////
00575 //     Function: glxGraphicsStateGuardian::query_gl_version
00576 //       Access: Protected, Virtual
00577 //  Description: Queries the runtime version of OpenGL in use.
00578 ////////////////////////////////////////////////////////////////////
00579 void glxGraphicsStateGuardian::
00580 query_gl_version() {
00581   GLGraphicsStateGuardian::query_gl_version();
00582 
00583   show_glx_client_string("GLX_VENDOR", GLX_VENDOR);
00584   show_glx_client_string("GLX_VERSION", GLX_VERSION);
00585   show_glx_server_string("GLX_VENDOR", GLX_VENDOR);
00586   show_glx_server_string("GLX_VERSION", GLX_VERSION);
00587 
00588   glXQueryVersion(_display, &_glx_version_major, &_glx_version_minor);
00589 
00590   // We output to glgsg_cat instead of glxdisplay_cat, since this is
00591   // where the GL version has been output, and it's nice to see the
00592   // two of these together.
00593   if (glgsg_cat.is_debug()) {
00594     glgsg_cat.debug()
00595       << "GLX_VERSION = " << _glx_version_major << "." << _glx_version_minor 
00596       << "\n";
00597   }
00598 }
00599 
00600 ////////////////////////////////////////////////////////////////////
00601 //     Function: glxGraphicsStateGuardian::get_extra_extensions
00602 //       Access: Protected, Virtual
00603 //  Description: This may be redefined by a derived class (e.g. glx or
00604 //               wgl) to get whatever further extensions strings may
00605 //               be appropriate to that interface, in addition to the
00606 //               GL extension strings return by glGetString().
00607 ////////////////////////////////////////////////////////////////////
00608 void glxGraphicsStateGuardian::
00609 get_extra_extensions() {
00610   save_extensions(glXQueryExtensionsString(_display, _screen));
00611 }
00612 
00613 ////////////////////////////////////////////////////////////////////
00614 //     Function: glxGraphicsStateGuardian::do_get_extension_func
00615 //       Access: Public, Virtual
00616 //  Description: Returns the pointer to the GL extension function with
00617 //               the indicated name.  It is the responsibility of the
00618 //               caller to ensure that the required extension is
00619 //               defined in the OpenGL runtime prior to calling this;
00620 //               it is an error to call this for a function that is
00621 //               not defined.
00622 ////////////////////////////////////////////////////////////////////
00623 void *glxGraphicsStateGuardian::
00624 do_get_extension_func(const char *prefix, const char *name) {
00625   nassertr(prefix != NULL, NULL);
00626   nassertr(name != NULL, NULL);
00627   string fullname = string(prefix) + string(name);
00628 
00629   if (glx_get_proc_address) {
00630     // First, check if we have glXGetProcAddress available.  This will
00631     // be superior if we can get it.
00632     
00633 #if defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESS)
00634       // If we are confident the system headers defined it, we can
00635       // call it directly.  This is more reliable than trying to
00636       // determine its address dynamically, but it may make
00637       // libpandagl.so fail to load if the symbol isn't in the runtime
00638       // library.
00639     return (void *)glXGetProcAddress((const GLubyte *)fullname.c_str());
00640       
00641 #elif defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESSARB)
00642     // The ARB extension version is OK too.  Sometimes the prototype
00643     // isn't supplied for some reason.
00644     return (void *)glXGetProcAddressARB((const GLubyte *)fullname.c_str());
00645     
00646 #else
00647     // Otherwise, we have to fiddle around with the dynamic runtime.
00648     
00649     if (!_checked_get_proc_address) {
00650       const char *funcName = NULL;
00651       
00652       if (glx_is_at_least_version(1, 4)) {
00653         funcName = "glXGetProcAddress";
00654 
00655       } else if (has_extension("GLX_ARB_get_proc_address")) {
00656         funcName = "glXGetProcAddressARB";
00657       }
00658       
00659       if (funcName != NULL) {
00660         _glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)get_system_func(funcName);
00661         if (_glXGetProcAddress == NULL) {
00662           glxdisplay_cat.warning()
00663             << "Couldn't load function " << funcName
00664             << ", GL extensions may be unavailable.\n";
00665         }
00666       }
00667 
00668       _checked_get_proc_address = true;
00669     }
00670     
00671     // Use glxGetProcAddress() if we've got it; it should be more robust.
00672     if (_glXGetProcAddress != NULL) {
00673       return (void *)_glXGetProcAddress((const GLubyte *)fullname.c_str());
00674     }
00675 #endif // HAVE_GLXGETPROCADDRESS
00676   }
00677 
00678   if (glx_get_os_address) {
00679     // Otherwise, fall back to the OS-provided calls.
00680     return get_system_func(fullname.c_str());
00681   }
00682 
00683   return NULL;
00684 }
00685 
00686 ////////////////////////////////////////////////////////////////////
00687 //     Function: glxGraphicsStateGuardian::get_system_func
00688 //       Access: Private
00689 //  Description: Support for get_extension_func(), above, that uses
00690 //               system calls to find a GL or GLX function (in the
00691 //               absence of a working glxGetProcAddress() function to
00692 //               call).
00693 ////////////////////////////////////////////////////////////////////
00694 void *glxGraphicsStateGuardian::
00695 get_system_func(const char *name) {
00696   if (_libgl_handle == (void *)NULL) {
00697     // We open the current executable, rather than naming a particular
00698     // library.  Presumably libGL.so (or whatever the library should
00699     // be called) is already available in the current executable
00700     // address space, so this is more portable than insisting on a
00701     // particular shared library name.
00702     _libgl_handle = dlopen(NULL, RTLD_LAZY);
00703     nassertr(_libgl_handle != (void *)NULL, NULL);
00704 
00705     // If that doesn't locate the symbol we expected, then fall back
00706     // to loading the GL library by its usual name.
00707     if (dlsym(_libgl_handle, name) == NULL) {
00708       dlclose(_libgl_handle);
00709       glxdisplay_cat.warning()
00710         << name << " not found in executable; looking in libGL.so instead.\n";
00711       _libgl_handle = dlopen("libGL.so", RTLD_LAZY);
00712       nassertr(_libgl_handle != (void *)NULL, NULL);
00713     }
00714   }
00715 
00716   return dlsym(_libgl_handle, name);
00717 }
00718 
00719 ////////////////////////////////////////////////////////////////////
00720 //     Function: glxGraphicsStateGuardian::show_glx_client_string
00721 //       Access: Protected
00722 //  Description: Outputs the result of glxGetClientString() on the
00723 //               indicated tag.
00724 ////////////////////////////////////////////////////////////////////
00725 void glxGraphicsStateGuardian::
00726 show_glx_client_string(const string &name, int id) {
00727   if (glgsg_cat.is_debug()) {
00728     const char *text = glXGetClientString(_display, id);
00729     if (text == (const char *)NULL) {
00730       glgsg_cat.debug()
00731         << "Unable to query " << name << " (client)\n";
00732     } else {
00733       glgsg_cat.debug()
00734         << name << " (client) = " << (const char *)text << "\n";
00735     }
00736   }
00737 }
00738 
00739 ////////////////////////////////////////////////////////////////////
00740 //     Function: glxGraphicsStateGuardian::show_glx_server_string
00741 //       Access: Protected
00742 //  Description: Outputs the result of glxQueryServerString() on the
00743 //               indicated tag.
00744 ////////////////////////////////////////////////////////////////////
00745 void glxGraphicsStateGuardian::
00746 show_glx_server_string(const string &name, int id) {
00747   if (glgsg_cat.is_debug()) {
00748     const char *text = glXQueryServerString(_display, _screen, id);
00749     if (text == (const char *)NULL) {
00750       glgsg_cat.debug()
00751         << "Unable to query " << name << " (server)\n";
00752     } else {
00753       glgsg_cat.debug()
00754         << name << " (server) = " << (const char *)text << "\n";
00755     }
00756   }
00757 }
00758 
00759 ////////////////////////////////////////////////////////////////////
00760 //     Function: glxGraphicsStateGuardian::choose_temp_visual
00761 //       Access: Private
00762 //  Description: Selects an XVisual for an initial OpenGL context.
00763 //               This may be called initially, to create the first
00764 //               context needed in order to create the fbconfig.  On
00765 //               successful return, _visual and _temp_context will be
00766 //               filled in with a non-NULL value.
00767 ////////////////////////////////////////////////////////////////////
00768 void glxGraphicsStateGuardian::
00769 choose_temp_visual(const FrameBufferProperties &properties) {
00770   nassertv(_temp_context == (GLXContext)NULL);
00771 
00772   int best_quality = 0;
00773   int best_result = 0;
00774   FrameBufferProperties best_props;
00775 
00776   // Scan available visuals.
00777   if (_visuals != (XVisualInfo *)NULL) {
00778     XFree(_visuals);
00779     _visuals = NULL;
00780   }
00781   int nvisuals = 0;
00782   _visuals = XGetVisualInfo(_display, 0, 0, &nvisuals);
00783   if (_visuals != 0) {
00784     for (int i = 0; i < nvisuals; i++) {
00785       FrameBufferProperties fbprops;
00786       get_properties(fbprops, _visuals + i);
00787       int quality = fbprops.get_quality(properties);
00788       if (quality > best_quality) {
00789         best_quality = quality;
00790         best_result = i;
00791         best_props = fbprops;
00792       }
00793     }
00794   }
00795   
00796   if (best_quality > 0) {
00797     _visual = _visuals + best_result;
00798     _temp_context = glXCreateContext(_display, _visual, None, GL_TRUE);    
00799     if (_temp_context) {
00800       _fbprops = best_props;
00801       return;
00802     }
00803   }
00804 
00805   glxdisplay_cat.error() 
00806     << "Could not find a usable pixel format.\n";
00807 }
00808 
00809 ////////////////////////////////////////////////////////////////////
00810 //     Function: glxGraphicsStateGuardian::init_temp_context
00811 //       Access: Private
00812 //  Description: Initializes the context created in
00813 //               choose_temp_visual() by creating a temporary window
00814 //               and binding the context to that window.
00815 ////////////////////////////////////////////////////////////////////
00816 void glxGraphicsStateGuardian::
00817 init_temp_context() {
00818   x11GraphicsPipe *x11_pipe;
00819   DCAST_INTO_V(x11_pipe, get_pipe());
00820   Window root_window = x11_pipe->get_root();
00821 
00822   // Assume everyone uses TrueColor or DirectColor these days.
00823   Visual *visual = _visual->visual;
00824   nassertv(visual->c_class == DirectColor || visual->c_class == TrueColor);
00825   _temp_colormap = XCreateColormap(_display, root_window,
00826                                    visual, AllocNone);
00827   XSetWindowAttributes wa;
00828   wa.colormap = _temp_colormap;
00829   unsigned long attrib_mask = CWColormap;
00830 
00831   _temp_xwindow = XCreateWindow
00832     (_display, root_window, 0, 0, 100, 100,
00833      0, _visual->depth, InputOutput,
00834      visual, attrib_mask, &wa);
00835   if (_temp_xwindow == (Window)NULL) {
00836     glxdisplay_cat.error()
00837       << "Could not create temporary window for context\n";
00838     return;
00839   }
00840 
00841   glXMakeCurrent(_display, _temp_xwindow, _temp_context);
00842   reset();
00843 }
00844 
00845 ////////////////////////////////////////////////////////////////////
00846 //     Function: glxGraphicsStateGuardian::destroy_temp_xwindow
00847 //       Access: Private
00848 //  Description: Destroys the temporary unmapped window created by
00849 //               init_temp_context().
00850 ////////////////////////////////////////////////////////////////////
00851 void glxGraphicsStateGuardian::
00852 destroy_temp_xwindow() {
00853   glXMakeCurrent(_display, None, NULL);
00854 
00855   if (_temp_colormap != (Colormap)NULL) {
00856     XFreeColormap(_display, _temp_colormap);
00857     _temp_colormap = (Colormap)NULL;
00858   }
00859   if (_temp_xwindow != (Window)NULL) {
00860     XDestroyWindow(_display, _temp_xwindow);
00861     _temp_xwindow = (Window)NULL;
00862   }
00863 
00864   if (_temp_context != (GLXContext)NULL){ 
00865     glXDestroyContext(_display, _temp_context);
00866     _temp_context = (GLXContext)NULL;
00867   }
00868 }
 All Classes Functions Variables Enumerations