Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improves paging preloader #3126

Merged
merged 23 commits into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 5 additions & 38 deletions apps/openmw/mwworld/cellpreloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace
{
template <class Contained>
bool contains(const std::vector<MWWorld::CellPreloader::PositionCellGrid>& container,
const Contained& contained, float tolerance=1.f)
const Contained& contained, float tolerance)
{
for (const auto& pos : contained)
{
Expand Down Expand Up @@ -180,14 +180,6 @@ namespace MWWorld
{
}

bool storeViews(double referenceTime)
{
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size(); ++i)
if (!mWorld->storeView(mTerrainViews[i], referenceTime))
return false;
return true;
}

void doWork() override
{
for (unsigned int i=0; i<mTerrainViews.size() && i<mPreloadPositions.size() && !mAbort; ++i)
Expand Down Expand Up @@ -246,7 +238,6 @@ namespace MWWorld
, mMaxCacheSize(0)
, mPreloadInstances(true)
, mLastResourceCacheUpdate(0.0)
, mStoreViewsFailCount(0)
, mLoadedTerrainTimestamp(0.0)
{
}
Expand Down Expand Up @@ -383,22 +374,8 @@ namespace MWWorld

if (mTerrainPreloadItem && mTerrainPreloadItem->isDone())
{
if (!mTerrainPreloadItem->storeViews(timestamp))
{
if (++mStoreViewsFailCount > 100)
{
OSG_ALWAYS << "paging views are rebuilt every frame, please check for faulty enable/disable scripts." << std::endl;
mStoreViewsFailCount = 0;
}
setTerrainPreloadPositions(std::vector<PositionCellGrid>());
}
else
{
mStoreViewsFailCount = 0;
mLoadedTerrainPositions = mTerrainPreloadPositions;
mLoadedTerrainTimestamp = timestamp;
}
mTerrainPreloadItem = nullptr;
mLoadedTerrainPositions = mTerrainPreloadPositions;
mLoadedTerrainTimestamp = timestamp;
}
}

Expand Down Expand Up @@ -443,17 +420,7 @@ namespace MWWorld
return true;
else if (mTerrainPreloadItem->isDone())
{
if (mTerrainPreloadItem->storeViews(timestamp))
{
mTerrainPreloadItem = nullptr;
return true;
}
else
{
setTerrainPreloadPositions(std::vector<CellPreloader::PositionCellGrid>());
setTerrainPreloadPositions(positions);
return false;
}
return true;
}
else
{
Expand Down Expand Up @@ -481,7 +448,7 @@ namespace MWWorld
mTerrainPreloadPositions.clear();
mLoadedTerrainPositions.clear();
}
else if (contains(mTerrainPreloadPositions, positions))
else if (contains(mTerrainPreloadPositions, positions, 128.f))
return;
if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone())
return;
Expand Down
116 changes: 82 additions & 34 deletions components/terrain/chunkmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ ChunkManager::ChunkManager(Storage *storage, Resource::SceneManager *sceneMgr, T
mMultiPassRoot->setAttributeAndModes(material, osg::StateAttribute::ON);
}

struct FindChunkTemplate
{
void operator() (ChunkId id, osg::Object* obj)
{
if (std::get<0>(id) == std::get<0>(mId) && std::get<1>(id) == std::get<1>(mId))
mFoundTemplate = obj;
}
ChunkId mId;
osg::ref_ptr<osg::Object> mFoundTemplate;
};

osg::ref_ptr<osg::Node> ChunkManager::getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile)
{
ChunkId id = std::make_tuple(center, lod, lodFlags);
Expand All @@ -52,7 +63,11 @@ osg::ref_ptr<osg::Node> ChunkManager::getChunk(float size, const osg::Vec2f& cen
return static_cast<osg::Node*>(obj.get());
else
{
osg::ref_ptr<osg::Node> node = createChunk(size, center, lod, lodFlags, compile);
FindChunkTemplate find;
find.mId = id;
mCache->call(find);
TerrainDrawable* templateGeometry = (find.mFoundTemplate && !mDebugChunks) ? static_cast<TerrainDrawable*>(find.mFoundTemplate.get()) : nullptr;
osg::ref_ptr<osg::Node> node = createChunk(size, center, lod, lodFlags, compile, templateGeometry);
mCache->addEntryToObjectCache(id, node.get());
return node;
}
Expand Down Expand Up @@ -170,24 +185,45 @@ std::vector<osg::ref_ptr<osg::StateSet> > ChunkManager::createPasses(float chunk
return ::Terrain::createPasses(useShaders, &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale);
}

osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, unsigned char lod, unsigned int lodFlags, bool compile)
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, unsigned char lod, unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry)
{
osg::ref_ptr<osg::Vec3Array> positions (new osg::Vec3Array);
osg::ref_ptr<osg::Vec3Array> normals (new osg::Vec3Array);
osg::ref_ptr<osg::Vec4ubArray> colors (new osg::Vec4ubArray);
colors->setNormalize(true);

osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
positions->setVertexBufferObject(vbo);
normals->setVertexBufferObject(vbo);
colors->setVertexBufferObject(vbo);

mStorage->fillVertexBuffers(lod, chunkSize, chunkCenter, positions, normals, colors);

osg::ref_ptr<TerrainDrawable> geometry (new TerrainDrawable);
geometry->setVertexArray(positions);
geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);

