Panda3D
|
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 }