1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 08:39:45 +00:00

Write png image of the global map for save asynchronously

Write global map to the save file last to give more time for async job to
finish.
This commit is contained in:
elsid 2022-02-13 20:45:05 +01:00
parent b43eb29465
commit a4d7b72511
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
8 changed files with 74 additions and 19 deletions

View file

@ -358,6 +358,8 @@ namespace MWBase
virtual void onDeleteCustomData(const MWWorld::Ptr& ptr) = 0;
virtual void forceLootMode(const MWWorld::Ptr& ptr) = 0;
virtual void asyncPrepareSaveMap() = 0;
};
}

View file

@ -759,7 +759,7 @@ namespace MWGui
, mGlobal(Settings::Manager::getBool("global", "Map"))
, mEventBoxGlobal(nullptr)
, mEventBoxLocal(nullptr)
, mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue))
, mGlobalMapRender(std::make_unique<MWRender::GlobalMap>(localMapRender->getRoot(), workQueue))
, mEditNoteDialog()
{
static bool registered = false;
@ -1028,7 +1028,6 @@ namespace MWGui
MapWindow::~MapWindow()
{
delete mGlobalMapRender;
}
void MapWindow::setCellName(const std::string& cellName)
@ -1357,6 +1356,11 @@ namespace MWGui
marker->eventMouseWheel += MyGUI::newDelegate(this, &MapWindow::onMapZoomed);
}
void MapWindow::asyncPrepareSaveMap()
{
mGlobalMapRender->asyncWritePng();
}
// -------------------------------------------------------------------
EditNoteDialog::EditNoteDialog()

View file

@ -260,6 +260,8 @@ namespace MWGui
void write (ESM::ESMWriter& writer, Loading::Listener& progress);
void readRecord (ESM::ESMReader& reader, uint32_t type);
void asyncPrepareSaveMap();
private:
void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
@ -304,7 +306,7 @@ namespace MWGui
MyGUI::Button* mEventBoxLocal;
float mGlobalMapZoom = 1.0f;
MWRender::GlobalMap* mGlobalMapRender;
std::unique_ptr<MWRender::GlobalMap> mGlobalMapRender;
struct MapMarkerType
{

View file

@ -2263,4 +2263,9 @@ namespace MWGui
for(auto* window : mWindows)
window->onDeleteCustomData(ptr);
}
void WindowManager::asyncPrepareSaveMap()
{
mMap->asyncPrepareSaveMap();
}
}

View file

@ -392,6 +392,8 @@ namespace MWGui
void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
void forceLootMode(const MWWorld::Ptr& ptr) override;
void asyncPrepareSaveMap() override;
private:
unsigned int mOldUpdateMask; unsigned int mOldCullMask;

View file

@ -93,6 +93,26 @@ namespace
MWRender::GlobalMap* mParent;
};
std::vector<char> writePng(const osg::Image& overlayImage)
{
std::ostringstream ostream;
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!readerwriter)
{
Log(Debug::Error) << "Error: Can't write map overlay: no png readerwriter found";
return std::vector<char>();
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(overlayImage, ostream);
if (!result.success())
{
Log(Debug::Warning) << "Error: Can't write map overlay: " << result.message() << " code " << result.status();
return std::vector<char>();
}
std::string data = ostream.str();
return std::vector<char>(data.begin(), data.end());
}
}
namespace MWRender
@ -221,6 +241,20 @@ namespace MWRender
osg::ref_ptr<osg::Texture2D> mOverlayTexture;
};
struct GlobalMap::WritePng final : public SceneUtil::WorkItem
{
osg::ref_ptr<const osg::Image> mOverlayImage;
std::vector<char> mImageData;
explicit WritePng(osg::ref_ptr<const osg::Image> overlayImage)
: mOverlayImage(std::move(overlayImage)) {}
void doWork() override
{
mImageData = writePng(*mOverlayImage);
}
};
GlobalMap::GlobalMap(osg::Group* root, SceneUtil::WorkQueue* workQueue)
: mRoot(root)
, mWorkQueue(workQueue)
@ -400,23 +434,15 @@ namespace MWRender
map.mBounds.mMinY = mMinY;
map.mBounds.mMaxY = mMaxY;
std::ostringstream ostream;
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!readerwriter)
if (mWritePng != nullptr)
{
Log(Debug::Error) << "Error: Can't write map overlay: no png readerwriter found";
mWritePng->waitTillDone();
map.mImageData = std::move(mWritePng->mImageData);
mWritePng = nullptr;
return;
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*mOverlayImage, ostream);
if (!result.success())
{
Log(Debug::Warning) << "Error: Can't write map overlay: " << result.message() << " code " << result.status();
return;
}
std::string data = ostream.str();
map.mImageData = std::vector<char>(data.begin(), data.end());
map.mImageData = writePng(*mOverlayImage);
}
struct Box
@ -606,4 +632,11 @@ namespace MWRender
cam->removeChildren(0, cam->getNumChildren());
mRoot->removeChild(cam);
}
void GlobalMap::asyncWritePng()
{
// Use deep copy to avoid any sychronization
mWritePng = new WritePng(new osg::Image(*mOverlayImage, osg::CopyOp::DEEP_COPY_ALL));
mWorkQueue->addWorkItem(mWritePng, /*front=*/true);
}
}

View file

@ -72,7 +72,11 @@ namespace MWRender
void ensureLoaded();
void asyncWritePng();
private:
struct WritePng;
/**
* Request rendering a 2d quad onto mOverlayTexture.
* x, y, width and height are the destination coordinates (top-left coordinate origin)
@ -121,6 +125,7 @@ namespace MWRender
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
osg::ref_ptr<CreateMapWorkItem> mWorkItem;
osg::ref_ptr<WritePng> mWritePng;
int mWidth;
int mHeight;

View file

@ -190,6 +190,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
{
const auto start = std::chrono::steady_clock::now();
MWBase::Environment::get().getWindowManager()->asyncPrepareSaveMap();
if (!character)
{
MWWorld::ConstPtr player = MWMechanics::getPlayer();
@ -257,9 +259,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
+MWBase::Environment::get().getWorld()->countSavedGameRecords()
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
+MWBase::Environment::get().getWindowManager()->countSavedGameRecords()
+MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords()
+MWBase::Environment::get().getInputManager()->countSavedGameRecords();
+MWBase::Environment::get().getInputManager()->countSavedGameRecords()
+MWBase::Environment::get().getWindowManager()->countSavedGameRecords();
writer.setRecordCount (recordCount);
writer.save (stream);
@ -282,9 +284,9 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
MWBase::Environment::get().getLuaManager()->write(writer, listener);
MWBase::Environment::get().getWorld()->write (writer, listener);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
MWBase::Environment::get().getWindowManager()->write(writer, listener);
MWBase::Environment::get().getMechanicsManager()->write(writer, listener);
MWBase::Environment::get().getInputManager()->write(writer, listener);
MWBase::Environment::get().getWindowManager()->write(writer, listener);
// Ensure we have written the number of records that was estimated
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record