ResourceManager.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Resource/ResourceManager.h>
  6. #include <AnKi/Resource/AsyncLoader.h>
  7. #include <AnKi/Resource/ShaderProgramResourceSystem.h>
  8. #include <AnKi/Resource/AnimationResource.h>
  9. #include <AnKi/Resource/AccelerationStructureScratchAllocator.h>
  10. #include <AnKi/Util/Logger.h>
  11. #include <AnKi/Util/CVarSet.h>
  12. #include <AnKi/Resource/MaterialResource.h>
  13. #include <AnKi/Resource/MeshResource.h>
  14. #include <AnKi/Resource/CpuMeshResource.h>
  15. #include <AnKi/Resource/ScriptResource.h>
  16. #include <AnKi/Resource/DummyResource.h>
  17. #include <AnKi/Resource/ParticleEmitterResource2.h>
  18. #include <AnKi/Resource/ImageResource.h>
  19. #include <AnKi/Resource/GenericResource.h>
  20. #include <AnKi/Resource/ImageAtlasResource.h>
  21. #include <AnKi/Resource/ShaderProgramResource.h>
  22. #include <AnKi/Resource/SkeletonResource.h>
  23. namespace anki {
  24. ResourceManager::ResourceManager()
  25. {
  26. }
  27. ResourceManager::~ResourceManager()
  28. {
  29. ANKI_RESOURCE_LOGI("Destroying resource manager");
  30. AsyncLoader::freeSingleton();
  31. ShaderProgramResourceSystem::freeSingleton();
  32. TransferGpuAllocator::freeSingleton();
  33. ResourceFilesystem::freeSingleton();
  34. #define ANKI_INSTANTIATE_RESOURCE(className) \
  35. static_cast<TypeData<className>&>(m_allTypes).m_entries.destroy(); \
  36. static_cast<TypeData<className>&>(m_allTypes).m_map.destroy();
  37. #include <AnKi/Resource/Resources.def.h>
  38. AccelerationStructureScratchAllocator::freeSingleton();
  39. ResourceMemoryPool::freeSingleton();
  40. }
  41. Error ResourceManager::init(AllocAlignedCallback allocCallback, void* allocCallbackData)
  42. {
  43. ANKI_RESOURCE_LOGI("Initializing resource manager");
  44. ResourceMemoryPool::allocateSingleton(allocCallback, allocCallbackData);
  45. ResourceFilesystem::allocateSingleton();
  46. ANKI_CHECK(ResourceFilesystem::getSingleton().init());
  47. // Init the thread
  48. AsyncLoader::allocateSingleton();
  49. TransferGpuAllocator::allocateSingleton();
  50. ANKI_CHECK(TransferGpuAllocator::getSingleton().init(g_cvarRsrcTransferScratchMemorySize));
  51. // Init the programs
  52. ShaderProgramResourceSystem::allocateSingleton();
  53. ANKI_CHECK(ShaderProgramResourceSystem::getSingleton().init());
  54. if(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
  55. {
  56. AccelerationStructureScratchAllocator::allocateSingleton();
  57. }
  58. m_trackFileUpdateTimes = g_cvarRsrcTrackFileUpdates;
  59. return Error::kNone;
  60. }
  61. template<typename T>
  62. Error ResourceManager::loadResource(CString filename, ResourcePtr<T>& out, Bool async)
  63. {
  64. ANKI_ASSERT(!out.isCreated() && "Already loaded");
  65. TypeData<T>& type = static_cast<TypeData<T>&>(m_allTypes);
  66. // Check if registered
  67. using EntryType = typename TypeData<T>::Entry;
  68. EntryType* entry;
  69. {
  70. RLockGuard lock(type.m_mtx);
  71. auto it = type.m_map.find(filename);
  72. entry = (it != type.m_map.getEnd()) ? &type.m_entries[*it] : nullptr;
  73. }
  74. if(!entry)
  75. {
  76. // Resource entry doesn't exist, create one
  77. WLockGuard lock(type.m_mtx);
  78. auto it = type.m_map.find(filename); // Search again
  79. if(it != type.m_map.getEnd())
  80. {
  81. entry = &type.m_entries[*it];
  82. }
  83. else
  84. {
  85. auto arrit = type.m_entries.emplace();
  86. type.m_map.emplace(filename, arrit.getArrayIndex());
  87. entry = &(*arrit);
  88. }
  89. }
  90. ANKI_ASSERT(entry);
  91. // Try to load the resource
  92. Error err = Error::kNone;
  93. T* rsrc = nullptr;
  94. {
  95. LockGuard lock(entry->m_mtx);
  96. if(entry->m_resources.getSize() == 0 || entry->m_resources.getBack()->isObsolete())
  97. {
  98. // Resource hasn't been loaded or it needs update, load it
  99. rsrc = newInstance<T>(ResourceMemoryPool::getSingleton(), filename, m_uuid.fetchAdd(1));
  100. // Increment the refcount in that case where async jobs increment it and decrement it in the scope of a load()
  101. rsrc->retain();
  102. err = rsrc->load(filename, async);
  103. // Decrement because of the increment happened a few lines above
  104. rsrc->release();
  105. if(err)
  106. {
  107. ANKI_RESOURCE_LOGE("Failed to load resource: %s", filename.cstr());
  108. deleteInstance(ResourceMemoryPool::getSingleton(), rsrc);
  109. rsrc = nullptr;
  110. }
  111. else
  112. {
  113. entry->m_resources.emplaceBack(rsrc);
  114. }
  115. if(m_trackFileUpdateTimes)
  116. {
  117. entry->m_fileUpdateTime = ResourceFilesystem::getSingleton().getFileUpdateTime(filename);
  118. }
  119. }
  120. else
  121. {
  122. rsrc = entry->m_resources.getBack();
  123. }
  124. if(!err)
  125. {
  126. ANKI_ASSERT(rsrc);
  127. out.reset(rsrc);
  128. }
  129. }
  130. return err;
  131. }
  132. template<typename T>
  133. void ResourceManager::freeResource(T* ptr)
  134. {
  135. ANKI_ASSERT(ptr);
  136. ANKI_ASSERT(ptr->m_refcount.load() == 0);
  137. TypeData<T>& type = static_cast<TypeData<T>&>(m_allTypes);
  138. typename TypeData<T>::Entry* entry = nullptr;
  139. {
  140. RLockGuard lock(type.m_mtx);
  141. auto it = type.m_map.find(ptr->m_fname);
  142. ANKI_ASSERT(it != type.m_map.getEnd());
  143. entry = &type.m_entries[*it];
  144. }
  145. {
  146. LockGuard lock(entry->m_mtx);
  147. auto it = entry->m_resources.getBegin();
  148. for(; it != entry->m_resources.getEnd(); ++it)
  149. {
  150. if(*it == ptr)
  151. {
  152. break;
  153. }
  154. }
  155. ANKI_ASSERT(it != entry->m_resources.getEnd());
  156. deleteInstance(ResourceMemoryPool::getSingleton(), *it);
  157. entry->m_resources.erase(it);
  158. }
  159. }
  160. // Instansiate
  161. #define ANKI_INSTANTIATE_RESOURCE(className) \
  162. template Error ResourceManager::loadResource<className>(CString filename, ResourcePtr<className> & out, Bool async); \
  163. template void ResourceManager::freeResource<className>(className * ptr);
  164. #include <AnKi/Resource/Resources.def.h>
  165. template<typename T>
  166. void ResourceManager::refreshFileUpdateTimesInternal()
  167. {
  168. TypeData<T>& type = static_cast<TypeData<T>&>(m_allTypes);
  169. WLockGuard lock(type.m_mtx);
  170. for(auto& entry : type.m_entries)
  171. {
  172. LockGuard lock(entry.m_mtx);
  173. if(entry.m_resources.getSize() == 0)
  174. {
  175. continue;
  176. }
  177. const U64 newTime = ResourceFilesystem::getSingleton().getFileUpdateTime(entry.m_resources[0]->getFilename());
  178. if(newTime != entry.m_fileUpdateTime)
  179. {
  180. ANKI_RESOURCE_LOGV("File updated, loaded resource now obsolete: %s", entry.m_resources[0]->getFilename().cstr());
  181. entry.m_fileUpdateTime = newTime;
  182. for(T* rsrc : entry.m_resources)
  183. {
  184. rsrc->m_isObsolete.store(1);
  185. }
  186. }
  187. }
  188. }
  189. void ResourceManager::refreshFileUpdateTimes()
  190. {
  191. if(!m_trackFileUpdateTimes)
  192. {
  193. return;
  194. }
  195. #define ANKI_INSTANTIATE_RESOURCE(className) refreshFileUpdateTimesInternal<className>();
  196. #include <AnKi/Resource/Resources.def.h>
  197. }
  198. } // end namespace anki