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::end_flip 00108 // Access: Public, Virtual 00109 // Description: This function will be called within the draw thread 00110 // after begin_flip() has been called on all windows, to 00111 // finish the exchange of the front and back buffers. 00112 // 00113 // This should cause the window to wait for the flip, if 00114 // necessary. 00115 //////////////////////////////////////////////////////////////////// 00116 void glxGraphicsWindow:: 00117 end_flip() { 00118 if (_gsg != (GraphicsStateGuardian *)NULL && _flip_ready) { 00119 00120 // It doesn't appear to be necessary to ensure the graphics 00121 // context is current before flipping the windows, and insisting 00122 // on doing so can be a significant performance hit. 00123 00124 //make_current(); 00125 00126 LightReMutexHolder holder(glxGraphicsPipe::_x_mutex); 00127 glXSwapBuffers(_display, _xwindow); 00128 } 00129 GraphicsWindow::end_flip(); 00130 } 00131 00132 //////////////////////////////////////////////////////////////////// 00133 // Function: glxGraphicsWindow::close_window 00134 // Access: Protected, Virtual 00135 // Description: Closes the window right now. Called from the window 00136 // thread. 00137 //////////////////////////////////////////////////////////////////// 00138 void glxGraphicsWindow:: 00139 close_window() { 00140 if (_gsg != (GraphicsStateGuardian *)NULL) { 00141 glXMakeCurrent(_display, None, NULL); 00142 _gsg.clear(); 00143 } 00144 00145 x11GraphicsWindow::close_window(); 00146 } 00147 00148 //////////////////////////////////////////////////////////////////// 00149 // Function: glxGraphicsWindow::open_window 00150 // Access: Protected, Virtual 00151 // Description: Opens the window right now. Called from the window 00152 // thread. Returns true if the window is successfully 00153 // opened, or false if there was a problem. 00154 //////////////////////////////////////////////////////////////////// 00155 bool glxGraphicsWindow:: 00156 open_window() { 00157 glxGraphicsPipe *glx_pipe; 00158 DCAST_INTO_R(glx_pipe, _pipe, false); 00159 00160 // GSG Creation/Initialization 00161 glxGraphicsStateGuardian *glxgsg; 00162 if (_gsg == 0) { 00163 // There is no old gsg. Create a new one. 00164 glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, NULL); 00165 glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false); 00166 _gsg = glxgsg; 00167 } else { 00168 // If the old gsg has the wrong pixel format, create a 00169 // new one that shares with the old gsg. 00170 DCAST_INTO_R(glxgsg, _gsg, false); 00171 if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) { 00172 glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg); 00173 glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false); 00174 _gsg = glxgsg; 00175 } 00176 } 00177 00178 if (glxgsg->_context == NULL) { 00179 // We're supposed to have a context at this point. 00180 glxdisplay_cat.error() 00181 << "No GLX context: cannot open window.\n"; 00182 return false; 00183 } 00184 00185 _visual_info = glxgsg->_visual; 00186 if (_visual_info == NULL) { 00187 // No X visual for this fbconfig; how can we open the window? 00188 glxdisplay_cat.error() 00189 << "No X visual: cannot open window.\n"; 00190 return false; 00191 } 00192 Visual *visual = _visual_info->visual; 00193 00194 if (glxgsg->_fbconfig != None) { 00195 setup_colormap(glxgsg->_fbconfig); 00196 } else { 00197 setup_colormap(_visual_info); 00198 } 00199 00200 if (!x11GraphicsWindow::open_window()) { 00201 return false; 00202 } 00203 00204 glXMakeCurrent(_display, _xwindow, glxgsg->_context); 00205 glxgsg->reset_if_new(); 00206 if (!glxgsg->is_valid()) { 00207 close_window(); 00208 return false; 00209 } 00210 if (!glxgsg->get_fb_properties().verify_hardware_software 00211 (_fb_properties, glxgsg->get_gl_renderer())) { 00212 close_window(); 00213 return false; 00214 } 00215 _fb_properties = glxgsg->get_fb_properties(); 00216 00217 return true; 00218 } 00219 00220 //////////////////////////////////////////////////////////////////// 00221 // Function: glxGraphicsWindow::setup_colormap 00222 // Access: Private 00223 // Description: Allocates a colormap appropriate to the fbconfig and 00224 // stores in in the _colormap method. 00225 //////////////////////////////////////////////////////////////////// 00226 void glxGraphicsWindow:: 00227 setup_colormap(GLXFBConfig fbconfig) { 00228 glxGraphicsStateGuardian *glxgsg; 00229 DCAST_INTO_V(glxgsg, _gsg); 00230 nassertv(glxgsg->_supports_fbconfig); 00231 00232 XVisualInfo *visual_info = glxgsg->_glXGetVisualFromFBConfig(_display, fbconfig); 00233 if (visual_info == NULL) { 00234 // No X visual; no need to set up a colormap. 00235 return; 00236 } 00237 int visual_class = visual_info->c_class; 00238 Visual *visual = visual_info->visual; 00239 XFree(visual_info); 00240 00241 glxGraphicsPipe *glx_pipe; 00242 DCAST_INTO_V(glx_pipe, _pipe); 00243 X11_Window root_window = glx_pipe->get_root(); 00244 00245 int rc, is_rgb; 00246 00247 switch (visual_class) { 00248 case PseudoColor: 00249 rc = glxgsg->_glXGetFBConfigAttrib(_display, fbconfig, GLX_RGBA, &is_rgb); 00250 if (rc == 0 && is_rgb) { 00251 glxdisplay_cat.warning() 00252 << "mesa pseudocolor not supported.\n"; 00253 // this is a terrible terrible hack, but it seems to work 00254 _colormap = (Colormap)0; 00255 00256 } else { 00257 _colormap = XCreateColormap(_display, root_window, 00258 visual, AllocAll); 00259 } 00260 break; 00261 case TrueColor: 00262 case DirectColor: 00263 _colormap = XCreateColormap(_display, root_window, 00264 visual, AllocNone); 00265 break; 00266 case StaticColor: 00267 case StaticGray: 00268 case GrayScale: 00269 _colormap = XCreateColormap(_display, root_window, 00270 visual, AllocNone); 00271 break; 00272 default: 00273 glxdisplay_cat.error() 00274 << "Could not allocate a colormap for visual class " 00275 << visual_class << ".\n"; 00276 break; 00277 } 00278 } 00279 00280 //////////////////////////////////////////////////////////////////// 00281 // Function: glxGraphicsWindow::setup_colormap 00282 // Access: Private, Virtual 00283 // Description: Allocates a colormap appropriate to the visual and 00284 // stores in in the _colormap method. 00285 //////////////////////////////////////////////////////////////////// 00286 void glxGraphicsWindow:: 00287 setup_colormap(XVisualInfo *visual) { 00288 glxGraphicsPipe *glx_pipe; 00289 DCAST_INTO_V(glx_pipe, _pipe); 00290 X11_Window root_window = glx_pipe->get_root(); 00291 00292 int visual_class = visual->c_class; 00293 int rc, is_rgb; 00294 00295 switch (visual_class) { 00296 case PseudoColor: 00297 rc = glXGetConfig(_display, visual, GLX_RGBA, &is_rgb); 00298 if (rc == 0 && is_rgb) { 00299 glxdisplay_cat.warning() 00300 << "mesa pseudocolor not supported.\n"; 00301 // this is a terrible terrible hack, but it seems to work 00302 _colormap = (Colormap)0; 00303 00304 } else { 00305 _colormap = XCreateColormap(_display, root_window, 00306 visual->visual, AllocAll); 00307 } 00308 break; 00309 case TrueColor: 00310 case DirectColor: 00311 _colormap = XCreateColormap(_display, root_window, 00312 visual->visual, AllocNone); 00313 break; 00314 case StaticColor: 00315 case StaticGray: 00316 case GrayScale: 00317 _colormap = XCreateColormap(_display, root_window, 00318 visual->visual, AllocNone); 00319 break; 00320 default: 00321 glxdisplay_cat.error() 00322 << "Could not allocate a colormap for visual class " 00323 << visual_class << ".\n"; 00324 break; 00325 } 00326 }