mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 20:29:57 +00:00
Merge branch 'fix_async_load' into 'master'
Fix crash related to async content loading (#7508) Closes #7508 See merge request OpenMW/openmw!3290
This commit is contained in:
commit
b2f669ca48
7 changed files with 82 additions and 28 deletions
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <future>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <osgDB/WriteFile>
|
#include <osgDB/WriteFile>
|
||||||
#include <osgViewer/ViewerEventHandlers>
|
#include <osgViewer/ViewerEventHandlers>
|
||||||
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#include <components/l10n/manager.hpp>
|
#include <components/l10n/manager.hpp>
|
||||||
|
|
||||||
|
#include <components/loadinglistener/asynclistener.hpp>
|
||||||
#include <components/loadinglistener/loadinglistener.hpp>
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
|
|
||||||
#include <components/misc/frameratelimiter.hpp>
|
#include <components/misc/frameratelimiter.hpp>
|
||||||
|
@ -742,8 +743,10 @@ void OMW::Engine::prepareEngine()
|
||||||
mWorld = std::make_unique<MWWorld::World>(
|
mWorld = std::make_unique<MWWorld::World>(
|
||||||
mResourceSystem.get(), mActivationDistanceOverride, mCellName, mCfgMgr.getUserDataPath());
|
mResourceSystem.get(), mActivationDistanceOverride, mCellName, mCfgMgr.getUserDataPath());
|
||||||
|
|
||||||
std::thread loadDataThread(
|
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
[&] { mWorld->loadData(mFileCollections, mContentFiles, mGroundcoverFiles, mEncoder.get()); });
|
Loading::AsyncListener asyncListener(*listener);
|
||||||
|
auto dataLoading = std::async(std::launch::async,
|
||||||
|
[&] { mWorld->loadData(mFileCollections, mContentFiles, mGroundcoverFiles, mEncoder.get(), &asyncListener); });
|
||||||
|
|
||||||
if (!mSkipMenu)
|
if (!mSkipMenu)
|
||||||
{
|
{
|
||||||
|
@ -752,9 +755,12 @@ void OMW::Engine::prepareEngine()
|
||||||
mWindowManager->playVideo(logo, true);
|
mWindowManager->playVideo(logo, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
|
||||||
listener->loadingOn();
|
listener->loadingOn();
|
||||||
loadDataThread.join();
|
{
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
while (dataLoading.wait_for(50ms) != std::future_status::ready)
|
||||||
|
asyncListener.update();
|
||||||
|
}
|
||||||
listener->loadingOff();
|
listener->loadingOff();
|
||||||
|
|
||||||
mWorld->init(mViewer, rootNode, mWorkQueue.get(), *mUnrefQueue);
|
mWorld->init(mViewer, rootNode, mWorkQueue.get(), *mUnrefQueue);
|
||||||
|
|
|
@ -76,10 +76,6 @@ namespace MWGui
|
||||||
|
|
||||||
void LoadingScreen::setLabel(const std::string& label, bool important)
|
void LoadingScreen::setLabel(const std::string& label, bool important)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(mMutex);
|
|
||||||
if (!isVisible())
|
|
||||||
return;
|
|
||||||
|
|
||||||
mImportantLabel = important;
|
mImportantLabel = important;
|
||||||
|
|
||||||
mLoadingText->setCaptionWithReplacing(label);
|
mLoadingText->setCaptionWithReplacing(label);
|
||||||
|
@ -145,8 +141,6 @@ namespace MWGui
|
||||||
|
|
||||||
void LoadingScreen::loadingOn(bool visible)
|
void LoadingScreen::loadingOn(bool visible)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(mMutex);
|
|
||||||
|
|
||||||
// Early-out if already on
|
// Early-out if already on
|
||||||
if (mNestedLoadingCount++ > 0 && mMainWidget->getVisible())
|
if (mNestedLoadingCount++ > 0 && mMainWidget->getVisible())
|
||||||
return;
|
return;
|
||||||
|
@ -187,8 +181,6 @@ namespace MWGui
|
||||||
|
|
||||||
void LoadingScreen::loadingOff()
|
void LoadingScreen::loadingOff()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(mMutex);
|
|
||||||
|
|
||||||
if (--mNestedLoadingCount > 0)
|
if (--mNestedLoadingCount > 0)
|
||||||
return;
|
return;
|
||||||
mLoadingBox->setVisible(true); // restore
|
mLoadingBox->setVisible(true); // restore
|
||||||
|
@ -247,10 +239,6 @@ namespace MWGui
|
||||||
|
|
||||||
void LoadingScreen::setProgress(size_t value)
|
void LoadingScreen::setProgress(size_t value)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(mMutex);
|
|
||||||
if (!isVisible())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// skip expensive update if there isn't enough visible progress
|
// skip expensive update if there isn't enough visible progress
|
||||||
if (mProgressBar->getWidth() <= 0
|
if (mProgressBar->getWidth() <= 0
|
||||||
|| value - mProgress < mProgressBar->getScrollRange() / mProgressBar->getWidth())
|
|| value - mProgress < mProgressBar->getScrollRange() / mProgressBar->getWidth())
|
||||||
|
@ -265,10 +253,6 @@ namespace MWGui
|
||||||
|
|
||||||
void LoadingScreen::increaseProgress(size_t increase)
|
void LoadingScreen::increaseProgress(size_t increase)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(mMutex);
|
|
||||||
if (!isVisible())
|
|
||||||
return;
|
|
||||||
|
|
||||||
mProgressBar->setScrollPosition(0);
|
mProgressBar->setScrollPosition(0);
|
||||||
size_t value = mProgress + increase;
|
size_t value = mProgress + increase;
|
||||||
value = std::min(value, mProgressBar->getScrollRange() - 1);
|
value = std::min(value, mProgressBar->getScrollRange() - 1);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define MWGUI_LOADINGSCREEN_H
|
#define MWGUI_LOADINGSCREEN_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include <osg/Timer>
|
#include <osg/Timer>
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
@ -70,8 +69,6 @@ namespace MWGui
|
||||||
bool mVisible;
|
bool mVisible;
|
||||||
int mNestedLoadingCount;
|
int mNestedLoadingCount;
|
||||||
|
|
||||||
std::mutex mMutex;
|
|
||||||
|
|
||||||
size_t mProgress;
|
size_t mProgress;
|
||||||
|
|
||||||
bool mShowWallpaper;
|
bool mShowWallpaper;
|
||||||
|
|
|
@ -270,13 +270,12 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::loadData(const Files::Collections& fileCollections, const std::vector<std::string>& contentFiles,
|
void World::loadData(const Files::Collections& fileCollections, const std::vector<std::string>& contentFiles,
|
||||||
const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder)
|
const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder, Loading::Listener* listener)
|
||||||
{
|
{
|
||||||
mContentFiles = contentFiles;
|
mContentFiles = contentFiles;
|
||||||
if (encoder)
|
if (encoder)
|
||||||
mReaders.setStatelessEncoder(encoder->getStatelessEncoder());
|
mReaders.setStatelessEncoder(encoder->getStatelessEncoder());
|
||||||
mESMVersions.resize(mContentFiles.size(), -1);
|
mESMVersions.resize(mContentFiles.size(), -1);
|
||||||
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
|
||||||
|
|
||||||
loadContentFiles(fileCollections, contentFiles, encoder, listener);
|
loadContentFiles(fileCollections, contentFiles, encoder, listener);
|
||||||
loadGroundcoverFiles(fileCollections, groundcoverFiles, encoder, listener);
|
loadGroundcoverFiles(fileCollections, groundcoverFiles, encoder, listener);
|
||||||
|
|
|
@ -199,7 +199,8 @@ namespace MWWorld
|
||||||
const std::filesystem::path& userDataPath);
|
const std::filesystem::path& userDataPath);
|
||||||
|
|
||||||
void loadData(const Files::Collections& fileCollections, const std::vector<std::string>& contentFiles,
|
void loadData(const Files::Collections& fileCollections, const std::vector<std::string>& contentFiles,
|
||||||
const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder);
|
const std::vector<std::string>& groundcoverFiles, ToUTF8::Utf8Encoder* encoder,
|
||||||
|
Loading::Listener* listener);
|
||||||
|
|
||||||
// Must be called after `loadData`.
|
// Must be called after `loadData`.
|
||||||
void init(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, SceneUtil::WorkQueue* workQueue,
|
void init(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, SceneUtil::WorkQueue* workQueue,
|
||||||
|
|
|
@ -292,7 +292,7 @@ add_component_dir (terrain
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (loadinglistener
|
add_component_dir (loadinglistener
|
||||||
loadinglistener
|
loadinglistener asynclistener
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (myguiplatform
|
add_component_dir (myguiplatform
|
||||||
|
|
67
components/loadinglistener/asynclistener.hpp
Normal file
67
components/loadinglistener/asynclistener.hpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef COMPONENTS_LOADINGLISTENER_ASYNCLISTENER_H
|
||||||
|
#define COMPONENTS_LOADINGLISTENER_ASYNCLISTENER_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "loadinglistener.hpp"
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class AsyncListener : public Listener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AsyncListener(Listener& baseListener)
|
||||||
|
: mBaseListener(baseListener)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabel(const std::string& label, bool important) override
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(mMutex);
|
||||||
|
mLabelUpdate = label;
|
||||||
|
mImportantLabel = important;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProgressRange(size_t range) override
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(mMutex);
|
||||||
|
mRangeUpdate = range;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProgress(size_t value) override
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(mMutex);
|
||||||
|
mProgressUpdate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void increaseProgress(size_t increase) override
|
||||||
|
{ /* not implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
void update()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(mMutex);
|
||||||
|
if (mLabelUpdate)
|
||||||
|
mBaseListener.setLabel(*mLabelUpdate, mImportantLabel);
|
||||||
|
if (mRangeUpdate)
|
||||||
|
mBaseListener.setProgressRange(*mRangeUpdate);
|
||||||
|
if (mProgressUpdate)
|
||||||
|
mBaseListener.setProgress(*mProgressUpdate);
|
||||||
|
mLabelUpdate = std::nullopt;
|
||||||
|
mRangeUpdate = std::nullopt;
|
||||||
|
mProgressUpdate = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Listener& mBaseListener;
|
||||||
|
std::mutex mMutex;
|
||||||
|
std::optional<std::string> mLabelUpdate;
|
||||||
|
bool mImportantLabel = false;
|
||||||
|
std::optional<size_t> mRangeUpdate;
|
||||||
|
std::optional<size_t> mProgressUpdate;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // COMPONENTS_LOADINGLISTENER_ASYNCLISTENER_H
|
Loading…
Reference in a new issue