mirror of
https://github.com/OpenMW/openmw.git
synced 2025-11-09 15:26:39 +00:00
Merge branch 'window_manager_profile' into 'master'
Profile window manager update See merge request OpenMW/openmw!2458
This commit is contained in:
commit
6630dbb9c2
6 changed files with 346 additions and 270 deletions
|
|
@ -63,6 +63,7 @@ add_openmw_dir (mwlua
|
||||||
luabindings localscripts playerscripts objectbindings cellbindings asyncbindings
|
luabindings localscripts playerscripts objectbindings cellbindings asyncbindings
|
||||||
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
||||||
types/types types/door types/actor types/container types/weapon types/npc types/creature types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair
|
types/types types/door types/actor types/container types/weapon types/npc types/creature types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair
|
||||||
|
worker
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwsound
|
add_openmw_dir (mwsound
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
#include "mwgui/windowmanagerimp.hpp"
|
#include "mwgui/windowmanagerimp.hpp"
|
||||||
|
|
||||||
#include "mwlua/luamanagerimp.hpp"
|
#include "mwlua/luamanagerimp.hpp"
|
||||||
|
#include "mwlua/worker.hpp"
|
||||||
|
|
||||||
#include "mwscript/interpretercontext.hpp"
|
#include "mwscript/interpretercontext.hpp"
|
||||||
#include "mwscript/scriptmanagerimp.hpp"
|
#include "mwscript/scriptmanagerimp.hpp"
|
||||||
|
|
@ -70,6 +71,8 @@
|
||||||
|
|
||||||
#include "mwstate/statemanagerimp.hpp"
|
#include "mwstate/statemanagerimp.hpp"
|
||||||
|
|
||||||
|
#include "profile.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void checkSDLError(int ret)
|
void checkSDLError(int ret)
|
||||||
|
|
@ -78,140 +81,6 @@ namespace
|
||||||
Log(Debug::Error) << "SDL error: " << SDL_GetError();
|
Log(Debug::Error) << "SDL error: " << SDL_GetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserStats
|
|
||||||
{
|
|
||||||
const std::string mLabel;
|
|
||||||
const std::string mBegin;
|
|
||||||
const std::string mEnd;
|
|
||||||
const std::string mTaken;
|
|
||||||
|
|
||||||
UserStats(const std::string& label, const std::string& prefix)
|
|
||||||
: mLabel(label)
|
|
||||||
, mBegin(prefix + "_time_begin")
|
|
||||||
, mEnd(prefix + "_time_end")
|
|
||||||
, mTaken(prefix + "_time_taken")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class UserStatsType : std::size_t
|
|
||||||
{
|
|
||||||
Input,
|
|
||||||
Sound,
|
|
||||||
State,
|
|
||||||
Script,
|
|
||||||
Mechanics,
|
|
||||||
Physics,
|
|
||||||
PhysicsWorker,
|
|
||||||
World,
|
|
||||||
Gui,
|
|
||||||
Lua,
|
|
||||||
LuaSyncUpdate,
|
|
||||||
Number,
|
|
||||||
};
|
|
||||||
|
|
||||||
template <UserStatsType type>
|
|
||||||
struct UserStatsValue
|
|
||||||
{
|
|
||||||
static const UserStats sValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::Input>::sValue{ "Input", "input" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::Sound>::sValue{ "Sound", "sound" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::State>::sValue{ "State", "state" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::Script>::sValue{ "Script", "script" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::Mechanics>::sValue{ "Mech", "mechanics" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::Physics>::sValue{ "Phys", "physics" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::PhysicsWorker>::sValue{ " -Async", "physicsworker" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::World>::sValue{ "World", "world" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::Gui>::sValue{ "Gui", "gui" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::Lua>::sValue{ "Lua", "lua" };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
const UserStats UserStatsValue<UserStatsType::LuaSyncUpdate>::sValue{ " -Sync", "luasyncupdate" };
|
|
||||||
|
|
||||||
template <UserStatsType type>
|
|
||||||
struct ForEachUserStatsValue
|
|
||||||
{
|
|
||||||
template <class F>
|
|
||||||
static void apply(F&& f)
|
|
||||||
{
|
|
||||||
f(UserStatsValue<type>::sValue);
|
|
||||||
using Next = ForEachUserStatsValue<static_cast<UserStatsType>(static_cast<std::size_t>(type) + 1)>;
|
|
||||||
Next::apply(std::forward<F>(f));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct ForEachUserStatsValue<UserStatsType::Number>
|
|
||||||
{
|
|
||||||
template <class F>
|
|
||||||
static void apply(F&&)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
void forEachUserStatsValue(F&& f)
|
|
||||||
{
|
|
||||||
ForEachUserStatsValue<static_cast<UserStatsType>(0)>::apply(std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <UserStatsType sType>
|
|
||||||
class ScopedProfile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ScopedProfile(osg::Timer_t frameStart, unsigned int frameNumber, const osg::Timer& timer, osg::Stats& stats)
|
|
||||||
: mScopeStart(timer.tick())
|
|
||||||
, mFrameStart(frameStart)
|
|
||||||
, mFrameNumber(frameNumber)
|
|
||||||
, mTimer(timer)
|
|
||||||
, mStats(stats)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedProfile(const ScopedProfile&) = delete;
|
|
||||||
ScopedProfile& operator=(const ScopedProfile&) = delete;
|
|
||||||
|
|
||||||
~ScopedProfile()
|
|
||||||
{
|
|
||||||
if (!mStats.collectStats("engine"))
|
|
||||||
return;
|
|
||||||
const osg::Timer_t end = mTimer.tick();
|
|
||||||
const UserStats& stats = UserStatsValue<sType>::sValue;
|
|
||||||
|
|
||||||
mStats.setAttribute(mFrameNumber, stats.mBegin, mTimer.delta_s(mFrameStart, mScopeStart));
|
|
||||||
mStats.setAttribute(mFrameNumber, stats.mTaken, mTimer.delta_s(mScopeStart, end));
|
|
||||||
mStats.setAttribute(mFrameNumber, stats.mEnd, mTimer.delta_s(mFrameStart, end));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const osg::Timer_t mScopeStart;
|
|
||||||
const osg::Timer_t mFrameStart;
|
|
||||||
const unsigned int mFrameNumber;
|
|
||||||
const osg::Timer& mTimer;
|
|
||||||
osg::Stats& mStats;
|
|
||||||
};
|
|
||||||
|
|
||||||
void initStatsHandler(Resource::Profiler& profiler)
|
void initStatsHandler(Resource::Profiler& profiler)
|
||||||
{
|
{
|
||||||
const osg::Vec4f textColor(1.f, 1.f, 1.f, 1.f);
|
const osg::Vec4f textColor(1.f, 1.f, 1.f, 1.f);
|
||||||
|
|
@ -221,7 +90,7 @@ namespace
|
||||||
const bool averageInInverseSpace = false;
|
const bool averageInInverseSpace = false;
|
||||||
const float maxValue = 10000;
|
const float maxValue = 10000;
|
||||||
|
|
||||||
forEachUserStatsValue([&](const UserStats& v) {
|
OMW::forEachUserStatsValue([&](const OMW::UserStats& v) {
|
||||||
profiler.addUserStatsLine(v.mLabel, textColor, barColor, v.mTaken, multiplier, average,
|
profiler.addUserStatsLine(v.mLabel, textColor, barColor, v.mTaken, multiplier, average,
|
||||||
averageInInverseSpace, v.mBegin, v.mEnd, maxValue);
|
averageInInverseSpace, v.mBegin, v.mEnd, maxValue);
|
||||||
});
|
});
|
||||||
|
|
@ -302,8 +171,6 @@ void OMW::Engine::executeLocalScripts()
|
||||||
|
|
||||||
bool OMW::Engine::frame(float frametime)
|
bool OMW::Engine::frame(float frametime)
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
const osg::Timer_t frameStart = mViewer->getStartTick();
|
const osg::Timer_t frameStart = mViewer->getStartTick();
|
||||||
const unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
const unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber();
|
||||||
const osg::Timer* const timer = osg::Timer::instance();
|
const osg::Timer* const timer = osg::Timer::instance();
|
||||||
|
|
@ -311,6 +178,8 @@ bool OMW::Engine::frame(float frametime)
|
||||||
|
|
||||||
mEnvironment.setFrameDuration(frametime);
|
mEnvironment.setFrameDuration(frametime);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
// update input
|
// update input
|
||||||
{
|
{
|
||||||
ScopedProfile<UserStatsType::Input> profile(frameStart, frameNumber, *timer, *stats);
|
ScopedProfile<UserStatsType::Input> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
|
|
@ -425,6 +294,11 @@ bool OMW::Engine::frame(float frametime)
|
||||||
ScopedProfile<UserStatsType::Gui> profile(frameStart, frameNumber, *timer, *stats);
|
ScopedProfile<UserStatsType::Gui> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
mWindowManager->update(frametime);
|
mWindowManager->update(frametime);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Error in frame: " << e.what();
|
||||||
|
}
|
||||||
|
|
||||||
const bool reportResource = stats->collectStats("resource");
|
const bool reportResource = stats->collectStats("resource");
|
||||||
|
|
||||||
|
|
@ -446,11 +320,21 @@ bool OMW::Engine::frame(float frametime)
|
||||||
mWorld->reportStats(frameNumber, *stats);
|
mWorld->reportStats(frameNumber, *stats);
|
||||||
mLuaManager->reportStats(frameNumber, *stats);
|
mLuaManager->reportStats(frameNumber, *stats);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
mViewer->eventTraversal();
|
||||||
|
mViewer->updateTraversal();
|
||||||
|
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Error in frame: " << e.what();
|
ScopedProfile<UserStatsType::WindowManager> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
|
mWorld->updateWindowManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLuaWorker->allowUpdate(); // if there is a separate Lua thread, it starts the update now
|
||||||
|
|
||||||
|
mViewer->renderingTraversals();
|
||||||
|
|
||||||
|
mLuaWorker->finishUpdate();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,6 +389,7 @@ OMW::Engine::~Engine()
|
||||||
mSoundManager = nullptr;
|
mSoundManager = nullptr;
|
||||||
mInputManager = nullptr;
|
mInputManager = nullptr;
|
||||||
mStateManager = nullptr;
|
mStateManager = nullptr;
|
||||||
|
mLuaWorker = nullptr;
|
||||||
mLuaManager = nullptr;
|
mLuaManager = nullptr;
|
||||||
|
|
||||||
mScriptContext = nullptr;
|
mScriptContext = nullptr;
|
||||||
|
|
@ -800,6 +685,9 @@ void OMW::Engine::prepareEngine()
|
||||||
mLuaManager = std::make_unique<MWLua::LuaManager>(mVFS.get(), mResDir / "lua_libs");
|
mLuaManager = std::make_unique<MWLua::LuaManager>(mVFS.get(), mResDir / "lua_libs");
|
||||||
mEnvironment.setLuaManager(*mLuaManager);
|
mEnvironment.setLuaManager(*mLuaManager);
|
||||||
|
|
||||||
|
// starts a separate lua thread if "lua num threads" > 0
|
||||||
|
mLuaWorker = std::make_unique<MWLua::Worker>(*mLuaManager, *mViewer);
|
||||||
|
|
||||||
// Create input and UI first to set up a bootstrapping environment for
|
// Create input and UI first to set up a bootstrapping environment for
|
||||||
// showing a loading screen and keeping the window responsive while doing so
|
// showing a loading screen and keeping the window responsive while doing so
|
||||||
|
|
||||||
|
|
@ -929,98 +817,6 @@ void OMW::Engine::prepareEngine()
|
||||||
mLuaManager->loadPermanentStorage(mCfgMgr.getUserConfigPath());
|
mLuaManager->loadPermanentStorage(mCfgMgr.getUserConfigPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
class OMW::Engine::LuaWorker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LuaWorker(Engine* engine)
|
|
||||||
: mEngine(engine)
|
|
||||||
{
|
|
||||||
if (Settings::Manager::getInt("lua num threads", "Lua") > 0)
|
|
||||||
mThread = std::thread([this] { threadBody(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
~LuaWorker()
|
|
||||||
{
|
|
||||||
if (mThread && mThread->joinable())
|
|
||||||
{
|
|
||||||
Log(Debug::Error)
|
|
||||||
<< "Unexpected destruction of LuaWorker; likely there is an unhandled exception in the main thread.";
|
|
||||||
join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void allowUpdate()
|
|
||||||
{
|
|
||||||
if (!mThread)
|
|
||||||
return;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(mMutex);
|
|
||||||
mUpdateRequest = true;
|
|
||||||
}
|
|
||||||
mCV.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void finishUpdate()
|
|
||||||
{
|
|
||||||
if (mThread)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lk(mMutex);
|
|
||||||
mCV.wait(lk, [&] { return !mUpdateRequest; });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void join()
|
|
||||||
{
|
|
||||||
if (mThread)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(mMutex);
|
|
||||||
mJoinRequest = true;
|
|
||||||
}
|
|
||||||
mCV.notify_one();
|
|
||||||
mThread->join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void update()
|
|
||||||
{
|
|
||||||
const auto& viewer = mEngine->mViewer;
|
|
||||||
const osg::Timer_t frameStart = viewer->getStartTick();
|
|
||||||
const unsigned int frameNumber = viewer->getFrameStamp()->getFrameNumber();
|
|
||||||
ScopedProfile<UserStatsType::Lua> profile(
|
|
||||||
frameStart, frameNumber, *osg::Timer::instance(), *viewer->getViewerStats());
|
|
||||||
|
|
||||||
mEngine->mLuaManager->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void threadBody()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lk(mMutex);
|
|
||||||
mCV.wait(lk, [&] { return mUpdateRequest || mJoinRequest; });
|
|
||||||
if (mJoinRequest)
|
|
||||||
break;
|
|
||||||
|
|
||||||
update();
|
|
||||||
|
|
||||||
mUpdateRequest = false;
|
|
||||||
lk.unlock();
|
|
||||||
mCV.notify_one();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine* mEngine;
|
|
||||||
std::mutex mMutex;
|
|
||||||
std::condition_variable mCV;
|
|
||||||
bool mUpdateRequest = false;
|
|
||||||
bool mJoinRequest = false;
|
|
||||||
std::optional<std::thread> mThread;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialise and enter main loop.
|
// Initialise and enter main loop.
|
||||||
void OMW::Engine::go()
|
void OMW::Engine::go()
|
||||||
{
|
{
|
||||||
|
|
@ -1109,8 +905,6 @@ void OMW::Engine::go()
|
||||||
mWindowManager->executeInConsole(mStartupScript);
|
mWindowManager->executeInConsole(mStartupScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaWorker luaWorker(this); // starts a separate lua thread if "lua num threads" > 0
|
|
||||||
|
|
||||||
// Start the main rendering loop
|
// Start the main rendering loop
|
||||||
double simulationTime = 0.0;
|
double simulationTime = 0.0;
|
||||||
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(mEnvironment.getFrameRateLimit());
|
Misc::FrameRateLimiter frameRateLimiter = Misc::makeFrameRateLimiter(mEnvironment.getFrameRateLimit());
|
||||||
|
|
@ -1131,17 +925,6 @@ void OMW::Engine::go()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mViewer->eventTraversal();
|
|
||||||
mViewer->updateTraversal();
|
|
||||||
|
|
||||||
mWorld->updateWindowManager();
|
|
||||||
|
|
||||||
luaWorker.allowUpdate(); // if there is a separate Lua thread, it starts the update now
|
|
||||||
|
|
||||||
mViewer->renderingTraversals();
|
|
||||||
|
|
||||||
luaWorker.finishUpdate();
|
|
||||||
|
|
||||||
bool guiActive = mWindowManager->isGuiMode();
|
bool guiActive = mWindowManager->isGuiMode();
|
||||||
if (!guiActive)
|
if (!guiActive)
|
||||||
simulationTime += dt;
|
simulationTime += dt;
|
||||||
|
|
@ -1163,7 +946,7 @@ void OMW::Engine::go()
|
||||||
frameRateLimiter.limit();
|
frameRateLimiter.limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
luaWorker.join();
|
mLuaWorker->join();
|
||||||
|
|
||||||
// Save user settings
|
// Save user settings
|
||||||
Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg");
|
Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg");
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ namespace Compiler
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
class LuaManager;
|
class LuaManager;
|
||||||
|
class Worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Stereo
|
namespace Stereo
|
||||||
|
|
@ -132,6 +133,7 @@ namespace OMW
|
||||||
std::unique_ptr<MWInput::InputManager> mInputManager;
|
std::unique_ptr<MWInput::InputManager> mInputManager;
|
||||||
std::unique_ptr<MWState::StateManager> mStateManager;
|
std::unique_ptr<MWState::StateManager> mStateManager;
|
||||||
std::unique_ptr<MWLua::LuaManager> mLuaManager;
|
std::unique_ptr<MWLua::LuaManager> mLuaManager;
|
||||||
|
std::unique_ptr<MWLua::Worker> mLuaWorker;
|
||||||
MWBase::Environment mEnvironment;
|
MWBase::Environment mEnvironment;
|
||||||
ToUTF8::FromType mEncoding;
|
ToUTF8::FromType mEncoding;
|
||||||
std::unique_ptr<ToUTF8::Utf8Encoder> mEncoder;
|
std::unique_ptr<ToUTF8::Utf8Encoder> mEncoder;
|
||||||
|
|
@ -262,7 +264,6 @@ namespace OMW
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Files::ConfigurationManager& mCfgMgr;
|
Files::ConfigurationManager& mCfgMgr;
|
||||||
class LuaWorker;
|
|
||||||
int mGlMaxTextureImageUnits;
|
int mGlMaxTextureImageUnits;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
92
apps/openmw/mwlua/worker.cpp
Normal file
92
apps/openmw/mwlua/worker.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include "worker.hpp"
|
||||||
|
|
||||||
|
#include "luamanagerimp.hpp"
|
||||||
|
|
||||||
|
#include <apps/openmw/profile.hpp>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
Worker::Worker(LuaManager& manager, osgViewer::Viewer& viewer)
|
||||||
|
: mManager(manager)
|
||||||
|
, mViewer(viewer)
|
||||||
|
{
|
||||||
|
if (Settings::Manager::getInt("lua num threads", "Lua") > 0)
|
||||||
|
mThread = std::thread([this] { run(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
Worker::~Worker()
|
||||||
|
{
|
||||||
|
if (mThread && mThread->joinable())
|
||||||
|
{
|
||||||
|
Log(Debug::Error)
|
||||||
|
<< "Unexpected destruction of LuaWorker; likely there is an unhandled exception in the main thread.";
|
||||||
|
join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::allowUpdate()
|
||||||
|
{
|
||||||
|
if (!mThread)
|
||||||
|
return;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(mMutex);
|
||||||
|
mUpdateRequest = true;
|
||||||
|
}
|
||||||
|
mCV.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::finishUpdate()
|
||||||
|
{
|
||||||
|
if (mThread)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(mMutex);
|
||||||
|
mCV.wait(lk, [&] { return !mUpdateRequest; });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::join()
|
||||||
|
{
|
||||||
|
if (mThread)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(mMutex);
|
||||||
|
mJoinRequest = true;
|
||||||
|
}
|
||||||
|
mCV.notify_one();
|
||||||
|
mThread->join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::update()
|
||||||
|
{
|
||||||
|
const osg::Timer_t frameStart = mViewer.getStartTick();
|
||||||
|
const unsigned int frameNumber = mViewer.getFrameStamp()->getFrameNumber();
|
||||||
|
OMW::ScopedProfile<OMW::UserStatsType::Lua> profile(
|
||||||
|
frameStart, frameNumber, *osg::Timer::instance(), *mViewer.getViewerStats());
|
||||||
|
|
||||||
|
mManager.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::run() noexcept
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(mMutex);
|
||||||
|
mCV.wait(lk, [&] { return mUpdateRequest || mJoinRequest; });
|
||||||
|
if (mJoinRequest)
|
||||||
|
break;
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
mUpdateRequest = false;
|
||||||
|
lk.unlock();
|
||||||
|
mCV.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
apps/openmw/mwlua/worker.hpp
Normal file
46
apps/openmw/mwlua/worker.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef OPENMW_MWLUA_WORKER_H
|
||||||
|
#define OPENMW_MWLUA_WORKER_H
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace osgViewer
|
||||||
|
{
|
||||||
|
class Viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
class LuaManager;
|
||||||
|
|
||||||
|
class Worker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Worker(LuaManager& manager, osgViewer::Viewer& viewer);
|
||||||
|
|
||||||
|
~Worker();
|
||||||
|
|
||||||
|
void allowUpdate();
|
||||||
|
|
||||||
|
void finishUpdate();
|
||||||
|
|
||||||
|
void join();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void update();
|
||||||
|
|
||||||
|
void run() noexcept;
|
||||||
|
|
||||||
|
LuaManager& mManager;
|
||||||
|
osgViewer::Viewer& mViewer;
|
||||||
|
std::mutex mMutex;
|
||||||
|
std::condition_variable mCV;
|
||||||
|
bool mUpdateRequest = false;
|
||||||
|
bool mJoinRequest = false;
|
||||||
|
std::optional<std::thread> mThread;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENMW_MWLUA_LUAWORKER_H
|
||||||
153
apps/openmw/profile.hpp
Normal file
153
apps/openmw/profile.hpp
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
#ifndef OPENMW_PROFILE_H
|
||||||
|
#define OPENMW_PROFILE_H
|
||||||
|
|
||||||
|
#include <osg/Stats>
|
||||||
|
#include <osg/Timer>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace OMW
|
||||||
|
{
|
||||||
|
struct UserStats
|
||||||
|
{
|
||||||
|
const std::string mLabel;
|
||||||
|
const std::string mBegin;
|
||||||
|
const std::string mEnd;
|
||||||
|
const std::string mTaken;
|
||||||
|
|
||||||
|
explicit UserStats(const std::string& label, const std::string& prefix)
|
||||||
|
: mLabel(label)
|
||||||
|
, mBegin(prefix + "_time_begin")
|
||||||
|
, mEnd(prefix + "_time_end")
|
||||||
|
, mTaken(prefix + "_time_taken")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class UserStatsType : std::size_t
|
||||||
|
{
|
||||||
|
Input,
|
||||||
|
Sound,
|
||||||
|
State,
|
||||||
|
Script,
|
||||||
|
Mechanics,
|
||||||
|
Physics,
|
||||||
|
PhysicsWorker,
|
||||||
|
World,
|
||||||
|
Gui,
|
||||||
|
Lua,
|
||||||
|
LuaSyncUpdate,
|
||||||
|
WindowManager,
|
||||||
|
Number,
|
||||||
|
};
|
||||||
|
|
||||||
|
template <UserStatsType type>
|
||||||
|
struct UserStatsValue
|
||||||
|
{
|
||||||
|
static const UserStats sValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::Input>::sValue{ "Input", "input" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::Sound>::sValue{ "Sound", "sound" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::State>::sValue{ "State", "state" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::Script>::sValue{ "Script", "script" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::Mechanics>::sValue{ "Mech", "mechanics" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::Physics>::sValue{ "Phys", "physics" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::PhysicsWorker>::sValue{ " -Async", "physicsworker" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::World>::sValue{ "World", "world" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::Gui>::sValue{ "Gui", "gui" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::Lua>::sValue{ "Lua", "lua" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::LuaSyncUpdate>::sValue{ " -Sync", "luasyncupdate" };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const UserStats UserStatsValue<UserStatsType::WindowManager>::sValue{ "WindowManager", "windowmanager" };
|
||||||
|
|
||||||
|
template <UserStatsType type>
|
||||||
|
struct ForEachUserStatsValue
|
||||||
|
{
|
||||||
|
template <class F>
|
||||||
|
static void apply(F&& f)
|
||||||
|
{
|
||||||
|
f(UserStatsValue<type>::sValue);
|
||||||
|
using Next = ForEachUserStatsValue<static_cast<UserStatsType>(static_cast<std::size_t>(type) + 1)>;
|
||||||
|
Next::apply(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ForEachUserStatsValue<UserStatsType::Number>
|
||||||
|
{
|
||||||
|
template <class F>
|
||||||
|
static void apply(F&&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void forEachUserStatsValue(F&& f)
|
||||||
|
{
|
||||||
|
ForEachUserStatsValue<static_cast<UserStatsType>(0)>::apply(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <UserStatsType type>
|
||||||
|
class ScopedProfile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ScopedProfile(
|
||||||
|
osg::Timer_t frameStart, unsigned int frameNumber, const osg::Timer& timer, osg::Stats& stats)
|
||||||
|
: mScopeStart(timer.tick())
|
||||||
|
, mFrameStart(frameStart)
|
||||||
|
, mFrameNumber(frameNumber)
|
||||||
|
, mTimer(timer)
|
||||||
|
, mStats(stats)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedProfile(const ScopedProfile&) = delete;
|
||||||
|
ScopedProfile& operator=(const ScopedProfile&) = delete;
|
||||||
|
|
||||||
|
~ScopedProfile()
|
||||||
|
{
|
||||||
|
if (!mStats.collectStats("engine"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const osg::Timer_t end = mTimer.tick();
|
||||||
|
const UserStats& stats = UserStatsValue<type>::sValue;
|
||||||
|
|
||||||
|
mStats.setAttribute(mFrameNumber, stats.mBegin, mTimer.delta_s(mFrameStart, mScopeStart));
|
||||||
|
mStats.setAttribute(mFrameNumber, stats.mTaken, mTimer.delta_s(mScopeStart, end));
|
||||||
|
mStats.setAttribute(mFrameNumber, stats.mEnd, mTimer.delta_s(mFrameStart, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const osg::Timer_t mScopeStart;
|
||||||
|
const osg::Timer_t mFrameStart;
|
||||||
|
const unsigned int mFrameNumber;
|
||||||
|
const osg::Timer& mTimer;
|
||||||
|
osg::Stats& mStats;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in a new issue