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   _visual_info = glxgsg->_visual;
00183   if (_visual_info == NULL) {
00184     // No X visual for this fbconfig; how can we open the window?
00185     glxdisplay_cat.error()
00186       << "No X visual: cannot open window.\n";
00187     return false;
00188   }
00189   Visual *visual = _visual_info->visual;
00190   
00191   if (glxgsg->_fbconfig != None) {
00192     setup_colormap(glxgsg->_fbconfig);
00193   } else {
00194     setup_colormap(_visual_info);
00195   }
00196 
00197   if (!x11GraphicsWindow::open_window()) {
00198     return false;
00199   }
00200 
00201   glXMakeCurrent(_display, _xwindow, glxgsg->_context);
00202   glxgsg->reset_if_new();
00203   if (!glxgsg->is_valid()) {
00204     close_window();
00205     return false;
00206   }
00207   if (!glxgsg->get_fb_properties().verify_hardware_software
00208       (_fb_properties, glxgsg->get_gl_renderer())) {
00209     close_window();
00210     return false;
00211   }
00212   _fb_properties = glxgsg->get_fb_properties();
00213 
00214   return true;
00215 }
00216 
00217 ////////////////////////////////////////////////////////////////////
00218 //     Function: glxGraphicsWindow::setup_colormap
00219 //       Access: Private
00220 //  Description: Allocates a colormap appropriate to the fbconfig and
00221 //               stores in in the _colormap method.
00222 ////////////////////////////////////////////////////////////////////
00223 void glxGraphicsWindow::
00224 setup_colormap(GLXFBConfig fbconfig) {
00225   glxGraphicsStateGuardian *glxgsg;
00226   DCAST_INTO_V(glxgsg, _gsg);
00227   nassertv(glxgsg->_supports_fbconfig);
00228 
00229   XVisualInfo *visual_info = glxgsg->_glXGetVisualFromFBConfig(_display, fbconfig);
00230   if (visual_info == NULL) {
00231     // No X visual; no need to set up a colormap.
00232     return;
00233   }
00234   int visual_class = visual_info->c_class;
00235   Visual *visual = visual_info->visual;
00236   XFree(visual_info);
00237 
00238   glxGraphicsPipe *glx_pipe;
00239   DCAST_INTO_V(glx_pipe, _pipe);
00240   Window root_window = glx_pipe->get_root();
00241 
00242   int rc, is_rgb;
00243 
00244   switch (visual_class) {
00245     case PseudoColor:
00246       rc = glxgsg->_glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb);
00247       if (rc == 0 && is_rgb) {
00248         glxdisplay_cat.warning()
00249           << "mesa pseudocolor not supported.\n";
00250         // this is a terrible terrible hack, but it seems to work
00251         _colormap = (Colormap)0;
00252 
00253       } else {
00254         _colormap = XCreateColormap(_display, root_window,
00255                                     visual, AllocAll);
00256       }
00257       break;
00258     case TrueColor:
00259     case DirectColor:
00260       _colormap = XCreateColormap(_display, root_window,
00261                                   visual, AllocNone);
00262       break;
00263     case StaticColor:
00264     case StaticGray:
00265     case GrayScale:
00266       _colormap = XCreateColormap(_display, root_window,
00267                                   visual, AllocNone);
00268       break;
00269     default:
00270       glxdisplay_cat.error()
00271         << "Could not allocate a colormap for visual class "
00272         << visual_class << ".\n";
00273       break;
00274   }
00275 }
00276 
00277 ////////////////////////////////////////////////////////////////////
00278 //     Function: glxGraphicsWindow::setup_colormap
00279 //       Access: Private, Virtual
00280 //  Description: Allocates a colormap appropriate to the visual and
00281 //               stores in in the _colormap method.
00282 ////////////////////////////////////////////////////////////////////
00283 void glxGraphicsWindow::
00284 setup_colormap(XVisualInfo *visual) {
00285   glxGraphicsPipe *glx_pipe;
00286   DCAST_INTO_V(glx_pipe, _pipe);
00287   Window root_window = glx_pipe->get_root();
00288 
00289   int visual_class = visual->c_class;
00290   int rc, is_rgb;
00291 
00292   switch (visual_class) {
00293     case PseudoColor:
00294       rc = glXGetConfig(_display, visual, GLX_RGBA, &is_rgb);
00295       if (rc == 0 && is_rgb) {
00296         glxdisplay_cat.warning()
00297           << "mesa pseudocolor not supported.\n";
00298         // this is a terrible terrible hack, but it seems to work
00299         _colormap = (Colormap)0;
00300 
00301       } else {
00302         _colormap = XCreateColormap(_display, root_window,
00303                                     visual->visual, AllocAll);
00304       }
00305       break;
00306     case TrueColor:
00307     case DirectColor:
00308       _colormap = XCreateColormap(_display, root_window,
00309                                   visual->visual, AllocNone);
00310       break;
00311     case StaticColor:
00312     case StaticGray:
00313     case GrayScale:
00314       _colormap = XCreateColormap(_display, root_window,
00315                                   visual->visual, AllocNone);
00316       break;
00317     default:
00318       glxdisplay_cat.error()
00319         << "Could not allocate a colormap for visual class "
00320         << visual_class << ".\n";
00321       break;
00322   }
00323 }
 All Classes Functions Variables Enumerations