if (!templateGeometry)
{
osg::ref_ptr<osg::Vec3Array> positions (new osg::Vec3Array);
osg::ref_ptr<osg::Vec3Array> normals (new osg::Vec3Array);
osg::ref_ptr<osg::Vec4ubArray> colors (new osg::Vec4ubArray);
colors->setNormalize(true);

mStorage->fillVertexBuffers(lod, chunkSize, chunkCenter, positions, normals, colors);

osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
positions->setVertexBufferObject(vbo);
normals->setVertexBufferObject(vbo);
colors->setVertexBufferObject(vbo);

geometry->setVertexArray(positions);
geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
}
else
{
// Unfortunately we need to copy vertex data because of poor coupling with VertexBufferObject.
osg::ref_ptr<osg::Array> positions = static_cast<osg::Array*>(templateGeometry->getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
osg::ref_ptr<osg::Array> normals = static_cast<osg::Array*>(templateGeometry->getNormalArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
osg::ref_ptr<osg::Array> colors = static_cast<osg::Array*>(templateGeometry->getColorArray()->clone(osg::CopyOp::DEEP_COPY_ALL));

osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
positions->setVertexBufferObject(vbo);
normals->setVertexBufferObject(vbo);
colors->setVertexBufferObject(vbo);

geometry->setVertexArray(positions);
geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
}

geometry->setUseDisplayList(false);
geometry->setUseVertexBufferObjects(true);

Expand All @@ -207,32 +243,44 @@ osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Ve

geometry->setStateSet(mMultiPassRoot);

if (useCompositeMap)
if (templateGeometry)
{
osg::ref_ptr<CompositeMap> compositeMap = new CompositeMap;
compositeMap->mTexture = createCompositeMapRTT();
if (templateGeometry->getCompositeMap())
{
geometry->setCompositeMap(templateGeometry->getCompositeMap());
geometry->setCompositeMapRenderer(mCompositeMapRenderer);
}
geometry->setPasses(templateGeometry->getPasses());
}
else
{
if (useCompositeMap)
{
osg::ref_ptr<CompositeMap> compositeMap = new CompositeMap;
compositeMap->mTexture = createCompositeMapRTT();

createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0,0,1,1), *compositeMap);
createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0,0,1,1), *compositeMap);

mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false);
mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false);

geometry->setCompositeMap(compositeMap);
geometry->setCompositeMapRenderer(mCompositeMapRenderer);
geometry->setCompositeMap(compositeMap);
geometry->setCompositeMapRenderer(mCompositeMapRenderer);

TextureLayer layer;
layer.mDiffuseMap = compositeMap->mTexture;
layer.mParallax = false;
layer.mSpecular = false;
geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D> >(), 1.f, 1.f));
}
else
{
geometry->setPasses(createPasses(chunkSize, chunkCenter, false));
TextureLayer layer;
layer.mDiffuseMap = compositeMap->mTexture;
layer.mParallax = false;
layer.mSpecular = false;
geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D> >(), 1.f, 1.f));
}
else
{
geometry->setPasses(createPasses(chunkSize, chunkCenter, false));
}
}

geometry->setupWaterBoundingBox(-1, chunkSize * mStorage->getCellWorldSize() / numVerts);

if (compile && mSceneManager->getIncrementalCompileOperation())
if (!templateGeometry && compile && mSceneManager->getIncrementalCompileOperation())
{
mSceneManager->getIncrementalCompileOperation()->add(geometry);
}
Expand Down
3 changes: 2 additions & 1 deletion components/terrain/chunkmanager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace Terrain
class CompositeMapRenderer;
class Storage;
class CompositeMap;
class TerrainDrawable;

typedef std::tuple<osg::Vec2f, unsigned char, unsigned int> ChunkId; // Center, Lod, Lod Flags

Expand All @@ -51,7 +52,7 @@ namespace Terrain
void releaseGLObjects(osg::State* state) override;

private:
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool compile);
osg::ref_ptr<osg::Node> createChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool compile, TerrainDrawable* templateGeometry);

osg::ref_ptr<osg::Texture2D> createCompositeMapRTT();

Expand Down
54 changes: 31 additions & 23 deletions components/terrain/quadtreeworld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ namespace Terrain
class DefaultLodCallback : public LodCallback
{
public:
DefaultLodCallback(float factor, float minSize, float viewDistance, const osg::Vec4i& grid)
DefaultLodCallback(float factor, float minSize, float viewDistance, const osg::Vec4i& grid, float distanceModifier=0.f)
: mFactor(factor)
, mMinSize(minSize)
, mViewDistance(viewDistance)
, mActiveGrid(grid)
, mDistanceModifier(distanceModifier)
{
}

Expand All @@ -77,6 +78,8 @@ class DefaultLodCallback : public LodCallback
return Deeper;
}

dist = std::max(0.f, dist + mDistanceModifier);

