diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b9f499ffb4..71d169c0bc 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,6 +1,6 @@ #include "engine.hpp" -#include +#include #include #include #include @@ -830,6 +830,82 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mLuaManager->init(); } +class OMW::Engine::LuaWorker +{ +public: + explicit LuaWorker(Engine* engine) : + mEngine(engine), + mSeparateThread(Settings::Manager::getInt("lua num threads", "Lua") > 0) + { + if (mSeparateThread) + mThread = std::thread([this]{ threadBody(); }); + }; + + void allowUpdate(double dt) + { + mDt = dt; + if (!mSeparateThread) + return; + { + std::lock_guard lk(mMutex); + mUpdateRequest = true; + } + mCV.notify_one(); + } + + void finishUpdate() + { + if (mSeparateThread) + { + std::unique_lock lk(mMutex); + mCV.wait(lk, [&]{ return !mUpdateRequest; }); + } + else + update(); + mEngine->mLuaManager->applyQueuedChanges(); + }; + + void join() + { + if (mSeparateThread) + 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 profile(frameStart, frameNumber, *osg::Timer::instance(), *viewer->getViewerStats()); + + mEngine->mLuaManager->update(mEngine->mEnvironment.getWindowManager()->isGuiMode(), mDt); + } + + void threadBody() + { + while (!mEngine->mViewer->done() && !mEngine->mEnvironment.getStateManager()->hasQuitRequest()) + { + std::unique_lock lk(mMutex); + mCV.wait(lk, [&]{ return mUpdateRequest; }); + + update(); + + mUpdateRequest = false; + lk.unlock(); + mCV.notify_one(); + } + } + + Engine* mEngine; + const bool mSeparateThread; + std::mutex mMutex; + std::condition_variable mCV; + bool mUpdateRequest; + double mDt = 0; + std::thread mThread; +}; + // Initialise and enter main loop. void OMW::Engine::go() { @@ -912,27 +988,7 @@ void OMW::Engine::go() mEnvironment.getWindowManager()->executeInConsole(mStartupScript); } - // Start Lua scripting thread - std::atomic_bool luaUpdateRequest; - double luaDt = 0; - std::thread scriptingThread([&]() { - const osg::Timer* const timer = osg::Timer::instance(); - osg::Stats* const stats = mViewer->getViewerStats(); - while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) - { - while (!luaUpdateRequest) - std::this_thread::yield(); - - { - const osg::Timer_t frameStart = mViewer->getStartTick(); - const unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); - ScopedProfile profile(frameStart, frameNumber, *timer, *stats); - - mLuaManager->update(mEnvironment.getWindowManager()->isGuiMode(), luaDt); - } - luaUpdateRequest = false; - } - }); + LuaWorker luaWorker(this); // starts a separate lua thread if "lua num threads" > 0 // Start the main rendering loop double simulationTime = 0.0; @@ -959,16 +1015,11 @@ void OMW::Engine::go() mEnvironment.getWorld()->updateWindowManager(); - // scriptingThread starts processing Lua scripts - luaDt = dt; - luaUpdateRequest = true; + luaWorker.allowUpdate(dt); // if there is a separate Lua thread, it starts the update now mViewer->renderingTraversals(); - // wait for scriptingThread to finish - while (luaUpdateRequest) - std::this_thread::yield(); - mLuaManager->applyQueuedChanges(); + luaWorker.finishUpdate(); bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); if (!guiActive) @@ -991,7 +1042,7 @@ void OMW::Engine::go() frameRateLimiter.limit(); } - scriptingThread.join(); + luaWorker.join(); // Save user settings settings.saveUser(settingspath); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 0645939694..180e06bcbc 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -194,6 +194,7 @@ namespace OMW private: Files::ConfigurationManager& mCfgMgr; + class LuaWorker; }; } diff --git a/docs/source/reference/modding/settings/index.rst b/docs/source/reference/modding/settings/index.rst index e9607fd9d1..b1cfad44ff 100644 --- a/docs/source/reference/modding/settings/index.rst +++ b/docs/source/reference/modding/settings/index.rst @@ -58,6 +58,7 @@ The ranges included with each setting are the physically possible ranges, not re HUD game general + lua shaders shadows input diff --git a/docs/source/reference/modding/settings/lua.rst b/docs/source/reference/modding/settings/lua.rst new file mode 100644 index 0000000000..4d1a3ca808 --- /dev/null +++ b/docs/source/reference/modding/settings/lua.rst @@ -0,0 +1,17 @@ +Lua Settings +############ + +lua num threads +--------------- + +:Type: integer +:Range: 0, 1 +:Default: 1 + +The maximum number of threads used for Lua scripts. +If zero, Lua scripts are processed in the main thread. +If one, a separate thread is used. +Values >1 are not yet supported. + +This setting can only be configured by editing the settings configuration file. + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 522762555d..d539ba34da 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1096,3 +1096,10 @@ stomp mode = 2 # 1 - Reduced levels. # 0 - Gentle levels. stomp intensity = 1 + +[Lua] + +# Set the maximum number of threads used for Lua scripts. +# If zero, Lua scripts are processed in the main thread. +lua num threads = 1 +