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