resource_manager.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * Copyright (c) 2012-2022 Daniele Bartolini et al.
  3. * License: https://github.com/crownengine/crown/blob/master/LICENSE
  4. */
  5. #include "core/containers/array.inl"
  6. #include "core/containers/hash_map.inl"
  7. #include "core/memory/temp_allocator.inl"
  8. #include "core/strings/dynamic_string.inl"
  9. #include "core/strings/string_id.inl"
  10. #include "resource/resource_id.inl"
  11. #include "resource/resource_loader.h"
  12. #include "resource/resource_manager.h"
  13. namespace crown
  14. {
  15. bool operator<(const ResourceManager::ResourcePair &a, const ResourceManager::ResourcePair &b)
  16. {
  17. return a.type < b.type
  18. || (a.type == b.type && a.name < b.name)
  19. ;
  20. }
  21. bool operator==(const ResourceManager::ResourcePair &a, const ResourceManager::ResourcePair &b)
  22. {
  23. return a.type == b.type
  24. && a.name == b.name
  25. ;
  26. }
  27. bool operator==(const ResourceManager::ResourceEntry &a, const ResourceManager::ResourceEntry &b)
  28. {
  29. return a.references == b.references
  30. && a.data == b.data
  31. ;
  32. }
  33. const ResourceManager::ResourceEntry ResourceManager::ResourceEntry::NOT_FOUND = { 0xffffffffu, NULL };
  34. template<>
  35. struct hash<ResourceManager::ResourcePair>
  36. {
  37. u32 operator()(const ResourceManager::ResourcePair &val) const
  38. {
  39. return u32(resource_id(val.type, val.name)._id);
  40. }
  41. };
  42. ResourceManager::ResourceManager(ResourceLoader &rl)
  43. : _resource_heap(default_allocator(), "resource")
  44. , _loader(&rl)
  45. , _type_data(default_allocator())
  46. , _rm(default_allocator())
  47. , _autoload(false)
  48. {
  49. }
  50. ResourceManager::~ResourceManager()
  51. {
  52. auto cur = hash_map::begin(_rm);
  53. auto end = hash_map::end(_rm);
  54. for (; cur != end; ++cur) {
  55. HASH_MAP_SKIP_HOLE(_rm, cur);
  56. const StringId64 type = cur->first.type;
  57. const StringId64 name = cur->first.name;
  58. on_offline(type, name);
  59. on_unload(type, cur->second.data);
  60. }
  61. }
  62. void ResourceManager::load(StringId64 type, StringId64 name)
  63. {
  64. ResourcePair id = { type, name };
  65. ResourceEntry &entry = hash_map::get(_rm, id, ResourceEntry::NOT_FOUND);
  66. if (entry == ResourceEntry::NOT_FOUND) {
  67. ResourceTypeData rtd;
  68. rtd.version = UINT32_MAX;
  69. rtd.load = NULL;
  70. rtd.online = NULL;
  71. rtd.offline = NULL;
  72. rtd.unload = NULL;
  73. rtd = hash_map::get(_type_data, type, rtd);
  74. ResourceRequest rr;
  75. rr.type = type;
  76. rr.name = name;
  77. rr.version = rtd.version;
  78. rr.load_function = rtd.load;
  79. rr.allocator = &_resource_heap;
  80. rr.data = NULL;
  81. _loader->add_request(rr);
  82. return;
  83. }
  84. entry.references++;
  85. }
  86. void ResourceManager::unload(StringId64 type, StringId64 name)
  87. {
  88. flush();
  89. ResourcePair id = { type, name };
  90. ResourceEntry &entry = hash_map::get(_rm, id, ResourceEntry::NOT_FOUND);
  91. if (--entry.references == 0) {
  92. on_offline(type, name);
  93. on_unload(type, entry.data);
  94. hash_map::remove(_rm, id);
  95. }
  96. }
  97. void ResourceManager::reload(StringId64 type, StringId64 name)
  98. {
  99. const ResourcePair id = { type, name };
  100. const ResourceEntry &entry = hash_map::get(_rm, id, ResourceEntry::NOT_FOUND);
  101. const u32 old_refs = entry.references;
  102. if (entry == ResourceEntry::NOT_FOUND)
  103. return;
  104. unload(type, name);
  105. load(type, name);
  106. flush();
  107. ResourceEntry &new_entry = hash_map::get(_rm, id, ResourceEntry::NOT_FOUND);
  108. new_entry.references = old_refs;
  109. }
  110. bool ResourceManager::can_get(StringId64 type, StringId64 name)
  111. {
  112. const ResourcePair id = { type, name };
  113. return _autoload ? true : hash_map::has(_rm, id);
  114. }
  115. const void *ResourceManager::get(StringId64 type, StringId64 name)
  116. {
  117. const ResourcePair id = { type, name };
  118. const ResourceId res_id = resource_id(type, name);
  119. CE_ASSERT(can_get(type, name), "Resource not loaded: " RESOURCE_ID_FMT, res_id._id);
  120. CE_UNUSED(res_id);
  121. if (_autoload && !hash_map::has(_rm, id)) {
  122. load(type, name);
  123. flush();
  124. }
  125. const ResourceEntry &entry = hash_map::get(_rm, id, ResourceEntry::NOT_FOUND);
  126. return entry.data;
  127. }
  128. void ResourceManager::enable_autoload(bool enable)
  129. {
  130. _autoload = enable;
  131. }
  132. void ResourceManager::flush()
  133. {
  134. _loader->flush();
  135. complete_requests();
  136. }
  137. void ResourceManager::complete_requests()
  138. {
  139. TempAllocator1024 ta;
  140. Array<ResourceRequest> loaded(ta);
  141. _loader->get_loaded(loaded);
  142. for (u32 i = 0; i < array::size(loaded); ++i)
  143. complete_request(loaded[i].type, loaded[i].name, loaded[i].data);
  144. }
  145. void ResourceManager::complete_request(StringId64 type, StringId64 name, void *data)
  146. {
  147. ResourceEntry entry;
  148. entry.references = 1;
  149. entry.data = data;
  150. ResourcePair id = { type, name };
  151. hash_map::set(_rm, id, entry);
  152. on_online(type, name);
  153. }
  154. void ResourceManager::register_type(StringId64 type, u32 version, LoadFunction load, UnloadFunction unload, OnlineFunction online, OfflineFunction offline)
  155. {
  156. ResourceTypeData rtd;
  157. rtd.version = version;
  158. rtd.load = load;
  159. rtd.online = online;
  160. rtd.offline = offline;
  161. rtd.unload = unload;
  162. hash_map::set(_type_data, type, rtd);
  163. }
  164. void ResourceManager::on_online(StringId64 type, StringId64 name)
  165. {
  166. OnlineFunction func = hash_map::get(_type_data, type, ResourceTypeData()).online;
  167. if (func)
  168. func(name, *this);
  169. }
  170. void ResourceManager::on_offline(StringId64 type, StringId64 name)
  171. {
  172. OfflineFunction func = hash_map::get(_type_data, type, ResourceTypeData()).offline;
  173. if (func)
  174. func(name, *this);
  175. }
  176. void ResourceManager::on_unload(StringId64 type, void *data)
  177. {
  178. UnloadFunction func = hash_map::get(_type_data, type, ResourceTypeData()).unload;
  179. if (func)
  180. func(_resource_heap, data);
  181. else
  182. _resource_heap.deallocate(data);
  183. }
  184. } // namespace crown