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     glxdisplay_cat.debug()
00270       <<" No FBConfig supported; using XVisual only.\n"
00271       << _fbprops << "\n";
00272 
00273     _context = _temp_context;
00274     _temp_context = (GLXContext)NULL;
00275 
00276     // By convention, every indirect XVisual that can render to a
00277     // window can also render to a GLXPixmap.  Direct visuals we're
00278     // not as sure about.
00279     _context_has_pixmap = !glXIsDirect(_display, _context);
00280 
00281     // Pbuffers aren't supported at all with the XVisual interface.
00282     _context_has_pbuffer = false;
00283     return;
00284   }
00285 
00286   // The OpenGL context supports the FBConfig interface, so we can use
00287   // that more advanced interface to choose the actual window format
00288   // we'll use.  FBConfig provides for more options than the older
00289   // XVisual interface, so we'd much rather use it if it's available.
00290 
00291   int best_quality = 0;
00292   int best_result = 0;
00293   FrameBufferProperties best_props;
00294 
00295   static const int max_attrib_list = 32;
00296   int attrib_list[max_attrib_list];
00297   int n = 0;
00298   attrib_list[n++] = GLX_STEREO;
00299   attrib_list[n++] = GLX_DONT_CARE;
00300   attrib_list[n++] = GLX_RENDER_TYPE;
00301   attrib_list[n++] = GLX_DONT_CARE;
00302   attrib_list[n++] = GLX_DRAWABLE_TYPE;
00303   attrib_list[n++] = GLX_DONT_CARE;
00304   attrib_list[n] = (int)None;
00305   
00306   int num_configs = 0;
00307   GLXFBConfig *configs =
00308     _glXChooseFBConfig(_display, _screen, attrib_list, &num_configs);
00309   
00310   if (configs != 0) {
00311     bool context_has_pbuffer, context_has_pixmap, slow;
00312     int quality, i;
00313     for (i = 0; i < num_configs; ++i) {
00314       FrameBufferProperties fbprops;
00315       get_properties_advanced(fbprops, context_has_pbuffer, context_has_pixmap,
00316                               slow, configs[i]);
00317       quality = fbprops.get_quality(properties);
00318       if ((quality > 0)&&(slow)) quality -= 10000000;
00319       if (glxdisplay_cat.is_debug()) {
00320         const char *pbuffertext = context_has_pbuffer ? " (pbuffer)" : "";
00321         const char *pixmaptext = context_has_pixmap ? " (pixmap)" : "";
00322         const char *slowtext = slow ? " (slow)" : "";
00323         glxdisplay_cat.debug()
00324           << i << ": " << fbprops << " quality=" << quality << pbuffertext << pixmaptext << slowtext << "\n";
00325       }
00326       if (need_pbuffer && !context_has_pbuffer) {
00327         continue;
00328       }
00329       if (need_pixmap && !context_has_pixmap) {
00330         continue;
00331       }
00332       
00333       if (quality > best_quality) {
00334         best_quality = quality;
00335         best_result = i;
00336         best_props = fbprops;
00337       }
00338     }
00339   }
00340 
00341   if (best_quality > 0) {
00342     _fbconfig = configs[best_result];
00343     _context = 
00344       _glXCreateNewContext(_display, _fbconfig, GLX_RGBA_TYPE, _share_context,
00345                            GL_TRUE);
00346     if (_context) {
00347       if (_visuals != (XVisualInfo *)NULL) {
00348         XFree(_visuals);
00349         _visuals = NULL;
00350       }
00351       _visuals = _glXGetVisualFromFBConfig(_display, _fbconfig);
00352       _visual = _visuals;
00353 
00354       if (_visual) {
00355         get_properties_advanced(_fbprops, _context_has_pbuffer, _context_has_pixmap,
00356                                 _slow, _fbconfig);
00357 
00358         if (glxdisplay_cat.is_debug()) {
00359           glxdisplay_cat.debug()
00360             << "Selected context " << best_result << ": " << _fbprops << "\n";
00361           glxdisplay_cat.debug()
00362             << "context_has_pbuffer = " << _context_has_pbuffer
00363             << ", context_has_pixmap = " << _context_has_pixmap << "\n";
00364         }
00365 
00366         return;
00367       }
00368     }
00369     // This really shouldn't happen, so I'm not too careful about cleanup.
00370     glxdisplay_cat.error()
00371       << "Could not create FBConfig context!\n";
00372     _fbconfig = 0;
00373     _context = 0;
00374     _visual = 0;
00375     _visuals = 0;
00376   }
00377 
00378   glxdisplay_cat.warning()
00379     << "No suitable FBConfig contexts available; using XVisual only.\n"
00380     << _fbprops << "\n";
00381 
00382   _context = _temp_context;
00383   _temp_context = (GLXContext)NULL;
00384 
00385   // By convention, every indirect XVisual that can render to a
00386   // window can also render to a GLXPixmap.  Direct visuals we're
00387   // not as sure about.
00388   _context_has_pixmap = !glXIsDirect(_display, _context);
00389 
00390   // Pbuffers aren't supported at all with the XVisual interface.
00391   _context_has_pbuffer = false;
00392 }
00393 
00394 ////////////////////////////////////////////////////////////////////
00395 //     Function: glxGraphicsStateGuardian::reset
00396 //       Access: Public, Virtual
00397 //  Description: Resets all internal state as if the gsg were newly
00398 //               created.
00399 ////////////////////////////////////////////////////////////////////
00400 void glxGraphicsStateGuardian::
00401 reset() {
00402   GLGraphicsStateGuardian::reset();
00403 
00404   _supports_swap_control = has_extension("GLX_SGI_swap_control");
00405 
00406   if (_supports_swap_control) {
00407     _glXSwapIntervalSGI = 
00408       (PFNGLXSWAPINTERVALSGIPROC)get_extension_func("glX", "SwapIntervalSGI");
00409     if (_glXSwapIntervalSGI == NULL) {
00410       glxdisplay_cat.error()
00411         << "Driver claims to support GLX_SGI_swap_control extension, but does not define all functions.\n";
00412       _supports_swap_control = false;
00413     }
00414   }
00415 
00416   if (_supports_swap_control) {
00417     // Set the video-sync setting up front, if we have the extension
00418     // that supports it.
00419     _glXSwapIntervalSGI(sync_video ? 1 : 0);
00420   }
00421 
00422   if (glx_support_fbconfig) {
00423     if (glx_is_at_least_version(1, 3)) {
00424       // If we have glx 1.3 or better, we have the FBConfig interface.
00425       _supports_fbconfig = true;
00426       
00427       _glXChooseFBConfig = 
00428         (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfig");
00429       _glXCreateNewContext = 
00430         (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateNewContext");
00431       _glXGetVisualFromFBConfig = 
00432         (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfig");
00433       _glXGetFBConfigAttrib = 
00434         (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttrib");
00435       _glXCreatePixmap = 
00436         (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreatePixmap");
00437       
00438       if (_glXChooseFBConfig == NULL ||
00439           _glXCreateNewContext == NULL ||
00440           _glXGetVisualFromFBConfig == NULL ||
00441           _glXGetFBConfigAttrib == NULL ||
00442           _glXCreatePixmap == NULL) {
00443         glxdisplay_cat.error()
00444           << "Driver claims to support GLX_fbconfig extension, but does not define all functions.\n";
00445         _supports_fbconfig = false;
00446       }
00447     } else if (has_extension("GLX_SGIX_fbconfig")) {
00448       // Or maybe we have the old SGIX extension for FBConfig.  This is
00449       // the same, but the function names are different--we just remap
00450       // them to the same function pointers.
00451       _supports_fbconfig = true;
00452       
00453       _glXChooseFBConfig = 
00454         (PFNGLXCHOOSEFBCONFIGPROC)get_extension_func("glX", "ChooseFBConfigSGIX");
00455       _glXCreateNewContext = 
00456         (PFNGLXCREATENEWCONTEXTPROC)get_extension_func("glX", "CreateContextWithConfigSGIX");
00457       _glXGetVisualFromFBConfig = 
00458         (PFNGLXGETVISUALFROMFBCONFIGPROC)get_extension_func("glX", "GetVisualFromFBConfigSGIX");
00459       _glXGetFBConfigAttrib = 
00460         (PFNGLXGETFBCONFIGATTRIBPROC)get_extension_func("glX", "GetFBConfigAttribSGIX");
00461       _glXCreatePixmap = 
00462         (PFNGLXCREATEPIXMAPPROC)get_extension_func("glX", "CreateGLXPixmapWithConfigSGIX");
00463       
00464       if (_glXChooseFBConfig == NULL ||
00465           _glXCreateNewContext == NULL ||
00466           _glXGetVisualFromFBConfig == NULL ||
00467           _glXGetFBConfigAttrib == NULL ||
00468           _glXCreatePixmap == NULL) {
00469         glxdisplay_cat.error()
00470           << "Driver claims to support GLX_SGIX_fbconfig extension, but does not define all functions.\n";
00471         _supports_fbconfig = false;
00472       }
00473     }
00474     
00475     if (glx_is_at_least_version(1, 3)) {
00476       // If we have glx 1.3 or better, we have the PBuffer interface.
00477       _supports_pbuffer = true;
00478       _uses_sgix_pbuffer = false;
00479       
00480       _glXCreatePbuffer = 
00481         (PFNGLXCREATEPBUFFERPROC)get_extension_func("glX", "CreatePbuffer");
00482       _glXCreateGLXPbufferSGIX = NULL;
00483       _glXDestroyPbuffer = 
00484         (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyPbuffer");
00485       if (_glXCreatePbuffer == NULL ||
00486           _glXDestroyPbuffer == NULL) {
00487         glxdisplay_cat.error()
00488           << "Driver claims to support GLX_pbuffer extension, but does not define all functions.\n";
00489         _supports_pbuffer = false;
00490       }
00491       
00492     } else if (has_extension("GLX_SGIX_pbuffer")) {
00493       // Or maybe we have the old SGIX extension for PBuffers.
00494       _uses_sgix_pbuffer = true;
00495       
00496       // CreatePbuffer has a different form between SGIX and 1.3,
00497       // however, so we must treat it specially.  But we can use the
00498       // same function pointer for DestroyPbuffer.
00499       _glXCreatePbuffer = NULL;
00500       _glXCreateGLXPbufferSGIX = 
00501         (PFNGLXCREATEGLXPBUFFERSGIXPROC)get_extension_func("glX", "CreateGLXPbufferSGIX");
00502       _glXDestroyPbuffer = 
00503         (PFNGLXDESTROYPBUFFERPROC)get_extension_func("glX", "DestroyGLXPbufferSGIX");
00504       if (_glXCreateGLXPbufferSGIX == NULL ||
00505           _glXDestroyPbuffer == NULL) {
00506         glxdisplay_cat.error()
00507           << "Driver claims to support GLX_SGIX_pbuffer extension, but does not define all functions.\n";
00508         _supports_pbuffer = false;
00509       }
00510     }
00511   }
00512 
00513 
00514   if (glxdisplay_cat.is_debug()) {
00515     glxdisplay_cat.debug()
00516       << "supports_swap_control = " << _supports_swap_control << "\n";
00517     glxdisplay_cat.debug()
00518       << "supports_fbconfig = " << _supports_fbconfig << "\n";
00519     glxdisplay_cat.debug()
00520       << "supports_pbuffer = " << _supports_pbuffer
00521       << " sgix = " << _uses_sgix_pbuffer << "\n";
00522   }
00523 
00524   // If "Mesa" is present, assume software.  However, if "Mesa DRI" is
00525   // found, it's actually a Mesa-based OpenGL layer running over a
00526   // hardware driver.
00527   if (_gl_renderer.find("Mesa") != string::npos &&
00528       _gl_renderer.find("Mesa DRI") == string::npos) {
00529     // It's Mesa, therefore probably a software context.
00530     _fbprops.set_force_software(1);
00531     _fbprops.set_force_hardware(0);
00532   } else {
00533     _fbprops.set_force_hardware(1);
00534     _fbprops.set_force_software(0);
00535   }
00536 }
00537 
00538 ////////////////////////////////////////////////////////////////////
00539 //     Function: glxGraphicsStateGuardian::glx_is_at_least_version
00540 //       Access: Public
00541 //  Description: Returns true if the runtime GLX version number is at
00542 //               least the indicated value, false otherwise.
00543 ////////////////////////////////////////////////////////////////////
00544 bool glxGraphicsStateGuardian::
00545 glx_is_at_least_version(int major_version, int minor_version) const {
00546   if (_glx_version_major < major_version) {
00547     return false;
00548   }
00549   if (_glx_version_major > major_version) {
00550     return true;
00551   }
00552   if (_glx_version_minor < minor_version) {
00553     return false;
00554   }
00555   return true;
00556 }
00557 
00558 ////////////////////////////////////////////////////////////////////
00559 //     Function: glxGraphicsStateGuardian::gl_flush
00560 //       Access: Protected, Virtual
00561 //  Description: Calls glFlush().
00562 ////////////////////////////////////////////////////////////////////
00563 void glxGraphicsStateGuardian::
00564 gl_flush() const {
00565   // This call requires synchronization with X.
00566   LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
00567   GLGraphicsStateGuardian::gl_flush();
00568 }
00569 
00570 ////////////////////////////////////////////////////////////////////
00571 //     Function: glxGraphicsStateGuardian::gl_get_error
00572 //       Access: Protected, Virtual
00573 //  Description: Returns the result of glGetError().
00574 ////////////////////////////////////////////////////////////////////
00575 GLenum glxGraphicsStateGuardian::
00576 gl_get_error() const {
00577   // This call requires synchronization with X.
00578   LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
00579   return GLGraphicsStateGuardian::gl_get_error();
00580 }
00581 
00582 ////////////////////////////////////////////////////////////////////
00583 //     Function: glxGraphicsStateGuardian::query_gl_version
00584 //       Access: Protected, Virtual
00585 //  Description: Queries the runtime version of OpenGL in use.
00586 ////////////////////////////////////////////////////////////////////
00587 void glxGraphicsStateGuardian::
00588 query_gl_version() {
00589   GLGraphicsStateGuardian::query_gl_version();
00590 
00591   show_glx_client_string("GLX_VENDOR", GLX_VENDOR);
00592   show_glx_client_string("GLX_VERSION", GLX_VERSION);
00593   show_glx_server_string("GLX_VENDOR", GLX_VENDOR);
00594   show_glx_server_string("GLX_VERSION", GLX_VERSION);
00595 
00596   glXQueryVersion(_display, &_glx_version_major, &_glx_version_minor);
00597 
00598   // We output to glgsg_cat instead of glxdisplay_cat, since this is
00599   // where the GL version has been output, and it's nice to see the
00600   // two of these together.
00601   if (glgsg_cat.is_debug()) {
00602     glgsg_cat.debug()
00603       << "GLX_VERSION = " << _glx_version_major << "." << _glx_version_minor 
00604       << "\n";
00605   }
00606 }
00607 
00608 ////////////////////////////////////////////////////////////////////
00609 //     Function: glxGraphicsStateGuardian::get_extra_extensions
00610 //       Access: Protected, Virtual
00611 //  Description: This may be redefined by a derived class (e.g. glx or
00612 //               wgl) to get whatever further extensions strings may
00613 //               be appropriate to that interface, in addition to the
00614 //               GL extension strings return by glGetString().
00615 ////////////////////////////////////////////////////////////////////
00616 void glxGraphicsStateGuardian::
00617 get_extra_extensions() {
00618   save_extensions(glXQueryExtensionsString(_display, _screen));
00619 }
00620 
00621 ////////////////////////////////////////////////////////////////////
00622 //     Function: glxGraphicsStateGuardian::do_get_extension_func
00623 //       Access: Public, Virtual
00624 //  Description: Returns the pointer to the GL extension function with
00625 //               the indicated name.  It is the responsibility of the
00626 //               caller to ensure that the required extension is
00627 //               defined in the OpenGL runtime prior to calling this;
00628 //               it is an error to call this for a function that is
00629 //               not defined.
00630 ////////////////////////////////////////////////////////////////////
00631 void *glxGraphicsStateGuardian::
00632 do_get_extension_func(const char *prefix, const char *name) {
00633   nassertr(prefix != NULL, NULL);
00634   nassertr(name != NULL, NULL);
00635   string fullname = string(prefix) + string(name);
00636 
00637   if (glx_get_proc_address) {
00638     // First, check if we have glXGetProcAddress available.  This will
00639     // be superior if we can get it.
00640     
00641 #if defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESS)
00642       // If we are confident the system headers defined it, we can
00643       // call it directly.  This is more reliable than trying to
00644       // determine its address dynamically, but it may make
00645       // libpandagl.so fail to load if the symbol isn't in the runtime
00646       // library.
00647     return (void *)glXGetProcAddress((const GLubyte *)fullname.c_str());
00648       
00649 #elif defined(LINK_IN_GLXGETPROCADDRESS) && defined(HAVE_GLXGETPROCADDRESSARB)
00650     // The ARB extension version is OK too.  Sometimes the prototype
00651     // isn't supplied for some reason.
00652     return (void *)glXGetProcAddressARB((const GLubyte *)fullname.c_str());
00653     
00654 #else
00655     // Otherwise, we have to fiddle around with the dynamic runtime.
00656     
00657     if (!_checked_get_proc_address) {
00658       const char *funcName = NULL;
00659       
00660       if (glx_is_at_least_version(1, 4)) {
00661         funcName = "glXGetProcAddress";
00662 
00663       } else if (has_extension("GLX_ARB_get_proc_address")) {
00664         funcName = "glXGetProcAddressARB";
00665       }
00666       
00667       if (funcName != NULL) {
00668         _glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)get_system_func(funcName);
00669         if (_glXGetProcAddress == NULL) {
00670           glxdisplay_cat.warning()
00671             << "Couldn't load function " << funcName
00672             << ", GL extensions may be unavailable.\n";
00673         }
00674       }
00675 
00676       _checked_get_proc_address = true;
00677     }
00678     
00679     // Use glxGetProcAddress() if we've got it; it should be more robust.
00680     if (_glXGetProcAddress != NULL) {
00681       return (void *)_glXGetProcAddress((const GLubyte *)fullname.c_str());
00682     }
00683 #endif // HAVE_GLXGETPROCADDRESS
00684   }
00685 
00686   if (glx_get_os_address) {
00687     // Otherwise, fall back to the OS-provided calls.
00688     return get_system_func(fullname.c_str());
00689   }
00690 
00691   return NULL;
00692 }
00693 
00694 ////////////////////////////////////////////////////////////////////
00695 //     Function: glxGraphicsStateGuardian::get_system_func
00696 //       Access: Private
00697 //  Description: Support for get_extension_func(), above, that uses
00698 //               system calls to find a GL or GLX function (in the
00699 //               absence of a working glxGetProcAddress() function to
00700 //               call).
00701 ////////////////////////////////////////////////////////////////////
00702 void *glxGraphicsStateGuardian::
00703 get_system_func(const char *name) {
00704   if (_libgl_handle == (void *)NULL) {
00705     // We open the current executable, rather than naming a particular
00706     // library.  Presumably libGL.so (or whatever the library should
00707     // be called) is already available in the current executable
00708     // address space, so this is more portable than insisting on a
00709     // particular shared library name.
00710     _libgl_handle = dlopen(NULL, RTLD_LAZY);
00711     nassertr(_libgl_handle != (void *)NULL, NULL);
00712 
00713     // If that doesn't locate the symbol we expected, then fall back
00714     // to loading the GL library by its usual name.
00715     if (dlsym(_libgl_handle, name) == NULL) {
00716       dlclose(_libgl_handle);
00717       glxdisplay_cat.warning()
00718         << name << " not found in executable; looking in libGL.so instead.\n";
00719       _libgl_handle = dlopen("libGL.so", RTLD_LAZY);
00720       nassertr(_libgl_handle != (void *)NULL, NULL);
00721     }
00722   }
00723 
00724   return dlsym(_libgl_handle, name);
00725 }
00726 
00727 ////////////////////////////////////////////////////////////////////
00728 //     Function: glxGraphicsStateGuardian::show_glx_client_string
00729 //       Access: Protected
00730 //  Description: Outputs the result of glxGetClientString() on the
00731 //               indicated tag.
00732 ////////////////////////////////////////////////////////////////////
00733 void glxGraphicsStateGuardian::
00734 show_glx_client_string(const string &name, int id) {
00735   if (glgsg_cat.is_debug()) {
00736     const char *text = glXGetClientString(_display, id);
00737     if (text == (const char *)NULL) {
00738       glgsg_cat.debug()
00739         << "Unable to query " << name << " (client)\n";
00740     } else {
00741       glgsg_cat.debug()
00742         << name << " (client) = " << (const char *)text << "\n";
00743     }
00744   }
00745 }
00746 
00747 ////////////////////////////////////////////////////////////////////
00748 //     Function: glxGraphicsStateGuardian::show_glx_server_string
00749 //       Access: Protected
00750 //  Description: Outputs the result of glxQueryServerString() on the
00751 //               indicated tag.
00752 ////////////////////////////////////////////////////////////////////
00753 void glxGraphicsStateGuardian::
00754 show_glx_server_string(const string &name, int id) {
00755   if (glgsg_cat.is_debug()) {
00756     const char *text = glXQueryServerString(_display, _screen, id);
00757     if (text == (const char *)NULL) {
00758       glgsg_cat.debug()
00759         << "Unable to query " << name << " (server)\n";
00760     } else {
00761       glgsg_cat.debug()
00762         << name << " (server) = " << (const char *)text << "\n";
00763     }
00764   }
00765 }
00766 
00767 ////////////////////////////////////////////////////////////////////
00768 //     Function: glxGraphicsStateGuardian::choose_temp_visual
00769 //       Access: Private
00770 //  Description: Selects an XVisual for an initial OpenGL context.
00771 //               This may be called initially, to create the first
00772 //               context needed in order to create the fbconfig.  On
00773 //               successful return, _visual and _temp_context will be
00774 //               filled in with a non-NULL value.
00775 ////////////////////////////////////////////////////////////////////
00776 void glxGraphicsStateGuardian::
00777 choose_temp_visual(const FrameBufferProperties &properties) {
00778   nassertv(_temp_context == (GLXContext)NULL);
00779 
00780   int best_quality = 0;
00781   int best_result = 0;
00782   FrameBufferProperties best_props;
00783 
00784   // Scan available visuals.
00785   if (_visuals != (XVisualInfo *)NULL) {
00786     XFree(_visuals);
00787     _visuals = NULL;
00788   }
00789   int nvisuals = 0;
00790   _visuals = XGetVisualInfo(_display, 0, 0, &nvisuals);
00791   if (_visuals != 0) {
00792     for (int i = 0; i < nvisuals; i++) {
00793       FrameBufferProperties fbprops;
00794       get_properties(fbprops, _visuals + i);
00795       int quality = fbprops.get_quality(properties);
00796       if (quality > best_quality) {
00797         best_quality = quality;
00798         best_result = i;
00799         best_props = fbprops;
00800       }
00801     }
00802   }
00803   
00804   if (best_quality > 0) {
00805     _visual = _visuals + best_result;
00806     _temp_context = glXCreateContext(_display, _visual, None, GL_TRUE);    
00807     if (_temp_context) {
00808       _fbprops = best_props;
00809       return;
00810     }
00811   }
00812 
00813   glxdisplay_cat.error() 
00814     << "Could not find a usable pixel format.\n";
00815 }
00816 
00817 ////////////////////////////////////////////////////////////////////
00818 //     Function: glxGraphicsStateGuardian::init_temp_context
00819 //       Access: Private
00820 //  Description: Initializes the context created in
00821 //               choose_temp_visual() by creating a temporary window
00822 //               and binding the context to that window.
00823 ////////////////////////////////////////////////////////////////////
00824 void glxGraphicsStateGuardian::
00825 init_temp_context() {
00826   x11GraphicsPipe *x11_pipe;
00827   DCAST_INTO_V(x11_pipe, get_pipe());
00828   Window root_window = x11_pipe->get_root();
00829 
00830   // Assume everyone uses TrueColor or DirectColor these days.
00831   Visual *visual = _visual->visual;
00832   nassertv(visual->c_class == DirectColor || visual->c_class == TrueColor);
00833   _temp_colormap = XCreateColormap(_display, root_window,
00834                                    visual, AllocNone);
00835   XSetWindowAttributes wa;
00836   wa.colormap = _temp_colormap;
00837   unsigned long attrib_mask = CWColormap;
00838 
00839   _temp_xwindow = XCreateWindow
00840     (_display, root_window, 0, 0, 100, 100,
00841      0, _visual->depth, InputOutput,
00842      visual, attrib_mask, &wa);
00843   if (_temp_xwindow == (Window)NULL) {
00844     glxdisplay_cat.error()
00845       << "Could not create temporary window for context\n";
00846     return;
00847   }
00848 
00849   glXMakeCurrent(_display, _temp_xwindow, _temp_context);
00850   reset();
00851 }
00852 
00853 ////////////////////////////////////////////////////////////////////
00854 //     Function: glxGraphicsStateGuardian::destroy_temp_xwindow
00855 //       Access: Private
00856 //  Description: Destroys the temporary unmapped window created by
00857 //               init_temp_context().
00858 ////////////////////////////////////////////////////////////////////
00859 void glxGraphicsStateGuardian::
00860 destroy_temp_xwindow() {
00861   glXMakeCurrent(_display, None, NULL);
00862 
00863   if (_temp_colormap != (Colormap)NULL) {
00864     XFreeColormap(_display, _temp_colormap);
00865     _temp_colormap = (Colormap)NULL;
00866   }
00867   if (_temp_xwindow != (Window)NULL) {
00868     XDestroyWindow(_display, _temp_xwindow);
00869     _temp_xwindow = (Window)NULL;
00870   }
00871 
00872   if (_temp_context != (GLXContext)NULL){ 
00873     glXDestroyContext(_display, _temp_context);
00874     _temp_context = (GLXContext)NULL;
00875   }
00876 }
 All Classes Functions Variables Enumerations