From 091cc39db3fc1cec17a487f33596c49c9bb3a926 Mon Sep 17 00:00:00 2001 From: "Matias N. Goldberg" Date: Thu, 23 Dec 2021 19:16:27 -0300 Subject: [PATCH] Support optionally skipping plugins that failed to load Plugins.cfg file must use "PluginOptional" instead of "Plugin" This feature is needed for Vulkan as old GPUs will crash the whole engine if the driver or the GPU is too old --- CMake/Templates/plugins.cfg.in | 12 +- CMake/Templates/plugins_d.cfg.in | 12 +- OgreMain/include/OgreDynLib.h | 6 +- OgreMain/include/OgreDynLibManager.h | 4 +- OgreMain/include/OgreRoot.h | 3 +- OgreMain/src/OgreDynLib.cpp | 46 ++++--- OgreMain/src/OgreDynLibManager.cpp | 10 +- OgreMain/src/OgreRoot.cpp | 126 ++++++++++++------ PlugIns/ParticleFX/src/OgreParticleFX.cpp | 7 +- .../Direct3D11/src/OgreD3D11EngineDll.cpp | 6 +- .../GL3Plus/src/OgreGL3PlusEngineDll.cpp | 6 +- RenderSystems/Metal/src/OgreMetalEngineDll.mm | 6 +- RenderSystems/NULL/src/OgreNULLEngineDll.cpp | 6 +- .../Vulkan/src/OgreVulkanEngineDll.cpp | 6 +- .../CMake/Dependencies/OGRE.cmake | 4 +- 15 files changed, 173 insertions(+), 87 deletions(-) diff --git a/CMake/Templates/plugins.cfg.in b/CMake/Templates/plugins.cfg.in index 3f160cf9ba2..c1ba1c4ef97 100644 --- a/CMake/Templates/plugins.cfg.in +++ b/CMake/Templates/plugins.cfg.in @@ -4,11 +4,11 @@ PluginFolder=@OGRE_PLUGIN_DIR_REL@ # Define plugins -@OGRE_COMMENT_RENDERSYSTEM_METAL@ Plugin=RenderSystem_Metal -@OGRE_COMMENT_RENDERSYSTEM_D3D11@ Plugin=RenderSystem_Direct3D11 -@OGRE_COMMENT_RENDERSYSTEM_GL3PLUS@ Plugin=RenderSystem_GL3Plus -@OGRE_COMMENT_RENDERSYSTEM_GLES@ Plugin=RenderSystem_GLES -@OGRE_COMMENT_RENDERSYSTEM_GLES2@ Plugin=RenderSystem_GLES2 +@OGRE_COMMENT_RENDERSYSTEM_METAL@ PluginOptional=RenderSystem_Metal +@OGRE_COMMENT_RENDERSYSTEM_D3D11@ PluginOptional=RenderSystem_Direct3D11 +@OGRE_COMMENT_RENDERSYSTEM_GL3PLUS@ PluginOptional=RenderSystem_GL3Plus +@OGRE_COMMENT_RENDERSYSTEM_GLES@ PluginOptional=RenderSystem_GLES +@OGRE_COMMENT_RENDERSYSTEM_GLES2@ PluginOptional=RenderSystem_GLES2 # If you add another RenderSystem make sure Vulkan is the last one or you might encounter issues on nVidia cards. -@OGRE_COMMENT_RENDERSYSTEM_VULKAN@ Plugin=RenderSystem_Vulkan +@OGRE_COMMENT_RENDERSYSTEM_VULKAN@ PluginOptional=RenderSystem_Vulkan @OGRE_COMMENT_PLUGIN_PARTICLEFX@ Plugin=Plugin_ParticleFX diff --git a/CMake/Templates/plugins_d.cfg.in b/CMake/Templates/plugins_d.cfg.in index bcc3e1c2a3b..1011519dbb7 100644 --- a/CMake/Templates/plugins_d.cfg.in +++ b/CMake/Templates/plugins_d.cfg.in @@ -4,11 +4,11 @@ PluginFolder=@OGRE_PLUGIN_DIR_DBG@ # Define plugins -@OGRE_COMMENT_RENDERSYSTEM_D3D11@ Plugin=RenderSystem_Direct3D11_d -@OGRE_COMMENT_RENDERSYSTEM_GL3PLUS@ Plugin=RenderSystem_GL3Plus_d -@OGRE_COMMENT_RENDERSYSTEM_GLES@ Plugin=RenderSystem_GLES_d -@OGRE_COMMENT_RENDERSYSTEM_GLES2@ Plugin=RenderSystem_GLES2_d -@OGRE_COMMENT_RENDERSYSTEM_METAL@ Plugin=RenderSystem_Metal_d +@OGRE_COMMENT_RENDERSYSTEM_D3D11@ PluginOptional=RenderSystem_Direct3D11_d +@OGRE_COMMENT_RENDERSYSTEM_GL3PLUS@ PluginOptional=RenderSystem_GL3Plus_d +@OGRE_COMMENT_RENDERSYSTEM_GLES@ PluginOptional=RenderSystem_GLES_d +@OGRE_COMMENT_RENDERSYSTEM_GLES2@ PluginOptional=RenderSystem_GLES2_d +@OGRE_COMMENT_RENDERSYSTEM_METAL@ PluginOptional=RenderSystem_Metal_d # If you add another RenderSystem make sure Vulkan is the last one or you might encounter issues on nVidia cards. -@OGRE_COMMENT_RENDERSYSTEM_VULKAN@ Plugin=RenderSystem_Vulkan_d +@OGRE_COMMENT_RENDERSYSTEM_VULKAN@ PluginOptional=RenderSystem_Vulkan_d @OGRE_COMMENT_PLUGIN_PARTICLEFX@ Plugin=Plugin_ParticleFX_d diff --git a/OgreMain/include/OgreDynLib.h b/OgreMain/include/OgreDynLib.h index 139229fcb42..07dd6dfdec6 100644 --- a/OgreMain/include/OgreDynLib.h +++ b/OgreMain/include/OgreDynLib.h @@ -99,14 +99,18 @@ namespace Ogre { ~DynLib(); /** Load the library + @param bOptional When true, we will skip it if it fails to initialize */ - void load(); + void load( const bool bOptional ); /** Unload the library */ void unload(); /// Get the name of the library const String& getName(void) const { return mName; } + /// Returns true if it's successfully loaded + bool isLoaded(void) const; + /** Returns the address of the given symbol from the loaded library. @param diff --git a/OgreMain/include/OgreDynLibManager.h b/OgreMain/include/OgreDynLibManager.h index 127411c4348..9e43cf608b4 100644 --- a/OgreMain/include/OgreDynLibManager.h +++ b/OgreMain/include/OgreDynLibManager.h @@ -72,8 +72,10 @@ namespace Ogre { /** Loads the passed library. @param filename The name of the library. The extension can be omitted. + @param bOptional + When true, we will skip it if it fails to initialize */ - DynLib* load(const String& filename); + DynLib *load( const String &filename, const bool bOptional ); /** Unloads the passed library. @param lib diff --git a/OgreMain/include/OgreRoot.h b/OgreMain/include/OgreRoot.h index 1714d29700b..5ce441d0fb9 100644 --- a/OgreMain/include/OgreRoot.h +++ b/OgreMain/include/OgreRoot.h @@ -711,8 +711,9 @@ namespace Ogre method which instantiates a Plugin subclass and calls Root::installPlugin. It should also implement dllStopPlugin (see Root::unloadPlugin) @param pluginName Name of the plugin library to load + @param bOptional When true, we will skip it if it fails to initialize */ - void loadPlugin(const String& pluginName); + void loadPlugin(const String& pluginName, const bool bOptional); /** Manually unloads a Plugin contained in a DLL / DSO. @remarks diff --git a/OgreMain/src/OgreDynLib.cpp b/OgreMain/src/OgreDynLib.cpp index 3802292218b..4457089e26a 100644 --- a/OgreMain/src/OgreDynLib.cpp +++ b/OgreMain/src/OgreDynLib.cpp @@ -68,7 +68,7 @@ namespace Ogre { } //----------------------------------------------------------------------- - void DynLib::load() + void DynLib::load( const bool bOptional ) { // Log library load LogManager::getSingleton().logMessage("Loading library " + mName); @@ -105,11 +105,21 @@ namespace Ogre { } #endif if( !mInst ) - OGRE_EXCEPT( - Exception::ERR_INTERNAL_ERROR, - "Could not load dynamic library " + mName + - ". System Error: " + dynlibError(), - "DynLib::load" ); + { + if( !bOptional ) + { + OGRE_EXCEPT( + Exception::ERR_INTERNAL_ERROR, + "Could not load dynamic library " + mName + ". System Error: " + dynlibError(), + "DynLib::load" ); + } + else + { + LogManager::getSingleton().logMessage( "Could not load optional dynamic library " + + mName + ". System Error: " + dynlibError(), + LML_CRITICAL ); + } + } } //----------------------------------------------------------------------- @@ -118,17 +128,19 @@ namespace Ogre { // Log library unload LogManager::getSingleton().logMessage("Unloading library " + mName); - if( DYNLIB_UNLOAD( mInst ) ) + if( mInst ) { - OGRE_EXCEPT( - Exception::ERR_INTERNAL_ERROR, - "Could not unload dynamic library " + mName + - ". System Error: " + dynlibError(), - "DynLib::unload"); + if( DYNLIB_UNLOAD( mInst ) ) + { + OGRE_EXCEPT( + Exception::ERR_INTERNAL_ERROR, + "Could not unload dynamic library " + mName + ". System Error: " + dynlibError(), + "DynLib::unload" ); + } } - } - + //----------------------------------------------------------------------- + bool DynLib::isLoaded( void ) const { return mInst != NULL; } //----------------------------------------------------------------------- void* DynLib::getSymbol( const String& strName ) const throw() { @@ -185,7 +197,11 @@ namespace Ogre { #endif return ret; #elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_FREEBSD - return String(dlerror()); + const char *errorStr = dlerror(); + if( errorStr ) + return String( errorStr ); + else + return String( "" ); #else return String(""); #endif diff --git a/OgreMain/src/OgreDynLibManager.cpp b/OgreMain/src/OgreDynLibManager.cpp index 0661ff3b64c..9ce4bb9309e 100644 --- a/OgreMain/src/OgreDynLibManager.cpp +++ b/OgreMain/src/OgreDynLibManager.cpp @@ -49,17 +49,17 @@ namespace Ogre { } //----------------------------------------------------------------------- - DynLib* DynLibManager::load( const String& filename) + DynLib *DynLibManager::load( const String &filename, const bool bOptional ) { - DynLibList::iterator i = mLibList.find(filename); - if (i != mLibList.end()) + DynLibList::iterator i = mLibList.find( filename ); + if( i != mLibList.end() ) { return i->second; } else { - DynLib* pLib = OGRE_NEW DynLib(filename); - pLib->load(); + DynLib *pLib = OGRE_NEW DynLib( filename ); + pLib->load( bOptional ); mLibList[filename] = pLib; return pLib; } diff --git a/OgreMain/src/OgreRoot.cpp b/OgreMain/src/OgreRoot.cpp index d4b2f665255..6bfae2df1fb 100644 --- a/OgreMain/src/OgreRoot.cpp +++ b/OgreMain/src/OgreRoot.cpp @@ -1203,23 +1203,22 @@ namespace Ogre { //----------------------------------------------------------------------- void Root::loadPlugins( const String& pluginsfile ) { - StringVector pluginList; - String pluginDir; ConfigFile cfg; - try { + try + { cfg.load( pluginsfile ); } - catch (Exception) + catch( Exception ) { - LogManager::getSingleton().logMessage(pluginsfile + " not found, automatic plugin loading disabled."); + LogManager::getSingleton().logMessage( pluginsfile + + " not found, automatic plugin loading disabled." ); return; } - pluginDir = cfg.getSetting("PluginFolder"); // Ignored on Mac OS X, uses Resources/ directory - pluginList = cfg.getMultiSetting("Plugin"); - - if (!pluginDir.empty() && *pluginDir.rbegin() != '/' && *pluginDir.rbegin() != '\\') + String pluginDir = + cfg.getSetting( "PluginFolder" ); // Ignored on Mac OS X, uses Resources/ directory + if( !pluginDir.empty() && *pluginDir.rbegin() != '/' && *pluginDir.rbegin() != '\\' ) { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WINRT pluginDir += "\\"; @@ -1228,11 +1227,22 @@ namespace Ogre { #endif } - for( StringVector::iterator it = pluginList.begin(); it != pluginList.end(); ++it ) { - loadPlugin(pluginDir + (*it)); + // First load optional plugins (which tend to be all RenderSystems) + const StringVector pluginList = cfg.getMultiSetting( "PluginOptional" ); + for( StringVector::const_iterator it = pluginList.begin(); it != pluginList.end(); ++it ) + { + loadPlugin( pluginDir + ( *it ), true ); + } + } + { + // Then load non-optional plugins (which tend to depend on RenderSystems) + const StringVector pluginList = cfg.getMultiSetting( "Plugin" ); + for( StringVector::const_iterator it = pluginList.begin(); it != pluginList.end(); ++it ) + { + loadPlugin( pluginDir + ( *it ), false ); + } } - } //----------------------------------------------------------------------- void Root::shutdownPlugins(void) @@ -1256,18 +1266,21 @@ namespace Ogre { { #if OGRE_PLATFORM != OGRE_PLATFORM_NACL && OGRE_PLATFORM != OGRE_PLATFORM_EMSCRIPTEN // unload dynamic libs first - for (PluginLibList::reverse_iterator i = mPluginLibs.rbegin(); i != mPluginLibs.rend(); ++i) + for( PluginLibList::reverse_iterator i = mPluginLibs.rbegin(); i != mPluginLibs.rend(); ++i ) { - // Call plugin shutdown - #ifdef __GNUC__ - __extension__ - #endif - DLL_STOP_PLUGIN pFunc = reinterpret_cast((*i)->getSymbol("dllStopPlugin")); - // this will call uninstallPlugin - pFunc(); + if( ( *i )->isLoaded() ) + { + // Call plugin shutdown +# ifdef __GNUC__ + __extension__ +# endif + DLL_STOP_PLUGIN pFunc = + reinterpret_cast( ( *i )->getSymbol( "dllStopPlugin" ) ); + // this will call uninstallPlugin + pFunc(); + } // Unload library & destroy - DynLibManager::getSingleton().unload(*i); - + DynLibManager::getSingleton().unload( *i ); } mPluginLibs.clear(); @@ -1459,29 +1472,52 @@ namespace Ogre { } //----------------------------------------------------------------------- - void Root::loadPlugin(const String& pluginName) + void Root::loadPlugin( const String &pluginName, const bool bOptional ) { #if OGRE_PLATFORM != OGRE_PLATFORM_NACL && OGRE_PLATFORM != OGRE_PLATFORM_EMSCRIPTEN // Load plugin library - DynLib* lib = DynLibManager::getSingleton().load( pluginName ); + DynLib* lib = DynLibManager::getSingleton().load( pluginName, bOptional ); + // Store for later unload // Check for existence, because if called 2+ times DynLibManager returns existing entry if (std::find(mPluginLibs.begin(), mPluginLibs.end(), lib) == mPluginLibs.end()) { mPluginLibs.push_back(lib); - // Call startup function - #ifdef __GNUC__ - __extension__ - #endif - DLL_START_PLUGIN pFunc = (DLL_START_PLUGIN)lib->getSymbol("dllStartPlugin"); + if( lib->isLoaded() ) + { + // Call startup function +# ifdef __GNUC__ + __extension__ +# endif + DLL_START_PLUGIN pFunc = (DLL_START_PLUGIN)lib->getSymbol( "dllStartPlugin" ); - if (!pFunc) - OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Cannot find symbol dllStartPlugin in library " + pluginName, - "Root::loadPlugin"); + if( !pFunc ) + { + OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, + "Cannot find symbol dllStartPlugin in library " + pluginName, + "Root::loadPlugin" ); + } - // This must call installPlugin - pFunc(); + try + { + // This must call installPlugin + pFunc(); + } + catch( Exception &e ) + { + if( !bOptional ) + { + throw; + } + else + { + LogManager::getSingleton().logMessage( + "Optional Plugin " + pluginName + " failed with exception:", LML_CRITICAL ); + LogManager::getSingleton().logMessage( e.getFullDescription(), LML_CRITICAL ); + } + } + } } #endif } @@ -1495,19 +1531,21 @@ namespace Ogre { { if ((*i)->getName() == pluginName) { - // Call plugin shutdown - #ifdef __GNUC__ - __extension__ - #endif - DLL_STOP_PLUGIN pFunc = (DLL_STOP_PLUGIN)(*i)->getSymbol("dllStopPlugin"); - // this must call uninstallPlugin - pFunc(); + if( ( *i )->isLoaded() ) + { + // Call plugin shutdown +# ifdef __GNUC__ + __extension__ +# endif + DLL_STOP_PLUGIN pFunc = ( DLL_STOP_PLUGIN )( *i )->getSymbol( "dllStopPlugin" ); + // this must call uninstallPlugin + pFunc(); + } // Unload library (destroyed by DynLibManager) - DynLibManager::getSingleton().unload(*i); - mPluginLibs.erase(i); + DynLibManager::getSingleton().unload( *i ); + mPluginLibs.erase( i ); return; } - } #endif } diff --git a/PlugIns/ParticleFX/src/OgreParticleFX.cpp b/PlugIns/ParticleFX/src/OgreParticleFX.cpp index e0fd2391672..552b8dfb2a2 100644 --- a/PlugIns/ParticleFX/src/OgreParticleFX.cpp +++ b/PlugIns/ParticleFX/src/OgreParticleFX.cpp @@ -35,7 +35,12 @@ namespace Ogre { ParticleFXPlugin* plugin; //----------------------------------------------------------------------- - extern "C" void _OgreParticleFXExport dllStartPlugin(void) throw() + +# if __cplusplus >= 201103L + extern "C" void _OgreParticleFXExport dllStartPlugin( void ) noexcept( false ) +# else + extern "C" void _OgreParticleFXExport dllStartPlugin( void ) throw( Exception ) +# endif { plugin = OGRE_NEW ParticleFXPlugin(); Root::getSingleton().installPlugin(plugin); diff --git a/RenderSystems/Direct3D11/src/OgreD3D11EngineDll.cpp b/RenderSystems/Direct3D11/src/OgreD3D11EngineDll.cpp index 494f06524af..c2d7e36257d 100644 --- a/RenderSystems/Direct3D11/src/OgreD3D11EngineDll.cpp +++ b/RenderSystems/Direct3D11/src/OgreD3D11EngineDll.cpp @@ -33,7 +33,11 @@ namespace Ogre { D3D11Plugin* plugin; - extern "C" void _OgreD3D11Export dllStartPlugin(void) throw() +# if __cplusplus >= 201103L + extern "C" void _OgreD3D11Export dllStartPlugin( void ) noexcept( false ) +# else + extern "C" void _OgreD3D11Export dllStartPlugin( void ) throw( Exception ) +# endif { plugin = new D3D11Plugin(); Root::getSingleton().installPlugin(plugin); diff --git a/RenderSystems/GL3Plus/src/OgreGL3PlusEngineDll.cpp b/RenderSystems/GL3Plus/src/OgreGL3PlusEngineDll.cpp index d1e6036bd81..783b77b288a 100644 --- a/RenderSystems/GL3Plus/src/OgreGL3PlusEngineDll.cpp +++ b/RenderSystems/GL3Plus/src/OgreGL3PlusEngineDll.cpp @@ -35,7 +35,11 @@ namespace Ogre { static GL3PlusPlugin* plugin; - extern "C" void _OgreGL3PlusExport dllStartPlugin(void) throw() +# if __cplusplus >= 201103L + extern "C" void _OgreGL3PlusExport dllStartPlugin( void ) noexcept( false ) +# else + extern "C" void _OgreD3D11Export dllStartPlugin( void ) throw( Exception ) +# endif { plugin = OGRE_NEW GL3PlusPlugin(); Root::getSingleton().installPlugin(plugin); diff --git a/RenderSystems/Metal/src/OgreMetalEngineDll.mm b/RenderSystems/Metal/src/OgreMetalEngineDll.mm index b1fc3580b2c..d8173d1fddd 100644 --- a/RenderSystems/Metal/src/OgreMetalEngineDll.mm +++ b/RenderSystems/Metal/src/OgreMetalEngineDll.mm @@ -36,7 +36,11 @@ of this software and associated documentation files (the "Software"), to deal { static MetalPlugin* plugin; - extern "C" void _OgreMetalExport dllStartPlugin(void) throw() +# if __cplusplus >= 201103L + extern "C" void _OgreMetalExport dllStartPlugin( void ) noexcept( false ) +# else + extern "C" void _OgreMetalExport dllStartPlugin( void ) throw( Exception ) +# endif { plugin = OGRE_NEW MetalPlugin(); Root::getSingleton().installPlugin(plugin); diff --git a/RenderSystems/NULL/src/OgreNULLEngineDll.cpp b/RenderSystems/NULL/src/OgreNULLEngineDll.cpp index 9f93cd2f82c..9990b75cfeb 100644 --- a/RenderSystems/NULL/src/OgreNULLEngineDll.cpp +++ b/RenderSystems/NULL/src/OgreNULLEngineDll.cpp @@ -35,7 +35,11 @@ namespace Ogre { static NULLPlugin* plugin; - extern "C" void _OgreNULLExport dllStartPlugin(void) throw() +# if __cplusplus >= 201103L + extern "C" void _OgreNULLExport dllStartPlugin( void ) noexcept( false ) +# else + extern "C" void _OgreNULLExport dllStartPlugin( void ) throw( Exception ) +# endif { plugin = OGRE_NEW NULLPlugin(); Root::getSingleton().installPlugin(plugin); diff --git a/RenderSystems/Vulkan/src/OgreVulkanEngineDll.cpp b/RenderSystems/Vulkan/src/OgreVulkanEngineDll.cpp index 0ed9d6d2447..2b846e4dc53 100644 --- a/RenderSystems/Vulkan/src/OgreVulkanEngineDll.cpp +++ b/RenderSystems/Vulkan/src/OgreVulkanEngineDll.cpp @@ -35,7 +35,11 @@ namespace Ogre { static VulkanPlugin *plugin; - extern "C" void _OgreVulkanExport dllStartPlugin( void ) throw() +# if __cplusplus >= 201103L + extern "C" void _OgreVulkanExport dllStartPlugin( void ) noexcept( false ) +# else + extern "C" void _OgreVulkanExport dllStartPlugin( void ) throw( Exception ) +# endif { plugin = OGRE_NEW VulkanPlugin(); Root::getSingleton().installPlugin( plugin ); diff --git a/Samples/2.0/Tutorials/EmptyProject/CMake/Dependencies/OGRE.cmake b/Samples/2.0/Tutorials/EmptyProject/CMake/Dependencies/OGRE.cmake index 4b4e0068c1f..83cd1c712a7 100644 --- a/Samples/2.0/Tutorials/EmptyProject/CMake/Dependencies/OGRE.cmake +++ b/Samples/2.0/Tutorials/EmptyProject/CMake/Dependencies/OGRE.cmake @@ -48,9 +48,9 @@ macro( findPluginAndSetPath BUILD_TYPE CFG_VARIABLE LIBRARY_NAME ) if( EXISTS ${REAL_LIB_PATH} ) # DLL Exists, set the variable for Plugins.cfg if( ${BUILD_TYPE} STREQUAL "Debug" ) - set( ${CFG_VARIABLE} "Plugin=${LIBRARY_NAME}_d" ) + set( ${CFG_VARIABLE} "PluginOptional=${LIBRARY_NAME}_d" ) else() - set( ${CFG_VARIABLE} "Plugin=${LIBRARY_NAME}" ) + set( ${CFG_VARIABLE} "PluginOptional=${LIBRARY_NAME}" ) endif() # Copy the DLLs to the folders.