From 804f873649fa7363c8eade47f981f7b3e4046fba Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 6 Mar 2017 16:32:56 +0100 Subject: [PATCH] terrain: factor out texture caching into a separate class --- apps/openmw/mwworld/cellpreloader.cpp | 2 +- components/CMakeLists.txt | 2 +- components/terrain/terraingrid.cpp | 46 +++---------------- components/terrain/terraingrid.hpp | 6 +-- components/terrain/texturemanager.cpp | 64 +++++++++++++++++++++++++++ components/terrain/texturemanager.hpp | 39 ++++++++++++++++ components/terrain/world.cpp | 9 ++++ components/terrain/world.hpp | 8 +++- 8 files changed, 128 insertions(+), 48 deletions(-) create mode 100644 components/terrain/texturemanager.cpp create mode 100644 components/terrain/texturemanager.hpp diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 278efa53d..c870369c9 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -174,7 +174,7 @@ namespace MWWorld { mResourceSystem->updateCache(mReferenceTime); - mTerrain->updateCache(); + mTerrain->updateCache(mReferenceTime); } private: diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9220f91ad..c1b329942 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -114,7 +114,7 @@ add_component_dir (translation ) add_component_dir (terrain - storage world buffercache defs terraingrid material terraindrawable + storage world buffercache defs terraingrid material terraindrawable texturemanager ) add_component_dir (loadinglistener diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index a542c8cee..ffb30c04a 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -23,6 +23,7 @@ #include "material.hpp" #include "storage.hpp" #include "terraindrawable.hpp" +#include "texturemanager.hpp" namespace { @@ -150,35 +151,17 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu useShaders = true; // always use shaders when lighting is unclamped, this is to avoid lighting seams between a terrain chunk with normal maps and one without normal maps std::vector layers; { - OpenThreads::ScopedLock lock(mTextureCacheMutex); for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { TextureLayer textureLayer; textureLayer.mParallax = it->mParallax; textureLayer.mSpecular = it->mSpecular; - osg::ref_ptr texture = mTextureCache[it->mDiffuseMap]; - if (!texture) - { - texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mDiffuseMap)); - texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); - texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); - mResourceSystem->getSceneManager()->applyFilterSettings(texture); - mTextureCache[it->mDiffuseMap] = texture; - } - textureLayer.mDiffuseMap = texture; + + textureLayer.mDiffuseMap = mTextureManager->getTexture(it->mDiffuseMap); if (!it->mNormalMap.empty()) { - texture = mTextureCache[it->mNormalMap]; - if (!texture) - { - texture = new osg::Texture2D(mResourceSystem->getImageManager()->getImage(it->mNormalMap)); - texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); - texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); - mResourceSystem->getSceneManager()->applyFilterSettings(texture); - mTextureCache[it->mNormalMap] = texture; - } - textureLayer.mNormalMap = texture; + textureLayer.mNormalMap = mTextureManager->getTexture(it->mNormalMap); } if (it->requiresShaders()) @@ -266,7 +249,7 @@ void TerrainGrid::unloadCell(int x, int y) mGrid.erase(it); } -void TerrainGrid::updateCache() +void TerrainGrid::updateCache(double referenceTime) { { OpenThreads::ScopedLock lock(mGridCacheMutex); @@ -278,24 +261,11 @@ void TerrainGrid::updateCache() ++it; } } - - { - OpenThreads::ScopedLock lock(mTextureCacheMutex); - for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end();) - { - if (it->second->referenceCount() <= 1) - mTextureCache.erase(it++); - else - ++it; - } - } } void TerrainGrid::updateTextureFiltering() { - OpenThreads::ScopedLock lock(mTextureCacheMutex); - for (TextureCache::iterator it = mTextureCache.begin(); it != mTextureCache.end(); ++it) - mResourceSystem->getSceneManager()->applyFilterSettings(it->second); + mTextureManager->updateTextureFiltering(); } void TerrainGrid::reportStats(unsigned int frameNumber, osg::Stats *stats) @@ -304,10 +274,6 @@ void TerrainGrid::reportStats(unsigned int frameNumber, osg::Stats *stats) OpenThreads::ScopedLock lock(mGridCacheMutex); stats->setAttribute(frameNumber, "Terrain Cell", mGridCache.size()); } - { - OpenThreads::ScopedLock lock(mTextureCacheMutex); - stats->setAttribute(frameNumber, "Terrain Texture", mTextureCache.size()); - } } } diff --git a/components/terrain/terraingrid.hpp b/components/terrain/terraingrid.hpp index d619ed8f7..7f6ea2d30 100644 --- a/components/terrain/terraingrid.hpp +++ b/components/terrain/terraingrid.hpp @@ -43,7 +43,7 @@ namespace Terrain /// Clear cached objects that are no longer referenced /// @note Thread safe. - void updateCache(); + void updateCache(double referenceTime); /// Apply the scene manager's texture filtering settings to all cached textures. /// @note Thread safe. @@ -57,10 +57,6 @@ namespace Terrain // split each ESM::Cell into mNumSplits*mNumSplits terrain chunks unsigned int mNumSplits; - typedef std::map > TextureCache; - TextureCache mTextureCache; - OpenThreads::Mutex mTextureCacheMutex; - typedef std::map, osg::ref_ptr > Grid; Grid mGrid; diff --git a/components/terrain/texturemanager.cpp b/components/terrain/texturemanager.cpp new file mode 100644 index 000000000..dd1e87bf6 --- /dev/null +++ b/components/terrain/texturemanager.cpp @@ -0,0 +1,64 @@ +#include "texturemanager.hpp" + +#include +#include + +#include +#include +#include + +namespace Terrain +{ + +TextureManager::TextureManager(Resource::SceneManager *sceneMgr) + : ResourceManager(sceneMgr->getVFS()) + , mSceneManager(sceneMgr) +{ + +} + +struct UpdateTextureFilteringFunctor +{ + UpdateTextureFilteringFunctor(Resource::SceneManager* sceneMgr) + : mSceneManager(sceneMgr) + { + } + Resource::SceneManager* mSceneManager; + + void operator()(osg::Object* obj) + { + mSceneManager->applyFilterSettings(static_cast(obj)); + } +}; + +void TextureManager::updateTextureFiltering() +{ + UpdateTextureFilteringFunctor f(mSceneManager); + mCache->call(f); +} + +osg::ref_ptr TextureManager::getTexture(const std::string &name) +{ + // don't bother with case folding, since there is only one way of referring to terrain textures we can assume the case is always the same + osg::ref_ptr obj = mCache->getRefFromObjectCache(name); + if (obj) + return static_cast(obj.get()); + else + { + osg::ref_ptr texture (new osg::Texture2D(mSceneManager->getImageManager()->getImage(name))); + texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); + mSceneManager->applyFilterSettings(texture); + mCache->addEntryToObjectCache(name, texture.get()); + return texture; + } +} + +void TextureManager::reportStats(unsigned int frameNumber, osg::Stats *stats) +{ + stats->setAttribute(frameNumber, "Terrain Texture", mCache->getCacheSize()); +} + + + +} diff --git a/components/terrain/texturemanager.hpp b/components/terrain/texturemanager.hpp new file mode 100644 index 000000000..9aba2f092 --- /dev/null +++ b/components/terrain/texturemanager.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_COMPONENTS_TERRAIN_TEXTUREMANAGER_H +#define OPENMW_COMPONENTS_TERRAIN_TEXTUREMANAGER_H + +#include + +#include + +namespace Resource +{ + class SceneManager; +} + +namespace osg +{ + class Texture2D; +} + +namespace Terrain +{ + + class TextureManager : public Resource::ResourceManager + { + public: + TextureManager(Resource::SceneManager* sceneMgr); + + void updateTextureFiltering(); + + osg::ref_ptr getTexture(const std::string& name); + + virtual void reportStats(unsigned int frameNumber, osg::Stats* stats); + + private: + Resource::SceneManager* mSceneManager; + + }; + +} + +#endif diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index f699cdc75..329ed5082 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -3,7 +3,10 @@ #include #include +#include + #include "storage.hpp" +#include "texturemanager.hpp" namespace Terrain { @@ -21,10 +24,16 @@ World::World(osg::Group* parent, Resource::ResourceSystem* resourceSystem, osgUt mTerrainRoot->setName("Terrain Root"); mParent->addChild(mTerrainRoot); + + mTextureManager.reset(new TextureManager(mResourceSystem->getSceneManager())); + + mResourceSystem->addResourceManager(mTextureManager.get()); } World::~World() { + mResourceSystem->removeResourceManager(mTextureManager.get()); + mParent->removeChild(mTerrainRoot); delete mStorage; diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index cc2285e45..30d765e2d 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -3,6 +3,8 @@ #include +#include + #include "defs.hpp" #include "buffercache.hpp" @@ -26,6 +28,8 @@ namespace Terrain { class Storage; + class TextureManager; + /** * @brief The basic interface for a terrain world. How the terrain chunks are paged and displayed * is up to the implementation. @@ -42,7 +46,7 @@ namespace Terrain virtual void updateTextureFiltering() {} - virtual void updateCache() {} + virtual void updateCache(double referenceTime) {} virtual void reportStats(unsigned int frameNumber, osg::Stats* stats) {} @@ -65,6 +69,8 @@ namespace Terrain Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; + + std::auto_ptr mTextureManager; }; }