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 = (X11_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 /* 00236 Currently, no support for eglGraphicsBuffer render-to-texture. 00237 if (eglgsg) { 00238 support_rtt = 00239 eglgsg -> get_supports_render_texture() && 00240 support_render_texture; 00241 } 00242 */ 00243 00244 // First thing to try: an eglGraphicsWindow 00245 00246 if (retry == 0) { 00247 if (((flags&BF_require_parasite)!=0)|| 00248 ((flags&BF_refuse_window)!=0)|| 00249 ((flags&BF_resizeable)!=0)|| 00250 ((flags&BF_size_track_host)!=0)|| 00251 ((flags&BF_rtt_cumulative)!=0)|| 00252 ((flags&BF_can_bind_color)!=0)|| 00253 ((flags&BF_can_bind_every)!=0)) { 00254 return NULL; 00255 } 00256 return new eglGraphicsWindow(engine, this, name, fb_prop, win_prop, 00257 flags, gsg, host); 00258 } 00259 00260 // Second thing to try: a GLES(2)GraphicsBuffer 00261 if (retry == 1) { 00262 if ((host==0)|| 00263 // (!gl_support_fbo)|| 00264 ((flags&BF_require_parasite)!=0)|| 00265 ((flags&BF_require_window)!=0)) { 00266 return NULL; 00267 } 00268 // Early failure - if we are sure that this buffer WONT 00269 // meet specs, we can bail out early. 00270 if ((flags & BF_fb_props_optional)==0) { 00271 if ((fb_prop.get_indexed_color() > 0)|| 00272 (fb_prop.get_back_buffers() > 0)|| 00273 (fb_prop.get_accum_bits() > 0)|| 00274 (fb_prop.get_multisamples() > 0)) { 00275 return NULL; 00276 } 00277 } 00278 // Early success - if we are sure that this buffer WILL 00279 // meet specs, we can precertify it. 00280 if ((eglgsg != 0) && 00281 (eglgsg->is_valid()) && 00282 (!eglgsg->needs_reset()) && 00283 (eglgsg->_supports_framebuffer_object) && 00284 (eglgsg->_glDrawBuffers != 0)&& 00285 (fb_prop.is_basic())) { 00286 precertify = true; 00287 } 00288 #ifdef OPENGLES_2 00289 return new GLES2GraphicsBuffer(engine, this, name, fb_prop, win_prop, 00290 flags, gsg, host); 00291 #else 00292 return new GLESGraphicsBuffer(engine, this, name, fb_prop, win_prop, 00293 flags, gsg, host); 00294 #endif 00295 } 00296 00297 // Third thing to try: a eglGraphicsBuffer 00298 if (retry == 2) { 00299 if (((flags&BF_require_parasite)!=0)|| 00300 ((flags&BF_require_window)!=0)|| 00301 ((flags&BF_resizeable)!=0)|| 00302 ((flags&BF_size_track_host)!=0)) { 00303 return NULL; 00304 } 00305 00306 if (!support_rtt) { 00307 if (((flags&BF_rtt_cumulative)!=0)|| 00308 ((flags&BF_can_bind_every)!=0)) { 00309 // If we require Render-to-Texture, but can't be sure we 00310 // support it, bail. 00311 return NULL; 00312 } 00313 } 00314 00315 return new eglGraphicsBuffer(engine, this, name, fb_prop, win_prop, 00316 flags, gsg, host); 00317 } 00318 00319 // Fourth thing to try: an eglGraphicsPixmap. 00320 if (retry == 3) { 00321 if (((flags&BF_require_parasite)!=0)|| 00322 ((flags&BF_require_window)!=0)|| 00323 ((flags&BF_resizeable)!=0)|| 00324 ((flags&BF_size_track_host)!=0)) { 00325 return NULL; 00326 } 00327 00328 if (((flags&BF_rtt_cumulative)!=0)|| 00329 ((flags&BF_can_bind_every)!=0)) { 00330 return NULL; 00331 } 00332 00333 return new eglGraphicsPixmap(engine, this, name, fb_prop, win_prop, 00334 flags, gsg, host); 00335 } 00336 00337 // Nothing else left to try. 00338 return NULL; 00339 } 00340 00341 //////////////////////////////////////////////////////////////////// 00342 // Function: eglGraphicsPipe::make_hidden_cursor 00343 // Access: Private 00344 // Description: Called once to make an invisible Cursor for return 00345 // from get_hidden_cursor(). 00346 //////////////////////////////////////////////////////////////////// 00347 void eglGraphicsPipe:: 00348 make_hidden_cursor() { 00349 nassertv(_hidden_cursor == None); 00350 00351 unsigned int x_size, y_size; 00352 XQueryBestCursor(_display, _root, 1, 1, &x_size, &y_size); 00353 00354 Pixmap empty = XCreatePixmap(_display, _root, x_size, y_size, 1); 00355 00356 XColor black; 00357 memset(&black, 0, sizeof(black)); 00358 00359 _hidden_cursor = XCreatePixmapCursor(_display, empty, empty, 00360 &black, &black, x_size, y_size); 00361 XFreePixmap(_display, empty); 00362 } 00363 00364 //////////////////////////////////////////////////////////////////// 00365 // Function: eglGraphicsPipe::release_hidden_cursor 00366 // Access: Private 00367 // Description: Called once to release the invisible cursor created 00368 // by make_hidden_cursor(). 00369 //////////////////////////////////////////////////////////////////// 00370 void eglGraphicsPipe:: 00371 release_hidden_cursor() { 00372 if (_hidden_cursor != None) { 00373 XFreeCursor(_display, _hidden_cursor); 00374 _hidden_cursor = None; 00375 } 00376 } 00377 00378 //////////////////////////////////////////////////////////////////// 00379 // Function: eglGraphicsPipe::install_error_handlers 00380 // Access: Private, Static 00381 // Description: Installs new Xlib error handler functions if this is 00382 // the first time this function has been called. These 00383 // error handler functions will attempt to reduce Xlib's 00384 // annoying tendency to shut down the client at the 00385 // first error. Unfortunately, it is difficult to play 00386 // nice with the client if it has already installed its 00387 // own error handlers. 00388 //////////////////////////////////////////////////////////////////// 00389 void eglGraphicsPipe:: 00390 install_error_handlers() { 00391 if (_error_handlers_installed) { 00392 return; 00393 } 00394 00395 _prev_error_handler = (ErrorHandlerFunc *)XSetErrorHandler(error_handler); 00396 _prev_io_error_handler = (IOErrorHandlerFunc *)XSetIOErrorHandler(io_error_handler); 00397 _error_handlers_installed = true; 00398 } 00399 00400 //////////////////////////////////////////////////////////////////// 00401 // Function: eglGraphicsPipe::error_handler 00402 // Access: Private, Static 00403 // Description: This function is installed as the error handler for a 00404 // non-fatal Xlib error. 00405 //////////////////////////////////////////////////////////////////// 00406 int eglGraphicsPipe:: 00407 error_handler(X11_Display *display, XErrorEvent *error) { 00408 static const int msg_len = 80; 00409 char msg[msg_len]; 00410 XGetErrorText(display, error->error_code, msg, msg_len); 00411 egldisplay_cat.error() 00412 << msg << "\n"; 00413 00414 if (x_error_abort) { 00415 abort(); 00416 } 00417 00418 // We return to allow the application to continue running, unlike 00419 // the default X error handler which exits. 00420 return 0; 00421 } 00422 00423 //////////////////////////////////////////////////////////////////// 00424 // Function: eglGraphicsPipe::io_error_handler 00425 // Access: Private, Static 00426 // Description: This function is installed as the error handler for a 00427 // fatal Xlib error. 00428 //////////////////////////////////////////////////////////////////// 00429 int eglGraphicsPipe:: 00430 io_error_handler(X11_Display *display) { 00431 egldisplay_cat.fatal() 00432 << "X fatal error on display " << (void *)display << "\n"; 00433 00434 // Unfortunately, we can't continue from this function, even if we 00435 // promise never to use X again. We're supposed to terminate 00436 // without returning, and if we do return, the caller will exit 00437 // anyway. Sigh. Very poor design on X's part. 00438 return 0; 00439 }