1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-25 03:40:40 +00:00

Merge branch 'fix_work_queue' into 'master'

Fix hang on exit (#6145)

Closes #6145

See merge request OpenMW/openmw!1004
This commit is contained in:
psi29a 2021-07-12 13:33:16 +00:00
commit 1da644668f
9 changed files with 81 additions and 11 deletions

View File

@ -427,7 +427,8 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
OMW::Engine::~Engine() OMW::Engine::~Engine()
{ {
mWorkQueue->stop(); if (mScreenCaptureOperation != nullptr)
mScreenCaptureOperation->stop();
mEnvironment.cleanup(); mEnvironment.cleanup();

View File

@ -21,6 +21,7 @@ namespace Resource
namespace SceneUtil namespace SceneUtil
{ {
class WorkQueue; class WorkQueue;
class AsyncScreenCaptureOperation;
} }
namespace VFS namespace VFS
@ -67,7 +68,7 @@ namespace OMW
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
osg::ref_ptr<osgViewer::Viewer> mViewer; osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler; osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mScreenCaptureOperation; osg::ref_ptr<SceneUtil::AsyncScreenCaptureOperation> mScreenCaptureOperation;
std::string mCellName; std::string mCellName;
std::vector<std::string> mContentFiles; std::vector<std::string> mContentFiles;
std::vector<std::string> mGroundcoverFiles; std::vector<std::string> mGroundcoverFiles;

View File

@ -492,7 +492,7 @@ namespace MWRender
workItem->mTextures.emplace_back("textures/_land_default.dds"); workItem->mTextures.emplace_back("textures/_land_default.dds");
mWorkQueue->addWorkItem(workItem); mWorkQueue->addWorkItem(std::move(workItem));
} }
double RenderingManager::getReferenceTime() const double RenderingManager::getReferenceTime() const

View File

@ -317,7 +317,7 @@ namespace MWWorld
if (found->second.mWorkItem) if (found->second.mWorkItem)
{ {
found->second.mWorkItem->abort(); found->second.mWorkItem->abort();
mUnrefQueue->push(mPreloadCells[cell].mWorkItem); mUnrefQueue->push(std::move(found->second.mWorkItem));
} }
mPreloadCells.erase(found); mPreloadCells.erase(found);

View File

@ -3,6 +3,7 @@
#include <limits> #include <limits>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <atomic>
#include <BulletCollision/CollisionDispatch/btCollisionObject.h> #include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include <BulletCollision/CollisionShapes/btCompoundShape.h> #include <BulletCollision/CollisionShapes/btCompoundShape.h>
@ -867,6 +868,11 @@ namespace MWWorld
Scene::~Scene() Scene::~Scene()
{ {
for (const osg::ref_ptr<SceneUtil::WorkItem>& v : mWorkItems)
v->abort();
for (const osg::ref_ptr<SceneUtil::WorkItem>& v : mWorkItems)
v->waitTillDone();
} }
bool Scene::hasCellChanged() const bool Scene::hasCellChanged() const
@ -1061,6 +1067,9 @@ namespace MWWorld
void doWork() override void doWork() override
{ {
if (mAborted)
return;
try try
{ {
mSceneManager->getTemplate(mMesh); mSceneManager->getTemplate(mMesh);
@ -1069,9 +1078,16 @@ namespace MWWorld
{ {
} }
} }
void abort() override
{
mAborted = true;
}
private: private:
std::string mMesh; std::string mMesh;
Resource::SceneManager* mSceneManager; Resource::SceneManager* mSceneManager;
std::atomic_bool mAborted {false};
}; };
void Scene::preload(const std::string &mesh, bool useAnim) void Scene::preload(const std::string &mesh, bool useAnim)
@ -1081,7 +1097,13 @@ namespace MWWorld
mesh_ = Misc::ResourceHelpers::correctActorModelPath(mesh_, mRendering.getResourceSystem()->getVFS()); mesh_ = Misc::ResourceHelpers::correctActorModelPath(mesh_, mRendering.getResourceSystem()->getVFS());
if (!mRendering.getResourceSystem()->getSceneManager()->checkLoaded(mesh_, mRendering.getReferenceTime())) if (!mRendering.getResourceSystem()->getSceneManager()->checkLoaded(mesh_, mRendering.getReferenceTime()))
mRendering.getWorkQueue()->addWorkItem(new PreloadMeshItem(mesh_, mRendering.getResourceSystem()->getSceneManager())); {
osg::ref_ptr<PreloadMeshItem> item(new PreloadMeshItem(mesh_, mRendering.getResourceSystem()->getSceneManager()));
mRendering.getWorkQueue()->addWorkItem(item);
const auto isDone = [] (const osg::ref_ptr<SceneUtil::WorkItem>& v) { return v->isDone(); };
mWorkItems.erase(std::remove_if(mWorkItems.begin(), mWorkItems.end(), isDone), mWorkItems.end());
mWorkItems.emplace_back(std::move(item));
}
} }
void Scene::preloadCells(float dt) void Scene::preloadCells(float dt)

View File

