1
0
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:
psi29a 2022-07-26 13:42:43 +00:00
commit 17a0063a7c
16 changed files with 136 additions and 44 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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*)

View File

@ -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&);

View File

@ -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;

View File

@ -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?

View 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)
{

View File

@ -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();

View File

@ -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();

View File

@ -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,

View File

@ -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

View File

@ -417,6 +417,7 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer)
"Compiling",
"WorkQueue",
"WorkThread",
"UnrefQueue",
"",
"Texture",
"StateSet",

View 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();
}
}

View 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