Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/glxdisplay/glxGraphicsPipe.cxx

Go to the documentation of this file.
00001 // Filename: glxGraphicsPipe.cxx
00002 // Created by:  mike (09Jan97)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "glxGraphicsPipe.h"
00020 #include "glxGraphicsWindow.h"
00021 #include "glxGraphicsStateGuardian.h"
00022 #include "config_glxdisplay.h"
00023 #include "frameBufferProperties.h"
00024 #include "mutexHolder.h"
00025 
00026 #include <GL/glx.h>
00027 
00028 TypeHandle glxGraphicsPipe::_type_handle;
00029 
00030 bool glxGraphicsPipe::_error_handlers_installed = false;
00031 glxGraphicsPipe::ErrorHandlerFunc *glxGraphicsPipe::_prev_error_handler;
00032 glxGraphicsPipe::IOErrorHandlerFunc *glxGraphicsPipe::_prev_io_error_handler;
00033 
00034 ////////////////////////////////////////////////////////////////////
00035 //     Function: glxGraphicsPipe::Constructor
00036 //       Access: Public
00037 //  Description: 
00038 ////////////////////////////////////////////////////////////////////
00039 glxGraphicsPipe::
00040 glxGraphicsPipe(const string &display) {
00041   string display_spec = display;
00042   if (display_spec.empty()) {
00043     display_spec = display_cfg;
00044   }
00045   if (display_spec.empty()) {
00046     display_spec = ExecutionEnvironment::get_environment_variable("DISPLAY");
00047   }
00048 
00049   _is_valid = false;
00050   _supports_fullscreen = false;
00051   _display = NULL;
00052   _screen = 0;
00053   _root = (Window)NULL;
00054 
00055   install_error_handlers();
00056 
00057   _display = XOpenDisplay(display_spec.c_str());
00058   if (!_display) {
00059     glxdisplay_cat.error()
00060       << "Could not open display \"" << display_spec << "\".\n";
00061     return;
00062   }
00063 
00064   int errorBase, eventBase;
00065   if (!glXQueryExtension(_display, &errorBase, &eventBase)) {
00066     glxdisplay_cat.error()
00067       << "OpenGL GLX extension not supported on display \"" << display_spec
00068       << "\".\n";
00069     return;
00070   }
00071 
00072   _screen = DefaultScreen(_display);
00073   _root = RootWindow(_display, _screen);
00074   _display_width = DisplayWidth(_display, _screen);
00075   _display_height = DisplayHeight(_display, _screen);
00076   _is_valid = true;
00077 
00078   // Get the X atom number.
00079   _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false);
00080 }
00081 
00082 ////////////////////////////////////////////////////////////////////
00083 //     Function: glxGraphicsPipe::Destructor
00084 //       Access: Public, Virtual
00085 //  Description: 
00086 ////////////////////////////////////////////////////////////////////
00087 glxGraphicsPipe::
00088 ~glxGraphicsPipe() {
00089   if (_display) {
00090     XCloseDisplay(_display);
00091   }
00092 }
00093 
00094 ////////////////////////////////////////////////////////////////////
00095 //     Function: glxGraphicsPipe::get_interface_name
00096 //       Access: Published, Virtual
00097 //  Description: Returns the name of the rendering interface
00098 //               associated with this GraphicsPipe.  This is used to
00099 //               present to the user to allow him/her to choose
00100 //               between several possible GraphicsPipes available on a
00101 //               particular platform, so the name should be meaningful
00102 //               and unique for a given platform.
00103 ////////////////////////////////////////////////////////////////////
00104 string glxGraphicsPipe::
00105 get_interface_name() const {
00106   return "OpenGL";
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: glxGraphicsPipe::pipe_constructor
00111 //       Access: Public, Static
00112 //  Description: This function is passed to the GraphicsPipeSelection
00113 //               object to allow the user to make a default
00114 //               glxGraphicsPipe.
00115 ////////////////////////////////////////////////////////////////////
00116 PT(GraphicsPipe) glxGraphicsPipe::
00117 pipe_constructor() {
00118   return new glxGraphicsPipe;
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: glxGraphicsPipe::make_gsg
00123 //       Access: Protected, Virtual
00124 //  Description: Creates a new GSG to use the pipe (but no windows
00125 //               have been created yet for the GSG).  This method will
00126 //               be called in the draw thread for the GSG.
00127 ////////////////////////////////////////////////////////////////////
00128 PT(GraphicsStateGuardian) glxGraphicsPipe::
00129 make_gsg(const FrameBufferProperties &properties) {
00130   if (!_is_valid) {
00131     return NULL;
00132   }
00133   
00134   FrameBufferProperties new_properties = properties;
00135   XVisualInfo *visual = choose_visual(new_properties);
00136 
00137   // Attempt to create a GL context.
00138   GLXContext context = glXCreateContext(_display, visual, None, GL_TRUE);
00139   if (context == NULL) {
00140     glxdisplay_cat.error()
00141       << "Could not create GL context.\n";
00142     XFree(visual);
00143     return NULL;
00144   }
00145 
00146   // Now we can make a GSG.
00147   PT(glxGraphicsStateGuardian) gsg = 
00148     new glxGraphicsStateGuardian(new_properties);
00149   gsg->_context = context;
00150   gsg->_visual = visual;
00151   gsg->_display = _display;
00152 
00153   return gsg.p();
00154 }
00155 
00156 ////////////////////////////////////////////////////////////////////
00157 //     Function: glxGraphicsPipe::make_window
00158 //       Access: Protected, Virtual
00159 //  Description: Creates a new window on the pipe, if possible.
00160 ////////////////////////////////////////////////////////////////////
00161 PT(GraphicsWindow) glxGraphicsPipe::
00162 make_window(GraphicsStateGuardian *gsg) {
00163   if (!_is_valid) {
00164     return NULL;
00165   }
00166 
00167   return new glxGraphicsWindow(this, gsg);
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: glxGraphicsPipe::choose visual
00172 //       Access: Private
00173 //  Description: Selects an appropriate X visual for the given frame
00174 //               buffer properties.  Returns the visual pointer if
00175 //               successful, or NULL otherwise.
00176 //
00177 //               If successful, this may modify properties to reflect
00178 //               the actual visual chosen.
00179 ////////////////////////////////////////////////////////////////////
00180 XVisualInfo *glxGraphicsPipe::
00181 choose_visual(FrameBufferProperties &properties) const {
00182   int frame_buffer_mode = 0;
00183   int want_depth_bits = 0;
00184   int want_color_bits = 0;
00185 
00186   if (properties.has_frame_buffer_mode()) {
00187     frame_buffer_mode = properties.get_frame_buffer_mode();
00188   }
00189 
00190   if (properties.has_depth_bits()) {
00191     want_depth_bits = properties.get_depth_bits();
00192   }
00193 
00194   if (properties.has_color_bits()) {
00195     want_color_bits = properties.get_color_bits();
00196   }
00197 
00198   /*
00199   if (frame_buffer_mode & FrameBufferProperties::FM_multisample) {
00200     if (!glx_supports("GLX_SGIS_multisample")) {
00201       glxdisplay_cat.info()
00202         << "multisample not supported by this glx implementation.\n";
00203       frame_buffer_mode &= ~FrameBufferProperties::FM_multisample;
00204     }
00205   }
00206   */
00207 
00208   XVisualInfo *visual = 
00209     try_for_visual(frame_buffer_mode, want_depth_bits, want_color_bits);
00210 
00211   // This is the severity level at which we'll report the details of
00212   // the visual we actually do find.  Normally, it's debug-level
00213   // information: we don't care about that much detail.
00214   NotifySeverity show_visual_severity = NS_debug;
00215 
00216   if (visual == NULL) {
00217     glxdisplay_cat.info()
00218       << "glxGraphicsWindow::choose_visual() - visual with requested\n"
00219       << "   capabilities not found; trying for lesser visual.\n";
00220 
00221     // If we're unable to get the visual we asked for, however, we
00222     // probably *do* care to know the details about what we actually
00223     // got, even if we don't have debug mode set.  So we'll report the
00224     // visual at a higher level.
00225     show_visual_severity = NS_info;
00226 
00227     bool special_size_request =
00228       (want_depth_bits != 1 || want_color_bits != 1);
00229 
00230     // We try to be smart about choosing a close match for the visual.
00231     // First, we'll eliminate some of the more esoteric options one at
00232     // a time, then two at a time, and finally we'll try just the bare
00233     // minimum.
00234 
00235     if (special_size_request) {
00236       // Actually, first we'll eliminate all of the minimum sizes, to
00237       // try to open a window with all of the requested options, but
00238       // maybe not as many bits in some options as we'd like.
00239       visual = try_for_visual(frame_buffer_mode, 1, 1);
00240     }
00241 
00242     if (visual == NULL) {
00243       // Ok, not good enough.  Now try to eliminate options, but keep
00244       // as many bits as we asked for.
00245 
00246       // This array keeps the bitmasks of options that we pull out of
00247       // the requested frame_buffer_mode, in order.
00248 
00249       static const int strip_properties[] = {
00250         // One esoteric option removed.
00251         FrameBufferProperties::FM_multisample,
00252         FrameBufferProperties::FM_stencil,
00253         FrameBufferProperties::FM_accum,
00254         FrameBufferProperties::FM_alpha,
00255         FrameBufferProperties::FM_stereo,
00256 
00257         // Two esoteric options removed.
00258         FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_multisample,
00259         FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
00260         FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_multisample,
00261         FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
00262         FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum,
00263         FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo,
00264         FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_multisample,
00265         FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
00266 
00267         // All esoteric options removed.
00268         FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample,
00269 
00270         // All esoteric options, plus some we'd really really prefer,
00271         // removed.
00272         FrameBufferProperties::FM_stencil | FrameBufferProperties::FM_accum | FrameBufferProperties::FM_alpha | FrameBufferProperties::FM_stereo | FrameBufferProperties::FM_multisample | FrameBufferProperties::FM_double_buffer,
00273 
00274         // A zero marks the end of the array.
00275         0
00276       };
00277 
00278       pset<int> tried_masks;
00279       tried_masks.insert(frame_buffer_mode);
00280 
00281       int i;
00282       for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
00283         int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
00284         if (tried_masks.insert(new_frame_buffer_mode).second) {
00285           visual = try_for_visual(new_frame_buffer_mode, want_depth_bits,
00286                                   want_color_bits);
00287         }
00288       }
00289 
00290       if (special_size_request) {
00291         tried_masks.clear();
00292         tried_masks.insert(frame_buffer_mode);
00293 
00294         if (visual == NULL) {
00295           // Try once more, this time eliminating all of the size
00296           // requests.
00297           for (i = 0; visual == NULL && strip_properties[i] != 0; i++) {
00298             int new_frame_buffer_mode = frame_buffer_mode & ~strip_properties[i];
00299             if (tried_masks.insert(new_frame_buffer_mode).second) {
00300               visual = try_for_visual(new_frame_buffer_mode, 1, 1);
00301             }
00302           }
00303         }
00304       }
00305 
00306       if (visual == NULL) {
00307         // Here's our last-ditch desparation attempt: give us any GLX
00308         // visual at all!
00309         visual = try_for_visual(0, 1, 1);
00310       }
00311 
00312       if (visual == NULL) {
00313         glxdisplay_cat.error()
00314           << "Could not get any GLX visual.\n";
00315         return NULL;
00316       }
00317     }
00318   }
00319 
00320   glxdisplay_cat.info()
00321     << "Got visual 0x" << hex << (int)visual->visualid << dec << ".\n";
00322 
00323   // Now update our frambuffer_mode and bit depth appropriately.
00324   int render_mode, double_buffer, stereo, red_size, green_size, blue_size,
00325     alpha_size, ared_size, agreen_size, ablue_size, aalpha_size,
00326     depth_size, stencil_size;
00327   
00328   glXGetConfig(_display, visual, GLX_RGBA, &render_mode);
00329   glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &double_buffer);
00330   glXGetConfig(_display, visual, GLX_STEREO, &stereo);
00331   glXGetConfig(_display, visual, GLX_RED_SIZE, &red_size);
00332   glXGetConfig(_display, visual, GLX_GREEN_SIZE, &green_size);
00333   glXGetConfig(_display, visual, GLX_BLUE_SIZE, &blue_size);
00334   glXGetConfig(_display, visual, GLX_ALPHA_SIZE, &alpha_size);
00335   glXGetConfig(_display, visual, GLX_ACCUM_RED_SIZE, &ared_size);
00336   glXGetConfig(_display, visual, GLX_ACCUM_GREEN_SIZE, &agreen_size);
00337   glXGetConfig(_display, visual, GLX_ACCUM_BLUE_SIZE, &ablue_size);
00338   glXGetConfig(_display, visual, GLX_ACCUM_ALPHA_SIZE, &aalpha_size);
00339   glXGetConfig(_display, visual, GLX_DEPTH_SIZE, &depth_size);
00340   glXGetConfig(_display, visual, GLX_STENCIL_SIZE, &stencil_size);
00341 
00342   frame_buffer_mode = 0;
00343   if (double_buffer) {
00344     frame_buffer_mode |= FrameBufferProperties::FM_double_buffer;
00345   }
00346   if (stereo) {
00347     frame_buffer_mode |= FrameBufferProperties::FM_stereo;
00348   }
00349   if (!render_mode) {
00350     frame_buffer_mode |= FrameBufferProperties::FM_index;
00351   }
00352   if (stencil_size != 0) {
00353     frame_buffer_mode |= FrameBufferProperties::FM_stencil;
00354   }
00355   if (depth_size != 0) {
00356     frame_buffer_mode |= FrameBufferProperties::FM_depth;
00357   }
00358   if (alpha_size != 0) {
00359     frame_buffer_mode |= FrameBufferProperties::FM_alpha;
00360   }
00361   if (ared_size + agreen_size + ablue_size != 0) {
00362     frame_buffer_mode |= FrameBufferProperties::FM_accum;
00363   }
00364 
00365   properties.set_frame_buffer_mode(frame_buffer_mode);
00366   properties.set_color_bits(red_size + green_size + blue_size + alpha_size);
00367   properties.set_depth_bits(depth_size);
00368 
00369   if (glxdisplay_cat.is_on(show_visual_severity)) {
00370     glxdisplay_cat.out(show_visual_severity)
00371       << "GLX Visual Info (# bits of each):" << endl
00372       << " RGBA: " << red_size << " " << green_size << " " << blue_size
00373       << " " << alpha_size << endl
00374       << " Accum RGBA: " << ared_size << " " << agreen_size << " "
00375       << ablue_size << " " << aalpha_size << endl
00376       << " Depth: " << depth_size << endl
00377       << " Stencil: " << stencil_size << endl
00378       << " DoubleBuffer? " << double_buffer << endl
00379       << " Stereo? " << stereo << endl;
00380   }
00381 
00382   return visual;
00383 }
00384 
00385 ////////////////////////////////////////////////////////////////////
00386 //     Function: glxGraphicsPipe::try_for_visual
00387 //       Access: Private
00388 //  Description: Attempt to get the requested visual, if it is
00389 //               available.  It's just a wrapper around
00390 //               glXChooseVisual().  It returns the visual information
00391 //               if possible, or NULL if it is not.
00392 ////////////////////////////////////////////////////////////////////
00393 XVisualInfo *glxGraphicsPipe::
00394 try_for_visual(int framebuffer_mode,
00395                int want_depth_bits, int want_color_bits) const {
00396   static const int max_attrib_list = 32;
00397   int attrib_list[max_attrib_list];
00398   int n=0;
00399 
00400   glxdisplay_cat.debug()
00401     << "Trying for visual with: RGB(" << want_color_bits << ")";
00402 
00403   int want_color_component_bits;
00404   if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
00405     want_color_component_bits = max(want_color_bits / 4, 1);
00406   } else {
00407     want_color_component_bits = max(want_color_bits / 3, 1);
00408   }
00409 
00410   attrib_list[n++] = GLX_RGBA;
00411   attrib_list[n++] = GLX_RED_SIZE;
00412   attrib_list[n++] = want_color_component_bits;
00413   attrib_list[n++] = GLX_GREEN_SIZE;
00414   attrib_list[n++] = want_color_component_bits;
00415   attrib_list[n++] = GLX_BLUE_SIZE;
00416   attrib_list[n++] = want_color_component_bits;
00417 
00418   if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
00419     glxdisplay_cat.debug(false) << " ALPHA";
00420     attrib_list[n++] = GLX_ALPHA_SIZE;
00421     attrib_list[n++] = want_color_component_bits;
00422   }
00423   if (framebuffer_mode & FrameBufferProperties::FM_double_buffer) {
00424     glxdisplay_cat.debug(false) << " DOUBLEBUFFER";
00425     attrib_list[n++] = GLX_DOUBLEBUFFER;
00426   }
00427   if (framebuffer_mode & FrameBufferProperties::FM_stereo) {
00428     glxdisplay_cat.debug(false) << " STEREO";
00429     attrib_list[n++] = GLX_STEREO;
00430   }
00431   if (framebuffer_mode & FrameBufferProperties::FM_depth) {
00432     glxdisplay_cat.debug(false) << " DEPTH(" << want_depth_bits << ")";
00433     attrib_list[n++] = GLX_DEPTH_SIZE;
00434     attrib_list[n++] = want_depth_bits;
00435   }
00436   if (framebuffer_mode & FrameBufferProperties::FM_stencil) {
00437     glxdisplay_cat.debug(false) << " STENCIL";
00438     attrib_list[n++] = GLX_STENCIL_SIZE;
00439     attrib_list[n++] = 1;
00440   }
00441   if (framebuffer_mode & FrameBufferProperties::FM_accum) {
00442     glxdisplay_cat.debug(false) << " ACCUM";
00443     attrib_list[n++] = GLX_ACCUM_RED_SIZE;
00444     attrib_list[n++] = want_color_component_bits;
00445     attrib_list[n++] = GLX_ACCUM_GREEN_SIZE;
00446     attrib_list[n++] = want_color_component_bits;
00447     attrib_list[n++] = GLX_ACCUM_BLUE_SIZE;
00448     attrib_list[n++] = want_color_component_bits;
00449     if (framebuffer_mode & FrameBufferProperties::FM_alpha) {
00450       attrib_list[n++] = GLX_ACCUM_ALPHA_SIZE;
00451       attrib_list[n++] = want_color_component_bits;
00452     }
00453   }
00454 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
00455   if (framebuffer_mode & FrameBufferProperties::FM_multisample) {
00456     glxdisplay_cat.debug(false) << " MULTISAMPLE";
00457     attrib_list[n++] = GLX_SAMPLES_SGIS;
00458     // We decide 4 is minimum number of samples
00459     attrib_list[n++] = 4;
00460   }
00461 #endif
00462 
00463   // Terminate the list
00464   nassertr(n < max_attrib_list, NULL);
00465   attrib_list[n] = (int)None;
00466 
00467   XVisualInfo *vinfo = glXChooseVisual(_display, _screen, attrib_list);
00468 
00469   if (glxdisplay_cat.is_debug()) {
00470     if (vinfo != NULL) {
00471       glxdisplay_cat.debug(false) << ", match found!\n";
00472     } else {
00473       glxdisplay_cat.debug(false) << ", no match.\n";
00474     }
00475   }
00476 
00477   return vinfo;
00478 }
00479 
00480 ////////////////////////////////////////////////////////////////////
00481 //     Function: glxGraphicsPipe::install_error_handlers
00482 //       Access: Private, Static
00483 //  Description: Installs new Xlib error handler functions if this is
00484 //               the first time this function has been called.  These
00485 //               error handler functions will attempt to reduce Xlib's
00486 //               annoying tendency to shut down the client at the
00487 //               first error.  Unfortunately, it is difficult to play
00488 //               nice with the client if it has already installed its
00489 //               own error handlers.
00490 ////////////////////////////////////////////////////////////////////
00491 void glxGraphicsPipe::
00492 install_error_handlers() {
00493   if (_error_handlers_installed) {
00494     return;
00495   }
00496 
00497   _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler);
00498   _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler);
00499   _error_handlers_installed = true;
00500 }
00501 
00502 ////////////////////////////////////////////////////////////////////
00503 //     Function: glxGraphicsPipe::error_handler
00504 //       Access: Private, Static
00505 //  Description: This function is installed as the error handler for a
00506 //               non-fatal Xlib error.
00507 ////////////////////////////////////////////////////////////////////
00508 int glxGraphicsPipe::
00509 error_handler(Display *display, XErrorEvent *error) {
00510   static const int msg_len = 80;
00511   char msg[msg_len];
00512   XGetErrorText(display, error->error_code, msg, msg_len);
00513   glxdisplay_cat.error()
00514     << msg << "\n";
00515 
00516   // We return to allow the application to continue running, unlike
00517   // the default X error handler which exits.
00518   return 0;
00519 }
00520 
00521 ////////////////////////////////////////////////////////////////////
00522 //     Function: glxGraphicsPipe::io_error_handler
00523 //       Access: Private, Static
00524 //  Description: This function is installed as the error handler for a
00525 //               fatal Xlib error.
00526 ////////////////////////////////////////////////////////////////////
00527 int glxGraphicsPipe::
00528 io_error_handler(Display *display) {
00529   glxdisplay_cat.fatal()
00530     << "X fatal error on display " << (void *)display << "\n";
00531 
00532   // Unfortunately, we can't continue from this function, even if we
00533   // promise never to use X again.  We're supposed to terminate
00534   // without returning, and if we do return, the caller will exit
00535   // anyway.  Sigh.  Very poor design on X's part.
00536   return 0;
00537 }

Generated on Fri May 2 00:39:11 2003 for Panda by doxygen1.3