containerManager.cpp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. #include "containerManager.h"
  2. #include "containerManager.h"
  3. #include "containerManager.h"
  4. #include <globalAllocator/globalAllocator.h>
  5. #include <unordered_set>
  6. #include <chrono>
  7. #include <thread>
  8. #include <unordered_map>
  9. #include <fileManipulation/fileManipulation.h>
  10. #include <stringManipulation/stringManipulation.h>
  11. #include <filesystem>
  12. #include <imgui.h>
  13. #include <containersWindow/containersWindow.h>
  14. #include <imgui_internal.h>
  15. #include <fstream>
  16. pika::containerId_t pika::ContainerManager::createContainer(std::string containerName,
  17. pika::LoadedDll &loadedDll, pika::LogManager &logManager,
  18. pika::pikaImgui::ImGuiIdsManager &imguiIDsManager, ConsoleWindow *consoleWindow, size_t memoryPos)
  19. {
  20. for(auto &i : loadedDll.containerInfo)
  21. {
  22. if (i.containerName == containerName)
  23. {
  24. return createContainer(i, loadedDll, logManager, imguiIDsManager, consoleWindow, memoryPos);
  25. }
  26. }
  27. logManager.log(("Couldn't create container, couldn't find the name: " + containerName).c_str(), pika::logError);
  28. return 0;
  29. }
  30. bool pika::ContainerManager::setSnapshotToContainer(pika::containerId_t containerId, const char *snapshotName, pika::LogManager &logManager
  31. , pika::pikaImgui::ImGuiIdsManager &imguiIdManager)
  32. {
  33. auto c = runningContainers.find(containerId);
  34. if (c == runningContainers.end())
  35. {
  36. logManager.log((std::string("Couldn't find container for setting snapshot: #")
  37. + std::to_string(containerId)).c_str(),
  38. pika::logError);
  39. return false;
  40. }
  41. if (!checkIfSnapshotIsCompatible(c->second, snapshotName))
  42. {
  43. logManager.log((std::string("Snapshot incompatible: ") + snapshotName).c_str(),
  44. pika::logError);
  45. return false;
  46. }
  47. std::string file = PIKA_ENGINE_RESOURCES_PATH;
  48. file += snapshotName;
  49. file += ".snapshot";
  50. auto s = pika::getFileSize(file.c_str());
  51. if (s != (c->second.totalSize + sizeof(pika::RuntimeContainer)) )
  52. {
  53. logManager.log((std::string("Snapshot corrupted probably, file size incorrect: ")
  54. + snapshotName).c_str(),
  55. pika::logError);
  56. return false;
  57. }
  58. pika::readEntireFile(file.c_str(), c->second.getBaseAdress(),
  59. c->second.totalSize, sizeof(pika::RuntimeContainer));
  60. //c->second.requestedContainerInfo.requestedImguiIds
  61. // = imguiIdManager.getImguiIds(c->second.requestedContainerInfo.imguiTotalRequestedIds);
  62. logManager.log("Loaded snapshot");
  63. return true;
  64. }
  65. bool pika::ContainerManager::setRecordingToContainer(pika::containerId_t containerId, const char *recordingName,
  66. pika::LogManager &logManager, pika::pikaImgui::ImGuiIdsManager &imguiIdManager)
  67. {
  68. auto c = runningContainers.find(containerId);
  69. if (c == runningContainers.end())
  70. {
  71. logManager.log((std::string("Couldn't find container for setting recording: #")
  72. + std::to_string(containerId)).c_str(),
  73. pika::logError);
  74. return false;
  75. }
  76. //todo not reset imgui id on input recording
  77. if (!setSnapshotToContainer(containerId, recordingName, logManager, imguiIdManager))
  78. {
  79. return false;
  80. }
  81. c->second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_BEING_PLAYBACK;
  82. c->second.flags.frameNumber = 0;
  83. pika::strlcpy(c->second.flags.recordingName, recordingName, sizeof(c->second.flags.recordingName));
  84. }
  85. //todo use regions further appart in production
  86. void* pika::ContainerManager::allocateContainerMemory(pika::RuntimeContainer &container,
  87. pika::ContainerInformation containerInformation, void *memPos)
  88. {
  89. size_t memoryRequired = containerInformation.calculateMemoryRequirements();
  90. void * baseMemory = allocateOSMemory(memoryRequired, memPos);
  91. if (baseMemory == nullptr) { return 0; }
  92. container.totalSize = memoryRequired;
  93. allocateContainerMemoryAtBuffer(container,
  94. containerInformation, baseMemory);
  95. return baseMemory;
  96. }
  97. void pika::ContainerManager::allocateContainerMemoryAtBuffer(pika::RuntimeContainer &container,
  98. pika::ContainerInformation containerInformation, void *buffer)
  99. {
  100. const size_t staticMemory = containerInformation.containerStructBaseSize;
  101. const size_t heapMemory = containerInformation.containerStaticInfo.defaultHeapMemorySize;
  102. char *currentMemoryAdress = (char *)buffer;
  103. container.arena.containerStructMemory.size = staticMemory;
  104. container.arena.containerStructMemory.block = currentMemoryAdress;
  105. currentMemoryAdress += staticMemory;
  106. pika::align64(currentMemoryAdress);
  107. container.allocator.init(currentMemoryAdress, heapMemory);
  108. currentMemoryAdress += heapMemory;
  109. for (int i = 0; i < containerInformation.containerStaticInfo.bonusAllocators.size(); i++)
  110. {
  111. pika::align64(currentMemoryAdress);
  112. pika::memory::FreeListAllocator allocator;
  113. allocator.init(
  114. currentMemoryAdress,
  115. containerInformation.containerStaticInfo.bonusAllocators[i]
  116. );
  117. container.bonusAllocators.push_back(allocator);
  118. currentMemoryAdress += containerInformation.containerStaticInfo.bonusAllocators[i];
  119. }
  120. }
  121. void pika::ContainerManager::freeContainerStuff(pika::RuntimeContainer &container)
  122. {
  123. deallocateOSMemory(container.arena.containerStructMemory.block);
  124. //container.arena.dealocateStaticMemory(); //static memory
  125. //deallocateOSMemory(container.allocator.originalBaseMemory); //heap memory
  126. //
  127. //for (auto &i : container.bonusAllocators)
  128. //{
  129. // deallocateOSMemory(i.originalBaseMemory);
  130. //}
  131. }
  132. pika::containerId_t pika::ContainerManager::createContainer
  133. (pika::ContainerInformation containerInformation,
  134. pika::LoadedDll &loadedDll, pika::LogManager &logManager, pika::pikaImgui::ImGuiIdsManager &imguiIDsManager,
  135. ConsoleWindow *consoleWindow,
  136. size_t memoryPos)
  137. {
  138. containerId_t id = ++idCounter;
  139. //not necessary if this is the only things that assigns ids.
  140. //if (runningContainers.find(id) != runningContainers.end())
  141. //{
  142. // logManager.log((std::string("Container id already exists: #") + std::to_string(id)).c_str(), pika::logError);
  143. // return false;
  144. //}
  145. //todo a create and destruct wrapper
  146. pika::RuntimeContainer container = {};
  147. pika::strlcpy(container.baseContainerName, containerInformation.containerName,
  148. sizeof(container.baseContainerName));
  149. if (!allocateContainerMemory(container, containerInformation, (void*)memoryPos))
  150. {
  151. logManager.log((std::string("Couldn't allocate memory for constructing container: #")
  152. + std::to_string(id)).c_str(), pika::logError);
  153. return 0;
  154. }
  155. if (containerInformation.containerStaticInfo.requestImguiFbo)
  156. {
  157. container.requestedContainerInfo.requestedFBO.createFramebuffer(400, 400); //todo resize small or sthing
  158. container.imguiWindowId = imguiIDsManager.getImguiIds();
  159. }
  160. loadedDll.bindAllocatorDllRealm(&container.allocator);
  161. //this calls the constructors (from the dll realm)
  162. if (!loadedDll.constructRuntimeContainer(container, containerInformation.containerName.c_str()))
  163. {
  164. loadedDll.resetAllocatorDllRealm();
  165. logManager.log((std::string("Couldn't construct container: #") + std::to_string(id)).c_str(), pika::logError);
  166. freeContainerStuff(container);
  167. container.requestedContainerInfo.requestedFBO.deleteFramebuffer();
  168. return 0;
  169. }
  170. loadedDll.resetAllocatorDllRealm();
  171. #pragma region setup requested container info
  172. container.requestedContainerInfo.mainAllocator = &container.allocator;
  173. container.requestedContainerInfo.bonusAllocators = &container.bonusAllocators;
  174. container.requestedContainerInfo.requestedImguiIds =
  175. imguiIDsManager.getImguiIds(containerInformation.containerStaticInfo.requestImguiIds);
  176. container.requestedContainerInfo.imguiTotalRequestedIds = containerInformation.containerStaticInfo.requestImguiIds;
  177. container.requestedContainerInfo.consoleWindow = consoleWindow;
  178. #pragma endregion
  179. loadedDll.bindAllocatorDllRealm(&container.allocator);
  180. container.pointer->create(container.requestedContainerInfo); //this calls create() (from the dll realm)
  181. loadedDll.resetAllocatorDllRealm();//sets the global allocator back to standard (used for runtime realm)
  182. runningContainers[id] = container;
  183. logManager.log(("Created container: " + std::string(container.baseContainerName) ).c_str());
  184. return id;
  185. }
  186. void pika::ContainerManager::init()
  187. {
  188. }
  189. void pika::ContainerManager::update(pika::LoadedDll &loadedDll, pika::PikaWindow &window,
  190. pika::LogManager &logs, pika::pikaImgui::ImGuiIdsManager &imguiIdManager, pika::ConsoleWindow *consoleWindow)
  191. {
  192. PIKA_DEVELOPMENT_ONLY_ASSERT(loadedDll.dllHand != 0, "dll not loaded when trying to update containers");
  193. #pragma region reload dll
  194. //todo try to recover from a failed load
  195. if (loadedDll.shouldReloadDll())
  196. {
  197. reloadDll(loadedDll, window, logs); //todo return 0 on fail
  198. //todo mark shouldCallReaload or just call reload
  199. }
  200. #pragma endregion
  201. #pragma region running containers
  202. for (auto &c : runningContainers)
  203. {
  204. c.second.requestedContainerInfo.consoleWindow = consoleWindow;
  205. if (c.second.flags.status == pika::RuntimeContainer::FLAGS::STATUS_RUNNING
  206. ||
  207. c.second.flags.status == pika::RuntimeContainer::FLAGS::STATUS_BEING_RECORDED
  208. ||
  209. c.second.flags.status == pika::RuntimeContainer::FLAGS::STATUS_BEING_PLAYBACK
  210. )
  211. {
  212. PIKA_DEVELOPMENT_ONLY_ASSERT(
  213. (c.second.requestedContainerInfo.requestedFBO.fbo == 0 &&
  214. c.second.imguiWindowId == 0) ||
  215. (
  216. c.second.requestedContainerInfo.requestedFBO.fbo != 0 &&
  217. c.second.imguiWindowId != 0), "we have a fbo but no imguiwindow id"
  218. );
  219. auto windowInput = window.input;
  220. #pragma region mouse pos
  221. #pragma endregion
  222. #if PIKA_DEVELOPMENT
  223. if (c.second.flags.status == pika::RuntimeContainer::FLAGS::STATUS_BEING_RECORDED)
  224. {
  225. if (!makeRecordingStep(c.first, logs, windowInput))
  226. {
  227. c.second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_RUNNING;
  228. logs.log((std::string("Stopped container recording because we couldn't oppen file")
  229. + std::to_string(c.first)).c_str(),
  230. pika::logError);
  231. }
  232. }
  233. if (c.second.flags.status == pika::RuntimeContainer::FLAGS::STATUS_BEING_PLAYBACK)
  234. {
  235. pika::Input readInput = {};
  236. std::string fileName = c.second.flags.recordingName;
  237. fileName += ".recording";
  238. fileName = PIKA_ENGINE_RESOURCES_PATH + fileName;
  239. auto s = pika::getFileSize(fileName.c_str());
  240. if (c.second.flags.frameNumber * sizeof(pika::Input) >= s && s != 0)
  241. {
  242. //todo optional logs here
  243. if (!setSnapshotToContainer(c.first, c.second.flags.recordingName, logs, imguiIdManager))
  244. {
  245. logs.log((std::string("Stopped container playback because we couldn't assign it's snapshot on frame 0")
  246. + std::to_string(c.first)).c_str(),
  247. pika::logError);
  248. c.second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_RUNNING;
  249. goto endContainerErrorChecking;
  250. }
  251. c.second.flags.frameNumber = 0;
  252. }
  253. if (s == 0)
  254. {
  255. logs.log((std::string("Stopped container playback because we couldn't oppen file or its content is empty")
  256. + std::to_string(c.first)).c_str(),
  257. pika::logError);
  258. c.second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_RUNNING;
  259. }
  260. else if (s % sizeof(pika::Input) != 0)
  261. {
  262. logs.log((std::string("Stopped container playback because the file content is corrupt")
  263. + std::to_string(c.first)).c_str(),
  264. pika::logError);
  265. c.second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_RUNNING;
  266. }
  267. if (!pika::readEntireFile(fileName.c_str(), &readInput, sizeof(pika::Input), sizeof(pika::Input) * c.second.flags.frameNumber))
  268. {
  269. logs.log((std::string("Stopped container playback because we couldn't oppen file")
  270. + std::to_string(c.first)).c_str(),
  271. pika::logError);
  272. c.second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_RUNNING;
  273. }
  274. else
  275. {
  276. windowInput = readInput;
  277. c.second.flags.frameNumber++;
  278. }
  279. }
  280. #endif
  281. endContainerErrorChecking:
  282. #if PIKA_PRODUCTION
  283. constexpr bool isProduction = 1;
  284. #else
  285. constexpr bool isProduction = 0;
  286. #endif
  287. auto callUpdate = [&](pika::WindowState &windowState)
  288. {
  289. loadedDll.bindAllocatorDllRealm(&c.second.allocator);
  290. c.second.pointer->update(windowInput, windowState, c.second.requestedContainerInfo);
  291. loadedDll.resetAllocatorDllRealm();
  292. };
  293. if (c.second.imguiWindowId && !isProduction)
  294. {
  295. #pragma region imguiwindow
  296. ImGui::PushID(c.second.imguiWindowId);
  297. ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.f, 0.f, 0.f, 1.0f));
  298. ImGui::SetNextWindowSize({200,200}, ImGuiCond_Once);
  299. ImGui::Begin( (std::string("gameplay window id: ") + std::to_string(c.first)).c_str(),
  300. 0, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
  301. //mouse pos and focus
  302. if(c.second.flags.status != pika::RuntimeContainer::FLAGS::STATUS_BEING_PLAYBACK)
  303. {
  304. auto windowPos = ImGui::GetWindowPos();
  305. ImVec2 globalMousePos = {};
  306. {
  307. ImGuiContext *g = ImGui::GetCurrentContext();
  308. globalMousePos = g->IO.MousePos;
  309. }
  310. windowInput.mouseX = globalMousePos.x;
  311. windowInput.mouseY = globalMousePos.y;
  312. ImVec2 vMin = ImGui::GetWindowContentRegionMin();
  313. windowInput.mouseX -= windowPos.x + vMin.x;
  314. windowInput.mouseY -= windowPos.y + vMin.y;
  315. //https://github.com/ocornut/imgui/issues/5882
  316. ImGuiViewport *viewPort = ImGui::GetWindowViewport();
  317. auto io = ImGui::GetIO();
  318. windowInput.hasFocus = viewPort->PlatformUserData && ImGui::GetPlatformIO().Platform_GetWindowFocus(viewPort) && !io.AppFocusLost;
  319. //windowInput.hasFocus = windowInput.hasFocus && !io.AppFocusLost;
  320. }
  321. auto s = ImGui::GetContentRegionMax();
  322. ImGui::Image((void *)c.second.requestedContainerInfo.requestedFBO.texture, s, {0, 1}, {1, 0},
  323. {1,1,1,1}, {0,0,0,1});
  324. ImGui::End();
  325. ImGui::PopStyleColor();
  326. ImGui::PopID();
  327. #pragma endregion
  328. auto windowState = window.windowState;
  329. windowState.w = s.x;
  330. windowState.h = s.y;
  331. c.second.requestedContainerInfo.requestedFBO.resizeFramebuffer(windowState.w, windowState.h);
  332. glBindFramebuffer(GL_FRAMEBUFFER, c.second.requestedContainerInfo.requestedFBO.fbo);
  333. callUpdate(windowState);
  334. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  335. }
  336. else
  337. {
  338. callUpdate(window.windowState);
  339. }
  340. }
  341. else //on pause
  342. {
  343. //still keep it running on the same frame mabe
  344. }
  345. }
  346. #pragma endregion
  347. }
  348. void pika::ContainerManager::reloadDll(pika::LoadedDll &loadedDll, pika::PikaWindow &window, pika::LogManager &logs)
  349. {
  350. std::this_thread::sleep_for(std::chrono::milliseconds(200)); // make sure that the compiler had enough time
  351. //to get hold onto the dll
  352. //pika::LoadedDll newDll;
  353. //if (!newDll.tryToloadDllUntillPossible(loadedDll.id + 1, logs, std::chrono::seconds(1)))
  354. //{
  355. // logs.log("Dll reload attemp failed", pika::logWarning);
  356. // newDll.unloadDll();
  357. // return;
  358. //}
  359. //else
  360. //{
  361. // newDll.unloadDll();
  362. //}
  363. //std::this_thread::sleep_for(std::chrono::milliseconds(10)); // make sure that the dll is unloaded
  364. auto oldContainerInfo = loadedDll.containerInfo;
  365. if (!loadedDll.tryToloadDllUntillPossible(loadedDll.id, logs, std::chrono::seconds(5)))
  366. {
  367. logs.log("Couldn't reloaded dll", pika::logWarning);
  368. return;
  369. }
  370. //todo pospone dll reloading
  371. std::unordered_map<std::string, pika::ContainerInformation> containerNames;
  372. for (auto &c : loadedDll.containerInfo)
  373. {
  374. containerNames[c.containerName] = c;
  375. }
  376. std::unordered_map<std::string, pika::ContainerInformation> oldContainerNames;
  377. for (auto &c : oldContainerInfo)
  378. {
  379. oldContainerNames[c.containerName] = c;
  380. }
  381. //clear containers that dissapeared
  382. {
  383. std::vector<pika::containerId_t> containersToClean;
  384. for (auto &i : runningContainers)
  385. {
  386. if (containerNames.find(i.second.baseContainerName) ==
  387. containerNames.end())
  388. {
  389. std::string l = "Killed container because it does not exist anymore in dll: " +
  390. std::string(i.second.baseContainerName)
  391. + " #" + std::to_string(i.first);
  392. logs.log(l.c_str(), pika::logError);
  393. containersToClean.push_back(i.first);
  394. }
  395. }
  396. for (auto i : containersToClean)
  397. {
  398. forceTerminateContainer(i, loadedDll, logs);
  399. }
  400. }
  401. //clear containers that changed static info
  402. {
  403. std::vector<pika::containerId_t> containersToClean;
  404. for (auto &i : runningContainers)
  405. {
  406. auto &newContainer = containerNames[i.second.baseContainerName];
  407. auto &oldContainer = oldContainerNames[i.second.baseContainerName];
  408. if (newContainer != oldContainer)
  409. {
  410. std::string l = "Killed container because its static container info\nhas changed: "
  411. + std::string(i.second.baseContainerName)
  412. + " #" + std::to_string(i.first);
  413. logs.log(l.c_str(), pika::logError);
  414. containersToClean.push_back(i.first);
  415. }
  416. }
  417. for (auto i : containersToClean)
  418. {
  419. forceTerminateContainer(i, loadedDll, logs);
  420. }
  421. }
  422. loadedDll.gameplayReload_(window.context);
  423. logs.log("Reloaded dll");
  424. }
  425. bool pika::ContainerManager::destroyContainer(containerId_t id, pika::LoadedDll &loadedDll,
  426. pika::LogManager &logManager)
  427. {
  428. PIKA_DEVELOPMENT_ONLY_ASSERT(loadedDll.dllHand != 0, "dll not loaded when trying to destroy container");
  429. auto c = runningContainers.find(id);
  430. if (c == runningContainers.end())
  431. {
  432. logManager.log((std::string("Couldn't find container for destruction: #") + std::to_string(id)).c_str(),
  433. pika::logError);
  434. return false;
  435. }
  436. auto name = c->second.baseContainerName;
  437. loadedDll.bindAllocatorDllRealm(&c->second.allocator);
  438. loadedDll.destructContainer_(&(c->second.pointer), &c->second.arena);
  439. loadedDll.resetAllocatorDllRealm();
  440. freeContainerStuff(c->second);
  441. c->second.requestedContainerInfo.requestedFBO.deleteFramebuffer();
  442. runningContainers.erase(c);
  443. logManager.log((std::string("Destroyed continer: ") + name + " #" + std::to_string(id)).c_str());
  444. return true;
  445. }
  446. //todo remove some of this functions in production
  447. //snapshot file format:
  448. //
  449. // binary
  450. //
  451. // pika::RuntimeContainer
  452. //
  453. // static memory
  454. //
  455. // heap memory
  456. //
  457. //
  458. bool pika::ContainerManager::makeSnapshot(containerId_t id, pika::LogManager &logManager, const char *fileName)
  459. {
  460. auto c = runningContainers.find(id);
  461. if (c == runningContainers.end())
  462. {
  463. logManager.log((std::string("Couldn't find container for making snapshot: #") + std::to_string(id)).c_str(),
  464. pika::logError);
  465. return false;
  466. }
  467. std::string filePath = PIKA_ENGINE_RESOURCES_PATH;
  468. filePath += fileName;
  469. filePath += ".snapshot";
  470. if(!pika::writeEntireFile(filePath.c_str(), &c->second, sizeof(c->second)))
  471. {
  472. logManager.log(("Couldn't write to file for making snapshot: " + filePath).c_str(),
  473. pika::logError);
  474. return false;
  475. }
  476. if (!pika::appendToFile(filePath.c_str(),
  477. c->second.getBaseAdress(), c->second.totalSize))
  478. {
  479. pika::deleteFile(filePath.c_str());
  480. logManager.log(("Couldn't write to file for making snapshot: " + filePath).c_str(),
  481. pika::logError);
  482. return false;
  483. }
  484. //if (!pika::appendToFile(filePath.c_str(),
  485. // c->second.arena.containerStructMemory.block, c->second.arena.containerStructMemory.size))
  486. //{
  487. // pika::deleteFile(filePath.c_str());
  488. // logManager.log(("Couldn't write to file for making snapshot: " + filePath).c_str(),
  489. // pika::logError);
  490. // return false;
  491. //}
  492. //
  493. //if (!pika::appendToFile(filePath.c_str(),
  494. // c->second.allocator.originalBaseMemory, c->second.allocatorSize))
  495. //{
  496. // pika::deleteFile(filePath.c_str());
  497. // logManager.log(("Couldn't write to file for making snapshot: " + filePath).c_str(),
  498. // pika::logError);
  499. // return false;
  500. //}
  501. return true;
  502. }
  503. bool pika::ContainerManager::startRecordingContainer(containerId_t id, pika::LogManager &logManager, const char *fileName)
  504. {
  505. auto c = runningContainers.find(id);
  506. if (c == runningContainers.end())
  507. {
  508. logManager.log((std::string("Couldn't find container for making recording: #") + std::to_string(id)).c_str(),
  509. pika::logError);
  510. return false;
  511. }
  512. if(c->second.flags.status != pika::RuntimeContainer::FLAGS::STATUS_RUNNING)
  513. {
  514. logManager.log((std::string("Trying to record a container that is not running (on status): #") + std::to_string(id)).c_str(),
  515. pika::logError);
  516. return false;
  517. }
  518. std::string filePath = PIKA_ENGINE_RESOURCES_PATH;
  519. filePath += fileName;
  520. filePath += ".recording";
  521. if (filePath.size() > sizeof(c->second.flags.recordingName) - 1)
  522. {
  523. logManager.log((std::string("File path too big (on trying to record)") + std::to_string(id)).c_str(),
  524. pika::logError);
  525. return 0;
  526. }
  527. if (!makeSnapshot(id, logManager, fileName))
  528. {
  529. logManager.log((std::string("Couldn't make snapshot for starting recording") + std::to_string(id)).c_str(),
  530. pika::logError);
  531. return 0;
  532. }
  533. //cear file
  534. {
  535. std::ofstream record(filePath);
  536. if (!record.is_open())
  537. {
  538. logManager.log((std::string("Couldn't open recording file for starting recording") + std::to_string(id)).c_str(),
  539. pika::logError);
  540. return 0;
  541. }
  542. record.close();
  543. }
  544. c->second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_BEING_RECORDED;
  545. pika::strlcpy(c->second.flags.recordingName, filePath, sizeof(c->second.flags.recordingName));
  546. }
  547. bool pika::ContainerManager::stopRecordingContainer(containerId_t id, pika::LogManager &logManager)
  548. {
  549. auto c = runningContainers.find(id);
  550. if (c == runningContainers.end())
  551. {
  552. logManager.log((std::string("Couldn't find container for stopping recording: #") + std::to_string(id)).c_str(),
  553. pika::logError);
  554. return false;
  555. }
  556. c->second.flags.status = pika::RuntimeContainer::FLAGS::STATUS_RUNNING;
  557. }
  558. bool pika::ContainerManager::makeRecordingStep(containerId_t id, pika::LogManager &logManager,
  559. pika::Input &input)
  560. {
  561. auto c = runningContainers.find(id);
  562. if (c == runningContainers.end())
  563. {
  564. logManager.log((std::string("Couldn't find container for making recording step: #") + std::to_string(id)).c_str(),
  565. pika::logError);
  566. return false;
  567. }
  568. if (!pika::appendToFile(c->second.flags.recordingName, &input, sizeof(input)))
  569. {
  570. logManager.log((std::string("Couldn't append to file for recording container") + std::to_string(id)).c_str(),
  571. pika::logError);
  572. return false;
  573. }
  574. return true;
  575. }
  576. bool pika::ContainerManager::forceTerminateContainer(containerId_t id, pika::LoadedDll &loadedDll, pika::LogManager &logManager)
  577. {
  578. PIKA_DEVELOPMENT_ONLY_ASSERT(loadedDll.dllHand != 0, "dll not loaded when trying to destroy container");
  579. auto c = runningContainers.find(id);
  580. if (c == runningContainers.end())
  581. {
  582. logManager.log((std::string("Couldn't find container for destruction: #") + std::to_string(id)).c_str(),
  583. pika::logError);
  584. return false;
  585. }
  586. auto name = c->second.baseContainerName;
  587. freeContainerStuff(c->second);
  588. runningContainers.erase(c);
  589. logManager.log((std::string("Force terminated continer: ") + name + " #" + std::to_string(id)).c_str());
  590. c->second.requestedContainerInfo.requestedFBO.deleteFramebuffer();
  591. return true;
  592. }
  593. void pika::ContainerManager::destroyAllContainers(pika::LoadedDll &loadedDll,
  594. pika::LogManager &logManager)
  595. {
  596. std::vector < pika::containerId_t> containersId;
  597. containersId.reserve(runningContainers.size());
  598. for (auto &c : runningContainers)
  599. {
  600. containersId.push_back(c.first);
  601. }
  602. for (auto i : containersId)
  603. {
  604. destroyContainer(i, loadedDll, logManager);
  605. }
  606. }
  607. #ifdef PIKA_PRODUCTION
  608. void *pika::ContainerManager::allocateOSMemory(size_t size, void *baseAdress)
  609. {
  610. PIKA_PERMA_ASSERT(baseAdress == nullptr, "can't allocate fixed memory in production");
  611. return malloc(size);
  612. }
  613. void pika::ContainerManager::deallocateOSMemory(void *baseAdress)
  614. {
  615. free(baseAdress);
  616. }
  617. #else
  618. #include <Windows.h>
  619. void *pika::ContainerManager::allocateOSMemory(size_t size, void *baseAdress)
  620. {
  621. return VirtualAlloc(baseAdress, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  622. }
  623. void pika::ContainerManager::deallocateOSMemory(void *baseAdress)
  624. {
  625. VirtualFree(baseAdress, 0, MEM_RELEASE);
  626. }
  627. #endif
  628. std::vector<std::string> pika::getAvailableSnapshots(pika::RuntimeContainer &info)
  629. {
  630. std::vector<std::string> files;
  631. auto curDir = std::filesystem::directory_iterator(PIKA_ENGINE_RESOURCES_PATH);
  632. for (const auto &iter : curDir)
  633. {
  634. if (std::filesystem::is_regular_file(iter)
  635. && iter.path().extension() == ".snapshot"
  636. )
  637. {
  638. if (pika::checkIfSnapshotIsCompatible(info, iter.path().stem().string().c_str()))
  639. {
  640. files.push_back(iter.path().stem().string());
  641. }
  642. }
  643. }
  644. return files;
  645. }
  646. std::vector<std::string> pika::getAvailableRecordings(pika::RuntimeContainer &info)
  647. {
  648. auto snapshots = getAvailableSnapshots(info);
  649. std::vector<std::string> returnVec;
  650. returnVec.reserve(snapshots.size());
  651. auto curDir = std::filesystem::directory_iterator(PIKA_ENGINE_RESOURCES_PATH);
  652. for (const auto &iter : curDir)
  653. {
  654. if (std::filesystem::is_regular_file(iter)
  655. && iter.path().extension() == ".recording"
  656. )
  657. {
  658. if (std::find(snapshots.begin(), snapshots.end(), iter.path().stem().string()) != snapshots.end())
  659. {
  660. returnVec.push_back(iter.path().stem().string());
  661. }
  662. }
  663. }
  664. return returnVec;
  665. }
  666. std::vector<std::string> pika::getAvailableSnapshotsAnyMemoryPosition(pika::RuntimeContainer &info)
  667. {
  668. std::vector<std::string> files;
  669. auto curDir = std::filesystem::directory_iterator(PIKA_ENGINE_RESOURCES_PATH);
  670. for (const auto &iter : curDir)
  671. {
  672. if (std::filesystem::is_regular_file(iter)
  673. && iter.path().extension() == ".snapshot"
  674. )
  675. {
  676. if (pika::checkIfSnapshotIsCompatibleAnyMemoryPosition(info, iter.path().stem().string().c_str()))
  677. {
  678. files.push_back(iter.path().stem().string());
  679. }
  680. }
  681. }
  682. return files;
  683. }
  684. std::vector<std::string> pika::getAvailableRecordingAnyMemoryPosition(pika::RuntimeContainer &info)
  685. {
  686. auto snapshots = getAvailableSnapshotsAnyMemoryPosition(info);
  687. std::vector<std::string> returnVec;
  688. returnVec.reserve(snapshots.size());
  689. auto curDir = std::filesystem::directory_iterator(PIKA_ENGINE_RESOURCES_PATH);
  690. for (const auto &iter : curDir)
  691. {
  692. if (std::filesystem::is_regular_file(iter)
  693. && iter.path().extension() == ".recording"
  694. )
  695. {
  696. if (std::find(snapshots.begin(), snapshots.end(), iter.path().stem().string()) != snapshots.end())
  697. {
  698. returnVec.push_back(iter.path().stem().string());
  699. }
  700. }
  701. }
  702. return returnVec;
  703. }
  704. std::vector<std::string> pika::getAvailableSnapshotsAnyMemoryPosition(pika::ContainerInformation &info)
  705. {
  706. std::vector<std::string> files;
  707. auto curDir = std::filesystem::directory_iterator(PIKA_ENGINE_RESOURCES_PATH);
  708. for (const auto &iter : curDir)
  709. {
  710. if (std::filesystem::is_regular_file(iter)
  711. && iter.path().extension() == ".snapshot"
  712. )
  713. {
  714. if (pika::checkIfSnapshotIsCompatibleAnyMemoryPosition(info, iter.path().stem().string().c_str()))
  715. {
  716. files.push_back(iter.path().stem().string());
  717. }
  718. }
  719. }
  720. return files;
  721. }
  722. std::vector<std::string> pika::getAvailableRecordingsAnyMemoryPosition(pika::ContainerInformation &info)
  723. {
  724. auto snapshots = getAvailableSnapshotsAnyMemoryPosition(info);
  725. std::vector<std::string> returnVec;
  726. returnVec.reserve(snapshots.size());
  727. auto curDir = std::filesystem::directory_iterator(PIKA_ENGINE_RESOURCES_PATH);
  728. for (const auto &iter : curDir)
  729. {
  730. if (std::filesystem::is_regular_file(iter)
  731. && iter.path().extension() == ".recording"
  732. )
  733. {
  734. if (std::find(snapshots.begin(), snapshots.end(), iter.path().stem().string()) != snapshots.end())
  735. {
  736. returnVec.push_back(iter.path().stem().string());
  737. }
  738. }
  739. }
  740. return returnVec;
  741. }
  742. bool pika::checkIfSnapshotIsCompatible(pika::RuntimeContainer &info, const char *snapshotName)
  743. {
  744. std::string file = PIKA_ENGINE_RESOURCES_PATH;
  745. file += snapshotName;
  746. file += ".snapshot";
  747. pika::RuntimeContainer loadedInfo = {};
  748. auto s = pika::readEntireFile(file.c_str(), &loadedInfo, sizeof(loadedInfo));
  749. if (s != sizeof(loadedInfo))
  750. {
  751. return 0;
  752. }
  753. //todo mabe a method here?
  754. if (loadedInfo.allocator.originalBaseMemory != info.allocator.originalBaseMemory)
  755. {
  756. return false;
  757. }
  758. if (loadedInfo.requestedContainerInfo.imguiTotalRequestedIds != info.requestedContainerInfo.imguiTotalRequestedIds)
  759. {
  760. return false;
  761. }
  762. if (loadedInfo.arena.containerStructMemory.block != info.arena.containerStructMemory.block)
  763. {
  764. return false;
  765. }
  766. if (loadedInfo.arena.containerStructMemory.size != info.arena.containerStructMemory.size)
  767. {
  768. return false;
  769. }
  770. if (std::strcmp(loadedInfo.baseContainerName, info.baseContainerName) != 0)
  771. {
  772. return false;
  773. }
  774. if (loadedInfo.requestedContainerInfo.bonusAllocators != info.requestedContainerInfo.bonusAllocators)
  775. {
  776. return false;
  777. }
  778. //check if user requested an imgui window
  779. if (
  780. !(
  781. (info.imguiWindowId == 0&&
  782. loadedInfo.imguiWindowId == 0
  783. )||
  784. (
  785. info.imguiWindowId != 0 &&
  786. loadedInfo.imguiWindowId != 0
  787. )
  788. )
  789. )
  790. {
  791. return false;
  792. }
  793. if (loadedInfo.totalSize != info.totalSize)
  794. {
  795. return false;
  796. }
  797. return true;
  798. }
  799. bool pika::checkIfSnapshotIsCompatibleAnyMemoryPosition(pika::RuntimeContainer &info, const char *snapshotName)
  800. {
  801. std::string file = PIKA_ENGINE_RESOURCES_PATH;
  802. file += snapshotName;
  803. file += ".snapshot";
  804. pika::RuntimeContainer loadedInfo = {};
  805. auto s = pika::readEntireFile(file.c_str(), &loadedInfo, sizeof(loadedInfo));
  806. if (s != sizeof(loadedInfo))
  807. {
  808. return 0;
  809. }
  810. if (loadedInfo.arena.containerStructMemory.size != info.arena.containerStructMemory.size)
  811. {
  812. return false;
  813. }
  814. if (std::strcmp(loadedInfo.baseContainerName, info.baseContainerName) != 0)
  815. {
  816. return false;
  817. }
  818. if (loadedInfo.requestedContainerInfo.bonusAllocators != info.requestedContainerInfo.bonusAllocators)
  819. {
  820. return false;
  821. }
  822. //check if user requested an imgui window
  823. if (
  824. !(
  825. (info.imguiWindowId == 0 &&
  826. loadedInfo.imguiWindowId == 0
  827. ) ||
  828. (
  829. info.imguiWindowId != 0 &&
  830. loadedInfo.imguiWindowId != 0
  831. )
  832. )
  833. )
  834. {
  835. return false;
  836. }
  837. if (loadedInfo.totalSize != info.totalSize)
  838. {
  839. return false;
  840. }
  841. return true;
  842. }
  843. bool pika::checkIfSnapshotIsCompatibleAnyMemoryPosition(pika::ContainerInformation &info, const char *snapshotName)
  844. {
  845. std::string file = PIKA_ENGINE_RESOURCES_PATH;
  846. file += snapshotName;
  847. file += ".snapshot";
  848. pika::RuntimeContainer loadedInfo = {};
  849. auto s = pika::readEntireFile(file.c_str(), &loadedInfo, sizeof(loadedInfo));
  850. if (s != sizeof(loadedInfo))
  851. {
  852. return 0;
  853. }
  854. if (loadedInfo.arena.containerStructMemory.size != info.containerStructBaseSize)
  855. {
  856. return false;
  857. }
  858. if (std::strcmp(loadedInfo.baseContainerName, info.containerName.c_str()) != 0)
  859. {
  860. return false;
  861. }
  862. if (loadedInfo.bonusAllocators.size() != info.containerStaticInfo.bonusAllocators.size())
  863. {
  864. return false;
  865. }
  866. for (int i = 0; i < loadedInfo.bonusAllocators.size(); i++)
  867. {
  868. if (loadedInfo.bonusAllocators[i].heapSize != info.containerStaticInfo.bonusAllocators[i]) //todo this doesn't seem to work
  869. {
  870. return false;
  871. }
  872. }
  873. //check if user requested an imgui window
  874. if (
  875. !(
  876. (info.containerStaticInfo.requestImguiFbo == false &&
  877. loadedInfo.imguiWindowId == 0
  878. ) ||
  879. (
  880. info.containerStaticInfo.requestImguiFbo == true &&
  881. loadedInfo.imguiWindowId != 0
  882. )
  883. )
  884. )
  885. {
  886. return false;
  887. }
  888. if (loadedInfo.allocator.heapSize != info.containerStaticInfo.defaultHeapMemorySize)
  889. {
  890. return false;
  891. }
  892. return true;
  893. }
  894. void *pika::getSnapshotMemoryPosition(const char *snapshotName)
  895. {
  896. std::string file = PIKA_ENGINE_RESOURCES_PATH;
  897. file += snapshotName;
  898. file += ".snapshot";
  899. pika::RuntimeContainer loadedInfo = {};
  900. auto s = pika::readEntireFile(file.c_str(), &loadedInfo, sizeof(loadedInfo));
  901. if (s != sizeof(loadedInfo))
  902. {
  903. return nullptr;
  904. }
  905. return loadedInfo.getBaseAdress();
  906. }