Panda3D

glxGraphicsWindow.cxx

00001 // Filename: glxGraphicsWindow.cxx
00002 // Created by:  mike (09Jan97)
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 "glxGraphicsWindow.h"
00016 #include "glxGraphicsStateGuardian.h"
00017 #include "config_glxdisplay.h"
00018 #include "glxGraphicsPipe.h"
00019 
00020 #include "graphicsPipe.h"
00021 #include "keyboardButton.h"
00022 #include "mouseButton.h"
00023 #include "glgsg.h"
00024 #include "clockObject.h"
00025 #include "pStatTimer.h"
00026 #include "textEncoder.h"
00027 #include "throw_event.h"
00028 #include "lightReMutexHolder.h"
00029 
00030 #include <errno.h>
00031 #include <sys/time.h>
00032 
00033 TypeHandle glxGraphicsWindow::_type_handle;
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: glxGraphicsWindow::Constructor
00037 //       Access: Public
00038 //  Description:
00039 ////////////////////////////////////////////////////////////////////
00040 glxGraphicsWindow::
00041 glxGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, 
00042                   const string &name,
00043                   const FrameBufferProperties &fb_prop,
00044                   const WindowProperties &win_prop,
00045                   int flags,
00046                   GraphicsStateGuardian *gsg,
00047                   GraphicsOutput *host) :
00048   x11GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00049 {
00050 }
00051 
00052 ////////////////////////////////////////////////////////////////////
00053 //     Function: glxGraphicsWindow::begin_frame
00054 //       Access: Public, Virtual
00055 //  Description: This function will be called within the draw thread
00056 //               before beginning rendering for a given frame.  It
00057 //               should do whatever setup is required, and return true
00058 //               if the frame should be rendered, or false if it
00059 //               should be skipped.
00060 ////////////////////////////////////////////////////////////////////
00061 bool glxGraphicsWindow::
00062 begin_frame(FrameMode mode, Thread *current_thread) {
00063   PStatTimer timer(_make_current_pcollector, current_thread);
00064 
00065   begin_frame_spam(mode);
00066   if (_gsg == (GraphicsStateGuardian *)NULL) {
00067     return false;
00068   }
00069   if (_awaiting_configure) {
00070     // Don't attempt to draw while we have just reconfigured the
00071     // window and we haven't got the notification back yet.
00072     return false;
00073   }
00074 
00075   glxGraphicsStateGuardian *glxgsg;
00076   DCAST_INTO_R(glxgsg, _gsg, false);
00077   {
00078     LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
00079 
00080     if (glXGetCurrentDisplay() == _display &&
00081         glXGetCurrentDrawable() == _xwindow &&
00082         glXGetCurrentContext() == glxgsg->_context) {
00083       // No need to make the context current again.  Short-circuit
00084       // this possibly-expensive call.
00085     } else {
00086       // Need to set the context.
00087       glXMakeCurrent(_display, _xwindow, glxgsg->_context);
00088     }
00089   }
00090   
00091   // Now that we have made the context current to a window, we can
00092   // reset the GSG state if this is the first time it has been used.
00093   // (We can't just call reset() when we construct the GSG, because
00094   // reset() requires having a current context.)
00095   glxgsg->reset_if_new();
00096   
00097   if (mode == FM_render) {
00098     // begin_render_texture();
00099     clear_cube_map_selection();
00100   }
00101   
00102   _gsg->set_current_properties(&get_fb_properties());
00103   return _gsg->begin_frame(current_thread);
00104 }
00105 
00106 ////////////////////////////////////////////////////////////////////
00107 //     Function: glxGraphicsWindow::begin_flip
00108 //       Access: Public, Virtual
00109 //  Description: This function will be called within the draw thread
00110 //               after end_frame() has been called on all windows, to
00111 //               initiate the exchange of the front and back buffers.
00112 //
00113 //               This should instruct the window to prepare for the
00114 //               flip at the next video sync, but it should not wait.
00115 //
00116 //               We have the two separate functions, begin_flip() and
00117 //               end_flip(), to make it easier to flip all of the
00118 //               windows at the same time.
00119 ////////////////////////////////////////////////////////////////////
00120 void glxGraphicsWindow::
00121 begin_flip() {
00122   if (_gsg != (GraphicsStateGuardian *)NULL) {
00123 
00124     // It doesn't appear to be necessary to ensure the graphics
00125     // context is current before flipping the windows, and insisting
00126     // on doing so can be a significant performance hit.
00127 
00128     //make_current();
00129 
00130     LightReMutexHolder holder(glxGraphicsPipe::_x_mutex);
00131     glXSwapBuffers(_display, _xwindow);
00132   }
00133 }
00134 
00135 ////////////////////////////////////////////////////////////////////
00136 //     Function: glxGraphicsWindow::close_window
00137 //       Access: Protected, Virtual
00138 //  Description: Closes the window right now.  Called from the window
00139 //               thread.
00140 ////////////////////////////////////////////////////////////////////
00141 void glxGraphicsWindow::
00142 close_window() {
00143   if (_gsg != (GraphicsStateGuardian *)NULL) {
00144     glXMakeCurrent(_display, None, NULL);
00145     _gsg.clear();
00146     _active = false;
00147   }
00148   
00149   x11GraphicsWindow::close_window();
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: glxGraphicsWindow::open_window
00154 //       Access: Protected, Virtual
00155 //  Description: Opens the window right now.  Called from the window
00156 //               thread.  Returns true if the window is successfully
00157 //               opened, or false if there was a problem.
00158 ////////////////////////////////////////////////////////////////////
00159 bool glxGraphicsWindow::
00160 open_window() {
00161   glxGraphicsPipe *glx_pipe;
00162   DCAST_INTO_R(glx_pipe, _pipe, false);
00163 
00164   // GSG Creation/Initialization
00165   glxGraphicsStateGuardian *glxgsg;
00166   if (_gsg == 0) {
00167     // There is no old gsg.  Create a new one.
00168     glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL);
00169     glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false);
00170     _gsg = glxgsg;
00171   } else {
00172     // If the old gsg has the wrong pixel format, create a
00173     // new one that shares with the old gsg.
00174     DCAST_INTO_R(glxgsg, _gsg, false);
00175     if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) {
00176       glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg);
00177       glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false);
00178       _gsg = glxgsg;
00179     }
00180   }
00181   
00182   if (glxgsg->_context == NULL) {
00183     // We're supposed to have a context at this point.
00184     glxdisplay_cat.error()
00185       << "No GLX context: cannot open window.\n";
00186     return false;
00187   }
00188   
00189   _visual_info = glxgsg->_visual;
00190   if (_visual_info == NULL) {
00191     // No X visual for this fbconfig; how can we open the window?
00192     glxdisplay_cat.error()
00193       << "No X visual: cannot open window.\n";
00194     return false;
00195   }
00196   Visual *visual = _visual_info->visual;
00197   
00198   if (glxgsg->_fbconfig != None) {
00199     setup_colormap(glxgsg->_fbconfig);
00200   } else {
00201     setup_colormap(_visual_info);
00202   }
00203 
00204   if (!x11GraphicsWindow::open_window()) {
00205     return false;
00206   }
00207 
00208   glXMakeCurrent(_display, _xwindow, glxgsg->_context);
00209   glxgsg->reset_if_new();
00210   if (!glxgsg->is_valid()) {
00211     close_window();
00212     return false;
00213   }
00214   if (!glxgsg->get_fb_properties().verify_hardware_software
00215       (_fb_properties, glxgsg->get_gl_renderer())) {
00216     close_window();
00217     return false;
00218   }
00219   _fb_properties = glxgsg->get_fb_properties();
00220 
00221   return true;
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: glxGraphicsWindow::setup_colormap
00226 //       Access: Private
00227 //  Description: Allocates a colormap appropriate to the fbconfig and
00228 //               stores in in the _colormap method.
00229 ////////////////////////////////////////////////////////////////////
00230 void glxGraphicsWindow::
00231 setup_colormap(GLXFBConfig fbconfig) {
00232   glxGraphicsStateGuardian *glxgsg;
00233   DCAST_INTO_V(glxgsg, _gsg);
00234   nassertv(glxgsg->_supports_fbconfig);
00235 
00236   XVisualInfo *visual_info = glxgsg->_glXGetVisualFromFBConfig(_display, fbconfig);
00237   if (visual_info == NULL) {
00238     // No X visual; no need to set up a colormap.
00239     return;
00240   }
00241   int visual_class = visual_info->c_class;
00242   Visual *visual = visual_info->visual;
00243   XFree(visual_info);
00244 
00245   glxGraphicsPipe *glx_pipe;
00246   DCAST_INTO_V(glx_pipe, _pipe);
00247   Window root_window = glx_pipe->get_root();
00248 
00249   int rc, is_rgb;
00250 
00251   switch (visual_class) {
00252     case PseudoColor:
00253       rc = glxgsg->_glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb);
00254       if (rc == 0 && is_rgb) {
00255         glxdisplay_cat.warning()
00256           << "mesa pseudocolor not supported.\n";
00257         // this is a terrible terrible hack, but it seems to work
00258         _colormap = (Colormap)0;
00259 
00260       } else {
00261         _colormap = XCreateColormap(_display, root_window,
00262                                     visual, AllocAll);
00263       }
00264       break;
00265     case TrueColor:
00266     case DirectColor:
00267       _colormap = XCreateColormap(_display, root_window,
00268                                   visual, AllocNone);
00269       break;
00270     case StaticColor:
00271     case StaticGray:
00272     case GrayScale:
00273       _colormap = XCreateColormap(_display, root_window,
00274                                   visual, AllocNone);
00275       break;
00276     default:
00277       glxdisplay_cat.error()
00278         << "Could not allocate a colormap for visual class "
00279         << visual_class << ".\n";
00280       break;
00281   }
00282 }
00283 
00284 ////////////////////////////////////////////////////////////////////
00285 //     Function: glxGraphicsWindow::setup_colormap
00286 //       Access: Private, Virtual
00287 //  Description: Allocates a colormap appropriate to the visual and
00288 //               stores in in the _colormap method.
00289 ////////////////////////////////////////////////////////////////////
00290 void glxGraphicsWindow::
00291 setup_colormap(XVisualInfo *visual) {
00292   glxGraphicsPipe *glx_pipe;
00293   DCAST_INTO_V(glx_pipe, _pipe);
00294   Window root_window = glx_pipe->get_root();
00295 
00296   int visual_class = visual->c_class;
00297   int rc, is_rgb;
00298 
00299   switch (visual_class) {
00300     case PseudoColor:
00301       rc = glXGetConfig(_display, visual, GLX_RGBA, &is_rgb);
00302       if (rc == 0 && is_rgb) {
00303         glxdisplay_cat.warning()
00304           << "mesa pseudocolor not supported.\n";
00305         // this is a terrible terrible hack, but it seems to work
00306         _colormap = (Colormap)0;
00307 
00308       } else {
00309         _colormap = XCreateColormap(_display, root_window,
00310                                     visual->visual, AllocAll);
00311       }
00312       break;
00313     case TrueColor:
00314     case DirectColor:
00315       _colormap = XCreateColormap(_display, root_window,
00316                                   visual->visual, AllocNone);
00317       break;
00318     case StaticColor:
00319     case StaticGray:
00320     case GrayScale:
00321       _colormap = XCreateColormap(_display, root_window,
00322                                   visual->visual, AllocNone);
00323       break;
00324     default:
00325       glxdisplay_cat.error()
00326         << "Could not allocate a colormap for visual class "
00327         << visual_class << ".\n";
00328       break;
00329   }
00330 }
 All Classes Functions Variables Enumerations