BsCoreObjectManager.cpp 12 KB

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