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