1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 #include "OgreResourceManager.h" 30 31 #include "OgreException.h" 32 #include "OgreArchive.h" 33 #include "OgreArchiveManager.h" 34 #include "OgreStringVector.h" 35 #include "OgreStringConverter.h" 36 #include "OgreResourceGroupManager.h" 37 38 namespace Ogre { 39 40 //----------------------------------------------------------------------- ResourceManager()41 ResourceManager::ResourceManager() 42 : mNextHandle(1), mMemoryUsage(0), mVerbose(true), mLoadOrder(0) 43 { 44 // Init memory limit & usage 45 mMemoryBudget = std::numeric_limits<unsigned long>::max(); 46 } 47 //----------------------------------------------------------------------- ~ResourceManager()48 ResourceManager::~ResourceManager() 49 { 50 destroyAllResourcePools(); 51 removeAll(); 52 } 53 //----------------------------------------------------------------------- createResource(const String & name,const String & group,bool isManual,ManualResourceLoader * loader,const NameValuePairList * params)54 ResourcePtr ResourceManager::createResource(const String& name, const String& group, 55 bool isManual, ManualResourceLoader* loader, const NameValuePairList* params) 56 { 57 // Call creation implementation 58 ResourcePtr ret = ResourcePtr( 59 createImpl(name, getNextHandle(), group, isManual, loader, params)); 60 if (params) 61 ret->setParameterList(*params); 62 63 addImpl(ret); 64 // Tell resource group manager 65 ResourceGroupManager::getSingleton()._notifyResourceCreated(ret); 66 return ret; 67 68 } 69 //----------------------------------------------------------------------- 70 ResourceManager::ResourceCreateOrRetrieveResult createOrRetrieve(const String & name,const String & group,bool isManual,ManualResourceLoader * loader,const NameValuePairList * params)71 ResourceManager::createOrRetrieve( 72 const String& name, const String& group, 73 bool isManual, ManualResourceLoader* loader, 74 const NameValuePairList* params) 75 { 76 // Lock for the whole get / insert 77 OGRE_LOCK_AUTO_MUTEX; 78 79 ResourcePtr res = getResourceByName(name, group); 80 bool created = false; 81 if (res.isNull()) 82 { 83 created = true; 84 res = createResource(name, group, isManual, loader, params); 85 } 86 87 return ResourceCreateOrRetrieveResult(res, created); 88 } 89 //----------------------------------------------------------------------- prepare(const String & name,const String & group,bool isManual,ManualResourceLoader * loader,const NameValuePairList * loadParams,bool backgroundThread)90 ResourcePtr ResourceManager::prepare(const String& name, 91 const String& group, bool isManual, ManualResourceLoader* loader, 92 const NameValuePairList* loadParams, bool backgroundThread) 93 { 94 ResourcePtr r = createOrRetrieve(name,group,isManual,loader,loadParams).first; 95 // ensure prepared 96 r->prepare(backgroundThread); 97 return r; 98 } 99 //----------------------------------------------------------------------- load(const String & name,const String & group,bool isManual,ManualResourceLoader * loader,const NameValuePairList * loadParams,bool backgroundThread)100 ResourcePtr ResourceManager::load(const String& name, 101 const String& group, bool isManual, ManualResourceLoader* loader, 102 const NameValuePairList* loadParams, bool backgroundThread) 103 { 104 ResourcePtr r = createOrRetrieve(name,group,isManual,loader,loadParams).first; 105 // ensure loaded 106 r->load(backgroundThread); 107 108 return r; 109 } 110 //----------------------------------------------------------------------- addImpl(ResourcePtr & res)111 void ResourceManager::addImpl( ResourcePtr& res ) 112 { 113 OGRE_LOCK_AUTO_MUTEX; 114 115 std::pair<ResourceMap::iterator, bool> result; 116 if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup())) 117 { 118 result = mResources.insert( ResourceMap::value_type( res->getName(), res ) ); 119 } 120 else 121 { 122 ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup()); 123 124 // we will create the group if it doesn't exists in our list 125 if( itGroup == mResourcesWithGroup.end()) 126 { 127 ResourceMap dummy; 128 mResourcesWithGroup.insert( ResourceWithGroupMap::value_type( res->getGroup(), dummy ) ); 129 itGroup = mResourcesWithGroup.find(res->getGroup()); 130 } 131 result = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) ); 132 133 } 134 135 if (!result.second) 136 { 137 // Attempt to resolve the collision 138 if(ResourceGroupManager::getSingleton().getLoadingListener()) 139 { 140 if(ResourceGroupManager::getSingleton().getLoadingListener()->resourceCollision(res.get(), this)) 141 { 142 // Try to do the addition again, no seconds attempts to resolve collisions are allowed 143 std::pair<ResourceMap::iterator, bool> insertResult; 144 if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup())) 145 { 146 insertResult = mResources.insert( ResourceMap::value_type( res->getName(), res ) ); 147 } 148 else 149 { 150 ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(res->getGroup()); 151 insertResult = itGroup->second.insert( ResourceMap::value_type( res->getName(), res ) ); 152 } 153 if (!insertResult.second) 154 { 155 OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the name " + res->getName() + 156 " already exists.", "ResourceManager::add"); 157 } 158 159 std::pair<ResourceHandleMap::iterator, bool> resultHandle = 160 mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) ); 161 if (!resultHandle.second) 162 { 163 OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " + 164 StringConverter::toString((long) (res->getHandle())) + 165 " already exists.", "ResourceManager::add"); 166 } 167 } 168 } 169 } 170 else 171 { 172 // Insert the handle 173 std::pair<ResourceHandleMap::iterator, bool> resultHandle = 174 mResourcesByHandle.insert( ResourceHandleMap::value_type( res->getHandle(), res ) ); 175 if (!resultHandle.second) 176 { 177 OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Resource with the handle " + 178 StringConverter::toString((long) (res->getHandle())) + 179 " already exists.", "ResourceManager::add"); 180 } 181 } 182 } 183 //----------------------------------------------------------------------- removeImpl(ResourcePtr & res)184 void ResourceManager::removeImpl( ResourcePtr& res ) 185 { 186 OGRE_LOCK_AUTO_MUTEX; 187 188 if(ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(res->getGroup())) 189 { 190 ResourceMap::iterator nameIt = mResources.find(res->getName()); 191 if (nameIt != mResources.end()) 192 { 193 mResources.erase(nameIt); 194 } 195 } 196 else 197 { 198 ResourceWithGroupMap::iterator groupIt = mResourcesWithGroup.find(res->getGroup()); 199 if (groupIt != mResourcesWithGroup.end()) 200 { 201 ResourceMap::iterator nameIt = groupIt->second.find(res->getName()); 202 if (nameIt != groupIt->second.end()) 203 { 204 groupIt->second.erase(nameIt); 205 } 206 207 if (groupIt->second.empty()) 208 { 209 mResourcesWithGroup.erase(groupIt); 210 } 211 } 212 } 213 214 ResourceHandleMap::iterator handleIt = mResourcesByHandle.find(res->getHandle()); 215 if (handleIt != mResourcesByHandle.end()) 216 { 217 mResourcesByHandle.erase(handleIt); 218 } 219 // Tell resource group manager 220 ResourceGroupManager::getSingleton()._notifyResourceRemoved(res); 221 } 222 //----------------------------------------------------------------------- setMemoryBudget(size_t bytes)223 void ResourceManager::setMemoryBudget( size_t bytes) 224 { 225 // Update limit & check usage 226 mMemoryBudget = bytes; 227 checkUsage(); 228 } 229 //----------------------------------------------------------------------- getMemoryBudget(void) const230 size_t ResourceManager::getMemoryBudget(void) const 231 { 232 return mMemoryBudget; 233 } 234 //----------------------------------------------------------------------- unload(const String & name)235 void ResourceManager::unload(const String& name) 236 { 237 ResourcePtr res = getResourceByName(name); 238 239 if (!res.isNull()) 240 { 241 // Unload resource 242 res->unload(); 243 244 } 245 } 246 //----------------------------------------------------------------------- unload(ResourceHandle handle)247 void ResourceManager::unload(ResourceHandle handle) 248 { 249 ResourcePtr res = getByHandle(handle); 250 251 if (!res.isNull()) 252 { 253 // Unload resource 254 res->unload(); 255 256 } 257 } 258 //----------------------------------------------------------------------- unloadAll(bool reloadableOnly)259 void ResourceManager::unloadAll(bool reloadableOnly) 260 { 261 OGRE_LOCK_AUTO_MUTEX; 262 263 ResourceMap::iterator i, iend; 264 iend = mResources.end(); 265 for (i = mResources.begin(); i != iend; ++i) 266 { 267 if (!reloadableOnly || i->second->isReloadable()) 268 { 269 i->second->unload(); 270 } 271 } 272 273 } 274 //----------------------------------------------------------------------- reloadAll(bool reloadableOnly)275 void ResourceManager::reloadAll(bool reloadableOnly) 276 { 277 OGRE_LOCK_AUTO_MUTEX; 278 279 ResourceMap::iterator i, iend; 280 iend = mResources.end(); 281 for (i = mResources.begin(); i != iend; ++i) 282 { 283 if (!reloadableOnly || i->second->isReloadable()) 284 { 285 i->second->reload(); 286 } 287 } 288 289 } 290 //----------------------------------------------------------------------- unloadUnreferencedResources(bool reloadableOnly)291 void ResourceManager::unloadUnreferencedResources(bool reloadableOnly) 292 { 293 OGRE_LOCK_AUTO_MUTEX; 294 295 ResourceMap::iterator i, iend; 296 iend = mResources.end(); 297 for (i = mResources.begin(); i != iend; ++i) 298 { 299 // A use count of 3 means that only RGM and RM have references 300 // RGM has one (this one) and RM has 2 (by name and by handle) 301 if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS) 302 { 303 Resource* res = i->second.get(); 304 if (!reloadableOnly || res->isReloadable()) 305 { 306 res->unload(); 307 } 308 } 309 } 310 } 311 //----------------------------------------------------------------------- reloadUnreferencedResources(bool reloadableOnly)312 void ResourceManager::reloadUnreferencedResources(bool reloadableOnly) 313 { 314 OGRE_LOCK_AUTO_MUTEX; 315 316 ResourceMap::iterator i, iend; 317 iend = mResources.end(); 318 for (i = mResources.begin(); i != iend; ++i) 319 { 320 // A use count of 3 means that only RGM and RM have references 321 // RGM has one (this one) and RM has 2 (by name and by handle) 322 if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS) 323 { 324 Resource* res = i->second.get(); 325 if (!reloadableOnly || res->isReloadable()) 326 { 327 res->reload(); 328 } 329 } 330 } 331 } 332 //----------------------------------------------------------------------- remove(ResourcePtr & res)333 void ResourceManager::remove(ResourcePtr& res) 334 { 335 removeImpl(res); 336 } 337 //----------------------------------------------------------------------- remove(const String & name)338 void ResourceManager::remove(const String& name) 339 { 340 ResourcePtr res = getResourceByName(name); 341 342 if (!res.isNull()) 343 { 344 removeImpl(res); 345 } 346 } 347 //----------------------------------------------------------------------- remove(ResourceHandle handle)348 void ResourceManager::remove(ResourceHandle handle) 349 { 350 ResourcePtr res = getByHandle(handle); 351 352 if (!res.isNull()) 353 { 354 removeImpl(res); 355 } 356 } 357 //----------------------------------------------------------------------- removeAll(void)358 void ResourceManager::removeAll(void) 359 { 360 OGRE_LOCK_AUTO_MUTEX; 361 362 mResources.clear(); 363 mResourcesWithGroup.clear(); 364 mResourcesByHandle.clear(); 365 // Notify resource group manager 366 ResourceGroupManager::getSingleton()._notifyAllResourcesRemoved(this); 367 } 368 //----------------------------------------------------------------------- removeUnreferencedResources(bool reloadableOnly)369 void ResourceManager::removeUnreferencedResources(bool reloadableOnly) 370 { 371 OGRE_LOCK_AUTO_MUTEX; 372 373 ResourceMap::iterator i, iend; 374 iend = mResources.end(); 375 for (i = mResources.begin(); i != iend; ) 376 { 377 // A use count of 3 means that only RGM and RM have references 378 // RGM has one (this one) and RM has 2 (by name and by handle) 379 if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS) 380 { 381 Resource* res = (i++)->second.get(); 382 if (!reloadableOnly || res->isReloadable()) 383 { 384 remove( res->getHandle() ); 385 } 386 } 387 else 388 { 389 ++i; 390 } 391 } 392 } 393 //----------------------------------------------------------------------- getResourceByName(const String & name,const String & groupName)394 ResourcePtr ResourceManager::getResourceByName(const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */) 395 { 396 ResourcePtr res; 397 398 // if not in the global pool - get it from the grouped pool 399 if(!ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(groupName)) 400 { 401 OGRE_LOCK_AUTO_MUTEX; 402 ResourceWithGroupMap::iterator itGroup = mResourcesWithGroup.find(groupName); 403 404 if( itGroup != mResourcesWithGroup.end()) 405 { 406 ResourceMap::iterator it = itGroup->second.find(name); 407 408 if( it != itGroup->second.end()) 409 { 410 res = it->second; 411 } 412 } 413 } 414 415 // if didn't find it the grouped pool - get it from the global pool 416 if (res.isNull()) 417 { 418 OGRE_LOCK_AUTO_MUTEX; 419 420 ResourceMap::iterator it = mResources.find(name); 421 422 if( it != mResources.end()) 423 { 424 res = it->second; 425 } 426 else 427 { 428 // this is the case when we need to search also in the grouped hash 429 if (groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME) 430 { 431 ResourceWithGroupMap::iterator iter = mResourcesWithGroup.begin(); 432 ResourceWithGroupMap::iterator iterE = mResourcesWithGroup.end(); 433 for ( ; iter != iterE ; ++iter ) 434 { 435 ResourceMap::iterator resMapIt = iter->second.find(name); 436 437 if( resMapIt != iter->second.end()) 438 { 439 res = resMapIt->second; 440 break; 441 } 442 } 443 } 444 } 445 } 446 447 return res; 448 } 449 //----------------------------------------------------------------------- getByHandle(ResourceHandle handle)450 ResourcePtr ResourceManager::getByHandle(ResourceHandle handle) 451 { 452 OGRE_LOCK_AUTO_MUTEX; 453 454 ResourceHandleMap::iterator it = mResourcesByHandle.find(handle); 455 if (it == mResourcesByHandle.end()) 456 { 457 return ResourcePtr(); 458 } 459 else 460 { 461 return it->second; 462 } 463 } 464 //----------------------------------------------------------------------- getNextHandle(void)465 ResourceHandle ResourceManager::getNextHandle(void) 466 { 467 // This is an atomic operation and hence needs no locking 468 return mNextHandle++; 469 } 470 //----------------------------------------------------------------------- checkUsage(void)471 void ResourceManager::checkUsage(void) 472 { 473 if (getMemoryUsage() > mMemoryBudget) 474 { 475 OGRE_LOCK_AUTO_MUTEX; 476 // unload unreferenced resources until we are within our budget again 477 const bool reloadableOnly = true; 478 ResourceMap::iterator i, iend; 479 iend = mResources.end(); 480 for (i = mResources.begin(); i != iend && getMemoryUsage() > mMemoryBudget; ++i) 481 { 482 // A use count of 3 means that only RGM and RM have references 483 // RGM has one (this one) and RM has 2 (by name and by handle) 484 if (i->second.useCount() == ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS) 485 { 486 Resource* res = i->second.get(); 487 if (!reloadableOnly || res->isReloadable()) 488 { 489 res->unload(); 490 } 491 } 492 } 493 } 494 } 495 //----------------------------------------------------------------------- _notifyResourceTouched(Resource * res)496 void ResourceManager::_notifyResourceTouched(Resource* res) 497 { 498 // TODO 499 } 500 //----------------------------------------------------------------------- _notifyResourceLoaded(Resource * res)501 void ResourceManager::_notifyResourceLoaded(Resource* res) 502 { 503 mMemoryUsage += res->getSize(); 504 checkUsage(); 505 } 506 //----------------------------------------------------------------------- _notifyResourceUnloaded(Resource * res)507 void ResourceManager::_notifyResourceUnloaded(Resource* res) 508 { 509 mMemoryUsage -= res->getSize(); 510 } 511 //--------------------------------------------------------------------- getResourcePool(const String & name)512 ResourceManager::ResourcePool* ResourceManager::getResourcePool(const String& name) 513 { 514 OGRE_LOCK_AUTO_MUTEX; 515 516 ResourcePoolMap::iterator i = mResourcePoolMap.find(name); 517 if (i == mResourcePoolMap.end()) 518 { 519 i = mResourcePoolMap.insert(ResourcePoolMap::value_type(name, 520 OGRE_NEW ResourcePool(name))).first; 521 } 522 return i->second; 523 524 } 525 //--------------------------------------------------------------------- destroyResourcePool(ResourcePool * pool)526 void ResourceManager::destroyResourcePool(ResourcePool* pool) 527 { 528 if(!pool) 529 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot destroy a null ResourcePool.", "ResourceManager::destroyResourcePool"); 530 531 OGRE_LOCK_AUTO_MUTEX; 532 533 ResourcePoolMap::iterator i = mResourcePoolMap.find(pool->getName()); 534 if (i != mResourcePoolMap.end()) 535 mResourcePoolMap.erase(i); 536 537 OGRE_DELETE pool; 538 539 } 540 //--------------------------------------------------------------------- destroyResourcePool(const String & name)541 void ResourceManager::destroyResourcePool(const String& name) 542 { 543 OGRE_LOCK_AUTO_MUTEX; 544 545 ResourcePoolMap::iterator i = mResourcePoolMap.find(name); 546 if (i != mResourcePoolMap.end()) 547 { 548 OGRE_DELETE i->second; 549 mResourcePoolMap.erase(i); 550 } 551 552 } 553 //--------------------------------------------------------------------- destroyAllResourcePools()554 void ResourceManager::destroyAllResourcePools() 555 { 556 OGRE_LOCK_AUTO_MUTEX; 557 558 for (ResourcePoolMap::iterator i = mResourcePoolMap.begin(); 559 i != mResourcePoolMap.end(); ++i) 560 OGRE_DELETE i->second; 561 562 mResourcePoolMap.clear(); 563 } 564 //----------------------------------------------------------------------- 565 //--------------------------------------------------------------------- ResourcePool(const String & name)566 ResourceManager::ResourcePool::ResourcePool(const String& name) 567 : mName(name) 568 { 569 570 } 571 //--------------------------------------------------------------------- ~ResourcePool()572 ResourceManager::ResourcePool::~ResourcePool() 573 { 574 clear(); 575 } 576 //--------------------------------------------------------------------- getName() const577 const String& ResourceManager::ResourcePool::getName() const 578 { 579 return mName; 580 } 581 //--------------------------------------------------------------------- clear()582 void ResourceManager::ResourcePool::clear() 583 { 584 OGRE_LOCK_AUTO_MUTEX; 585 for (ItemList::iterator i = mItems.begin(); i != mItems.end(); ++i) 586 { 587 (*i)->getCreator()->remove((*i)->getHandle()); 588 } 589 mItems.clear(); 590 } 591 } 592 593 594 595 596