Panda3D

eglGraphicsStateGuardian.cxx

00001 // Filename: eglGraphicsStateGuardian.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 "eglGraphicsStateGuardian.h"
00016 #include "config_egldisplay.h"
00017 #include "lightReMutexHolder.h"
00018 
00019 #include <dlfcn.h>
00020 
00021 TypeHandle eglGraphicsStateGuardian::_type_handle;
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: eglGraphicsStateGuardian::Constructor
00025 //       Access: Public
00026 //  Description:
00027 ////////////////////////////////////////////////////////////////////
00028 eglGraphicsStateGuardian::
00029 eglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
00030        eglGraphicsStateGuardian *share_with) :
00031 #ifdef OPENGLES_2
00032   GLES2GraphicsStateGuardian(engine, pipe)
00033 #else
00034   GLESGraphicsStateGuardian(engine, pipe)
00035 #endif
00036 {
00037   _share_context=0;
00038   _context=0;
00039   _display=0;
00040   _egl_display=0;
00041   _screen=0;
00042   _visual=0;
00043   _visuals=0;
00044   _fbconfig=0;
00045 
00046   if (share_with != (eglGraphicsStateGuardian *)NULL) {
00047     _prepared_objects = share_with->get_prepared_objects();
00048     _share_context = share_with->_context;
00049   }
00050 }
00051 
00052 ////////////////////////////////////////////////////////////////////
00053 //     Function: eglGraphicsStateGuardian::Destructor
00054 //       Access: Public
00055 //  Description:
00056 ////////////////////////////////////////////////////////////////////
00057 eglGraphicsStateGuardian::
00058 ~eglGraphicsStateGuardian() {
00059   if (_visuals != (XVisualInfo *)NULL) {
00060     XFree(_visuals);
00061   }
00062   if (_context != (EGLContext)NULL) {
00063     if (!eglDestroyContext(_egl_display, _context)) {
00064       egldisplay_cat.error() << "Failed to destroy EGL context: "
00065         << get_egl_error_string(eglGetError()) << "\n";
00066     }
00067     _context = (EGLContext)NULL;
00068   }
00069 }
00070 
00071 ////////////////////////////////////////////////////////////////////
00072 //     Function: eglGraphicsStateGuardian::get_properties
00073 //       Access: Private
00074 //  Description: Gets the FrameBufferProperties to match the
00075 //               indicated config.
00076 ////////////////////////////////////////////////////////////////////
00077 void eglGraphicsStateGuardian::
00078 get_properties(FrameBufferProperties &properties,
00079       bool &pbuffer_supported, bool &pixmap_supported,
00080                         bool &slow, EGLConfig config) {
00081 
00082   properties.clear();
00083 
00084   // Now update our framebuffer_mode and bit depth appropriately.
00085   EGLint red_size, green_size, blue_size,
00086     alpha_size,
00087     depth_size, stencil_size, samples, surface_type, caveat;
00088 
00089   eglGetConfigAttrib(_egl_display, config, EGL_RED_SIZE, &red_size);
00090   eglGetConfigAttrib(_egl_display, config, EGL_GREEN_SIZE, &green_size);
00091   eglGetConfigAttrib(_egl_display, config, EGL_BLUE_SIZE, &blue_size);
00092   eglGetConfigAttrib(_egl_display, config, EGL_ALPHA_SIZE, &alpha_size);
00093   eglGetConfigAttrib(_egl_display, config, EGL_DEPTH_SIZE, &depth_size);
00094   eglGetConfigAttrib(_egl_display, config, EGL_STENCIL_SIZE, &stencil_size);
00095   eglGetConfigAttrib(_egl_display, config, EGL_SAMPLES, &samples);
00096   eglGetConfigAttrib(_egl_display, config, EGL_SURFACE_TYPE, &surface_type);
00097   eglGetConfigAttrib(_egl_display, config, EGL_CONFIG_CAVEAT, &caveat);
00098   int err = eglGetError();
00099   if (err != EGL_SUCCESS) {
00100     egldisplay_cat.error() << "Failed to get EGL config attrib: "
00101       << get_egl_error_string(err) << "\n";
00102   }
00103 
00104   pbuffer_supported = false;
00105   if ((surface_type & EGL_PBUFFER_BIT)!=0) {
00106     pbuffer_supported = true;
00107   }
00108 
00109   pixmap_supported = false;
00110   if ((surface_type & EGL_PIXMAP_BIT)!=0) {
00111     pixmap_supported = true;
00112   }
00113 
00114   slow = false;
00115   if (caveat == EGL_SLOW_CONFIG) {
00116     slow = true;
00117   }
00118 
00119   if ((surface_type & EGL_WINDOW_BIT)==0) {
00120     // We insist on having a context that will support an onscreen window.
00121     return;
00122   }
00123 
00124   properties.set_back_buffers(1);
00125   properties.set_rgb_color(1);
00126   properties.set_color_bits(red_size+green_size+blue_size);
00127   properties.set_stencil_bits(stencil_size);
00128   properties.set_depth_bits(depth_size);
00129   properties.set_alpha_bits(alpha_size);
00130   properties.set_multisamples(samples);
00131 
00132   // Set both hardware and software bits, indicating not-yet-known.
00133   properties.set_force_software(1);
00134   properties.set_force_hardware(1);
00135 }
00136 
00137 ////////////////////////////////////////////////////////////////////
00138 //     Function: eglGraphicsStateGuardian::choose_pixel_format
00139 //       Access: Private
00140 //  Description: Selects a visual or fbconfig for all the windows
00141 //               and buffers that use this gsg.  Also creates the GL
00142 //               context and obtains the visual.
00143 ////////////////////////////////////////////////////////////////////
00144 void eglGraphicsStateGuardian::
00145 choose_pixel_format(const FrameBufferProperties &properties,
00146         Display *display,
00147         int screen, bool need_pbuffer, bool need_pixmap) {
00148 
00149   _display = display;
00150   _egl_display = eglGetDisplay((NativeDisplayType) display);
00151   _screen = screen;
00152   _context = 0;
00153   _fbconfig = 0;
00154   _visual = 0;
00155   _visuals = 0;
00156   _fbprops.clear();
00157 
00158   int attrib_list[] = {
00159 #ifdef OPENGLES_1
00160     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
00161 #endif
00162 #ifdef OPENGLES_2
00163     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
00164 #endif
00165     EGL_SURFACE_TYPE, EGL_DONT_CARE,
00166     EGL_NONE
00167   };
00168 
00169   int num_configs = 0;
00170   EGLConfig configs[256];
00171   if (!eglChooseConfig(_egl_display, attrib_list, configs, 256, &num_configs) || num_configs <= 0) {
00172     egldisplay_cat.error() << "eglChooseConfig failed: "
00173       << get_egl_error_string(eglGetError()) << "\n";
00174     return;
00175   }
00176 
00177   int best_quality = 0;
00178   int best_result = 0;
00179   FrameBufferProperties best_props;
00180 
00181   if (configs != 0) {
00182     for (int i = 0; i < num_configs; ++i) {
00183       FrameBufferProperties fbprops;
00184       bool pbuffer_supported, pixmap_supported, slow;
00185       get_properties(fbprops, pbuffer_supported, pixmap_supported,
00186                      slow, configs[i]);
00187       // We're not protecting this code by an is_debug() check, because if we do,
00188       // some weird compiler bug appears and somehow makes the quality always 0.
00189       const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : "";
00190       const char *pixmaptext = pixmap_supported ? " (pixmap)" : "";
00191       const char *slowtext = slow ? " (slow)" : "";
00192       egldisplay_cat.debug()
00193         << i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n";
00194       int quality = fbprops.get_quality(properties);
00195       if ((quality > 0)&&(slow)) quality -= 10000000;
00196 
00197       if (need_pbuffer && !pbuffer_supported) {
00198         continue;
00199       }
00200       if (need_pixmap && !pixmap_supported) {
00201         continue;
00202       }
00203 
00204       if (quality > best_quality) {
00205         best_quality = quality;
00206         best_result = i;
00207         best_props = fbprops;
00208       }
00209     }
00210   }
00211   int depth = DefaultDepth(_display, _screen);
00212   _visual = new XVisualInfo;
00213   XMatchVisualInfo(_display, _screen, depth, TrueColor, _visual);
00214 
00215   if (best_quality > 0) {
00216     egldisplay_cat.debug()
00217       << "Chosen config " << best_result << ": " << best_props << "\n";
00218     _fbconfig = configs[best_result];
00219 #ifdef OPENGLES_2
00220     EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
00221     _context = eglCreateContext(_egl_display, _fbconfig, _share_context, context_attribs);
00222 #else
00223     _context = eglCreateContext(_egl_display, _fbconfig, _share_context, NULL);
00224 #endif
00225     int err = eglGetError();
00226     if (_context && err == EGL_SUCCESS) {
00227       if (_visual) {
00228         _fbprops = best_props;
00229         return;
00230       }
00231     }
00232     // This really shouldn't happen, so I'm not too careful about cleanup.
00233     egldisplay_cat.error()
00234       << "Could not create EGL context!\n"
00235       << get_egl_error_string(err) << "\n";
00236     _fbconfig = 0;
00237     _context = 0;
00238     _visual = 0;
00239     _visuals = 0;
00240   }
00241 
00242   egldisplay_cat.error() <<
00243     "Could not find a usable pixel format.\n";
00244 }
00245 
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: eglGraphicsStateGuardian::reset
00248 //       Access: Public, Virtual
00249 //  Description: Resets all internal state as if the gsg were newly
00250 //               created.
00251 ////////////////////////////////////////////////////////////////////
00252 void eglGraphicsStateGuardian::
00253 reset() {
00254 #ifdef OPENGLES_2
00255   GLES2GraphicsStateGuardian::reset();
00256 #else
00257   GLESGraphicsStateGuardian::reset();
00258 #endif
00259 
00260   // If "Mesa" is present, assume software.  However, if "Mesa DRI" is
00261   // found, it's actually a Mesa-based OpenGL layer running over a
00262   // hardware driver.
00263   if (_gl_renderer.find("Mesa") != string::npos &&
00264       _gl_renderer.find("Mesa DRI") == string::npos) {
00265     // It's Mesa, therefore probably a software context.
00266     _fbprops.set_force_software(1);
00267     _fbprops.set_force_hardware(0);
00268   } else {
00269     _fbprops.set_force_hardware(1);
00270     _fbprops.set_force_software(0);
00271   }
00272 }
00273 
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: eglGraphicsStateGuardian::egl_is_at_least_version
00276 //       Access: Public
00277 //  Description: Returns true if the runtime GLX version number is at
00278 //               least the indicated value, false otherwise.
00279 ////////////////////////////////////////////////////////////////////
00280 bool eglGraphicsStateGuardian::
00281 egl_is_at_least_version(int major_version, int minor_version) const {
00282   if (_egl_version_major < major_version) {
00283     return false;
00284   }
00285   if (_egl_version_minor < minor_version) {
00286     return false;
00287   }
00288   return true;
00289 }
00290 
00291 ////////////////////////////////////////////////////////////////////
00292 //     Function: eglGraphicsStateGuardian::gl_flush
00293 //       Access: Protected, Virtual
00294 //  Description: Calls glFlush().
00295 ////////////////////////////////////////////////////////////////////
00296 void eglGraphicsStateGuardian::
00297 gl_flush() const {
00298   // This call requires synchronization with X.
00299   LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
00300 #ifdef OPENGLES_2
00301   GLES2GraphicsStateGuardian::gl_flush();
00302 #else
00303   GLESGraphicsStateGuardian::gl_flush();
00304 #endif
00305 }
00306 
00307 ////////////////////////////////////////////////////////////////////
00308 //     Function: eglGraphicsStateGuardian::gl_get_error
00309 //       Access: Protected, Virtual
00310 //  Description: Returns the result of glGetError().
00311 ////////////////////////////////////////////////////////////////////
00312 GLenum eglGraphicsStateGuardian::
00313 gl_get_error() const {
00314   // This call requires synchronization with X.
00315   LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
00316 #ifdef OPENGLES_2
00317   return GLES2GraphicsStateGuardian::gl_get_error();
00318 #else
00319   return GLESGraphicsStateGuardian::gl_get_error();
00320 #endif
00321 }
00322 
00323 ////////////////////////////////////////////////////////////////////
00324 //     Function: eglGraphicsStateGuardian::query_gl_version
00325 //       Access: Protected, Virtual
00326 //  Description: Queries the runtime version of OpenGL in use.
00327 ////////////////////////////////////////////////////////////////////
00328 void eglGraphicsStateGuardian::
00329 query_gl_version() {
00330 #ifdef OPENGLES_2
00331   GLES2GraphicsStateGuardian::query_gl_version();
00332 #else
00333   GLESGraphicsStateGuardian::query_gl_version();
00334 #endif
00335 
00336   // Calling eglInitialize on an already-initialized display will
00337   // just provide us the version numbers.
00338   if (!eglInitialize(_egl_display, &_egl_version_major, &_egl_version_minor)) {
00339     egldisplay_cat.error() << "Failed to get EGL version number: "
00340       << get_egl_error_string(eglGetError()) << "\n";
00341   }
00342 
00343   // We output to glesgsg_cat instead of egldisplay_cat, since this is
00344   // where the GL version has been output, and it's nice to see the
00345   // two of these together.
00346 #ifdef OPENGLES_2
00347   if (gles2gsg_cat.is_debug()) {
00348     gles2gsg_cat.debug()
00349 #else
00350   if (glesgsg_cat.is_debug()) {
00351     glesgsg_cat.debug()
00352 #endif
00353       << "EGL_VERSION = " << _egl_version_major << "." << _egl_version_minor
00354       << "\n";
00355   }
00356 }
00357 
00358 ////////////////////////////////////////////////////////////////////
00359 //     Function: eglGraphicsStateGuardian::get_extra_extensions
00360 //       Access: Protected, Virtual
00361 //  Description: This may be redefined by a derived class (e.g. glx or
00362 //               wgl) to get whatever further extensions strings may
00363 //               be appropriate to that interface, in addition to the
00364 //               GL extension strings return by glGetString().
00365 ////////////////////////////////////////////////////////////////////
00366 void eglGraphicsStateGuardian::
00367 get_extra_extensions() {
00368   save_extensions(eglQueryString(_egl_display, EGL_EXTENSIONS));
00369 }
00370 
00371 ////////////////////////////////////////////////////////////////////
00372 //     Function: eglGraphicsStateGuardian::do_get_extension_func
00373 //       Access: Public, Virtual
00374 //  Description: Returns the pointer to the GL extension function with
00375 //               the indicated name.  It is the responsibility of the
00376 //               caller to ensure that the required extension is
00377 //               defined in the OpenGL runtime prior to calling this;
00378 //               it is an error to call this for a function that is
00379 //               not defined.
00380 ////////////////////////////////////////////////////////////////////
00381 void *eglGraphicsStateGuardian::
00382 do_get_extension_func(const char *prefix, const char *name) {
00383   string fullname = string(prefix) + string(name);
00384 
00385   return (void *)eglGetProcAddress(fullname.c_str());
00386 }
 All Classes Functions Variables Enumerations