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         X11_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   // First get the number of matching configurations, so we know how much memory to allocate.
00170   int num_configs = 0, returned_configs;
00171   if (!eglChooseConfig(_egl_display, attrib_list, NULL, num_configs, &returned_configs) || returned_configs <= 0) {
00172     egldisplay_cat.error() << "eglChooseConfig failed: "
00173       << get_egl_error_string(eglGetError()) << "\n";
00174     return;
00175   }
00176 
00177   num_configs = returned_configs;
00178   EGLConfig *configs = new EGLConfig[num_configs];
00179 
00180   if (!eglChooseConfig(_egl_display, attrib_list, configs, num_configs, &returned_configs) || returned_configs <= 0) {
00181     egldisplay_cat.error() << "eglChooseConfig failed: "
00182       << get_egl_error_string(eglGetError()) << "\n";
00183     delete[] configs;
00184     return;
00185   }
00186 
00187   int best_quality = 0;
00188   int best_result = 0;
00189   FrameBufferProperties best_props;
00190 
00191   for (int i = 0; i < num_configs; ++i) {
00192     FrameBufferProperties fbprops;
00193     bool pbuffer_supported, pixmap_supported, slow;
00194     get_properties(fbprops, pbuffer_supported, pixmap_supported,
00195                    slow, configs[i]);
00196     // We're not protecting this code by an is_debug() check, because if we do,
00197     // some weird compiler bug appears and somehow makes the quality always 0.
00198     const char *pbuffertext = pbuffer_supported ? " (pbuffer)" : "";
00199     const char *pixmaptext = pixmap_supported ? " (pixmap)" : "";
00200     const char *slowtext = slow ? " (slow)" : "";
00201     egldisplay_cat.debug()
00202       << i << ": " << fbprops << pbuffertext << pixmaptext << slowtext << "\n";
00203     int quality = fbprops.get_quality(properties);
00204     if ((quality > 0)&&(slow)) quality -= 10000000;
00205 
00206     if (need_pbuffer && !pbuffer_supported) {
00207       continue;
00208     }
00209     if (need_pixmap && !pixmap_supported) {
00210       continue;
00211     }
00212 
00213     if (quality > best_quality) {
00214       best_quality = quality;
00215       best_result = i;
00216       best_props = fbprops;
00217     }
00218   }
00219   int depth = DefaultDepth(_display, _screen);
00220   _visual = new XVisualInfo;
00221   XMatchVisualInfo(_display, _screen, depth, TrueColor, _visual);
00222 
00223   if (best_quality > 0) {
00224     egldisplay_cat.debug()
00225       << "Chosen config " << best_result << ": " << best_props << "\n";
00226     _fbconfig = configs[best_result];
00227 #ifdef OPENGLES_2
00228     EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
00229     _context = eglCreateContext(_egl_display, _fbconfig, _share_context, context_attribs);
00230 #else
00231     _context = eglCreateContext(_egl_display, _fbconfig, _share_context, NULL);
00232 #endif
00233     int err = eglGetError();
00234     if (_context && err == EGL_SUCCESS) {
00235       if (_visual) {
00236         _fbprops = best_props;
00237         delete[] configs;
00238         return;
00239       }
00240     }
00241     // This really shouldn't happen, so I'm not too careful about cleanup.
00242     egldisplay_cat.error()
00243       << "Could not create EGL context!\n"
00244       << get_egl_error_string(err) << "\n";
00245     _fbconfig = 0;
00246     _context = 0;
00247     _visual = 0;
00248     _visuals = 0;
00249   }
00250 
00251   egldisplay_cat.error() <<
00252     "Could not find a usable pixel format.\n";
00253 
00254   delete[] configs;
00255 }
00256 
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: eglGraphicsStateGuardian::reset
00259 //       Access: Public, Virtual
00260 //  Description: Resets all internal state as if the gsg were newly
00261 //               created.
00262 ////////////////////////////////////////////////////////////////////
00263 void eglGraphicsStateGuardian::
00264 reset() {
00265 #ifdef OPENGLES_2
00266   GLES2GraphicsStateGuardian::reset();
00267 #else
00268   GLESGraphicsStateGuardian::reset();
00269 #endif
00270 
00271   // If "Mesa" is present, assume software.  However, if "Mesa DRI" is
00272   // found, it's actually a Mesa-based OpenGL layer running over a
00273   // hardware driver.
00274   if (_gl_renderer.find("Mesa") != string::npos &&
00275       _gl_renderer.find("Mesa DRI") == string::npos) {
00276     // It's Mesa, therefore probably a software context.
00277     _fbprops.set_force_software(1);
00278     _fbprops.set_force_hardware(0);
00279   } else {
00280     _fbprops.set_force_hardware(1);
00281     _fbprops.set_force_software(0);
00282   }
00283 }
00284 
00285 ////////////////////////////////////////////////////////////////////
00286 //     Function: eglGraphicsStateGuardian::egl_is_at_least_version
00287 //       Access: Public
00288 //  Description: Returns true if the runtime GLX version number is at
00289 //               least the indicated value, false otherwise.
00290 ////////////////////////////////////////////////////////////////////
00291 bool eglGraphicsStateGuardian::
00292 egl_is_at_least_version(int major_version, int minor_version) const {
00293   if (_egl_version_major < major_version) {
00294     return false;
00295   }
00296   if (_egl_version_minor < minor_version) {
00297     return false;
00298   }
00299   return true;
00300 }
00301 
00302 ////////////////////////////////////////////////////////////////////
00303 //     Function: eglGraphicsStateGuardian::gl_flush
00304 //       Access: Protected, Virtual
00305 //  Description: Calls glFlush().
00306 ////////////////////////////////////////////////////////////////////
00307 void eglGraphicsStateGuardian::
00308 gl_flush() const {
00309   // This call requires synchronization with X.
00310   LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
00311 #ifdef OPENGLES_2
00312   GLES2GraphicsStateGuardian::gl_flush();
00313 #else
00314   GLESGraphicsStateGuardian::gl_flush();
00315 #endif
00316 }
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: eglGraphicsStateGuardian::gl_get_error
00320 //       Access: Protected, Virtual
00321 //  Description: Returns the result of glGetError().
00322 ////////////////////////////////////////////////////////////////////
00323 GLenum eglGraphicsStateGuardian::
00324 gl_get_error() const {
00325   // This call requires synchronization with X.
00326   LightReMutexHolder holder(eglGraphicsPipe::_x_mutex);
00327 #ifdef OPENGLES_2
00328   return GLES2GraphicsStateGuardian::gl_get_error();
00329 #else
00330   return GLESGraphicsStateGuardian::gl_get_error();
00331 #endif
00332 }
00333 
00334 ////////////////////////////////////////////////////////////////////
00335 //     Function: eglGraphicsStateGuardian::query_gl_version
00336 //       Access: Protected, Virtual
00337 //  Description: Queries the runtime version of OpenGL in use.
00338 ////////////////////////////////////////////////////////////////////
00339 void eglGraphicsStateGuardian::
00340 query_gl_version() {
00341 #ifdef OPENGLES_2
00342   GLES2GraphicsStateGuardian::query_gl_version();
00343 #else
00344   GLESGraphicsStateGuardian::query_gl_version();
00345 #endif
00346 
00347   // Calling eglInitialize on an already-initialized display will
00348   // just provide us the version numbers.
00349   if (!eglInitialize(_egl_display, &_egl_version_major, &_egl_version_minor)) {
00350     egldisplay_cat.error() << "Failed to get EGL version number: "
00351       << get_egl_error_string(eglGetError()) << "\n";
00352   }
00353 
00354   // We output to glesgsg_cat instead of egldisplay_cat, since this is
00355   // where the GL version has been output, and it's nice to see the
00356   // two of these together.
00357 #ifdef OPENGLES_2
00358   if (gles2gsg_cat.is_debug()) {
00359     gles2gsg_cat.debug()
00360 #else
00361   if (glesgsg_cat.is_debug()) {
00362     glesgsg_cat.debug()
00363 #endif
00364       << "EGL_VERSION = " << _egl_version_major << "." << _egl_version_minor
00365       << "\n";
00366   }
00367 }
00368 
00369 ////////////////////////////////////////////////////////////////////
00370 //     Function: eglGraphicsStateGuardian::get_extra_extensions
00371 //       Access: Protected, Virtual
00372 //  Description: This may be redefined by a derived class (e.g. glx or
00373 //               wgl) to get whatever further extensions strings may
00374 //               be appropriate to that interface, in addition to the
00375 //               GL extension strings return by glGetString().
00376 ////////////////////////////////////////////////////////////////////
00377 void eglGraphicsStateGuardian::
00378 get_extra_extensions() {
00379   save_extensions(eglQueryString(_egl_display, EGL_EXTENSIONS));
00380 }
00381 
00382 ////////////////////////////////////////////////////////////////////
00383 //     Function: eglGraphicsStateGuardian::do_get_extension_func
00384 //       Access: Public, Virtual
00385 //  Description: Returns the pointer to the GL extension function with
00386 //               the indicated name.  It is the responsibility of the
00387 //               caller to ensure that the required extension is
00388 //               defined in the OpenGL runtime prior to calling this;
00389 //               it is an error to call this for a function that is
00390 //               not defined.
00391 ////////////////////////////////////////////////////////////////////
00392 void *eglGraphicsStateGuardian::
00393 do_get_extension_func(const char *prefix, const char *name) {
00394   string fullname = string(prefix) + string(name);
00395 
00396   return (void *)eglGetProcAddress(fullname.c_str());
00397 }