diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d4199d5f6c..07b477c436 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -233,11 +233,15 @@ namespace MWRender void RenderingManager::clearCache() { - mResourceSystem->updateCache(mViewer->getFrameStamp()->getReferenceTime()); if (mTerrain.get()) mTerrain->clearCache(); } + double RenderingManager::getReferenceTime() const + { + return mViewer->getFrameStamp()->getReferenceTime(); + } + osg::Group* RenderingManager::getLightRoot() { return mLightRoot.get(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 550e48e636..bc5db562c3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -67,6 +67,8 @@ namespace MWRender void clearCache(); + double getReferenceTime() const; + osg::Group* getLightRoot(); void setNightEyeFactor(float factor); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index dd6850abae..16bf920bbb 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "../mwbase/environment.hpp" @@ -33,6 +34,7 @@ namespace MWWorld std::vector& mOut; }; + /// Worker thread item: preload models in a cell. class PreloadItem : public SceneUtil::WorkItem { public: @@ -92,8 +94,30 @@ namespace MWWorld std::vector > mPreloadedShapes; }; - CellPreloader::CellPreloader(Resource::SceneManager *sceneManager, Resource::BulletShapeManager* bulletShapeManager) - : mSceneManager(sceneManager) + /// Worker thread item: update the resource system's cache, effectively deleting unused entries. + class UpdateCacheItem : public SceneUtil::WorkItem + { + public: + UpdateCacheItem(Resource::ResourceSystem* resourceSystem, double referenceTime) + : mReferenceTime(referenceTime) + , mResourceSystem(resourceSystem) + { + } + + virtual void doWork() + { + osg::Timer timer; + mResourceSystem->updateCache(mReferenceTime); + std::cout << "cleared cache in " << timer.time_m() << std::endl; + } + + private: + double mReferenceTime; + Resource::ResourceSystem* mResourceSystem; + }; + + CellPreloader::CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager) + : mResourceSystem(resourceSystem) , mBulletShapeManager(bulletShapeManager) { mWorkQueue = new SceneUtil::WorkQueue; @@ -120,7 +144,7 @@ namespace MWWorld return; } - osg::ref_ptr item (new PreloadItem(cell, mSceneManager, mBulletShapeManager)); + osg::ref_ptr item (new PreloadItem(cell, mResourceSystem->getSceneManager(), mBulletShapeManager)); mWorkQueue->addWorkItem(item); mPreloadCells[cell] = PreloadEntry(timestamp, item); @@ -129,6 +153,7 @@ namespace MWWorld void CellPreloader::updateCache(double timestamp) { // time (in seconds) to keep a preloaded cell in cache after it's no longer needed + // additionally we could support a minimum/maximum size for the cache const double expiryTime = 60.0; for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();) @@ -138,6 +163,9 @@ namespace MWWorld else ++it; } + + // the resource cache is cleared from the worker thread so that we're not holding up the main thread with delete operations + mWorkQueue->addWorkItem(new UpdateCacheItem(mResourceSystem, timestamp)); } void CellPreloader::setWorkQueue(osg::ref_ptr workQueue) diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index 7e02cb7d10..b3413b1743 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -7,7 +7,7 @@ namespace Resource { - class SceneManager; + class ResourceSystem; class BulletShapeManager; } @@ -18,7 +18,7 @@ namespace MWWorld class CellPreloader { public: - CellPreloader(Resource::SceneManager* sceneManager, Resource::BulletShapeManager* bulletShapeManager); + CellPreloader(Resource::ResourceSystem* resourceSystem, Resource::BulletShapeManager* bulletShapeManager); /// Ask a background thread to preload rendering meshes and collision shapes for objects in this cell. /// @note The cell itself must be in State_Loaded or State_Preloaded. @@ -30,7 +30,7 @@ namespace MWWorld void setWorkQueue(osg::ref_ptr workQueue); private: - Resource::SceneManager* mSceneManager; + Resource::ResourceSystem* mResourceSystem; Resource::BulletShapeManager* mBulletShapeManager; osg::ref_ptr mWorkQueue; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f30e6efe10..70a461b5b9 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -24,6 +24,7 @@ #include "class.hpp" #include "cellvisitors.hpp" #include "cellstore.hpp" +#include "cellpreloader.hpp" namespace { @@ -402,6 +403,7 @@ namespace MWWorld mCellChanged = true; + mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); } @@ -439,6 +441,7 @@ namespace MWWorld Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics) : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) { + mPreloader.reset(new CellPreloader(rendering.getResourceSystem(), physics->getShapeManager())); } Scene::~Scene() @@ -515,6 +518,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); + mPreloader->updateCache(mRendering.getReferenceTime()); mRendering.clearCache(); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index c6de3ebdf7..b428d0ddd7 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -1,12 +1,11 @@ #ifndef GAME_MWWORLD_SCENE_H #define GAME_MWWORLD_SCENE_H -//#include "../mwrender/renderingmanager.hpp" - #include "ptr.hpp" #include "globals.hpp" #include +#include namespace osg { @@ -43,6 +42,7 @@ namespace MWWorld { class Player; class CellStore; + class CellPreloader; class Scene { @@ -57,6 +57,7 @@ namespace MWWorld bool mCellChanged; MWPhysics::PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; + std::auto_ptr mPreloader; void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 68ed136440..1f25bd461f 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -54,13 +54,9 @@ namespace Resource void ResourceSystem::updateCache(double referenceTime) { - // TODO: call updateCache from the worker thread so the main thread isn't held up by the delete operations - // change ObjectCache to not hold lock while the unref happens - - osg::Timer timer; + // TODO: change ObjectCache to not hold lock while the unref happens for (std::vector::iterator it = mResourceManagers.begin(); it != mResourceManagers.end(); ++it) (*it)->updateCache(referenceTime); - std::cout << "updateCache took " << timer.time_m() << " ms" << std::endl; } void ResourceSystem::addResourceManager(ResourceManager *resourceMgr)