From 4e0011bfc8a71165d8b6e60e956736fd4bf74628 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 1 Mar 2017 03:00:49 +0100 Subject: [PATCH] Improve NPC loading performance by caching the cleaned objectRoot --- apps/openmw/mwrender/animation.cpp | 38 +++++++++++++++++++++------- components/resource/scenemanager.cpp | 9 +++++-- components/resource/scenemanager.hpp | 6 +++-- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0a1d5eb09..d293a8bd3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1123,6 +1123,32 @@ namespace MWRender state->second.mLoopingEnabled = enabled; } + osg::ref_ptr getModelInstance(Resource::SceneManager* sceneMgr, const std::string& model, bool baseonly) + { + if (baseonly) + { + typedef std::map > Cache; + static Cache cache; + Cache::iterator found = cache.find(model); + if (found == cache.end()) + { + osg::ref_ptr created = sceneMgr->getInstance(model); + + RemoveDrawableVisitor removeDrawableVisitor; + created->accept(removeDrawableVisitor); + removeDrawableVisitor.remove(); + + cache.insert(std::make_pair(model, created)); + + return sceneMgr->createInstance(created); + } + else + return sceneMgr->createInstance(found->second); + } + else + return sceneMgr->createInstance(model); + } + void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature) { osg::ref_ptr previousStateset; @@ -1144,7 +1170,8 @@ namespace MWRender if (!forceskeleton) { - osg::ref_ptr created = mResourceSystem->getSceneManager()->getInstance(model, mInsert); + osg::ref_ptr created = getModelInstance(mResourceSystem->getSceneManager(), model, baseonly); + mInsert->addChild(created); mObjectRoot = created->asGroup(); if (!mObjectRoot) { @@ -1156,7 +1183,7 @@ namespace MWRender } else { - osg::ref_ptr created = mResourceSystem->getSceneManager()->getInstance(model); + osg::ref_ptr created = getModelInstance(mResourceSystem->getSceneManager(), model, baseonly); osg::ref_ptr skel = dynamic_cast(created.get()); if (!skel) { @@ -1171,13 +1198,6 @@ namespace MWRender if (previousStateset) mObjectRoot->setStateSet(previousStateset); - if (baseonly) - { - RemoveDrawableVisitor removeDrawableVisitor; - mObjectRoot->accept(removeDrawableVisitor); - removeDrawableVisitor.remove(); - } - if (isCreature) { RemoveTriBipVisitor removeTriBipVisitor; diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index b7dda6276..d050d5448 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -538,10 +538,15 @@ namespace Resource osg::ref_ptr SceneManager::createInstance(const std::string& name) { osg::ref_ptr scene = getTemplate(name); - osg::ref_ptr cloned = osg::clone(scene.get(), SceneUtil::CopyOp()); + return createInstance(scene); + } + + osg::ref_ptr SceneManager::createInstance(const osg::Node *base) + { + osg::ref_ptr cloned = osg::clone(base, SceneUtil::CopyOp()); // add a ref to the original template, to hint to the cache that it's still being used and should be kept in cache - cloned->getOrCreateUserDataContainer()->addUserObject(new TemplateRef(scene)); + cloned->getOrCreateUserDataContainer()->addUserObject(new TemplateRef(base)); // we can skip any scene graphs without update callbacks since we know that particle emitters will have an update callback set if (cloned->getNumChildrenRequiringUpdateTraversal() > 0) diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 62ffe0871..fdd1d6583 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -93,6 +93,10 @@ namespace Resource /// @note Thread safe. osg::ref_ptr cacheInstance(const std::string& name); + osg::ref_ptr createInstance(const std::string& name); + + osg::ref_ptr createInstance(const osg::Node* base); + /// Get an instance of the given scene template /// @see getTemplate /// @note Thread safe. @@ -141,8 +145,6 @@ namespace Resource private: - osg::ref_ptr createInstance(const std::string& name); - std::auto_ptr mShaderManager; bool mForceShaders; bool mClampLighting;