BsCoreObjectManager.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include "BsCoreObjectManager.h"
  2. #include "BsCoreObject.h"
  3. #include "BsCoreObjectCore.h"
  4. #include "BsException.h"
  5. #include "BsMath.h"
  6. #include "BsFrameAlloc.h"
  7. #include "BsCoreThread.h"
  8. namespace BansheeEngine
  9. {
  10. CoreObjectManager::CoreObjectManager()
  11. :mNextAvailableID(1)
  12. {
  13. }
  14. CoreObjectManager::~CoreObjectManager()
  15. {
  16. #if BS_DEBUG_MODE
  17. BS_LOCK_MUTEX(mObjectsMutex);
  18. if(mObjects.size() > 0)
  19. {
  20. // All objects MUST be destroyed at this point, otherwise there might be memory corruption.
  21. // (Reason: This is called on application shutdown and at that point we also unload any dynamic libraries,
  22. // which will invalidate any pointers to objects created from those libraries. Therefore we require of the user to
  23. // clean up all objects manually before shutting down the application).
  24. BS_EXCEPT(InternalErrorException, "Core object manager shut down, but not all objects were released. Application must release ALL " \
  25. "engine objects before shutdown.");
  26. }
  27. #endif
  28. }
  29. UINT64 CoreObjectManager::registerObject(CoreObject* object)
  30. {
  31. assert(object != nullptr);
  32. BS_LOCK_MUTEX(mObjectsMutex);
  33. mObjects[mNextAvailableID] = object;
  34. return mNextAvailableID++;
  35. }
  36. void CoreObjectManager::unregisterObject(CoreObject* object)
  37. {
  38. assert(object != nullptr);
  39. UINT64 internalId = object->getInternalID();
  40. // If dirty, we generate sync data before it is destroyed
  41. if (object->isCoreDirty())
  42. {
  43. BS_LOCK_MUTEX(mObjectsMutex);
  44. SPtr<CoreObjectCore> coreObject = object->getCore();
  45. if (coreObject != nullptr)
  46. {
  47. CoreSyncData objSyncData = object->syncToCore(gCoreThread().getFrameAlloc());
  48. mDestroyedSyncData.push_back(CoreStoredSyncObjData(coreObject, internalId, objSyncData));
  49. DirtyObjectData& dirtyObjData = mDirtyObjects[internalId];
  50. dirtyObjData.syncDataId = (INT32)mDestroyedSyncData.size() - 1;
  51. dirtyObjData.object = nullptr;
  52. }
  53. }
  54. {
  55. BS_LOCK_MUTEX(mObjectsMutex);
  56. mObjects.erase(internalId);
  57. }
  58. updateDependencies(object, nullptr);
  59. }
  60. void CoreObjectManager::notifyCoreDirty(CoreObject* object)
  61. {
  62. UINT64 id = object->getInternalID();
  63. BS_LOCK_MUTEX(mObjectsMutex);
  64. mDirtyObjects[id] = { object, -1 };
  65. }
  66. void CoreObjectManager::notifyDependenciesDirty(CoreObject* object)
  67. {
  68. Vector<CoreObject*> dependencies;
  69. object->getCoreDependencies(dependencies);
  70. updateDependencies(object, &dependencies);
  71. }
  72. void CoreObjectManager::updateDependencies(CoreObject* object, Vector<CoreObject*>* dependencies)
  73. {
  74. UINT64 id = object->getInternalID();
  75. bs_frame_mark();
  76. {
  77. FrameVector<CoreObject*> toRemove;
  78. FrameVector<CoreObject*> toAdd;
  79. BS_LOCK_MUTEX(mObjectsMutex);
  80. // Add dependencies and clear old dependencies from dependants
  81. {
  82. auto iterFind = mDependencies.find(id);
  83. if (iterFind != mDependencies.end())
  84. {
  85. const Vector<CoreObject*>& oldDependencies = iterFind->second;
  86. if (dependencies != nullptr)
  87. {
  88. std::set_difference(dependencies->begin(), dependencies->end(),
  89. dependencies->begin(), dependencies->end(), toRemove.begin());
  90. std::set_difference(oldDependencies.begin(), oldDependencies.end(),
  91. oldDependencies.begin(), oldDependencies.end(), toAdd.begin());
  92. }
  93. else
  94. {
  95. for (auto& dependency : oldDependencies)
  96. toRemove.push_back(dependency);
  97. }
  98. for (auto& dependency : toRemove)
  99. {
  100. UINT64 dependencyId = dependency->getInternalID();
  101. auto iterFind2 = mDependants.find(dependencyId);
  102. if (iterFind2 != mDependants.end())
  103. {
  104. Vector<CoreObject*>& dependants = iterFind2->second;
  105. auto findIter3 = std::find(dependants.begin(), dependants.end(), object);
  106. dependants.erase(findIter3);
  107. if (dependants.size() == 0)
  108. mDependants.erase(iterFind2);
  109. }
  110. }
  111. }
  112. else
  113. {
  114. for (auto& dependency : *dependencies)
  115. toAdd.push_back(dependency);
  116. }
  117. if (dependencies != nullptr)
  118. mDependencies[id] = *dependencies;
  119. }
  120. // Register dependants
  121. {
  122. for (auto& dependency : toAdd)
  123. {
  124. UINT64 dependencyId = dependency->getInternalID();
  125. Vector<CoreObject*>& dependants = mDependants[dependencyId];
  126. dependants.push_back(object);
  127. }
  128. }
  129. }
  130. bs_frame_clear();
  131. }
  132. void CoreObjectManager::syncToCore(CoreAccessor& accessor)
  133. {
  134. syncDownload(gCoreThread().getFrameAlloc());
  135. accessor.queueCommand(std::bind(&CoreObjectManager::syncUpload, this));
  136. }
  137. void CoreObjectManager::syncToCore(CoreObject* object, CoreAccessor& accessor)
  138. {
  139. struct IndividualCoreSyncData
  140. {
  141. SPtr<CoreObjectCore> destination;
  142. CoreSyncData syncData;
  143. FrameAlloc* allocator;
  144. };
  145. BS_LOCK_MUTEX(mObjectsMutex);
  146. FrameAlloc* allocator = gCoreThread().getFrameAlloc();
  147. Vector<IndividualCoreSyncData> syncData;
  148. std::function<void(CoreObject*)> syncObject = [&](CoreObject* curObj)
  149. {
  150. if (!curObj->isCoreDirty())
  151. return; // We already processed it as some other object's dependency
  152. // Sync dependencies before dependants
  153. // Note: I don't check for recursion. Possible infinite loop if two objects
  154. // are dependent on one another.
  155. UINT64 id = curObj->getInternalID();
  156. auto iterFind = mDependencies.find(id);
  157. if (iterFind != mDependencies.end())
  158. {
  159. const Vector<CoreObject*>& dependencies = iterFind->second;
  160. for (auto& dependency : dependencies)
  161. syncObject(dependency);
  162. }
  163. SPtr<CoreObjectCore> objectCore = curObj->getCore();
  164. if (objectCore == nullptr)
  165. {
  166. curObj->markCoreClean();
  167. mDirtyObjects.erase(id);
  168. return;
  169. }
  170. syncData.push_back(IndividualCoreSyncData());
  171. IndividualCoreSyncData& data = syncData.back();
  172. data.allocator = allocator;
  173. data.destination = objectCore;
  174. data.syncData = curObj->syncToCore(allocator);
  175. curObj->markCoreClean();
  176. mDirtyObjects.erase(id);
  177. };
  178. syncObject(object);
  179. std::function<void(const Vector<IndividualCoreSyncData>&)> callback =
  180. [](const Vector<IndividualCoreSyncData>& data)
  181. {
  182. // Traverse in reverse to sync dependencies before dependants
  183. for (auto& riter = data.rbegin(); riter != data.rend(); ++riter)
  184. {
  185. const IndividualCoreSyncData& entry = *riter;
  186. entry.destination->syncToCore(entry.syncData);
  187. UINT8* dataPtr = entry.syncData.getBuffer();
  188. if (dataPtr != nullptr)
  189. entry.allocator->dealloc(dataPtr);
  190. }
  191. };
  192. if (syncData.size() > 0)
  193. accessor.queueCommand(std::bind(callback, syncData));
  194. }
  195. void CoreObjectManager::syncDownload(FrameAlloc* allocator)
  196. {
  197. BS_LOCK_MUTEX(mObjectsMutex);
  198. mCoreSyncData.push_back(CoreStoredSyncData());
  199. CoreStoredSyncData& syncData = mCoreSyncData.back();
  200. syncData.alloc = allocator;
  201. // Add all objects dependant on the dirty objects
  202. bs_frame_mark();
  203. {
  204. FrameSet<CoreObject*> dirtyDependants;
  205. for (auto& objectData : mDirtyObjects)
  206. {
  207. auto iterFind = mDependants.find(objectData.first);
  208. if (iterFind != mDependants.end())
  209. {
  210. const Vector<CoreObject*>& dependants = iterFind->second;
  211. for (auto& dependant : dependants)
  212. {
  213. if (!dependant->isCoreDirty())
  214. dirtyDependants.insert(dependant);
  215. }
  216. }
  217. }
  218. for (auto& dirtyDependant : dirtyDependants)
  219. {
  220. UINT64 id = dirtyDependant->getInternalID();
  221. mDirtyObjects[id] = { dirtyDependant, -1 };
  222. }
  223. }
  224. bs_frame_clear();
  225. // Order in which objects are recursed in matters, ones with lower ID will have been created before
  226. // ones with higher ones and should be updated first.
  227. for (auto& objectData : mDirtyObjects)
  228. {
  229. std::function<void(CoreObject*)> syncObject = [&](CoreObject* curObj)
  230. {
  231. if (!curObj->isCoreDirty())
  232. return; // We already processed it as some other object's dependency
  233. // Sync dependencies before dependants
  234. // Note: I don't check for recursion. Possible infinite loop if two objects
  235. // are dependent on one another.
  236. UINT64 id = curObj->getInternalID();
  237. auto iterFind = mDependencies.find(id);
  238. if (iterFind != mDependencies.end())
  239. {
  240. const Vector<CoreObject*>& dependencies = iterFind->second;
  241. for (auto& dependency : dependencies)
  242. syncObject(dependency);
  243. }
  244. SPtr<CoreObjectCore> objectCore = curObj->getCore();
  245. if (objectCore == nullptr)
  246. {
  247. curObj->markCoreClean();
  248. return;
  249. }
  250. CoreSyncData objSyncData = curObj->syncToCore(allocator);
  251. curObj->markCoreClean();
  252. syncData.entries.push_back(CoreStoredSyncObjData(objectCore,
  253. curObj->getInternalID(), objSyncData));
  254. };
  255. CoreObject* object = objectData.second.object;
  256. if (object != nullptr)
  257. syncObject(object);
  258. else
  259. {
  260. // Object was destroyed but we still need to sync its modifications before it was destroyed
  261. if (objectData.second.syncDataId != -1)
  262. syncData.entries.push_back(mDestroyedSyncData[objectData.second.syncDataId]);
  263. }
  264. }
  265. mDirtyObjects.clear();
  266. mDestroyedSyncData.clear();
  267. }
  268. void CoreObjectManager::syncUpload()
  269. {
  270. BS_LOCK_MUTEX(mObjectsMutex);
  271. if (mCoreSyncData.size() == 0)
  272. return;
  273. CoreStoredSyncData& syncData = mCoreSyncData.front();
  274. for (auto& iter = syncData.entries.begin(); iter != syncData.entries.end(); ++iter)
  275. {
  276. const CoreStoredSyncObjData& objSyncData = *iter;
  277. objSyncData.destinationObj->syncToCore(objSyncData.syncData);
  278. UINT8* data = objSyncData.syncData.getBuffer();
  279. if (data != nullptr)
  280. syncData.alloc->dealloc(data);
  281. }
  282. syncData.entries.clear();
  283. mCoreSyncData.pop_front();
  284. }
  285. }