Panda3D
|
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 }