Panda3D
|
00001 // Filename: eglGraphicsPipe.cxx 00002 // Created by: pro-rsoft (21May09) 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 "eglGraphicsBuffer.h" 00016 #include "eglGraphicsPipe.h" 00017 #include "eglGraphicsPixmap.h" 00018 #include "eglGraphicsWindow.h" 00019 #include "eglGraphicsStateGuardian.h" 00020 #include "config_egldisplay.h" 00021 #include "frameBufferProperties.h" 00022 00023 TypeHandle eglGraphicsPipe::_type_handle; 00024 00025 bool eglGraphicsPipe::_error_handlers_installed = false; 00026 eglGraphicsPipe::ErrorHandlerFunc *eglGraphicsPipe::_prev_error_handler; 00027 eglGraphicsPipe::IOErrorHandlerFunc *eglGraphicsPipe::_prev_io_error_handler; 00028 00029 LightReMutex eglGraphicsPipe::_x_mutex; 00030 00031 //////////////////////////////////////////////////////////////////// 00032 // Function: eglGraphicsPipe::Constructor 00033 // Access: Public 00034 // Description: 00035 //////////////////////////////////////////////////////////////////// 00036 eglGraphicsPipe:: 00037 eglGraphicsPipe(const string &display) { 00038 string display_spec = display; 00039 if (display_spec.empty()) { 00040 display_spec = display_cfg; 00041 } 00042 if (display_spec.empty()) { 00043 display_spec = ExecutionEnvironment::get_environment_variable("DISPLAY"); 00044 } 00045 if (display_spec.empty()) { 00046 display_spec = ":0.0"; 00047 } 00048 00049 // The X docs say we should do this to get international character 00050 // support from the keyboard. 00051 setlocale(LC_ALL, ""); 00052 00053 // But it's important that we use the "C" locale for numeric 00054 // formatting, since all of the internal Panda code assumes this--we 00055 // need a decimal point to mean a decimal point. 00056 setlocale(LC_NUMERIC, "C"); 00057 00058 _is_valid = false; 00059 _supported_types = OT_window | OT_buffer | OT_texture_buffer; 00060 _display = NULL; 00061 _screen = 0; 00062 _root = (Window)NULL; 00063 _im = (XIM)NULL; 00064 _hidden_cursor = None; 00065 _egl_display = NULL; 00066 00067 install_error_handlers(); 00068 00069 _display = XOpenDisplay(display_spec.c_str()); 00070 if (!_display) { 00071 egldisplay_cat.error() 00072 << "Could not open display \"" << display_spec << "\".\n"; 00073 return; 00074 } 00075 00076 if (!XSupportsLocale()) { 00077 egldisplay_cat.warning() 00078 << "X does not support locale " << setlocale(LC_ALL, NULL) << "\n"; 00079 } 00080 XSetLocaleModifiers(""); 00081 00082 _screen = DefaultScreen(_display); 00083 _root = RootWindow(_display, _screen); 00084 _display_width = DisplayWidth(_display, _screen); 00085 _display_height = DisplayHeight(_display, _screen); 00086 _is_valid = true; 00087 00088 _egl_display = eglGetDisplay((NativeDisplayType) _display); 00089 if (!eglInitialize(_egl_display, NULL, NULL)) { 00090 egldisplay_cat.error() 00091 << "Couldn't initialize the EGL display: " 00092 << get_egl_error_string(eglGetError()) << "\n"; 00093 } 00094 00095 if (!eglBindAPI(EGL_OPENGL_ES_API)) { 00096 egldisplay_cat.error() 00097 << "Couldn't bind EGL to the OpenGL ES API: " 00098 << get_egl_error_string(eglGetError()) << "\n"; 00099 } 00100 00101 // Connect to an input method for supporting international text 00102 // entry. 00103 _im = XOpenIM(_display, NULL, NULL, NULL); 00104 if (_im == (XIM)NULL) { 00105 egldisplay_cat.warning() 00106 << "Couldn't open input method.\n"; 00107 } 00108 00109 // What styles does the current input method support? 00110 /* 00111 XIMStyles *im_supported_styles; 00112 XGetIMValues(_im, XNQueryInputStyle, &im_supported_styles, NULL); 00113 00114 for (int i = 0; i < im_supported_styles->count_styles; i++) { 00115 XIMStyle style = im_supported_styles->supported_styles[i]; 00116 cerr << "style " << i << ". " << hex << style << dec << "\n"; 00117 } 00118 00119 XFree(im_supported_styles); 00120 */ 00121 00122 // Get some X atom numbers. 00123 _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false); 00124 _net_wm_window_type = XInternAtom(_display, "_NET_WM_WINDOW_TYPE", false); 00125 _net_wm_window_type_splash = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_SPLASH", false); 00126 _net_wm_window_type_fullscreen = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_FULLSCREEN", false); 00127 _net_wm_state = XInternAtom(_display, "_NET_WM_STATE", false); 00128 _net_wm_state_fullscreen = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", false); 00129 _net_wm_state_above = XInternAtom(_display, "_NET_WM_STATE_ABOVE", false); 00130 _net_wm_state_below = XInternAtom(_display, "_NET_WM_STATE_BELOW", false); 00131 _net_wm_state_add = XInternAtom(_display, "_NET_WM_STATE_ADD", false); 00132 _net_wm_state_remove = XInternAtom(_display, "_NET_WM_STATE_REMOVE", false); 00133 } 00134 00135 //////////////////////////////////////////////////////////////////// 00136 // Function: eglGraphicsPipe::Destructor 00137 // Access: Public, Virtual 00138 // Description: 00139 //////////////////////////////////////////////////////////////////// 00140 eglGraphicsPipe:: 00141 ~eglGraphicsPipe() { 00142 release_hidden_cursor(); 00143 if (_im) { 00144 XCloseIM(_im); 00145 } 00146 if (_display) { 00147 XCloseDisplay(_display); 00148 } 00149 if (_egl_display) { 00150 if (!eglTerminate(_egl_display)) { 00151 egldisplay_cat.error() << "Failed to terminate EGL display: " 00152 << get_egl_error_string(eglGetError()) << "\n"; 00153 } 00154 } 00155 } 00156 00157 //////////////////////////////////////////////////////////////////// 00158 // Function: eglGraphicsPipe::get_interface_name 00159 // Access: Published, Virtual 00160 // Description: Returns the name of the rendering interface 00161 // associated with this GraphicsPipe. This is used to 00162 // present to the user to allow him/her to choose 00163 // between several possible GraphicsPipes available on a 00164 // particular platform, so the name should be meaningful 00165 // and unique for a given platform. 00166 //////////////////////////////////////////////////////////////////// 00167 string eglGraphicsPipe:: 00168 get_interface_name() const { 00169 return "OpenGL ES"; 00170 } 00171 00172 //////////////////////////////////////////////////////////////////// 00173 // Function: eglGraphicsPipe::pipe_constructor 00174 // Access: Public, Static 00175 // Description: This function is passed to the GraphicsPipeSelection 00176 // object to allow the user to make a default 00177 // eglGraphicsPipe. 00178 //////////////////////////////////////////////////////////////////// 00179 PT(GraphicsPipe) eglGraphicsPipe:: 00180 pipe_constructor() { 00181 return new eglGraphicsPipe; 00182 } 00183 00184 //////////////////////////////////////////////////////////////////// 00185 // Function: eglGraphicsPipe::get_preferred_window_thread 00186 // Access: Public, Virtual 00187 // Description: Returns an indication of the thread in which this 00188 // GraphicsPipe requires its window processing to be 00189 // performed: typically either the app thread (e.g. X) 00190 // or the draw thread (Windows). 00191 //////////////////////////////////////////////////////////////////// 00192 GraphicsPipe::PreferredWindowThread 00193 eglGraphicsPipe::get_preferred_window_thread() const { 00194 // Actually, since we're creating the graphics context in 00195 // open_window() now, it appears we need to ensure the open_window() 00196 // call is performed in the draw thread for now, even though X wants 00197 // all of its calls to be single-threaded. 00198 00199 // This means that all X windows may have to be handled by the same 00200 // draw thread, which we didn't intend (though the global _x_mutex 00201 // may allow them to be technically served by different threads, 00202 // even though the actual X calls will be serialized). There might 00203 // be a better way. 00204 00205 return PWT_draw; 00206 } 00207 00208 //////////////////////////////////////////////////////////////////// 00209 // Function: eglGraphicsPipe::make_output 00210 // Access: Protected, Virtual 00211 // Description: Creates a new window on the pipe, if possible. 00212 //////////////////////////////////////////////////////////////////// 00213 PT(GraphicsOutput) eglGraphicsPipe:: 00214 make_output(const string &name, 00215 const FrameBufferProperties &fb_prop, 00216 const WindowProperties &win_prop, 00217 int flags, 00218 GraphicsEngine *engine, 00219 GraphicsStateGuardian *gsg, 00220 GraphicsOutput *host, 00221 int retry, 00222 bool &precertify) { 00223 00224 if (!_is_valid) { 00225 return NULL; 00226 } 00227 00228 eglGraphicsStateGuardian *eglgsg = 0; 00229 if (gsg != 0) { 00230 DCAST_INTO_R(eglgsg, gsg, NULL); 00231 } 00232 00233 bool support_rtt; 00234 support_rtt = false; 00235 if (eglgsg) { 00236 support_rtt = 00237 eglgsg -> get_supports_render_texture() && 00238 support_render_texture; 00239 } 00240 // First thing to try: an eglGraphicsWindow 00241 00242 if (retry == 0) { 00243 if (((flags&BF_require_parasite)!=0)|| 00244 ((flags&BF_refuse_window)!=0)|| 00245 ((flags&BF_resizeable)!=0)|| 00246 ((flags&BF_size_track_host)!=0)|| 00247 ((flags&BF_rtt_cumulative)!=0)|| 00248 ((flags&BF_can_bind_color)!=0)|| 00249 ((flags&BF_can_bind_every)!=0)) { 00250 return NULL; 00251 } 00252 return new eglGraphicsWindow(engine, this, name, fb_prop, win_prop, 00253 flags, gsg, host); 00254 } 00255 00256 // Second thing to try: a GLES(2)GraphicsBuffer 00257 if (retry == 1) { 00258 if ((host==0)|| 00259 // (!gl_support_fbo)|| 00260 ((flags&BF_require_parasite)!=0)|| 00261 ((flags&BF_require_window)!=0)) { 00262 return NULL; 00263 } 00264 // Early failure - if we are sure that this buffer WONT 00265 // meet specs, we can bail out early. 00266 if ((flags & BF_fb_props_optional)==0) { 00267 if ((fb_prop.get_indexed_color() > 0)|| 00268 (fb_prop.get_back_buffers() > 0)|| 00269 (fb_prop.get_accum_bits() > 0)|| 00270 (fb_prop.get_multisamples() > 0)) { 00271 return NULL; 00272 } 00273 } 00274 // Early success - if we are sure that this buffer WILL 00275 // meet specs, we can precertify it. 00276 if ((eglgsg != 0) && 00277 (eglgsg->is_valid()) && 00278 (!eglgsg->needs_reset()) && 00279 (eglgsg->_supports_framebuffer_object) && 00280 (eglgsg->_glDrawBuffers != 0)&& 00281 (fb_prop.is_basic())) { 00282 precertify = true; 00283 } 00284 #ifdef OPENGLES_2 00285 return new GLES2GraphicsBuffer(engine, this, name, fb_prop, win_prop, 00286 flags, gsg, host); 00287 #else 00288 return new GLESGraphicsBuffer(engine, this, name, fb_prop, win_prop, 00289 flags, gsg, host); 00290 #endif 00291 } 00292 00293 // Third thing to try: a eglGraphicsBuffer 00294 if (retry == 2) { 00295 if (((flags&BF_require_parasite)!=0)|| 00296 ((flags&BF_require_window)!=0)|| 00297 ((flags&BF_resizeable)!=0)|| 00298 ((flags&BF_size_track_host)!=0)) { 00299 return NULL; 00300 } 00301 00302 if (!support_rtt) { 00303 if (((flags&BF_rtt_cumulative)!=0)|| 00304 ((flags&BF_can_bind_every)!=0)) { 00305 // If we require Render-to-Texture, but can't be sure we 00306 // support it, bail. 00307 return NULL; 00308 } 00309 } 00310 00311 return new eglGraphicsBuffer(engine, this, name, fb_prop, win_prop, 00312 flags, gsg, host); 00313 } 00314 00315 // Fourth thing to try: an eglGraphicsPixmap. 00316 if (retry == 3) { 00317 if (((flags&BF_require_parasite)!=0)|| 00318 ((flags&BF_require_window)!=0)|| 00319 ((flags&BF_resizeable)!=0)|| 00320 ((flags&BF_size_track_host)!=0)) { 00321 return NULL; 00322 } 00323 00324 if (((flags&BF_rtt_cumulative)!=0)|| 00325 ((flags&BF_can_bind_every)!=0)) { 00326 return NULL; 00327 } 00328 00329 return new eglGraphicsPixmap(engine, this, name, fb_prop, win_prop, 00330 flags, gsg, host); 00331 } 00332 00333 // Nothing else left to try. 00334 return NULL; 00335 } 00336 00337 //////////////////////////////////////////////////////////////////// 00338 // Function: eglGraphicsPipe::make_hidden_cursor 00339 // Access: Private 00340 // Description: Called once to make an invisible Cursor for return 00341 // from get_hidden_cursor(). 00342 //////////////////////////////////////////////////////////////////// 00343 void eglGraphicsPipe:: 00344 make_hidden_cursor() { 00345 nassertv(_hidden_cursor == None); 00346 00347 unsigned int x_size, y_size; 00348 XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size); 00349 00350 Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1); 00351 00352 XColor black; 00353 memset(&black, 0, sizeof(black)); 00354 00355 _hidden_cursor = XCreatePixmapCursor(_display, empty, empty, 00356 &black, &black, x_size, y_size); 00357 XFreePixmap(_display, empty); 00358 } 00359 00360 //////////////////////////////////////////////////////////////////// 00361 // Function: eglGraphicsPipe::release_hidden_cursor 00362 // Access: Private 00363 // Description: Called once to release the invisible cursor created 00364 // by make_hidden_cursor(). 00365 //////////////////////////////////////////////////////////////////// 00366 void eglGraphicsPipe:: 00367 release_hidden_cursor() { 00368 if (_hidden_cursor != None) { 00369 XFreeCursor(_display, _hidden_cursor); 00370 _hidden_cursor = None; 00371 } 00372 } 00373 00374 //////////////////////////////////////////////////////////////////// 00375 // Function: eglGraphicsPipe::install_error_handlers 00376 // Access: Private, Static 00377 // Description: Installs new Xlib error handler functions if this is 00378 // the first time this function has been called. These 00379 // error handler functions will attempt to reduce Xlib's 00380 // annoying tendency to shut down the client at the 00381 // first error. Unfortunately, it is difficult to play 00382 // nice with the client if it has already installed its 00383 // own error handlers. 00384 //////////////////////////////////////////////////////////////////// 00385 void eglGraphicsPipe:: 00386 install_error_handlers() { 00387 if (_error_handlers_installed) { 00388 return; 00389 } 00390 00391 _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler); 00392 _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler); 00393 _error_handlers_installed = true; 00394 } 00395 00396 //////////////////////////////////////////////////////////////////// 00397 // Function: eglGraphicsPipe::error_handler 00398 // Access: Private, Static 00399 // Description: This function is installed as the error handler for a 00400 // non-fatal Xlib error. 00401 //////////////////////////////////////////////////////////////////// 00402 int eglGraphicsPipe:: 00403 error_handler(Display *display, XErrorEvent *error) { 00404 static const int msg_len = 80; 00405 char msg[msg_len]; 00406 XGetErrorText(display, error->error_code, msg, msg_len); 00407 egldisplay_cat.error() 00408 << msg << "\n"; 00409 00410 if (x_error_abort) { 00411 abort(); 00412 } 00413 00414 // We return to allow the application to continue running, unlike 00415 // the default X error handler which exits. 00416 return 0; 00417 } 00418 00419 //////////////////////////////////////////////////////////////////// 00420 // Function: eglGraphicsPipe::io_error_handler 00421 // Access: Private, Static 00422 // Description: This function is installed as the error handler for a 00423 // fatal Xlib error. 00424 //////////////////////////////////////////////////////////////////// 00425 int eglGraphicsPipe:: 00426 io_error_handler(Display *display) { 00427 egldisplay_cat.fatal() 00428 << "X fatal error on display " << (void *)display << "\n"; 00429 00430 // Unfortunately, we can't continue from this function, even if we 00431 // promise never to use X again. We're supposed to terminate 00432 // without returning, and if we do return, the caller will exit 00433 // anyway. Sigh. Very poor design on X's part. 00434 return 0; 00435 }