1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 21:49:55 +00:00

Make Land::loadData thread safe

This commit is contained in:
scrawl 2016-02-09 20:14:16 +01:00
parent 1457a0de78
commit 596fe56bfd
4 changed files with 31 additions and 23 deletions

View file

@ -224,8 +224,6 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
CSMWorld::Land newLand (land); CSMWorld::Land newLand (land);
newLand.mEsm = 0; // avoid potential dangling pointer (ESMReader isn't needed anyway,
// because record is already fully loaded)
newLand.mPlugin = 0; newLand.mPlugin = 0;
if (land.mDataTypes & ESM::Land::DATA_VTEX) if (land.mDataTypes & ESM::Land::DATA_VTEX)

View file

@ -62,6 +62,9 @@ namespace MWRender
const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX;
if (!land->isDataLoaded(flags)) if (!land->isDataLoaded(flags))
land->loadData(flags); land->loadData(flags);
// TODO: unload land data when it's no longer needed
return land; return land;
} }

View file

@ -2,6 +2,8 @@
#include <utility> #include <utility>
#include <OpenThreads/ScopedLock>
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include "defs.hpp" #include "defs.hpp"
@ -60,7 +62,6 @@ namespace ESM
, mX(0) , mX(0)
, mY(0) , mY(0)
, mPlugin(0) , mPlugin(0)
, mEsm(NULL)
, mDataTypes(0) , mDataTypes(0)
, mDataLoaded(false) , mDataLoaded(false)
, mLandData(NULL) , mLandData(NULL)
@ -86,8 +87,7 @@ namespace ESM
{ {
isDeleted = false; isDeleted = false;
mEsm = &esm; mPlugin = esm.getIndex();
mPlugin = mEsm->getIndex();
bool hasLocation = false; bool hasLocation = false;
bool isLoaded = false; bool isLoaded = false;
@ -180,6 +180,8 @@ namespace ESM
void Land::loadData(int flags) const void Land::loadData(int flags) const
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
// Try to load only available data // Try to load only available data
flags = flags & mDataTypes; flags = flags & mDataTypes;
// Return if all required data is loaded // Return if all required data is loaded
@ -191,15 +193,17 @@ namespace ESM
mLandData = new LandData; mLandData = new LandData;
mLandData->mDataTypes = mDataTypes; mLandData->mDataTypes = mDataTypes;
} }
mEsm->restoreContext(mContext);
if (mEsm->isNextSub("VNML")) { ESM::ESMReader reader;
condLoad(flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals)); reader.restoreContext(mContext);
if (reader.isNextSub("VNML")) {
condLoad(reader, flags, DATA_VNML, mLandData->mNormals, sizeof(mLandData->mNormals));
} }
if (mEsm->isNextSub("VHGT")) { if (reader.isNextSub("VHGT")) {
static VHGT vhgt; static VHGT vhgt;
if (condLoad(flags, DATA_VHGT, &vhgt, sizeof(vhgt))) { if (condLoad(reader, flags, DATA_VHGT, &vhgt, sizeof(vhgt))) {
float rowOffset = vhgt.mHeightOffset; float rowOffset = vhgt.mHeightOffset;
for (int y = 0; y < LAND_SIZE; y++) { for (int y = 0; y < LAND_SIZE; y++) {
rowOffset += vhgt.mHeightData[y * LAND_SIZE]; rowOffset += vhgt.mHeightData[y * LAND_SIZE];
@ -217,14 +221,14 @@ namespace ESM
} }
} }
if (mEsm->isNextSub("WNAM")) { if (reader.isNextSub("WNAM")) {
condLoad(flags, DATA_WNAM, mLandData->mWnam, 81); condLoad(reader, flags, DATA_WNAM, mLandData->mWnam, 81);
} }
if (mEsm->isNextSub("VCLR")) if (reader.isNextSub("VCLR"))
condLoad(flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS); condLoad(reader, flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS);
if (mEsm->isNextSub("VTEX")) { if (reader.isNextSub("VTEX")) {
static uint16_t vtex[LAND_NUM_TEXTURES]; static uint16_t vtex[LAND_NUM_TEXTURES];
if (condLoad(flags, DATA_VTEX, vtex, sizeof(vtex))) { if (condLoad(reader, flags, DATA_VTEX, vtex, sizeof(vtex))) {
LandData::transposeTextureData(vtex, mLandData->mTextures); LandData::transposeTextureData(vtex, mLandData->mTextures);
} }
} }
@ -240,25 +244,26 @@ namespace ESM
} }
} }
bool Land::condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const bool Land::condLoad(ESM::ESMReader& reader, int flags, int dataFlag, void *ptr, unsigned int size) const
{ {
if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) { if ((mDataLoaded & dataFlag) == 0 && (flags & dataFlag) != 0) {
mEsm->getHExact(ptr, size); reader.getHExact(ptr, size);
mDataLoaded |= dataFlag; mDataLoaded |= dataFlag;
return true; return true;
} }
mEsm->skipHSubSize(size); reader.skipHSubSize(size);
return false; return false;
} }
bool Land::isDataLoaded(int flags) const bool Land::isDataLoaded(int flags) const
{ {
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(mMutex);
return (mDataLoaded & flags) == (flags & mDataTypes); return (mDataLoaded & flags) == (flags & mDataTypes);
} }
Land::Land (const Land& land) Land::Land (const Land& land)
: mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin), : mFlags (land.mFlags), mX (land.mX), mY (land.mY), mPlugin (land.mPlugin),
mEsm (land.mEsm), mContext (land.mContext), mDataTypes (land.mDataTypes), mContext (land.mContext), mDataTypes (land.mDataTypes),
mDataLoaded (land.mDataLoaded), mDataLoaded (land.mDataLoaded),
mLandData (land.mLandData ? new LandData (*land.mLandData) : 0) mLandData (land.mLandData ? new LandData (*land.mLandData) : 0)
{} {}
@ -275,7 +280,6 @@ namespace ESM
std::swap (mX, land.mX); std::swap (mX, land.mX);
std::swap (mY, land.mY); std::swap (mY, land.mY);
std::swap (mPlugin, land.mPlugin); std::swap (mPlugin, land.mPlugin);
std::swap (mEsm, land.mEsm);
std::swap (mContext, land.mContext); std::swap (mContext, land.mContext);
std::swap (mDataTypes, land.mDataTypes); std::swap (mDataTypes, land.mDataTypes);
std::swap (mDataLoaded, land.mDataLoaded); std::swap (mDataLoaded, land.mDataLoaded);

View file

@ -3,6 +3,8 @@
#include <stdint.h> #include <stdint.h>
#include <OpenThreads/Mutex>
#include "esmcommon.hpp" #include "esmcommon.hpp"
namespace ESM namespace ESM
@ -31,7 +33,6 @@ struct Land
// File context. This allows the ESM reader to be 'reset' to this // File context. This allows the ESM reader to be 'reset' to this
// location later when we are ready to load the full data set. // location later when we are ready to load the full data set.
ESMReader* mEsm;
ESM_Context mContext; ESM_Context mContext;
int mDataTypes; int mDataTypes;
@ -155,7 +156,9 @@ struct Land
/// Loads data and marks it as loaded /// Loads data and marks it as loaded
/// \return true if data is actually loaded from file, false otherwise /// \return true if data is actually loaded from file, false otherwise
/// including the case when data is already loaded /// including the case when data is already loaded
bool condLoad(int flags, int dataFlag, void *ptr, unsigned int size) const; bool condLoad(ESM::ESMReader& reader, int flags, int dataFlag, void *ptr, unsigned int size) const;
mutable OpenThreads::Mutex mMutex;
mutable int mDataLoaded; mutable int mDataLoaded;