@ -3,6 +3,7 @@
#include <osg/Vec4i> #include <osg/Vec4i>
#include <osg/Vec2i> #include <osg/Vec2i>
#include <osg/ref_ptr>
#include "ptr.hpp" #include "ptr.hpp"
#include "globals.hpp" #include "globals.hpp"
@ -10,6 +11,7 @@
#include <set> #include <set>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <vector>
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
@ -49,6 +51,11 @@ namespace MWPhysics
class PhysicsSystem; class PhysicsSystem;
} }
namespace SceneUtil
{
class WorkItem;
}
namespace MWWorld namespace MWWorld
{ {
class Player; class Player;
@ -91,6 +98,8 @@ namespace MWWorld
std::set<ESM::RefNum> mPagedRefs; std::set<ESM::RefNum> mPagedRefs;
std::vector<osg::ref_ptr<SceneUtil::WorkItem>> mWorkItems;
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyObjects, bool test = false); void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyObjects, bool test = false);
osg::Vec2i mCurrentGridCenter; osg::Vec2i mCurrentGridCenter;

View File

@ -15,6 +15,7 @@
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <atomic>
namespace namespace
{ {
@ -32,6 +33,9 @@ namespace
void doWork() override void doWork() override
{ {
if (mAborted)
return;
try try
{ {
(*mImpl)(*mImage, mContextId); (*mImpl)(*mImage, mContextId);
@ -42,10 +46,16 @@ namespace
} }
} }
void abort() override
{
mAborted = true;
}
private: private:
const osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mImpl; const osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mImpl;
const osg::ref_ptr<const osg::Image> mImage; const osg::ref_ptr<const osg::Image> mImage;
const unsigned int mContextId; const unsigned int mContextId;
std::atomic_bool mAborted {false};
}; };
} }
@ -130,8 +140,27 @@ namespace SceneUtil
assert(mImpl != nullptr); assert(mImpl != nullptr);
} }
AsyncScreenCaptureOperation::~AsyncScreenCaptureOperation()
{
stop();
}
void AsyncScreenCaptureOperation::stop()
{
for (const osg::ref_ptr<SceneUtil::WorkItem>& item : *mWorkItems.lockConst())
item->abort();
for (const osg::ref_ptr<SceneUtil::WorkItem>& item : *mWorkItems.lockConst())
item->waitTillDone();
}
void AsyncScreenCaptureOperation::operator()(const osg::Image& image, const unsigned int context_id) void AsyncScreenCaptureOperation::operator()(const osg::Image& image, const unsigned int context_id)
{ {
mQueue->addWorkItem(new ScreenCaptureWorkItem(mImpl, image, context_id)); osg::ref_ptr<SceneUtil::WorkItem> item(new ScreenCaptureWorkItem(mImpl, image, context_id));
mQueue->addWorkItem(item);
const auto isDone = [] (const osg::ref_ptr<SceneUtil::WorkItem>& v) { return v->isDone(); };
const auto workItems = mWorkItems.lock();
workItems->erase(std::remove_if(workItems->begin(), workItems->end(), isDone), workItems->end());
workItems->emplace_back(std::move(item));
} }
} }

View File

@ -1,10 +1,13 @@
#ifndef OPENMW_COMPONENTS_SCENEUTIL_SCREENCAPTURE_H #ifndef OPENMW_COMPONENTS_SCENEUTIL_SCREENCAPTURE_H
#define OPENMW_COMPONENTS_SCENEUTIL_SCREENCAPTURE_H #define OPENMW_COMPONENTS_SCENEUTIL_SCREENCAPTURE_H
#include <components/misc/guarded.hpp>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osgViewer/ViewerEventHandlers> #include <osgViewer/ViewerEventHandlers>
#include <string> #include <string>
#include <vector>
namespace osg namespace osg
{ {
@ -14,6 +17,7 @@ namespace osg
namespace SceneUtil namespace SceneUtil
{ {
class WorkQueue; class WorkQueue;
class WorkItem;
std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat, std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
const osg::Image& image); const osg::Image& image);
@ -38,11 +42,16 @@ namespace SceneUtil
AsyncScreenCaptureOperation(osg::ref_ptr<SceneUtil::WorkQueue> queue, AsyncScreenCaptureOperation(osg::ref_ptr<SceneUtil::WorkQueue> queue,
osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> impl); osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> impl);
~AsyncScreenCaptureOperation();
void stop();
void operator()(const osg::Image& image, const unsigned int context_id) override; void operator()(const osg::Image& image, const unsigned int context_id) override;
private: private:
const osg::ref_ptr<SceneUtil::WorkQueue> mQueue; const osg::ref_ptr<SceneUtil::WorkQueue> mQueue;
const osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mImpl; const osg::ref_ptr<osgViewer::ScreenCaptureHandler::CaptureOperation> mImpl;
Misc::ScopeGuarded<std::vector<osg::ref_ptr<SceneUtil::WorkItem>>> mWorkItems;
}; };
} }

View File

@ -74,9 +74,9 @@ void WorkQueue::addWorkItem(osg::ref_ptr<WorkItem> item, bool front)
std::unique_lock<std::mutex> lock(mMutex); std::unique_lock<std::mutex> lock(mMutex);
if (front) if (front)
mQueue.push_front(item); mQueue.push_front(std::move(item));
else else
mQueue.push_back(item); mQueue.push_back(std::move(item));
mCondition.notify_one(); mCondition.notify_one();
} }
@ -89,12 +89,11 @@ osg::ref_ptr<WorkItem> WorkQueue::removeWorkItem()
} }
if (!mQueue.empty()) if (!mQueue.empty())
{ {
osg::ref_ptr<WorkItem> item = mQueue.front(); osg::ref_ptr<WorkItem> item = std::move(mQueue.front());
mQueue.pop_front(); mQueue.pop_front();
return item; return item;
} }
else return nullptr;
return nullptr;
} }
unsigned int WorkQueue::getNumItems() const unsigned int WorkQueue::getNumItems() const