diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index 12cc61da8e..cab222aad3 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -29,12 +29,10 @@ #include "geomNodeContext.h" #include "geomContext.h" -Configure(config_display); +ConfigureDef(config_display); NotifyCategoryDef(display, ""); NotifyCategoryDef(gsg, display_cat); -static Config::ConfigTable::Symbol *disp; - ConfigureFn(config_display) { init_libdisplay(); } @@ -59,20 +57,16 @@ const bool pstats_unused_states = config_display.GetBool("pstats-unused-states", // system! const string threading_model = config_display.GetString("threading-model", ""); -// Use this to specify a particular pipe you prefer to use, when more -// than one GraphicsPipe is available (for instance, if both GL and DX -// are linked in). This should be the name of the type preferred, or -// a substring unique to the type name. -const string preferred_pipe = config_display.GetString("preferred-pipe", ""); +// Use the variable load-display to specifiy the name of the default +// graphics display library or GraphicsPipe to load. It is the name +// of a shared library (or * for all libraries named in aux-display), +// optionally followed by the name of the particular GraphicsPipe +// class to create. +// Also use the variable aux-display to name each of the graphics +// display libraries that are available on a particular platform. +// This variable may be repeated several times. -Config::ConfigTable::Symbol::iterator display_modules_begin(void) { - return disp->begin(); -} - -Config::ConfigTable::Symbol::iterator display_modules_end(void) { - return disp->end(); -} //////////////////////////////////////////////////////////////////// // Function: init_libdisplay @@ -102,7 +96,4 @@ init_libdisplay() { TextureContext::init_type(); GeomNodeContext::init_type(); GeomContext::init_type(); - - disp = new Config::ConfigTable::Symbol; - config_display.GetAll("load-display", *disp); } diff --git a/panda/src/display/config_display.h b/panda/src/display/config_display.h index 14cb2f2c72..6d7bfe346d 100644 --- a/panda/src/display/config_display.h +++ b/panda/src/display/config_display.h @@ -26,6 +26,7 @@ #include #include "pvector.h" +ConfigureDecl(config_display, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(display, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(gsg, EXPCL_PANDA, EXPTP_PANDA); @@ -33,10 +34,6 @@ extern const bool view_frustum_cull; extern const bool pstats_unused_states; extern const string threading_model; -extern const string preferred_pipe; - -extern Config::ConfigTable::Symbol::iterator display_modules_begin(void); -extern Config::ConfigTable::Symbol::iterator display_modules_end(void); extern EXPCL_PANDA void init_libdisplay(); diff --git a/panda/src/display/graphicsPipe.I b/panda/src/display/graphicsPipe.I index a6d4aae8f3..3da9d91ba6 100644 --- a/panda/src/display/graphicsPipe.I +++ b/panda/src/display/graphicsPipe.I @@ -16,3 +16,21 @@ // //////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsPipe::is_valid +// Access: Published +// Description: Returns false if this pipe is known to be invalid, +// meaning that an attempt to create a GraphicsWindow +// with the pipe will certainly fail. Returns true if +// the pipe is probably valid (is this case, an attempt +// to create a GraphicsWindow should succeed, but might +// still fail). +// +// Use the GraphicsEngine class to create a +// GraphicsWindow on a particular pipe. +//////////////////////////////////////////////////////////////////// +INLINE bool GraphicsPipe:: +is_valid() const { + return _is_valid; +} diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index e763cd1943..3b1be1a8cd 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -29,6 +29,9 @@ TypeHandle GraphicsPipe::_type_handle; //////////////////////////////////////////////////////////////////// GraphicsPipe:: GraphicsPipe() { + // Initially, we assume the GraphicsPipe is valid. A derived class + // should set this to false if it determines otherwise. + _is_valid = true; } //////////////////////////////////////////////////////////////////// @@ -38,6 +41,7 @@ GraphicsPipe() { //////////////////////////////////////////////////////////////////// GraphicsPipe:: GraphicsPipe(const GraphicsPipe &) { + _is_valid = false; nassertv(false); } diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index 11c4dc9e18..9690c8ee2c 100644 --- a/panda/src/display/graphicsPipe.h +++ b/panda/src/display/graphicsPipe.h @@ -59,11 +59,18 @@ PUBLISHED: int get_num_windows() const; PT(GraphicsWindow) get_window(int n) const; + INLINE bool is_valid() const; + virtual string get_interface_name() const=0; + public: virtual int get_num_hw_channels(); virtual HardwareChannel *get_hw_channel(GraphicsWindow *window, int index); protected: + // The make_window() interface on GraphicsPipe is protected; don't + // try to call it directly. Instead, use + // GraphicsEngine::make_window() to make a new window on a + // particular pipe. virtual PT(GraphicsWindow) make_window()=0; void add_window(GraphicsWindow *window); @@ -73,6 +80,7 @@ protected: Windows _windows; Mutex _lock; + bool _is_valid; public: static TypeHandle get_class_type() { diff --git a/panda/src/display/graphicsPipeSelection.I b/panda/src/display/graphicsPipeSelection.I index e02bf68e4d..f6b9f4e124 100644 --- a/panda/src/display/graphicsPipeSelection.I +++ b/panda/src/display/graphicsPipeSelection.I @@ -16,18 +16,17 @@ // //////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////// -// Function: GraphicsPipeSelection::resolve_modules +// Function: GraphicsPipeSelection::get_num_aux_modules // Access: Published -// Description: Conditionally calls do_resolve_modules(), if it has -// not been called before. +// Description: Returns the number of display modules that are still +// to be loaded. If this is nonzero, then calling +// load_aux_modules() will likely increase the number of +// GraphicsPipes available. //////////////////////////////////////////////////////////////////// -INLINE void GraphicsPipeSelection:: -resolve_modules() const { - if (!_resolved_modules) { - ((GraphicsPipeSelection *)this)->do_resolve_modules(); - } +INLINE int GraphicsPipeSelection:: +get_num_aux_modules() const { + return _display_modules.size(); } //////////////////////////////////////////////////////////////////// @@ -44,6 +43,19 @@ get_global_ptr() { return _global_ptr; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsPipeSelection::load_default_module +// Access: Private +// Description: Conditionally calls do_load_default_module(), if it has +// not been called before. +//////////////////////////////////////////////////////////////////// +INLINE void GraphicsPipeSelection:: +load_default_module() const { + if (!_default_module_loaded) { + ((GraphicsPipeSelection *)this)->do_load_default_module(); + } +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsPipeSelection::PipeType::Constructor // Access: Public diff --git a/panda/src/display/graphicsPipeSelection.cxx b/panda/src/display/graphicsPipeSelection.cxx index 591b351532..b5ec8c326a 100644 --- a/panda/src/display/graphicsPipeSelection.cxx +++ b/panda/src/display/graphicsPipeSelection.cxx @@ -32,7 +32,43 @@ GraphicsPipeSelection *GraphicsPipeSelection::_global_ptr = NULL; //////////////////////////////////////////////////////////////////// GraphicsPipeSelection:: GraphicsPipeSelection() { - _resolved_modules = false; + // Get the set of modules named in the various aux-display Configrc + // variables. We'll want to know this when we call load_modules() + // later. + Config::ConfigTable::Symbol disp; + config_display.GetAll("aux-display", disp); + + Config::ConfigTable::Symbol::iterator ci; + for (ci = disp.begin(); ci != disp.end(); ++ci) { + _display_modules.insert((*ci).Val()); + } + + // Also get the name of the default module from the load-display + // variable. We get this explicitly from Configrc now (instead of + // retrieving it in config_display), in case this constructor is + // running at static init time. + string load_display = config_display.GetString("load-display", ""); + load_display = trim_right(load_display); + size_t space = load_display.rfind(' '); + if (space != string::npos) { + // If there's a space, it indicates the name of the GraphicsPipe + // class to prefer. + _default_pipe_name = load_display.substr(space + 1); + load_display = trim_right(load_display.substr(0, space)); + } + + // Everything else is the name of the .dll (or .so) file to load. + _default_display_module = load_display; + + if (_default_display_module == "*") { + // '*' or empty string is the key for all display modules. + _default_display_module = string(); + + } else if (!_default_display_module.empty()) { + _display_modules.insert(_default_display_module); + } + + _default_module_loaded = false; } //////////////////////////////////////////////////////////////////// @@ -53,7 +89,7 @@ GraphicsPipeSelection:: //////////////////////////////////////////////////////////////////// int GraphicsPipeSelection:: get_num_pipe_types() const { - resolve_modules(); + load_default_module(); int result; { @@ -71,7 +107,7 @@ get_num_pipe_types() const { //////////////////////////////////////////////////////////////////// TypeHandle GraphicsPipeSelection:: get_pipe_type(int n) const { - resolve_modules(); + load_default_module(); TypeHandle result; { @@ -83,6 +119,31 @@ get_pipe_type(int n) const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsPipeSelection::print_pipe_types +// Access: Published +// Description: Writes a list of the currently known GraphicsPipe +// types to nout, for the user's information. +//////////////////////////////////////////////////////////////////// +void GraphicsPipeSelection:: +print_pipe_types() const { + load_default_module(); + + MutexHolder holder(_lock); + nout << "Known pipe types:" << endl; + PipeTypes::const_iterator pi; + for (pi = _pipe_types.begin(); pi != _pipe_types.end(); ++pi) { + const PipeType &pipe_type = (*pi); + nout << " " << pipe_type._type << "\n"; + } + if (_display_modules.empty()) { + nout << "(all display modules loaded.)\n"; + } else { + nout << "(" << _display_modules.size() + << " aux display modules not yet loaded.)\n"; + } +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsPipeSelection::make_pipe // Access: Published @@ -93,7 +154,7 @@ get_pipe_type(int n) const { //////////////////////////////////////////////////////////////////// PT(GraphicsPipe) GraphicsPipeSelection:: make_pipe(TypeHandle type) { - resolve_modules(); + load_default_module(); MutexHolder holder(_lock); PipeTypes::const_iterator ti; @@ -135,38 +196,40 @@ make_pipe(TypeHandle type) { //////////////////////////////////////////////////////////////////// PT(GraphicsPipe) GraphicsPipeSelection:: make_default_pipe() { - resolve_modules(); + load_default_module(); MutexHolder holder(_lock); PipeTypes::const_iterator ti; - // First, look for an exact match of the requested type (excepting - // case and hyphen/underscore). - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); - if (cmp_nocase_uh(ptype._type.get_name(), preferred_pipe) == 0) { - // Here's an exact match. - PT(GraphicsPipe) pipe = (*ptype._constructor)(); - if (pipe != (GraphicsPipe *)NULL) { - return pipe; + if (!_default_pipe_name.empty()) { + // First, look for an exact match of the requested type (excepting + // case and hyphen/underscore). + for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { + const PipeType &ptype = (*ti); + if (cmp_nocase_uh(ptype._type.get_name(), _default_pipe_name) == 0) { + // Here's an exact match. + PT(GraphicsPipe) pipe = (*ptype._constructor)(); + if (pipe != (GraphicsPipe *)NULL) { + return pipe; + } + } + } + + // No match; look for a substring match. + string preferred_name = downcase(_default_pipe_name); + for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { + const PipeType &ptype = (*ti); + string ptype_name = downcase(ptype._type.get_name()); + if (ptype_name.find(preferred_name) != string::npos) { + // Here's a substring match. + PT(GraphicsPipe) pipe = (*ptype._constructor)(); + if (pipe != (GraphicsPipe *)NULL) { + return pipe; + } } } } - - // No match; look for a substring match. - string preferred_name = downcase(preferred_pipe); - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); - string ptype_name = downcase(ptype._type.get_name()); - if (ptype_name.find(preferred_name) != string::npos) { - // Here's a substring match. - PT(GraphicsPipe) pipe = (*ptype._constructor)(); - if (pipe != (GraphicsPipe *)NULL) { - return pipe; - } - } - } - + // Couldn't find a matching pipe type; choose one arbitrarily. for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { const PipeType &ptype = (*ti); @@ -180,6 +243,24 @@ make_default_pipe() { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsPipeSelection::load_aux_modules +// Access: Published +// Description: Loads all the modules named in the aux-display +// Configrc variable, making as many graphics pipes as +// possible available. +//////////////////////////////////////////////////////////////////// +void GraphicsPipeSelection:: +load_aux_modules() { + DisplayModules::iterator di; + for (di = _display_modules.begin(); di != _display_modules.end(); ++di) { + load_named_module(*di); + } + + _display_modules.clear(); + _default_module_loaded = true; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsPipeSelection::add_pipe_type // Access: Public @@ -217,35 +298,42 @@ add_pipe_type(TypeHandle type, PipeConstructorFunc *func) { return true; } + //////////////////////////////////////////////////////////////////// -// Function: GraphicsPipeSelection::do_resolve_modules +// Function: GraphicsPipeSelection::do_load_default_module // Access: Private -// Description: Loads the shared objects listed in the load-display -// Configrc variable, which should make all of the -// dynamic GraphicsPipes available. +// Description: Loads the particular display module listed in the +// load-display Configrc variable, which should default +// the default pipe time. If this string is empty or +// "*", loads all modules named in aux-display. //////////////////////////////////////////////////////////////////// void GraphicsPipeSelection:: -do_resolve_modules() { - Config::ConfigTable::Symbol::iterator ci; +do_load_default_module() { + _default_module_loaded = true; - // Build up a set of the modules we've already loaded as we go, so - // we don't attempt to load a given module more than once. - pset already_loaded; - - for (ci = display_modules_begin(); ci != display_modules_end(); ++ci) { - string name = (*ci).Val(); - if (already_loaded.insert(name).second) { - Filename dlname = Filename::dso_filename("lib" + name + ".so"); - display_cat.info() - << "loading display module: " << dlname.to_os_specific() << endl; - void *tmp = load_dso(dlname); - if (tmp == (void *)NULL) { - display_cat.info() - << "Unable to load: " << load_dso_error() << endl; - } - } + if (_default_display_module.empty()) { + load_aux_modules(); + return; } - _resolved_modules = true; + load_named_module(_default_display_module); + _display_modules.erase(_default_display_module); } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsPipeSelection::load_named_module +// Access: Private +// Description: Loads the indicated display module by looking for a +// matching .dll or .so file. +//////////////////////////////////////////////////////////////////// +void GraphicsPipeSelection:: +load_named_module(const string &name) { + Filename dlname = Filename::dso_filename("lib" + name + ".so"); + display_cat.info() + << "loading display module: " << dlname.to_os_specific() << endl; + void *tmp = load_dso(dlname); + if (tmp == (void *)NULL) { + display_cat.info() + << "Unable to load: " << load_dso_error() << endl; + } +} diff --git a/panda/src/display/graphicsPipeSelection.h b/panda/src/display/graphicsPipeSelection.h index 05b8d6d6b9..e35a19c826 100644 --- a/panda/src/display/graphicsPipeSelection.h +++ b/panda/src/display/graphicsPipeSelection.h @@ -51,11 +51,13 @@ protected: PUBLISHED: int get_num_pipe_types() const; TypeHandle get_pipe_type(int n) const; + void print_pipe_types() const; PT(GraphicsPipe) make_pipe(TypeHandle type); PT(GraphicsPipe) make_default_pipe(); - INLINE void resolve_modules() const; + INLINE int get_num_aux_modules() const; + void load_aux_modules(); INLINE static GraphicsPipeSelection *get_global_ptr(); @@ -64,7 +66,9 @@ public: bool add_pipe_type(TypeHandle type, PipeConstructorFunc *func); private: - void do_resolve_modules(); + INLINE void load_default_module() const; + void do_load_default_module(); + void load_named_module(const string &name); class PipeType { public: @@ -74,9 +78,14 @@ private: }; typedef pvector PipeTypes; PipeTypes _pipe_types; - bool _resolved_modules; Mutex _lock; + typedef pset DisplayModules; + DisplayModules _display_modules; + string _default_display_module; + string _default_pipe_name; + bool _default_module_loaded; + static GraphicsPipeSelection *_global_ptr; };