Panda3D

eglGraphicsPipe.cxx

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 }
 All Classes Functions Variables Enumerations