App.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. // Copyright (C) 2009-2017, 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/core/App.h>
  6. #include <anki/misc/ConfigSet.h>
  7. #include <anki/util/Logger.h>
  8. #include <anki/util/File.h>
  9. #include <anki/util/Filesystem.h>
  10. #include <anki/util/System.h>
  11. #include <anki/util/ThreadPool.h>
  12. #include <anki/util/ThreadHive.h>
  13. #include <anki/core/Trace.h>
  14. #include <anki/core/NativeWindow.h>
  15. #include <anki/input/Input.h>
  16. #include <anki/scene/SceneGraph.h>
  17. #include <anki/resource/ResourceManager.h>
  18. #include <anki/physics/PhysicsWorld.h>
  19. #include <anki/renderer/MainRenderer.h>
  20. #include <anki/script/ScriptManager.h>
  21. #include <anki/resource/ResourceFilesystem.h>
  22. #include <anki/resource/AsyncLoader.h>
  23. #include <anki/core/StagingGpuMemoryManager.h>
  24. #if ANKI_OS == ANKI_OS_ANDROID
  25. #include <android_native_app_glue.h>
  26. #endif
  27. namespace anki
  28. {
  29. #if ANKI_OS == ANKI_OS_ANDROID
  30. /// The one and only android hack
  31. android_app* gAndroidApp = nullptr;
  32. #endif
  33. App::App()
  34. {
  35. }
  36. App::~App()
  37. {
  38. cleanup();
  39. }
  40. void App::cleanup()
  41. {
  42. if(m_script)
  43. {
  44. m_heapAlloc.deleteInstance(m_script);
  45. m_script = nullptr;
  46. }
  47. if(m_scene)
  48. {
  49. m_heapAlloc.deleteInstance(m_scene);
  50. m_scene = nullptr;
  51. }
  52. if(m_renderer)
  53. {
  54. m_heapAlloc.deleteInstance(m_renderer);
  55. m_renderer = nullptr;
  56. }
  57. if(m_resources)
  58. {
  59. m_heapAlloc.deleteInstance(m_resources);
  60. m_resources = nullptr;
  61. }
  62. if(m_resourceFs)
  63. {
  64. m_heapAlloc.deleteInstance(m_resourceFs);
  65. m_resourceFs = nullptr;
  66. }
  67. if(m_physics)
  68. {
  69. m_heapAlloc.deleteInstance(m_physics);
  70. m_physics = nullptr;
  71. }
  72. if(m_stagingMem)
  73. {
  74. m_heapAlloc.deleteInstance(m_stagingMem);
  75. m_stagingMem = nullptr;
  76. }
  77. if(m_gr)
  78. {
  79. m_heapAlloc.deleteInstance(m_gr);
  80. m_gr = nullptr;
  81. }
  82. if(m_threadpool)
  83. {
  84. m_heapAlloc.deleteInstance(m_threadpool);
  85. m_threadpool = nullptr;
  86. }
  87. if(m_threadHive)
  88. {
  89. m_heapAlloc.deleteInstance(m_threadHive);
  90. m_threadHive = nullptr;
  91. }
  92. if(m_input)
  93. {
  94. m_heapAlloc.deleteInstance(m_input);
  95. m_input = nullptr;
  96. }
  97. if(m_window)
  98. {
  99. m_heapAlloc.deleteInstance(m_window);
  100. m_window = nullptr;
  101. }
  102. m_settingsDir.destroy(m_heapAlloc);
  103. m_cacheDir.destroy(m_heapAlloc);
  104. #if ANKI_ENABLE_TRACE
  105. TraceManagerSingleton::destroy();
  106. #endif
  107. }
  108. Error App::init(const ConfigSet& config, AllocAlignedCallback allocCb, void* allocCbUserData)
  109. {
  110. Error err = initInternal(config, allocCb, allocCbUserData);
  111. if(err)
  112. {
  113. cleanup();
  114. ANKI_CORE_LOGE("App initialization failed");
  115. }
  116. return err;
  117. }
  118. Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb, void* allocCbUserData)
  119. {
  120. m_allocCb = allocCb;
  121. m_allocCbData = allocCbUserData;
  122. m_heapAlloc = HeapAllocator<U8>(allocCb, allocCbUserData);
  123. ConfigSet config = config_;
  124. ANKI_CHECK(initDirs(config));
  125. // Print a message
  126. const char* buildType =
  127. #if ANKI_OPTIMIZE
  128. "optimized, "
  129. #else
  130. "NOT optimized, "
  131. #endif
  132. #if ANKI_DEBUG_SYMBOLS
  133. "dbg symbols, "
  134. #else
  135. "NO dbg symbols, "
  136. #endif
  137. #if ANKI_EXTRA_CHECKS
  138. "extra checks";
  139. #else
  140. "NO extra checks";
  141. #endif
  142. ANKI_CORE_LOGI("Initializing application ("
  143. "version %u.%u, "
  144. "%s, "
  145. "compiler %s, "
  146. "build date %s, "
  147. "commit %s)",
  148. ANKI_VERSION_MAJOR,
  149. ANKI_VERSION_MINOR,
  150. buildType,
  151. ANKI_COMPILER_STR,
  152. __DATE__,
  153. ANKI_REVISION);
  154. m_timerTick = 1.0 / 60.0; // in sec. 1.0 / period
  155. // Check SIMD support
  156. #if ANKI_SIMD == ANKI_SIMD_SSE
  157. if(!__builtin_cpu_supports("sse4.2"))
  158. {
  159. ANKI_CORE_LOGF(
  160. "AnKi is built with sse4.2 support but your CPU doesn't support it. Try bulding without SSE support");
  161. }
  162. #endif
  163. #if ANKI_ENABLE_TRACE
  164. ANKI_CHECK(TraceManagerSingleton::get().create(m_heapAlloc, m_settingsDir.toCString()));
  165. #endif
  166. ANKI_CORE_LOGI("Number of main threads: %u", U(config.getNumber("core.mainThreadCount")));
  167. //
  168. // Window
  169. //
  170. NativeWindowInitInfo nwinit;
  171. nwinit.m_width = config.getNumber("width");
  172. nwinit.m_height = config.getNumber("height");
  173. nwinit.m_depthBits = 0;
  174. nwinit.m_stencilBits = 0;
  175. nwinit.m_fullscreenDesktopRez = config.getNumber("fullscreenDesktopResolution");
  176. m_window = m_heapAlloc.newInstance<NativeWindow>();
  177. ANKI_CHECK(m_window->init(nwinit, m_heapAlloc));
  178. //
  179. // Input
  180. //
  181. m_input = m_heapAlloc.newInstance<Input>();
  182. ANKI_CHECK(m_input->init(m_window));
  183. //
  184. // ThreadPool
  185. //
  186. m_threadpool = m_heapAlloc.newInstance<ThreadPool>(config.getNumber("core.mainThreadCount"));
  187. m_threadHive = m_heapAlloc.newInstance<ThreadHive>(config.getNumber("core.mainThreadCount"), m_heapAlloc);
  188. //
  189. // Graphics API
  190. //
  191. m_gr = m_heapAlloc.newInstance<GrManager>();
  192. GrManagerInitInfo grInit;
  193. grInit.m_allocCallback = m_allocCb;
  194. grInit.m_allocCallbackUserData = m_allocCbData;
  195. grInit.m_cacheDirectory = m_cacheDir.toCString();
  196. grInit.m_config = &config;
  197. grInit.m_window = m_window;
  198. ANKI_CHECK(m_gr->init(grInit));
  199. //
  200. // Staging mem
  201. //
  202. m_stagingMem = m_heapAlloc.newInstance<StagingGpuMemoryManager>();
  203. ANKI_CHECK(m_stagingMem->init(m_gr, config));
  204. //
  205. // Physics
  206. //
  207. m_physics = m_heapAlloc.newInstance<PhysicsWorld>();
  208. ANKI_CHECK(m_physics->create(m_allocCb, m_allocCbData));
  209. //
  210. // Resource FS
  211. //
  212. m_resourceFs = m_heapAlloc.newInstance<ResourceFilesystem>(m_heapAlloc);
  213. ANKI_CHECK(m_resourceFs->init(config, m_cacheDir.toCString()));
  214. //
  215. // Resources
  216. //
  217. ResourceManagerInitInfo rinit;
  218. rinit.m_gr = m_gr;
  219. rinit.m_physics = m_physics;
  220. rinit.m_resourceFs = m_resourceFs;
  221. rinit.m_config = &config;
  222. rinit.m_cacheDir = m_cacheDir.toCString();
  223. rinit.m_allocCallback = m_allocCb;
  224. rinit.m_allocCallbackData = m_allocCbData;
  225. m_resources = m_heapAlloc.newInstance<ResourceManager>();
  226. ANKI_CHECK(m_resources->init(rinit));
  227. //
  228. // Renderer
  229. //
  230. if(nwinit.m_fullscreenDesktopRez)
  231. {
  232. config.set("width", m_window->getWidth());
  233. config.set("height", m_window->getHeight());
  234. }
  235. m_renderer = m_heapAlloc.newInstance<MainRenderer>();
  236. ANKI_CHECK(m_renderer->create(
  237. m_threadpool, m_resources, m_gr, m_stagingMem, m_allocCb, m_allocCbData, config, &m_globalTimestamp));
  238. //
  239. // Scene
  240. //
  241. m_scene = m_heapAlloc.newInstance<SceneGraph>();
  242. ANKI_CHECK(m_scene->init(m_allocCb,
  243. m_allocCbData,
  244. m_threadpool,
  245. m_threadHive,
  246. m_resources,
  247. m_stagingMem,
  248. m_input,
  249. &m_globalTimestamp,
  250. config));
  251. //
  252. // Script
  253. //
  254. m_script = m_heapAlloc.newInstance<ScriptManager>();
  255. ANKI_CHECK(m_script->init(m_allocCb, m_allocCbData, m_scene, m_renderer));
  256. ANKI_CORE_LOGI("Application initialized");
  257. return ErrorCode::NONE;
  258. }
  259. Error App::initDirs(const ConfigSet& cfg)
  260. {
  261. #if ANKI_OS != ANKI_OS_ANDROID
  262. // Settings path
  263. StringAuto home(m_heapAlloc);
  264. ANKI_CHECK(getHomeDirectory(m_heapAlloc, home));
  265. m_settingsDir.sprintf(m_heapAlloc, "%s/.anki", &home[0]);
  266. if(!directoryExists(m_settingsDir.toCString()))
  267. {
  268. ANKI_CORE_LOGI("Creating settings dir \"%s\"", &m_settingsDir[0]);
  269. ANKI_CHECK(createDirectory(m_settingsDir.toCString()));
  270. }
  271. else
  272. {
  273. ANKI_CORE_LOGI("Using settings dir \"%s\"", &m_settingsDir[0]);
  274. }
  275. // Cache
  276. m_cacheDir.sprintf(m_heapAlloc, "%s/cache", &m_settingsDir[0]);
  277. const Bool cacheDirExists = directoryExists(m_cacheDir.toCString());
  278. if(cfg.getNumber("clearCaches") && cacheDirExists)
  279. {
  280. ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", &m_cacheDir[0]);
  281. ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
  282. ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
  283. }
  284. else if(!cacheDirExists)
  285. {
  286. ANKI_CORE_LOGI("Will create cache dir: %s", &m_cacheDir[0]);
  287. ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
  288. }
  289. #else
  290. // ANKI_ASSERT(gAndroidApp);
  291. // ANativeActivity* activity = gAndroidApp->activity;
  292. // Settings path
  293. // settingsDir = String(activity->internalDataDir, alloc);
  294. settingsDir = String("/sdcard/.anki/");
  295. if(!directoryExists(settingsDir.c_str()))
  296. {
  297. createDirectory(settingsDir.c_str());
  298. }
  299. // Cache
  300. cacheDir = settingsDir + "/cache";
  301. if(directoryExists(cacheDir.c_str()))
  302. {
  303. removeDirectory(cacheDir.c_str());
  304. }
  305. createDirectory(cacheDir.c_str());
  306. #endif
  307. return ErrorCode::NONE;
  308. }
  309. Error App::mainLoop()
  310. {
  311. ANKI_CORE_LOGI("Entering main loop");
  312. Bool quit = false;
  313. HighRezTimer::Scalar prevUpdateTime = HighRezTimer::getCurrentTime();
  314. HighRezTimer::Scalar crntTime = prevUpdateTime;
  315. while(!quit)
  316. {
  317. ANKI_TRACE_START_FRAME();
  318. HighRezTimer timer;
  319. timer.start();
  320. prevUpdateTime = crntTime;
  321. crntTime = HighRezTimer::getCurrentTime();
  322. m_gr->beginFrame();
  323. // Update
  324. ANKI_CHECK(m_input->handleEvents());
  325. // User update
  326. ANKI_CHECK(userMainLoop(quit));
  327. ANKI_CHECK(m_scene->update(prevUpdateTime, crntTime, *m_renderer));
  328. ANKI_CHECK(m_renderer->render(*m_scene));
  329. // Pause and sync async loader. That will force all tasks before the pause to finish in this frame.
  330. m_resources->getAsyncLoader().pause();
  331. m_gr->swapBuffers();
  332. m_stagingMem->endFrame();
  333. // Update the trace info with some async loader stats
  334. U64 asyncTaskCount = m_resources->getAsyncLoader().getCompletedTaskCount();
  335. ANKI_TRACE_INC_COUNTER(RESOURCE_ASYNC_TASKS, asyncTaskCount - m_resourceCompletedAsyncTaskCount);
  336. m_resourceCompletedAsyncTaskCount = asyncTaskCount;
  337. // Now resume the loader
  338. m_resources->getAsyncLoader().resume();
  339. // Sleep
  340. timer.stop();
  341. if(timer.getElapsedTime() < m_timerTick)
  342. {
  343. HighRezTimer::sleep(m_timerTick - timer.getElapsedTime());
  344. }
  345. ++m_globalTimestamp;
  346. ANKI_TRACE_STOP_FRAME();
  347. }
  348. return ErrorCode::NONE;
  349. }
  350. } // end namespace anki