Panda3D
|
00001 // Filename: graphicsPipeSelection.cxx 00002 // Created by: drose (15Aug02) 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 "graphicsPipeSelection.h" 00016 #include "lightMutexHolder.h" 00017 #include "string_utils.h" 00018 #include "filename.h" 00019 #include "load_dso.h" 00020 #include "config_display.h" 00021 #include "typeRegistry.h" 00022 #include "pset.h" 00023 #include "config_util.h" 00024 00025 #include <algorithm> 00026 00027 GraphicsPipeSelection *GraphicsPipeSelection::_global_ptr = NULL; 00028 00029 //////////////////////////////////////////////////////////////////// 00030 // Function: GraphicsPipeSelection::Constructor 00031 // Access: Protected 00032 // Description: 00033 //////////////////////////////////////////////////////////////////// 00034 GraphicsPipeSelection:: 00035 GraphicsPipeSelection() : _lock("GraphicsPipeSelection") { 00036 // We declare these variables here instead of in config_display, in 00037 // case this constructor is running at static init time. 00038 ConfigVariableString load_display 00039 ("load-display", "*", 00040 PRC_DESC("Specify the name of the default graphics display library or " 00041 "GraphicsPipe to load. It is the name of a shared library (or * for " 00042 "all libraries named in aux-display), optionally followed by the " 00043 "name of the particular GraphicsPipe class to create.")); 00044 00045 ConfigVariableList aux_display 00046 ("aux-display", 00047 PRC_DESC("Names each of the graphics display libraries that are available on " 00048 "a particular platform. This variable may be repeated several " 00049 "times. These libraries will be tried one at a time if the library " 00050 "specified by load_display cannot be loaded.")); 00051 00052 _default_display_module = load_display.get_word(0); 00053 _default_pipe_name = load_display.get_word(1); 00054 00055 if (_default_display_module == "*") { 00056 // '*' or empty string is the key for all display modules. 00057 _default_display_module = string(); 00058 00059 } else if (!_default_display_module.empty()) { 00060 _display_modules.push_back(_default_display_module); 00061 } 00062 00063 // Also get the set of modules named in the various aux-display 00064 // Config variables. We'll want to know this when we call 00065 // load_modules() later. 00066 int num_aux = aux_display.get_num_unique_values(); 00067 for (int i = 0; i < num_aux; i++) { 00068 string name = aux_display.get_unique_value(i); 00069 if (name != _default_display_module) { 00070 _display_modules.push_back(name); 00071 } 00072 } 00073 00074 _default_module_loaded = false; 00075 } 00076 00077 //////////////////////////////////////////////////////////////////// 00078 // Function: GraphicsPipeSelection::Destructor 00079 // Access: Protected 00080 // Description: 00081 //////////////////////////////////////////////////////////////////// 00082 GraphicsPipeSelection:: 00083 ~GraphicsPipeSelection() { 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 // Function: GraphicsPipeSelection::get_num_pipe_types 00088 // Access: Published 00089 // Description: Returns the number of different types of 00090 // GraphicsPipes that are available to create through 00091 // this interface. 00092 //////////////////////////////////////////////////////////////////// 00093 int GraphicsPipeSelection:: 00094 get_num_pipe_types() const { 00095 load_default_module(); 00096 00097 int result; 00098 { 00099 LightMutexHolder holder(_lock); 00100 result = _pipe_types.size(); 00101 } 00102 return result; 00103 } 00104 00105 //////////////////////////////////////////////////////////////////// 00106 // Function: GraphicsPipeSelection::get_pipe_type 00107 // Access: Published 00108 // Description: Returns the nth type of GraphicsPipe available 00109 // through this interface. 00110 //////////////////////////////////////////////////////////////////// 00111 TypeHandle GraphicsPipeSelection:: 00112 get_pipe_type(int n) const { 00113 load_default_module(); 00114 00115 TypeHandle result; 00116 { 00117 LightMutexHolder holder(_lock); 00118 if (n >= 0 && n < (int)_pipe_types.size()) { 00119 result = _pipe_types[n]._type; 00120 } 00121 } 00122 return result; 00123 } 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: GraphicsPipeSelection::print_pipe_types 00127 // Access: Published 00128 // Description: Writes a list of the currently known GraphicsPipe 00129 // types to nout, for the user's information. 00130 //////////////////////////////////////////////////////////////////// 00131 void GraphicsPipeSelection:: 00132 print_pipe_types() const { 00133 load_default_module(); 00134 00135 LightMutexHolder holder(_lock); 00136 nout << "Known pipe types:" << endl; 00137 PipeTypes::const_iterator pi; 00138 for (pi = _pipe_types.begin(); pi != _pipe_types.end(); ++pi) { 00139 const PipeType &pipe_type = (*pi); 00140 nout << " " << pipe_type._type << "\n"; 00141 } 00142 if (_display_modules.empty()) { 00143 nout << "(all display modules loaded.)\n"; 00144 } else { 00145 nout << "(" << _display_modules.size() 00146 << " aux display modules not yet loaded.)\n"; 00147 } 00148 } 00149 00150 //////////////////////////////////////////////////////////////////// 00151 // Function: GraphicsPipeSelection::make_pipe 00152 // Access: Published 00153 // Description: Creates a new GraphicsPipe of the indicated type (or 00154 // a type more specific than the indicated type, if 00155 // necessary) and returns it. Returns NULL if the type 00156 // cannot be matched. 00157 // 00158 // If the type is not already defined, this will 00159 // implicitly load the named module, or if module_name 00160 // is empty, it will call load_aux_modules(). 00161 //////////////////////////////////////////////////////////////////// 00162 PT(GraphicsPipe) GraphicsPipeSelection:: 00163 make_pipe(const string &type_name, const string &module_name) { 00164 TypeRegistry *type_reg = TypeRegistry::ptr(); 00165 00166 // First, see if the type is already available. 00167 TypeHandle type = type_reg->find_type(type_name); 00168 00169 // If it isn't, try the named module. 00170 if (type == TypeHandle::none()) { 00171 if (!module_name.empty()) { 00172 load_named_module(module_name); 00173 type = type_reg->find_type(type_name); 00174 } 00175 } 00176 00177 // If that didn't help, try the default module. 00178 if (type == TypeHandle::none()) { 00179 load_default_module(); 00180 type = type_reg->find_type(type_name); 00181 } 00182 00183 // Still not enough, try all modules. 00184 if (type == TypeHandle::none()) { 00185 load_aux_modules(); 00186 type = type_reg->find_type(type_name); 00187 } 00188 00189 if (type == TypeHandle::none()) { 00190 return NULL; 00191 } 00192 00193 return make_pipe(type); 00194 } 00195 00196 //////////////////////////////////////////////////////////////////// 00197 // Function: GraphicsPipeSelection::make_pipe 00198 // Access: Published 00199 // Description: Creates a new GraphicsPipe of the indicated type (or 00200 // a type more specific than the indicated type, if 00201 // necessary) and returns it. Returns NULL if the type 00202 // cannot be matched. 00203 //////////////////////////////////////////////////////////////////// 00204 PT(GraphicsPipe) GraphicsPipeSelection:: 00205 make_pipe(TypeHandle type) { 00206 LightMutexHolder holder(_lock); 00207 PipeTypes::const_iterator ti; 00208 00209 // First, look for an exact match of the requested type. 00210 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00211 const PipeType &ptype = (*ti); 00212 if (ptype._type == type) { 00213 // Here's an exact match. 00214 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00215 if (pipe != (GraphicsPipe *)NULL) { 00216 return pipe; 00217 } 00218 } 00219 } 00220 00221 // Now look for a more-specific type. 00222 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00223 const PipeType &ptype = (*ti); 00224 if (ptype._type.is_derived_from(type)) { 00225 // Here's an approximate match. 00226 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00227 if (pipe != (GraphicsPipe *)NULL) { 00228 return pipe; 00229 } 00230 } 00231 } 00232 00233 // Couldn't find any match; load the default module and try again. 00234 load_default_module(); 00235 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00236 const PipeType &ptype = (*ti); 00237 if (ptype._type.is_derived_from(type)) { 00238 // Here's an approximate match. 00239 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00240 if (pipe != (GraphicsPipe *)NULL) { 00241 return pipe; 00242 } 00243 } 00244 } 00245 00246 // Couldn't find a matching pipe type. 00247 return NULL; 00248 } 00249 00250 //////////////////////////////////////////////////////////////////// 00251 // Function: GraphicsPipeSelection::make_module_pipe 00252 // Access: Published 00253 // Description: Returns a new GraphicsPipe of a type defined by the 00254 // indicated module. Returns NULL if the module is not 00255 // found or does not properly recommend a GraphicsPipe. 00256 //////////////////////////////////////////////////////////////////// 00257 PT(GraphicsPipe) GraphicsPipeSelection:: 00258 make_module_pipe(const string &module_name) { 00259 if (display_cat.is_debug()) { 00260 display_cat.debug() 00261 << "make_module_pipe(" << module_name << ")\n"; 00262 } 00263 00264 TypeHandle pipe_type = load_named_module(module_name); 00265 if (pipe_type == TypeHandle::none()) { 00266 return NULL; 00267 } 00268 00269 return make_pipe(pipe_type); 00270 } 00271 00272 //////////////////////////////////////////////////////////////////// 00273 // Function: GraphicsPipeSelection::make_default_pipe 00274 // Access: Published 00275 // Description: Creates a new GraphicsPipe of some arbitrary type. 00276 // The user may specify a preference using the Configrc 00277 // file; otherwise, one will be chosen arbitrarily. 00278 //////////////////////////////////////////////////////////////////// 00279 PT(GraphicsPipe) GraphicsPipeSelection:: 00280 make_default_pipe() { 00281 load_default_module(); 00282 00283 LightMutexHolder holder(_lock); 00284 PipeTypes::const_iterator ti; 00285 00286 if (!_default_pipe_name.empty()) { 00287 // First, look for an exact match of the default type name from 00288 // the Configrc file (excepting case and hyphen/underscore). 00289 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00290 const PipeType &ptype = (*ti); 00291 if (cmp_nocase_uh(ptype._type.get_name(), _default_pipe_name) == 0) { 00292 // Here's an exact match. 00293 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00294 if (pipe != (GraphicsPipe *)NULL) { 00295 return pipe; 00296 } 00297 } 00298 } 00299 00300 // No match; look for a substring match. 00301 string preferred_name = downcase(_default_pipe_name); 00302 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00303 const PipeType &ptype = (*ti); 00304 string ptype_name = downcase(ptype._type.get_name()); 00305 if (ptype_name.find(preferred_name) != string::npos) { 00306 // Here's a substring match. 00307 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00308 if (pipe != (GraphicsPipe *)NULL) { 00309 return pipe; 00310 } 00311 } 00312 } 00313 } 00314 00315 // Couldn't find a matching pipe type; choose the first one on the 00316 // list. 00317 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00318 const PipeType &ptype = (*ti); 00319 PT(GraphicsPipe) pipe = (*ptype._constructor)(); 00320 if (pipe != (GraphicsPipe *)NULL) { 00321 return pipe; 00322 } 00323 } 00324 00325 // Nothing. Probably the list was empty. 00326 return NULL; 00327 } 00328 00329 //////////////////////////////////////////////////////////////////// 00330 // Function: GraphicsPipeSelection::load_aux_modules 00331 // Access: Published 00332 // Description: Loads all the modules named in the aux-display 00333 // Configrc variable, making as many graphics pipes as 00334 // possible available. 00335 //////////////////////////////////////////////////////////////////// 00336 void GraphicsPipeSelection:: 00337 load_aux_modules() { 00338 DisplayModules::iterator di; 00339 for (di = _display_modules.begin(); di != _display_modules.end(); ++di) { 00340 load_named_module(*di); 00341 } 00342 00343 _display_modules.clear(); 00344 _default_module_loaded = true; 00345 } 00346 00347 //////////////////////////////////////////////////////////////////// 00348 // Function: GraphicsPipeSelection::add_pipe_type 00349 // Access: Public 00350 // Description: Adds a new kind of GraphicsPipe to the list of 00351 // available pipes for creation. Normally, this is 00352 // called at static init type by the various shared 00353 // libraries as they are linked in. Returns true on 00354 // success, false on failure. 00355 //////////////////////////////////////////////////////////////////// 00356 bool GraphicsPipeSelection:: 00357 add_pipe_type(TypeHandle type, PipeConstructorFunc *func) { 00358 nassertr(func != NULL, false); 00359 00360 if (!type.is_derived_from(GraphicsPipe::get_class_type())) { 00361 display_cat.warning() 00362 << "Attempt to register " << type << " as a GraphicsPipe type.\n"; 00363 return false; 00364 } 00365 00366 // First, make sure we don't already have a GraphicsPipe of this 00367 // type. 00368 LightMutexHolder holder(_lock); 00369 PipeTypes::const_iterator ti; 00370 for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { 00371 const PipeType &ptype = (*ti); 00372 if (ptype._type == type) { 00373 display_cat.warning() 00374 << "Attempt to register GraphicsPipe type " << type 00375 << " more than once.\n"; 00376 return false; 00377 } 00378 } 00379 00380 if (display_cat.is_debug()) { 00381 display_cat.debug() 00382 << "Registering " << type << " as a GraphicsPipe type.\n"; 00383 } 00384 00385 // Ok, now add a new entry. 00386 _pipe_types.push_back(PipeType(type, func)); 00387 00388 return true; 00389 } 00390 00391 00392 //////////////////////////////////////////////////////////////////// 00393 // Function: GraphicsPipeSelection::do_load_default_module 00394 // Access: Private 00395 // Description: Loads the particular display module listed in the 00396 // load-display Configrc variable, which should default 00397 // the default pipe time. If this string is empty or 00398 // "*", loads all modules named in aux-display. 00399 //////////////////////////////////////////////////////////////////// 00400 void GraphicsPipeSelection:: 00401 do_load_default_module() { 00402 if (_default_display_module.empty()) { 00403 load_aux_modules(); 00404 return; 00405 } 00406 00407 load_named_module(_default_display_module); 00408 00409 DisplayModules::iterator di = 00410 find(_display_modules.begin(), _display_modules.end(), 00411 _default_display_module); 00412 if (di != _display_modules.end()) { 00413 _display_modules.erase(di); 00414 } 00415 00416 _default_module_loaded = true; 00417 00418 if (_pipe_types.empty()) { 00419 // If we still don't have any pipes after loading the default 00420 // module, automatically load the aux modules. 00421 load_aux_modules(); 00422 } 00423 } 00424 00425 //////////////////////////////////////////////////////////////////// 00426 // Function: GraphicsPipeSelection::load_named_module 00427 // Access: Private 00428 // Description: Loads the indicated display module by looking for a 00429 // matching .dll or .so file. Returns the TypeHandle 00430 // recommended by the module, or TypeHandle::none() on 00431 // failure. 00432 //////////////////////////////////////////////////////////////////// 00433 TypeHandle GraphicsPipeSelection:: 00434 load_named_module(const string &name) { 00435 LightMutexHolder holder(_loaded_modules_lock); 00436 00437 LoadedModules::iterator mi = _loaded_modules.find(name); 00438 if (mi != _loaded_modules.end()) { 00439 // We have previously loaded this module. Don't attempt to 00440 // re-load it. 00441 return (*mi).second._default_pipe_type; 00442 } 00443 00444 // We have not yet loaded this module. Load it now. 00445 Filename dlname = Filename::dso_filename("lib" + name + ".so"); 00446 display_cat.info() 00447 << "loading display module: " << dlname.to_os_specific() << endl; 00448 void *handle = load_dso(get_plugin_path().get_value(), dlname); 00449 if (handle == (void *)NULL) { 00450 display_cat.warning() 00451 << "Unable to load: " << load_dso_error() << endl; 00452 return TypeHandle::none(); 00453 } 00454 00455 // Now get the module's recommended pipe type. This requires 00456 // calling a specially-named function that should have been exported 00457 // from the module. 00458 string symbol_name = "get_pipe_type_" + name; 00459 void *dso_symbol = get_dso_symbol(handle, symbol_name); 00460 if (display_cat.is_debug()) { 00461 display_cat.debug() 00462 << "symbol of " << symbol_name << " = " << dso_symbol << "\n"; 00463 } 00464 00465 TypeHandle pipe_type = TypeHandle::none(); 00466 00467 if (dso_symbol == (void *)NULL) { 00468 // Couldn't find the module function. 00469 display_cat.warning() 00470 << "Unable to find " << symbol_name << " in " << dlname.get_basename() 00471 << "\n"; 00472 00473 } else { 00474 // We successfully loaded the module, and we found the 00475 // get_pipe_type_* recommendation function. Call it to figure 00476 // out what pipe type we should expect. 00477 typedef int FuncType(); 00478 int pipe_type_index = (*(FuncType *)dso_symbol)(); 00479 if (display_cat.is_debug()) { 00480 display_cat.debug() 00481 << "pipe_type_index = " << pipe_type_index << "\n"; 00482 } 00483 00484 if (pipe_type_index != 0) { 00485 TypeRegistry *type_reg = TypeRegistry::ptr(); 00486 pipe_type = type_reg->find_type_by_id(pipe_type_index); 00487 if (display_cat.is_debug()) { 00488 display_cat.debug() 00489 << "pipe_type = " << pipe_type << "\n"; 00490 } 00491 } 00492 } 00493 00494 if (pipe_type == TypeHandle::none()) { 00495 // The recommendation function returned a bogus type index, or the 00496 // function didn't work at all. We can't safely unload the 00497 // module, though, because it may have assigned itself into the 00498 // GraphicsPipeSelection table. So we carry on. 00499 display_cat.warning() 00500 << "No default pipe type available for " << dlname.get_basename() 00501 << "\n"; 00502 } 00503 00504 LoadedModule &module = _loaded_modules[name]; 00505 module._module_name = name; 00506 module._module_handle = handle; 00507 module._default_pipe_type = pipe_type; 00508 00509 return pipe_type; 00510 }