App.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. // Copyright (C) 2009-2023, 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/Core/CVarSet.h>
  7. #include <AnKi/Core/GpuMemory/UnifiedGeometryBuffer.h>
  8. #include <AnKi/Util/Logger.h>
  9. #include <AnKi/Util/File.h>
  10. #include <AnKi/Util/Filesystem.h>
  11. #include <AnKi/Util/System.h>
  12. #include <AnKi/Util/ThreadHive.h>
  13. #include <AnKi/Util/Tracer.h>
  14. #include <AnKi/Util/HighRezTimer.h>
  15. #include <AnKi/Core/CoreTracer.h>
  16. #include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
  17. #include <AnKi/Core/GpuMemory/GpuVisibleTransientMemoryPool.h>
  18. #include <AnKi/Core/GpuMemory/GpuReadbackMemoryPool.h>
  19. #include <AnKi/Core/StatsSet.h>
  20. #include <AnKi/Window/NativeWindow.h>
  21. #include <AnKi/Core/MaliHwCounters.h>
  22. #include <AnKi/Window/Input.h>
  23. #include <AnKi/Scene/SceneGraph.h>
  24. #include <AnKi/Resource/ResourceManager.h>
  25. #include <AnKi/Physics/PhysicsWorld.h>
  26. #include <AnKi/Renderer/MainRenderer.h>
  27. #include <AnKi/Script/ScriptManager.h>
  28. #include <AnKi/Resource/ResourceFilesystem.h>
  29. #include <AnKi/Resource/AsyncLoader.h>
  30. #include <AnKi/Ui/UiManager.h>
  31. #include <AnKi/Ui/Canvas.h>
  32. #include <AnKi/Scene/DeveloperConsoleUiNode.h>
  33. #include <csignal>
  34. #if ANKI_OS_ANDROID
  35. # include <android_native_app_glue.h>
  36. #endif
  37. namespace anki {
  38. #if ANKI_OS_ANDROID
  39. /// The one and only android hack
  40. android_app* g_androidApp = nullptr;
  41. #endif
  42. StatCounter g_cpuTotalTime(StatCategory::kTime, "CPU total", StatFlag::kMilisecond | StatFlag::kShowAverage);
  43. static StatCounter g_cpuAllocatedMem(StatCategory::kCpuMem, "Total", StatFlag::kBytes | StatFlag::kThreadSafe);
  44. static StatCounter g_cpuAllocationCount(StatCategory::kCpuMem, "Allocations/frame",
  45. StatFlag::kBytes | StatFlag::kZeroEveryFrame | StatFlag::kThreadSafe);
  46. static StatCounter g_cpuFreesCount(StatCategory::kCpuMem, "Frees/frame", StatFlag::kBytes | StatFlag::kZeroEveryFrame | StatFlag::kThreadSafe);
  47. NumericCVar<U32> g_windowWidthCVar(CVarSubsystem::kCore, "Width", 1920, 16, 16 * 1024, "Width");
  48. NumericCVar<U32> g_windowHeightCVar(CVarSubsystem::kCore, "Height", 1080, 16, 16 * 1024, "Height");
  49. NumericCVar<U32> g_windowFullscreenCVar(CVarSubsystem::kCore, "WindowFullscreen", 1, 0, 2,
  50. "0: windowed, 1: borderless fullscreen, 2: exclusive fullscreen");
  51. NumericCVar<U32> g_targetFpsCVar(CVarSubsystem::kCore, "TargetFps", 60u, 1u, kMaxU32, "Target FPS");
  52. static NumericCVar<U32> g_jobThreadCountCVar(CVarSubsystem::kCore, "JobThreadCount", max(2u, getCpuCoresCount() / 2u), 2u, 1024u,
  53. "Number of job thread");
  54. NumericCVar<U32> g_displayStatsCVar(CVarSubsystem::kCore, "DisplayStats", 0, 0, 2, "Display stats, 0: None, 1: Simple, 2: Detailed");
  55. BoolCVar g_clearCachesCVar(CVarSubsystem::kCore, "ClearCaches", false, "Clear all caches");
  56. BoolCVar g_verboseLogCVar(CVarSubsystem::kCore, "VerboseLog", false, "Verbose logging");
  57. BoolCVar g_benchmarkModeCVar(CVarSubsystem::kCore, "BenchmarkMode", false, "Run in a benchmark mode. Fixed timestep, unlimited target FPS");
  58. NumericCVar<U32> g_benchmarkModeFrameCountCVar(CVarSubsystem::kCore, "BenchmarkModeFrameCount", 60 * 60 * 2, 1, kMaxU32,
  59. "How many frames the benchmark will run before it quits");
  60. NumericCVar<F32> g_lod0MaxDistanceCVar(CVarSubsystem::kCore, "Lod0MaxDistance", 20.0f, 1.0f, kMaxF32,
  61. "Distance that will be used to calculate the LOD 0");
  62. NumericCVar<F32> g_lod1MaxDistanceCVar(CVarSubsystem::kCore, "Lod1MaxDistance", 40.0f, 2.0f, kMaxF32,
  63. "Distance that will be used to calculate the LOD 1");
  64. #if ANKI_PLATFORM_MOBILE
  65. static StatCounter g_maliGpuActive(StatCategory::kGpuMisc, "Mali active cycles");
  66. static StatCounter g_maliGpuReadBandwidth(StatCategory::kGpuMisc, "Mali read bandwidth");
  67. static StatCounter g_maliGpuWriteBandwidth(StatCategory::kGpuMisc, "Mali write bandwidth");
  68. static BoolCVar g_maliHwCountersCVar(CVarSubsystem::kCore, "MaliHwCounters", false, "Enable Mali counters");
  69. #endif
  70. void* App::statsAllocCallback(void* userData, void* ptr, PtrSize size, [[maybe_unused]] PtrSize alignment)
  71. {
  72. ANKI_ASSERT(userData);
  73. constexpr PtrSize kMaxAlignment = 64;
  74. struct alignas(kMaxAlignment) Header
  75. {
  76. PtrSize m_allocatedSize;
  77. Array<U8, kMaxAlignment - sizeof(PtrSize)> _m_padding;
  78. };
  79. static_assert(sizeof(Header) == kMaxAlignment, "See file");
  80. static_assert(alignof(Header) == kMaxAlignment, "See file");
  81. void* out = nullptr;
  82. if(ptr == nullptr)
  83. {
  84. // Need to allocate
  85. ANKI_ASSERT(size > 0);
  86. ANKI_ASSERT(alignment > 0 && alignment <= kMaxAlignment);
  87. const PtrSize newAlignment = kMaxAlignment;
  88. const PtrSize newSize = sizeof(Header) + size;
  89. // Allocate
  90. App* self = static_cast<App*>(userData);
  91. Header* allocation = static_cast<Header*>(self->m_originalAllocCallback(self->m_originalAllocUserData, nullptr, newSize, newAlignment));
  92. allocation->m_allocatedSize = size;
  93. ++allocation;
  94. out = static_cast<void*>(allocation);
  95. // Update stats
  96. g_cpuAllocatedMem.atomicIncrement(size);
  97. g_cpuAllocationCount.atomicIncrement(1);
  98. }
  99. else
  100. {
  101. // Need to free
  102. App* self = static_cast<App*>(userData);
  103. Header* allocation = static_cast<Header*>(ptr);
  104. --allocation;
  105. ANKI_ASSERT(allocation->m_allocatedSize > 0);
  106. // Update stats
  107. g_cpuAllocatedMem.atomicDecrement(allocation->m_allocatedSize);
  108. g_cpuFreesCount.atomicIncrement(1);
  109. // Free
  110. self->m_originalAllocCallback(self->m_originalAllocUserData, allocation, 0, 0);
  111. }
  112. return out;
  113. }
  114. App::App(AllocAlignedCallback allocCb, void* allocCbUserData)
  115. {
  116. m_originalAllocCallback = allocCb;
  117. m_originalAllocUserData = allocCbUserData;
  118. }
  119. App::~App()
  120. {
  121. ANKI_CORE_LOGI("Destroying application");
  122. cleanup();
  123. }
  124. void App::cleanup()
  125. {
  126. SceneGraph::freeSingleton();
  127. ScriptManager::freeSingleton();
  128. MainRenderer::freeSingleton();
  129. UiManager::freeSingleton();
  130. GpuSceneMicroPatcher::freeSingleton();
  131. ResourceManager::freeSingleton();
  132. PhysicsWorld::freeSingleton();
  133. RebarTransientMemoryPool::freeSingleton();
  134. GpuVisibleTransientMemoryPool::freeSingleton();
  135. UnifiedGeometryBuffer::freeSingleton();
  136. GpuSceneBuffer::freeSingleton();
  137. GpuReadbackMemoryPool::freeSingleton();
  138. CoreThreadHive::freeSingleton();
  139. MaliHwCounters::freeSingleton();
  140. GrManager::freeSingleton();
  141. Input::freeSingleton();
  142. NativeWindow::freeSingleton();
  143. #if ANKI_TRACING_ENABLED
  144. CoreTracer::freeSingleton();
  145. #endif
  146. GlobalFrameIndex::freeSingleton();
  147. m_settingsDir.destroy();
  148. m_cacheDir.destroy();
  149. CoreMemoryPool::freeSingleton();
  150. DefaultMemoryPool::freeSingleton();
  151. }
  152. Error App::init()
  153. {
  154. const Error err = initInternal();
  155. if(err)
  156. {
  157. ANKI_CORE_LOGE("App initialization failed. Shutting down");
  158. cleanup();
  159. }
  160. return err;
  161. }
  162. Error App::initInternal()
  163. {
  164. Logger::getSingleton().enableVerbosity(g_verboseLogCVar.get());
  165. setSignalHandlers();
  166. AllocAlignedCallback allocCb = m_originalAllocCallback;
  167. void* allocCbUserData = m_originalAllocUserData;
  168. initMemoryCallbacks(allocCb, allocCbUserData);
  169. DefaultMemoryPool::allocateSingleton(allocCb, allocCbUserData);
  170. CoreMemoryPool::allocateSingleton(allocCb, allocCbUserData);
  171. ANKI_CHECK(initDirs());
  172. // Print a message
  173. const char* buildType =
  174. #if ANKI_OPTIMIZE
  175. "optimized, "
  176. #else
  177. "NOT optimized, "
  178. #endif
  179. #if ANKI_DEBUG_SYMBOLS
  180. "dbg symbols, "
  181. #else
  182. "NO dbg symbols, "
  183. #endif
  184. #if ANKI_EXTRA_CHECKS
  185. "extra checks, "
  186. #else
  187. "NO extra checks, "
  188. #endif
  189. #if ANKI_TRACING_ENABLED
  190. "built with tracing";
  191. #else
  192. "NOT built with tracing";
  193. #endif
  194. ANKI_CORE_LOGI("Initializing application ("
  195. "version %u.%u, "
  196. "%s, "
  197. "compiler %s, "
  198. "build date %s, "
  199. "commit %s)",
  200. ANKI_VERSION_MAJOR, ANKI_VERSION_MINOR, buildType, ANKI_COMPILER_STR, __DATE__, ANKI_REVISION);
  201. // Check SIMD support
  202. #if ANKI_SIMD_SSE && ANKI_COMPILER_GCC_COMPATIBLE
  203. if(!__builtin_cpu_supports("sse4.2"))
  204. {
  205. ANKI_CORE_LOGF("AnKi is built with sse4.2 support but your CPU doesn't support it. Try bulding without SSE support");
  206. }
  207. #endif
  208. ANKI_CORE_LOGI("Number of job threads: %u", g_jobThreadCountCVar.get());
  209. if(g_benchmarkModeCVar.get() && g_vsyncCVar.get())
  210. {
  211. ANKI_CORE_LOGW("Vsync is enabled and benchmark mode as well. Will turn vsync off");
  212. g_vsyncCVar.set(false);
  213. }
  214. GlobalFrameIndex::allocateSingleton();
  215. //
  216. // Core tracer
  217. //
  218. #if ANKI_TRACING_ENABLED
  219. ANKI_CHECK(CoreTracer::allocateSingleton().init(m_settingsDir));
  220. #endif
  221. //
  222. // Window
  223. //
  224. NativeWindowInitInfo nwinit;
  225. nwinit.m_width = g_windowWidthCVar.get();
  226. nwinit.m_height = g_windowHeightCVar.get();
  227. nwinit.m_depthBits = 0;
  228. nwinit.m_stencilBits = 0;
  229. nwinit.m_fullscreenDesktopRez = g_windowFullscreenCVar.get() > 0;
  230. nwinit.m_exclusiveFullscreen = g_windowFullscreenCVar.get() == 2;
  231. nwinit.m_targetFps = g_targetFpsCVar.get();
  232. NativeWindow::allocateSingleton();
  233. ANKI_CHECK(NativeWindow::getSingleton().init(nwinit));
  234. //
  235. // Input
  236. //
  237. Input::allocateSingleton();
  238. ANKI_CHECK(Input::getSingleton().init());
  239. //
  240. // ThreadPool
  241. //
  242. const Bool pinThreads = !ANKI_OS_ANDROID;
  243. CoreThreadHive::allocateSingleton(g_jobThreadCountCVar.get(), pinThreads);
  244. //
  245. // Graphics API
  246. //
  247. GrManagerInitInfo grInit;
  248. grInit.m_allocCallback = allocCb;
  249. grInit.m_allocCallbackUserData = allocCbUserData;
  250. grInit.m_cacheDirectory = m_cacheDir.toCString();
  251. ANKI_CHECK(GrManager::allocateSingleton().init(grInit));
  252. //
  253. // Mali HW counters
  254. //
  255. #if ANKI_PLATFORM_MOBILE
  256. if(ANKI_STATS_ENABLED && GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kArm && g_maliHwCountersCVar.get())
  257. {
  258. MaliHwCounters::allocateSingleton();
  259. }
  260. #endif
  261. //
  262. // GPU mem
  263. //
  264. UnifiedGeometryBuffer::allocateSingleton().init();
  265. GpuSceneBuffer::allocateSingleton().init();
  266. RebarTransientMemoryPool::allocateSingleton().init();
  267. GpuVisibleTransientMemoryPool::allocateSingleton();
  268. GpuReadbackMemoryPool::allocateSingleton();
  269. //
  270. // Physics
  271. //
  272. PhysicsWorld::allocateSingleton();
  273. ANKI_CHECK(PhysicsWorld::getSingleton().init(allocCb, allocCbUserData));
  274. //
  275. // Resources
  276. //
  277. #if !ANKI_OS_ANDROID
  278. // Add the location of the executable where the shaders are supposed to be
  279. String executableFname;
  280. ANKI_CHECK(getApplicationPath(executableFname));
  281. ANKI_CORE_LOGI("Executable path is: %s", executableFname.cstr());
  282. String shadersPath;
  283. getParentFilepath(executableFname, shadersPath);
  284. shadersPath += ":";
  285. shadersPath += g_dataPathsCVar.get();
  286. g_dataPathsCVar.set(shadersPath);
  287. #endif
  288. ANKI_CHECK(ResourceManager::allocateSingleton().init(allocCb, allocCbUserData));
  289. //
  290. // UI
  291. //
  292. ANKI_CHECK(UiManager::allocateSingleton().init(allocCb, allocCbUserData));
  293. //
  294. // GPU scene
  295. //
  296. ANKI_CHECK(GpuSceneMicroPatcher::allocateSingleton().init());
  297. //
  298. // Renderer
  299. //
  300. MainRendererInitInfo renderInit;
  301. renderInit.m_swapchainSize = UVec2(NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight());
  302. renderInit.m_allocCallback = allocCb;
  303. renderInit.m_allocCallbackUserData = allocCbUserData;
  304. ANKI_CHECK(MainRenderer::allocateSingleton().init(renderInit));
  305. //
  306. // Script
  307. //
  308. ScriptManager::allocateSingleton(allocCb, allocCbUserData);
  309. //
  310. // Scene
  311. //
  312. ANKI_CHECK(SceneGraph::allocateSingleton().init(allocCb, allocCbUserData));
  313. ANKI_CORE_LOGI("Application initialized");
  314. return Error::kNone;
  315. }
  316. Error App::initDirs()
  317. {
  318. // Settings path
  319. #if !ANKI_OS_ANDROID
  320. String home;
  321. ANKI_CHECK(getHomeDirectory(home));
  322. m_settingsDir.sprintf("%s/.anki", &home[0]);
  323. #else
  324. m_settingsDir.sprintf("%s/.anki", g_androidApp->activity->internalDataPath);
  325. #endif
  326. if(!directoryExists(m_settingsDir.toCString()))
  327. {
  328. ANKI_CORE_LOGI("Creating settings dir \"%s\"", &m_settingsDir[0]);
  329. ANKI_CHECK(createDirectory(m_settingsDir.toCString()));
  330. }
  331. else
  332. {
  333. ANKI_CORE_LOGI("Using settings dir \"%s\"", &m_settingsDir[0]);
  334. }
  335. // Cache
  336. m_cacheDir.sprintf("%s/cache", &m_settingsDir[0]);
  337. const Bool cacheDirExists = directoryExists(m_cacheDir.toCString());
  338. if(g_clearCachesCVar.get() && cacheDirExists)
  339. {
  340. ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", m_cacheDir.cstr());
  341. ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
  342. ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
  343. }
  344. else if(!cacheDirExists)
  345. {
  346. ANKI_CORE_LOGI("Will create cache dir: %s", m_cacheDir.cstr());
  347. ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
  348. }
  349. return Error::kNone;
  350. }
  351. Error App::mainLoop()
  352. {
  353. ANKI_CORE_LOGI("Entering main loop");
  354. Bool quit = false;
  355. Second prevUpdateTime = HighRezTimer::getCurrentTime();
  356. Second crntTime = prevUpdateTime;
  357. // Benchmark mode stuff:
  358. const Bool benchmarkMode = g_benchmarkModeCVar.get();
  359. Second aggregatedCpuTime = 0.0;
  360. Second aggregatedGpuTime = 0.0;
  361. constexpr U32 kBenchmarkFramesToGatherBeforeFlush = 60;
  362. U32 benchmarkFramesGathered = 0;
  363. File benchmarkCsvFile;
  364. CoreString benchmarkCsvFileFilename;
  365. if(benchmarkMode)
  366. {
  367. benchmarkCsvFileFilename.sprintf("%s/Benchmark.csv", m_settingsDir.cstr());
  368. ANKI_CHECK(benchmarkCsvFile.open(benchmarkCsvFileFilename, FileOpenFlag::kWrite));
  369. ANKI_CHECK(benchmarkCsvFile.writeText("CPU, GPU\n"));
  370. }
  371. while(!quit)
  372. {
  373. {
  374. ANKI_TRACE_SCOPED_EVENT(Frame);
  375. const Second startTime = HighRezTimer::getCurrentTime();
  376. prevUpdateTime = crntTime;
  377. crntTime = (!benchmarkMode) ? HighRezTimer::getCurrentTime() : (prevUpdateTime + 1.0_sec / 60.0_sec);
  378. // Update
  379. ANKI_CHECK(Input::getSingleton().handleEvents());
  380. // User update
  381. ANKI_CHECK(userMainLoop(quit, crntTime - prevUpdateTime));
  382. ANKI_CHECK(SceneGraph::getSingleton().update(prevUpdateTime, crntTime));
  383. // Render
  384. TexturePtr presentableTex = GrManager::getSingleton().acquireNextPresentableTexture();
  385. ANKI_CHECK(MainRenderer::getSingleton().render(presentableTex.get()));
  386. // If we get stats exclude the time of GR because it forces some GPU-CPU serialization. We don't want to count that
  387. Second grTime = 0.0;
  388. if(benchmarkMode || g_displayStatsCVar.get() > 0) [[unlikely]]
  389. {
  390. grTime = HighRezTimer::getCurrentTime();
  391. }
  392. GrManager::getSingleton().swapBuffers();
  393. if(benchmarkMode || g_displayStatsCVar.get() > 0) [[unlikely]]
  394. {
  395. grTime = HighRezTimer::getCurrentTime() - grTime;
  396. }
  397. RebarTransientMemoryPool::getSingleton().endFrame();
  398. UnifiedGeometryBuffer::getSingleton().endFrame();
  399. GpuSceneBuffer::getSingleton().endFrame();
  400. GpuVisibleTransientMemoryPool::getSingleton().endFrame();
  401. GpuReadbackMemoryPool::getSingleton().endFrame();
  402. // Sleep
  403. const Second endTime = HighRezTimer::getCurrentTime();
  404. const Second frameTime = endTime - startTime;
  405. g_cpuTotalTime.set((frameTime - grTime) * 1000.0);
  406. if(!benchmarkMode) [[likely]]
  407. {
  408. const Second timerTick = 1.0_sec / Second(g_targetFpsCVar.get());
  409. if(frameTime < timerTick)
  410. {
  411. ANKI_TRACE_SCOPED_EVENT(TimerTickSleep);
  412. HighRezTimer::sleep(timerTick - frameTime);
  413. }
  414. }
  415. // Benchmark stats
  416. else
  417. {
  418. aggregatedCpuTime += frameTime - grTime;
  419. aggregatedGpuTime += 0; // TODO
  420. ++benchmarkFramesGathered;
  421. if(benchmarkFramesGathered >= kBenchmarkFramesToGatherBeforeFlush)
  422. {
  423. aggregatedCpuTime = aggregatedCpuTime / Second(kBenchmarkFramesToGatherBeforeFlush) * 1000.0;
  424. aggregatedGpuTime = aggregatedGpuTime / Second(kBenchmarkFramesToGatherBeforeFlush) * 1000.0;
  425. ANKI_CHECK(benchmarkCsvFile.writeTextf("%f,%f\n", aggregatedCpuTime, aggregatedGpuTime));
  426. benchmarkFramesGathered = 0;
  427. aggregatedCpuTime = 0.0;
  428. aggregatedGpuTime = 0.0;
  429. }
  430. }
  431. // Stats
  432. #if ANKI_PLATFORM_MOBILE
  433. if(MaliHwCounters::isAllocated())
  434. {
  435. MaliHwCountersOut out;
  436. MaliHwCounters::getSingleton().sample(out);
  437. g_maliGpuActive.set(out.m_gpuActive);
  438. g_maliGpuReadBandwidth.set(out.m_readBandwidth);
  439. g_maliGpuWriteBandwidth.set(out.m_writeBandwidth);
  440. }
  441. #endif
  442. StatsSet::getSingleton().endFrame();
  443. ++GlobalFrameIndex::getSingleton().m_value;
  444. if(benchmarkMode) [[unlikely]]
  445. {
  446. if(GlobalFrameIndex::getSingleton().m_value >= g_benchmarkModeFrameCountCVar.get())
  447. {
  448. quit = true;
  449. }
  450. }
  451. }
  452. #if ANKI_TRACING_ENABLED
  453. static U64 frame = 1;
  454. CoreTracer::getSingleton().flushFrame(frame++);
  455. #endif
  456. }
  457. if(benchmarkMode) [[unlikely]]
  458. {
  459. ANKI_CORE_LOGI("Benchmark file saved in: %s", benchmarkCsvFileFilename.cstr());
  460. }
  461. return Error::kNone;
  462. }
  463. void App::initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserData)
  464. {
  465. if(ANKI_STATS_ENABLED && g_displayStatsCVar.get() > 1)
  466. {
  467. allocCb = statsAllocCallback;
  468. allocCbUserData = this;
  469. }
  470. else
  471. {
  472. // Leave the default
  473. }
  474. }
  475. void App::setSignalHandlers()
  476. {
  477. auto handler = [](int signum) -> void {
  478. const char* name = nullptr;
  479. switch(signum)
  480. {
  481. case SIGABRT:
  482. name = "SIGABRT";
  483. break;
  484. case SIGSEGV:
  485. name = "SIGSEGV";
  486. break;
  487. #if ANKI_POSIX
  488. case SIGBUS:
  489. name = "SIGBUS";
  490. break;
  491. #endif
  492. case SIGILL:
  493. name = "SIGILL";
  494. break;
  495. case SIGFPE:
  496. name = "SIGFPE";
  497. break;
  498. }
  499. if(name)
  500. printf("Caught signal %d (%s)\n", signum, name);
  501. else
  502. printf("Caught signal %d\n", signum);
  503. U32 count = 0;
  504. printf("Backtrace:\n");
  505. backtrace([&count](CString symbol) {
  506. printf("%.2u: %s\n", count++, symbol.cstr());
  507. });
  508. ANKI_DEBUG_BREAK();
  509. };
  510. signal(SIGSEGV, handler);
  511. signal(SIGILL, handler);
  512. signal(SIGFPE, handler);
  513. #if ANKI_POSIX
  514. signal(SIGBUS, handler);
  515. #endif
  516. // Ignore for now: signal(SIGABRT, handler);
  517. }
  518. Bool App::toggleDeveloperConsole()
  519. {
  520. SceneNode& node = SceneGraph::getSingleton().findSceneNode("_DevConsole");
  521. static_cast<DeveloperConsoleUiNode&>(node).toggleConsole();
  522. m_consoleEnabled = static_cast<DeveloperConsoleUiNode&>(node).isConsoleEnabled();
  523. return m_consoleEnabled;
  524. }
  525. } // end namespace anki