mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 03:35:27 +00:00
Merge branch 'async_delete_animation' into 'master'
Destruct animation asynchronously when unloading a cell See merge request OpenMW/openmw!2177
This commit is contained in:
commit
17a0063a7c
@ -46,6 +46,7 @@
|
||||
#include <components/sceneutil/depth.hpp>
|
||||
#include <components/sceneutil/color.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/sceneutil/unrefqueue.hpp>
|
||||
|
||||
#include <components/settings/shadermanager.hpp>
|
||||
|
||||
@ -419,7 +420,14 @@ bool OMW::Engine::frame(float frametime)
|
||||
mWindowManager->update(frametime);
|
||||
}
|
||||
|
||||
if (stats->collectStats("resource"))
|
||||
const bool reportResource = stats->collectStats("resource");
|
||||
|
||||
if (reportResource)
|
||||
stats->setAttribute(frameNumber, "UnrefQueue", mUnrefQueue->getSize());
|
||||
|
||||
mUnrefQueue->flush(*mWorkQueue);
|
||||
|
||||
if (reportResource)
|
||||
{
|
||||
stats->setAttribute(frameNumber, "FrameNumber", frameNumber);
|
||||
|
||||
@ -492,6 +500,7 @@ OMW::Engine::~Engine()
|
||||
|
||||
mScriptContext = nullptr;
|
||||
|
||||
mUnrefQueue = nullptr;
|
||||
mWorkQueue = nullptr;
|
||||
|
||||
mViewer = nullptr;
|
||||
@ -751,6 +760,7 @@ void OMW::Engine::prepareEngine()
|
||||
if (numThreads <= 0)
|
||||
throw std::runtime_error("Invalid setting: 'preload num threads' must be >0");
|
||||
mWorkQueue = new SceneUtil::WorkQueue(numThreads);
|
||||
mUnrefQueue = std::make_unique<SceneUtil::UnrefQueue>();
|
||||
|
||||
mScreenCaptureOperation = new SceneUtil::AsyncScreenCaptureOperation(
|
||||
mWorkQueue,
|
||||
@ -842,7 +852,7 @@ void OMW::Engine::prepareEngine()
|
||||
}
|
||||
|
||||
// Create the world
|
||||
mWorld = std::make_unique<MWWorld::World>(mViewer, rootNode, mResourceSystem.get(), mWorkQueue.get(),
|
||||
mWorld = std::make_unique<MWWorld::World>(mViewer, rootNode, mResourceSystem.get(), mWorkQueue.get(), *mUnrefQueue,
|
||||
mFileCollections, mContentFiles, mGroundcoverFiles, mEncoder.get(), mActivationDistanceOverride, mCellName,
|
||||
mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string());
|
||||
mWorld->setupPlayer();
|
||||
|
@ -22,6 +22,7 @@ namespace SceneUtil
|
||||
{
|
||||
class WorkQueue;
|
||||
class AsyncScreenCaptureOperation;
|
||||
class UnrefQueue;
|
||||
}
|
||||
|
||||
namespace VFS
|
||||
@ -120,6 +121,7 @@ namespace OMW
|
||||
std::unique_ptr<VFS::Manager> mVFS;
|
||||
std::unique_ptr<Resource::ResourceSystem> mResourceSystem;
|
||||
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
|
||||
std::unique_ptr<SceneUtil::UnrefQueue> mUnrefQueue;
|
||||
std::unique_ptr<MWWorld::World> mWorld;
|
||||
std::unique_ptr<MWSound::SoundManager> mSoundManager;
|
||||
std::unique_ptr<MWScript::ScriptManager> mScriptManager;
|
||||
|
@ -58,16 +58,7 @@ ActorAnimation::ActorAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group>
|
||||
removeEffects();
|
||||
}
|
||||
|
||||
ActorAnimation::~ActorAnimation()
|
||||
{
|
||||
for (ItemLightMap::iterator iter = mItemLights.begin(); iter != mItemLights.end(); ++iter)
|
||||
{
|
||||
mInsert->removeChild(iter->second);
|
||||
}
|
||||
|
||||
mScabbard.reset();
|
||||
mHolsteredShield.reset();
|
||||
}
|
||||
ActorAnimation::~ActorAnimation() = default;
|
||||
|
||||
PartHolderPtr ActorAnimation::attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor)
|
||||
{
|
||||
@ -597,4 +588,11 @@ void ActorAnimation::removeHiddenItemLight(const MWWorld::ConstPtr& item)
|
||||
mItemLights.erase(iter);
|
||||
}
|
||||
|
||||
void ActorAnimation::removeFromScene()
|
||||
{
|
||||
for (const auto& [k, v] : mItemLights)
|
||||
mInsert->removeChild(v);
|
||||
Animation::removeFromScene();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener
|
||||
bool useShieldAnimations() const override;
|
||||
bool updateCarriedLeftVisible(const int weaptype) const override;
|
||||
|
||||
void removeFromScene() override;
|
||||
|
||||
protected:
|
||||
osg::Group* getBoneByName(const std::string& boneName) const;
|
||||
virtual void updateHolsteredWeapon(bool showHolsteredWeapons);
|
||||
|
@ -527,23 +527,7 @@ namespace MWRender
|
||||
mLightListCallback = new SceneUtil::LightListCallback;
|
||||
}
|
||||
|
||||
Animation::~Animation()
|
||||
{
|
||||
Animation::setLightEffect(0.f);
|
||||
|
||||
if (mObjectRoot)
|
||||
mInsert->removeChild(mObjectRoot);
|
||||
}
|
||||
|
||||
MWWorld::ConstPtr Animation::getPtr() const
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
MWWorld::Ptr Animation::getPtr()
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
Animation::~Animation() = default;
|
||||
|
||||
void Animation::setActive(int active)
|
||||
{
|
||||
@ -1779,6 +1763,15 @@ namespace MWRender
|
||||
return mHeadYawRadians;
|
||||
}
|
||||
|
||||
void Animation::removeFromScene()
|
||||
{
|
||||
if (mGlowLight != nullptr)
|
||||
mInsert->removeChild(mGlowLight);
|
||||
|
||||
if (mObjectRoot != nullptr)
|
||||
mInsert->removeChild(mObjectRoot);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
||||
float Animation::AnimationTime::getValue(osg::NodeVisitor*)
|
||||
|
@ -351,9 +351,9 @@ public:
|
||||
/// Must be thread safe
|
||||
virtual ~Animation();
|
||||
|
||||
MWWorld::ConstPtr getPtr() const;
|
||||
MWWorld::ConstPtr getPtr() const { return mPtr; }
|
||||
|
||||
MWWorld::Ptr getPtr();
|
||||
MWWorld::Ptr getPtr() { return mPtr; }
|
||||
|
||||
/// Set active flag on the object skeleton, if one exists.
|
||||
/// @see SceneUtil::Skeleton::setActive
|
||||
@ -497,6 +497,8 @@ public:
|
||||
virtual void setAccurateAiming(bool enabled) {}
|
||||
virtual bool canBeHarvested() const { return false; }
|
||||
|
||||
virtual void removeFromScene();
|
||||
|
||||
private:
|
||||
Animation(const Animation&);
|
||||
void operator=(Animation&);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <osg/UserDataContainer>
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include <components/sceneutil/unrefqueue.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
@ -17,9 +18,11 @@
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
Objects::Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode)
|
||||
Objects::Objects(Resource::ResourceSystem* resourceSystem, const osg::ref_ptr<osg::Group>& rootNode,
|
||||
SceneUtil::UnrefQueue& unrefQueue)
|
||||
: mRootNode(rootNode)
|
||||
, mResourceSystem(resourceSystem)
|
||||
, mUnrefQueue(unrefQueue)
|
||||
{
|
||||
}
|
||||
|
||||
@ -115,6 +118,8 @@ bool Objects::removeObject (const MWWorld::Ptr& ptr)
|
||||
const auto iter = mObjects.find(ptr.mRef);
|
||||
if(iter != mObjects.end())
|
||||
{
|
||||
iter->second->removeFromScene();
|
||||
mUnrefQueue.push(std::move(iter->second));
|
||||
mObjects.erase(iter);
|
||||
|
||||
if (ptr.getClass().isActor())
|
||||
@ -148,7 +153,9 @@ void Objects::removeCell(const MWWorld::CellStore* store)
|
||||
ptr.getClass().getContainerStore(ptr).setContListener(nullptr);
|
||||
}
|
||||
|
||||
mObjects.erase(iter++);
|
||||
iter->second->removeFromScene();
|
||||
mUnrefQueue.push(std::move(iter->second));
|
||||
iter = mObjects.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
|
@ -24,6 +24,11 @@ namespace MWWorld
|
||||
class CellStore;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
class UnrefQueue;
|
||||
}
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
class Animation;
|
||||
@ -57,15 +62,15 @@ class Objects
|
||||
typedef std::map<const MWWorld::CellStore*, osg::ref_ptr<osg::Group> > CellMap;
|
||||
CellMap mCellSceneNodes;
|
||||
PtrAnimationMap mObjects;
|
||||
|
||||
osg::ref_ptr<osg::Group> mRootNode;
|
||||
|
||||
Resource::ResourceSystem* mResourceSystem;
|
||||
SceneUtil::UnrefQueue& mUnrefQueue;
|
||||
|
||||
void insertBegin(const MWWorld::Ptr& ptr);
|
||||
|
||||
public:
|
||||
Objects(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Group> rootNode);
|
||||
Objects(Resource::ResourceSystem* resourceSystem, const osg::ref_ptr<osg::Group>& rootNode,
|
||||
SceneUtil::UnrefQueue& unrefQueue);
|
||||
~Objects();
|
||||
|
||||
/// @param animated Attempt to load separate keyframes from a .kf file matching the model file?
|
||||
|
@ -367,8 +367,9 @@ namespace MWRender
|
||||
};
|
||||
|
||||
RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
const std::string& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore)
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::string& resourcePath,
|
||||
DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore,
|
||||
SceneUtil::UnrefQueue& unrefQueue)
|
||||
: mSkyBlending(Settings::Manager::getBool("sky blending", "Fog"))
|
||||
, mViewer(viewer)
|
||||
, mRootNode(rootNode)
|
||||
@ -479,7 +480,7 @@ namespace MWRender
|
||||
mRecastMesh = std::make_unique<RecastMesh>(mRootNode, Settings::Manager::getBool("enable recast mesh render", "Navigator"));
|
||||
mPathgrid = std::make_unique<Pathgrid>(mRootNode);
|
||||
|
||||
mObjects = std::make_unique<Objects>(mResourceSystem, sceneRoot);
|
||||
mObjects = std::make_unique<Objects>(mResourceSystem, sceneRoot, unrefQueue);
|
||||
|
||||
if (getenv("OPENMW_DONT_PRECOMPILE") == nullptr)
|
||||
{
|
||||
|
@ -60,6 +60,7 @@ namespace SceneUtil
|
||||
class ShadowManager;
|
||||
class WorkQueue;
|
||||
class LightManager;
|
||||
class UnrefQueue;
|
||||
}
|
||||
|
||||
namespace DetourNavigator
|
||||
@ -100,9 +101,10 @@ namespace MWRender
|
||||
class RenderingManager : public MWRender::RenderingInterface
|
||||
{
|
||||
public:
|
||||
RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
const std::string& resourcePath, DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore);
|
||||
RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::string& resourcePath,
|
||||
DetourNavigator::Navigator& navigator, const MWWorld::GroundcoverStore& groundcoverStore,
|
||||
SceneUtil::UnrefQueue& unrefQueue);
|
||||
~RenderingManager();
|
||||
|
||||
osgUtil::IncrementalCompileOperation* getIncrementalCompileOperation();
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
#include <components/sceneutil/workqueue.hpp>
|
||||
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
@ -139,6 +140,7 @@ namespace MWWorld
|
||||
osgViewer::Viewer* viewer,
|
||||
osg::ref_ptr<osg::Group> rootNode,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
SceneUtil::UnrefQueue& unrefQueue,
|
||||
const Files::Collections& fileCollections,
|
||||
const std::vector<std::string>& contentFiles,
|
||||
const std::vector<std::string>& groundcoverFiles,
|
||||
@ -187,7 +189,8 @@ namespace MWWorld
|
||||
mNavigator = DetourNavigator::makeNavigatorStub();
|
||||
}
|
||||
|
||||
mRendering = std::make_unique<MWRender::RenderingManager>(viewer, rootNode, resourceSystem, workQueue, resourcePath, *mNavigator, mGroundcoverStore);
|
||||
mRendering = std::make_unique<MWRender::RenderingManager>(viewer, rootNode, resourceSystem, workQueue,
|
||||
resourcePath, *mNavigator, mGroundcoverStore, unrefQueue);
|
||||
mProjectileManager = std::make_unique<ProjectileManager>(mRendering->getLightRoot()->asGroup(), resourceSystem, mRendering.get(), mPhysics.get());
|
||||
mRendering->preloadCommonAssets();
|
||||
|
||||
|
@ -38,6 +38,7 @@ namespace Resource
|
||||
namespace SceneUtil
|
||||
{
|
||||
class WorkQueue;
|
||||
class UnrefQueue;
|
||||
}
|
||||
|
||||
namespace ESM
|
||||
@ -192,6 +193,7 @@ namespace MWWorld
|
||||
osgViewer::Viewer* viewer,
|
||||
osg::ref_ptr<osg::Group> rootNode,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
SceneUtil::UnrefQueue& unrefQueue,
|
||||
const Files::Collections& fileCollections,
|
||||
const std::vector<std::string>& contentFiles,
|
||||
const std::vector<std::string>& groundcoverFiles,
|
||||
|
@ -61,7 +61,7 @@ add_component_dir (sceneutil
|
||||
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
|
||||
lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer
|
||||
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt
|
||||
screencapture depth color riggeometryosgaextension extradata
|
||||
screencapture depth color riggeometryosgaextension extradata unrefqueue
|
||||
)
|
||||
|
||||
add_component_dir (nif
|
||||
|
@ -417,6 +417,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer)
|
||||
"Compiling",
|
||||
"WorkQueue",
|
||||
"WorkThread",
|
||||
"UnrefQueue",
|
||||
"",
|
||||
"Texture",
|
||||
"StateSet",
|
||||
|
28
components/sceneutil/unrefqueue.cpp
Normal file
28
components/sceneutil/unrefqueue.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "unrefqueue.hpp"
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct ClearVector final : SceneUtil::WorkItem
|
||||
{
|
||||
std::vector<osg::ref_ptr<osg::Referenced>> mObjects;
|
||||
|
||||
explicit ClearVector(std::vector<osg::ref_ptr<osg::Referenced>>&& objects)
|
||||
: mObjects(std::move(objects)) {}
|
||||
|
||||
void doWork() override { mObjects.clear(); }
|
||||
};
|
||||
}
|
||||
|
||||
void UnrefQueue::flush(SceneUtil::WorkQueue& workQueue)
|
||||
{
|
||||
if (mObjects.empty())
|
||||
return;
|
||||
|
||||
// Move only objects to keep allocated storage in mObjects
|
||||
workQueue.addWorkItem(new ClearVector(std::vector<osg::ref_ptr<osg::Referenced>>(
|
||||
std::move_iterator(mObjects.begin()), std::move_iterator(mObjects.end()))));
|
||||
mObjects.clear();
|
||||
}
|
||||
}
|
36
components/sceneutil/unrefqueue.hpp
Normal file
36
components/sceneutil/unrefqueue.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef OPENMW_COMPONENTS_UNREFQUEUE_H
|
||||
#define OPENMW_COMPONENTS_UNREFQUEUE_H
|
||||
|
||||
#include "workqueue.hpp"
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Referenced>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
class WorkQueue;
|
||||
|
||||
/// @brief Handles unreferencing of objects through the WorkQueue. Typical use scenario
|
||||
/// would be the main thread pushing objects that are no longer needed, and the background thread deleting them.
|
||||
class UnrefQueue
|
||||
{
|
||||
public:
|
||||
/// Adds an object to the list of objects to be unreferenced. Call from the main thread.
|
||||
void push(osg::ref_ptr<osg::Referenced>&& obj) { mObjects.push_back(std::move(obj)); }
|
||||
|
||||
void push(const osg::ref_ptr<osg::Referenced>& obj) { mObjects.push_back(obj); }
|
||||
|
||||
/// Adds a WorkItem to the given WorkQueue that will clear the list of objects in a worker thread,
|
||||
/// thus unreferencing them. Call from the main thread.
|
||||
void flush(SceneUtil::WorkQueue& workQueue);
|
||||
|
||||
std::size_t getSize() const { return mObjects.size(); }
|
||||
|
||||
private:
|
||||
std::vector<osg::ref_ptr<osg::Referenced>> mObjects;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user