if (dist > mViewDistance && !activeGrid) // for Scene<->ObjectPaging sync the activegrid must remain loaded
return StopTraversal;

Expand All @@ -91,6 +94,7 @@ class DefaultLodCallback : public LodCallback
float mMinSize;
float mViewDistance;
osg::Vec4i mActiveGrid;
float mDistanceModifier;
};

class RootNode : public QuadTreeNode
Expand Down Expand Up @@ -343,7 +347,7 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, f

for (QuadTreeWorld::ChunkManager* m : chunkManagers)
{
if (m->getViewDistance() && entry.mNode->distance(vd->getViewPoint()) > m->getViewDistance() + reuseDistance*10)
if (m->getViewDistance() && entry.mNode->distance(vd->getViewPoint()) > m->getViewDistance() + reuseDistance)
continue;
osg::ref_ptr<osg::Node> n = m->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags, activeGrid, vd->getViewPoint(), compile);
if (n) pat->addChild(n);
Expand Down Expand Up @@ -496,39 +500,43 @@ View* QuadTreeWorld::createView()
void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::Vec4i &grid, std::atomic<bool> &abort, Loading::Reporter& reporter)
{
ensureQuadTreeBuilt();
const float cellWorldSize = mStorage->getCellWorldSize();

ViewData* vd = static_cast<ViewData*>(view);
vd->setViewPoint(viewPoint);
vd->setActiveGrid(grid);
DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid);
mRootNode->traverseNodes(vd, viewPoint, &lodCallback);

std::size_t progressTotal = 0;
for (unsigned int i = 0, n = vd->getNumEntries(); i < n; ++i)
progressTotal += vd->getEntry(i).mNode->getSize();

reporter.addTotal(progressTotal);

const float cellWorldSize = mStorage->getCellWorldSize();
for (unsigned int i=0; i<vd->getNumEntries() && !abort; ++i)
for (unsigned int pass=0; pass<3; ++pass)
{
ViewData::Entry& entry = vd->getEntry(i);


unsigned int startEntry = vd->getNumEntries();

loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true, mViewDataMap->getReuseDistance());
reporter.addProgress(entry.mNode->getSize());
float distanceModifier=0.f;
if (pass == 1)
distanceModifier = 1024;
else if (pass == 2)
distanceModifier = -1024;
DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid, distanceModifier);
mRootNode->traverseNodes(vd, viewPoint, &lodCallback);

if (pass==0)
{
std::size_t progressTotal = 0;
for (unsigned int i = 0, n = vd->getNumEntries(); i < n; ++i)
progressTotal += vd->getEntry(i).mNode->getSize();

reporter.addTotal(progressTotal);
}

const float reuseDistance = std::max(mViewDataMap->getReuseDistance(), std::abs(distanceModifier));
for (unsigned int i=startEntry; i<vd->getNumEntries() && !abort; ++i)
{
ViewData::Entry& entry = vd->getEntry(i);

loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true, reuseDistance);
if (pass==0) reporter.addProgress(entry.mNode->getSize());
entry.mNode = nullptr; // Clear node lest we break the neighbours search for the next pass
}
}
vd->markUnchanged();
}

bool QuadTreeWorld::storeView(const View* view, double referenceTime)
{
return mViewDataMap->storeView(static_cast<const ViewData*>(view), referenceTime);
}

void QuadTreeWorld::reportStats(unsigned int frameNumber, osg::Stats *stats)
Expand Down
1 change: 0 additions & 1 deletion components/terrain/quadtreeworld.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ namespace Terrain

View* createView() override;
void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i &cellgrid, std::atomic<bool>& abort, Loading::Reporter& reporter) override;
bool storeView(const View* view, double referenceTime) override;
void rebuildViews() override;

void reportStats(unsigned int frameNumber, osg::Stats* stats) override;
Expand Down
4 changes: 2 additions & 2 deletions components/terrain/terraindrawable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ void TerrainDrawable::cull(osgUtil::CullVisitor *cv)
return;
}

if (mCompositeMap)
if (mCompositeMap && mCompositeMapRenderer)
{
mCompositeMapRenderer->setImmediate(mCompositeMap);
mCompositeMap = nullptr;
mCompositeMapRenderer = nullptr;
}

bool pushedLight = mLightListCallback && mLightListCallback->pushLightState(this, cv);
Expand Down
2 changes: 2 additions & 0 deletions components/terrain/terraindrawable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace Terrain

typedef std::vector<osg::ref_ptr<osg::StateSet> > PassVector;
void setPasses (const PassVector& passes);
const PassVector& getPasses() const { return mPasses; }

void setLightListCallback(SceneUtil::LightListCallback* lightListCallback);

Expand All @@ -56,6 +57,7 @@ namespace Terrain
const osg::BoundingBox& getWaterBoundingBox() const { return mWaterBoundingBox; }

void setCompositeMap(CompositeMap* map) { mCompositeMap = map; }
CompositeMap* getCompositeMap() { return mCompositeMap; }
void setCompositeMapRenderer(CompositeMapRenderer* renderer) { mCompositeMapRenderer = renderer; }

private:
Expand Down
Loading