App.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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/ConfigSet.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/DeveloperConsole.h>
  19. #include <AnKi/Core/StatsUi.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/Renderer/RenderQueue.h>
  25. #include <AnKi/Resource/ResourceManager.h>
  26. #include <AnKi/Physics/PhysicsWorld.h>
  27. #include <AnKi/Renderer/MainRenderer.h>
  28. #include <AnKi/Script/ScriptManager.h>
  29. #include <AnKi/Resource/ResourceFilesystem.h>
  30. #include <AnKi/Resource/AsyncLoader.h>
  31. #include <AnKi/Ui/UiManager.h>
  32. #include <AnKi/Ui/Canvas.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. void* App::MemStats::allocCallback(void* userData, void* ptr, PtrSize size, [[maybe_unused]] PtrSize alignment)
  43. {
  44. ANKI_ASSERT(userData);
  45. constexpr PtrSize kMaxAlignment = 64;
  46. struct alignas(kMaxAlignment) Header
  47. {
  48. PtrSize m_allocatedSize;
  49. Array<U8, kMaxAlignment - sizeof(PtrSize)> _m_padding;
  50. };
  51. static_assert(sizeof(Header) == kMaxAlignment, "See file");
  52. static_assert(alignof(Header) == kMaxAlignment, "See file");
  53. void* out = nullptr;
  54. if(ptr == nullptr)
  55. {
  56. // Need to allocate
  57. ANKI_ASSERT(size > 0);
  58. ANKI_ASSERT(alignment > 0 && alignment <= kMaxAlignment);
  59. const PtrSize newAlignment = kMaxAlignment;
  60. const PtrSize newSize = sizeof(Header) + size;
  61. // Allocate
  62. App* self = static_cast<App*>(userData);
  63. Header* allocation = static_cast<Header*>(self->m_originalAllocCallback(self->m_originalAllocUserData, nullptr, newSize, newAlignment));
  64. allocation->m_allocatedSize = size;
  65. ++allocation;
  66. out = static_cast<void*>(allocation);
  67. // Update stats
  68. self->m_memStats.m_allocatedMem.fetchAdd(size);
  69. self->m_memStats.m_allocCount.fetchAdd(1);
  70. }
  71. else
  72. {
  73. // Need to free
  74. App* self = static_cast<App*>(userData);
  75. Header* allocation = static_cast<Header*>(ptr);
  76. --allocation;
  77. ANKI_ASSERT(allocation->m_allocatedSize > 0);
  78. // Update stats
  79. self->m_memStats.m_freeCount.fetchAdd(1);
  80. self->m_memStats.m_allocatedMem.fetchSub(allocation->m_allocatedSize);
  81. // Free
  82. self->m_originalAllocCallback(self->m_originalAllocUserData, allocation, 0, 0);
  83. }
  84. return out;
  85. }
  86. App::App(AllocAlignedCallback allocCb, void* allocCbUserData)
  87. {
  88. m_originalAllocCallback = allocCb;
  89. m_originalAllocUserData = allocCbUserData;
  90. // Config set is a bit special so init it ASAP
  91. ConfigSet::allocateSingleton(allocCb, allocCbUserData);
  92. }
  93. App::~App()
  94. {
  95. ANKI_CORE_LOGI("Destroying application");
  96. cleanup();
  97. }
  98. void App::cleanup()
  99. {
  100. m_statsUi.reset(nullptr);
  101. m_console.reset(nullptr);
  102. SceneGraph::freeSingleton();
  103. ScriptManager::freeSingleton();
  104. MainRenderer::freeSingleton();
  105. UiManager::freeSingleton();
  106. GpuSceneMicroPatcher::freeSingleton();
  107. ResourceManager::freeSingleton();
  108. PhysicsWorld::freeSingleton();
  109. RebarTransientMemoryPool::freeSingleton();
  110. GpuVisibleTransientMemoryPool::freeSingleton();
  111. UnifiedGeometryBuffer::freeSingleton();
  112. GpuSceneBuffer::freeSingleton();
  113. CoreThreadHive::freeSingleton();
  114. MaliHwCounters::freeSingleton();
  115. GrManager::freeSingleton();
  116. Input::freeSingleton();
  117. NativeWindow::freeSingleton();
  118. #if ANKI_ENABLE_TRACE
  119. CoreTracer::freeSingleton();
  120. #endif
  121. GlobalFrameIndex::freeSingleton();
  122. ConfigSet::freeSingleton();
  123. m_settingsDir.destroy();
  124. m_cacheDir.destroy();
  125. CoreMemoryPool::freeSingleton();
  126. DefaultMemoryPool::freeSingleton();
  127. }
  128. Error App::init()
  129. {
  130. const Error err = initInternal();
  131. if(err)
  132. {
  133. ANKI_CORE_LOGE("App initialization failed. Shutting down");
  134. cleanup();
  135. }
  136. return err;
  137. }
  138. Error App::initInternal()
  139. {
  140. Logger::getSingleton().enableVerbosity(ConfigSet::getSingleton().getCoreVerboseLog());
  141. setSignalHandlers();
  142. AllocAlignedCallback allocCb = m_originalAllocCallback;
  143. void* allocCbUserData = m_originalAllocUserData;
  144. initMemoryCallbacks(allocCb, allocCbUserData);
  145. DefaultMemoryPool::allocateSingleton(allocCb, allocCbUserData);
  146. CoreMemoryPool::allocateSingleton(allocCb, allocCbUserData);
  147. ANKI_CHECK(initDirs());
  148. // Print a message
  149. const char* buildType =
  150. #if ANKI_OPTIMIZE
  151. "optimized, "
  152. #else
  153. "NOT optimized, "
  154. #endif
  155. #if ANKI_DEBUG_SYMBOLS
  156. "dbg symbols, "
  157. #else
  158. "NO dbg symbols, "
  159. #endif
  160. #if ANKI_EXTRA_CHECKS
  161. "extra checks, "
  162. #else
  163. "NO extra checks, "
  164. #endif
  165. #if ANKI_ENABLE_TRACE
  166. "built with tracing";
  167. #else
  168. "NOT built with tracing";
  169. #endif
  170. ANKI_CORE_LOGI("Initializing application ("
  171. "version %u.%u, "
  172. "%s, "
  173. "compiler %s, "
  174. "build date %s, "
  175. "commit %s)",
  176. ANKI_VERSION_MAJOR, ANKI_VERSION_MINOR, buildType, ANKI_COMPILER_STR, __DATE__, ANKI_REVISION);
  177. // Check SIMD support
  178. #if ANKI_SIMD_SSE && ANKI_COMPILER_GCC_COMPATIBLE
  179. if(!__builtin_cpu_supports("sse4.2"))
  180. {
  181. ANKI_CORE_LOGF("AnKi is built with sse4.2 support but your CPU doesn't support it. Try bulding without SSE support");
  182. }
  183. #endif
  184. ANKI_CORE_LOGI("Number of job threads: %u", ConfigSet::getSingleton().getCoreJobThreadCount());
  185. if(ConfigSet::getSingleton().getCoreBenchmarkMode() && ConfigSet::getSingleton().getGrVsync())
  186. {
  187. ANKI_CORE_LOGW("Vsync is enabled and benchmark mode as well. Will turn vsync off");
  188. ConfigSet::getSingleton().setGrVsync(false);
  189. }
  190. GlobalFrameIndex::allocateSingleton();
  191. //
  192. // Core tracer
  193. //
  194. #if ANKI_ENABLE_TRACE
  195. ANKI_CHECK(CoreTracer::allocateSingleton().init(m_settingsDir));
  196. #endif
  197. //
  198. // Window
  199. //
  200. NativeWindowInitInfo nwinit;
  201. nwinit.m_width = ConfigSet::getSingleton().getWidth();
  202. nwinit.m_height = ConfigSet::getSingleton().getHeight();
  203. nwinit.m_depthBits = 0;
  204. nwinit.m_stencilBits = 0;
  205. nwinit.m_fullscreenDesktopRez = ConfigSet::getSingleton().getWindowFullscreen() > 0;
  206. nwinit.m_exclusiveFullscreen = ConfigSet::getSingleton().getWindowFullscreen() == 2;
  207. nwinit.m_targetFps = ConfigSet::getSingleton().getCoreTargetFps();
  208. NativeWindow::allocateSingleton();
  209. ANKI_CHECK(NativeWindow::getSingleton().init(nwinit));
  210. //
  211. // Input
  212. //
  213. Input::allocateSingleton();
  214. ANKI_CHECK(Input::getSingleton().init());
  215. //
  216. // ThreadPool
  217. //
  218. const Bool pinThreads = !ANKI_OS_ANDROID;
  219. CoreThreadHive::allocateSingleton(ConfigSet::getSingleton().getCoreJobThreadCount(), pinThreads);
  220. //
  221. // Graphics API
  222. //
  223. GrManagerInitInfo grInit;
  224. grInit.m_allocCallback = allocCb;
  225. grInit.m_allocCallbackUserData = allocCbUserData;
  226. grInit.m_cacheDirectory = m_cacheDir.toCString();
  227. ANKI_CHECK(GrManager::allocateSingleton().init(grInit));
  228. //
  229. // Mali HW counters
  230. //
  231. if(GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kArm && ConfigSet::getSingleton().getCoreMaliHwCounters())
  232. {
  233. MaliHwCounters::allocateSingleton();
  234. }
  235. //
  236. // GPU mem
  237. //
  238. UnifiedGeometryBuffer::allocateSingleton().init();
  239. GpuSceneBuffer::allocateSingleton().init();
  240. RebarTransientMemoryPool::allocateSingleton().init();
  241. GpuVisibleTransientMemoryPool::allocateSingleton();
  242. //
  243. // Physics
  244. //
  245. PhysicsWorld::allocateSingleton();
  246. ANKI_CHECK(PhysicsWorld::getSingleton().init(allocCb, allocCbUserData));
  247. //
  248. // Resources
  249. //
  250. #if !ANKI_OS_ANDROID
  251. // Add the location of the executable where the shaders are supposed to be
  252. String executableFname;
  253. ANKI_CHECK(getApplicationPath(executableFname));
  254. ANKI_CORE_LOGI("Executable path is: %s", executableFname.cstr());
  255. String shadersPath;
  256. getParentFilepath(executableFname, shadersPath);
  257. shadersPath += ":";
  258. shadersPath += ConfigSet::getSingleton().getRsrcDataPaths();
  259. ConfigSet::getSingleton().setRsrcDataPaths(shadersPath);
  260. #endif
  261. ANKI_CHECK(ResourceManager::allocateSingleton().init(allocCb, allocCbUserData));
  262. //
  263. // UI
  264. //
  265. ANKI_CHECK(UiManager::allocateSingleton().init(allocCb, allocCbUserData));
  266. //
  267. // GPU scene
  268. //
  269. ANKI_CHECK(GpuSceneMicroPatcher::allocateSingleton().init());
  270. //
  271. // Renderer
  272. //
  273. MainRendererInitInfo renderInit;
  274. renderInit.m_swapchainSize = UVec2(NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight());
  275. renderInit.m_allocCallback = allocCb;
  276. renderInit.m_allocCallbackUserData = allocCbUserData;
  277. ANKI_CHECK(MainRenderer::allocateSingleton().init(renderInit));
  278. //
  279. // Script
  280. //
  281. ScriptManager::allocateSingleton(allocCb, allocCbUserData);
  282. //
  283. // Scene
  284. //
  285. ANKI_CHECK(SceneGraph::allocateSingleton().init(allocCb, allocCbUserData));
  286. //
  287. // Misc
  288. //
  289. ANKI_CHECK(UiManager::getSingleton().newInstance<StatsUi>(m_statsUi));
  290. ANKI_CHECK(UiManager::getSingleton().newInstance<DeveloperConsole>(m_console));
  291. ANKI_CORE_LOGI("Application initialized");
  292. return Error::kNone;
  293. }
  294. Error App::initDirs()
  295. {
  296. // Settings path
  297. #if !ANKI_OS_ANDROID
  298. String home;
  299. ANKI_CHECK(getHomeDirectory(home));
  300. m_settingsDir.sprintf("%s/.anki", &home[0]);
  301. #else
  302. m_settingsDir.sprintf("%s/.anki", g_androidApp->activity->internalDataPath);
  303. #endif
  304. if(!directoryExists(m_settingsDir.toCString()))
  305. {
  306. ANKI_CORE_LOGI("Creating settings dir \"%s\"", &m_settingsDir[0]);
  307. ANKI_CHECK(createDirectory(m_settingsDir.toCString()));
  308. }
  309. else
  310. {
  311. ANKI_CORE_LOGI("Using settings dir \"%s\"", &m_settingsDir[0]);
  312. }
  313. // Cache
  314. m_cacheDir.sprintf("%s/cache", &m_settingsDir[0]);
  315. const Bool cacheDirExists = directoryExists(m_cacheDir.toCString());
  316. if(ConfigSet::getSingleton().getCoreClearCaches() && cacheDirExists)
  317. {
  318. ANKI_CORE_LOGI("Will delete the cache dir and start fresh: %s", m_cacheDir.cstr());
  319. ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
  320. ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
  321. }
  322. else if(!cacheDirExists)
  323. {
  324. ANKI_CORE_LOGI("Will create cache dir: %s", m_cacheDir.cstr());
  325. ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
  326. }
  327. return Error::kNone;
  328. }
  329. Error App::mainLoop()
  330. {
  331. ANKI_CORE_LOGI("Entering main loop");
  332. Bool quit = false;
  333. Second prevUpdateTime = HighRezTimer::getCurrentTime();
  334. Second crntTime = prevUpdateTime;
  335. // Benchmark mode stuff:
  336. const Bool benchmarkMode = ConfigSet::getSingleton().getCoreBenchmarkMode();
  337. Second aggregatedCpuTime = 0.0;
  338. Second aggregatedGpuTime = 0.0;
  339. constexpr U32 kBenchmarkFramesToGatherBeforeFlush = 60;
  340. U32 benchmarkFramesGathered = 0;
  341. File benchmarkCsvFile;
  342. CoreString benchmarkCsvFileFilename;
  343. if(benchmarkMode)
  344. {
  345. benchmarkCsvFileFilename.sprintf("%s/Benchmark.csv", m_settingsDir.cstr());
  346. ANKI_CHECK(benchmarkCsvFile.open(benchmarkCsvFileFilename, FileOpenFlag::kWrite));
  347. ANKI_CHECK(benchmarkCsvFile.writeText("CPU, GPU\n"));
  348. }
  349. while(!quit)
  350. {
  351. {
  352. ANKI_TRACE_SCOPED_EVENT(Frame);
  353. const Second startTime = HighRezTimer::getCurrentTime();
  354. prevUpdateTime = crntTime;
  355. crntTime = (!benchmarkMode) ? HighRezTimer::getCurrentTime() : (prevUpdateTime + 1.0_sec / 60.0_sec);
  356. // Update
  357. ANKI_CHECK(Input::getSingleton().handleEvents());
  358. // User update
  359. ANKI_CHECK(userMainLoop(quit, crntTime - prevUpdateTime));
  360. ANKI_CHECK(SceneGraph::getSingleton().update(prevUpdateTime, crntTime));
  361. RenderQueue rqueue;
  362. SceneGraph::getSingleton().doVisibilityTests(rqueue);
  363. // Inject stats UI
  364. CoreDynamicArray<UiQueueElement> newUiElementArr;
  365. injectUiElements(newUiElementArr, rqueue);
  366. // Render
  367. TexturePtr presentableTex = GrManager::getSingleton().acquireNextPresentableTexture();
  368. MainRenderer::getSingleton().setStatsEnabled(ConfigSet::getSingleton().getCoreDisplayStats() > 0 || benchmarkMode
  369. #if ANKI_ENABLE_TRACE
  370. || Tracer::getSingleton().getEnabled()
  371. #endif
  372. );
  373. ANKI_CHECK(MainRenderer::getSingleton().render(rqueue, presentableTex));
  374. // Pause and sync async loader. That will force all tasks before the pause to finish in this frame.
  375. ResourceManager::getSingleton().getAsyncLoader().pause();
  376. // If we get stats exclude the time of GR because it forces some GPU-CPU serialization. We don't want to
  377. // count that
  378. Second grTime = 0.0;
  379. if(benchmarkMode || ConfigSet::getSingleton().getCoreDisplayStats() > 0) [[unlikely]]
  380. {
  381. grTime = HighRezTimer::getCurrentTime();
  382. }
  383. GrManager::getSingleton().swapBuffers();
  384. if(benchmarkMode || ConfigSet::getSingleton().getCoreDisplayStats() > 0) [[unlikely]]
  385. {
  386. grTime = HighRezTimer::getCurrentTime() - grTime;
  387. }
  388. const PtrSize rebarMemUsed = RebarTransientMemoryPool::getSingleton().endFrame();
  389. UnifiedGeometryBuffer::getSingleton().endFrame();
  390. GpuSceneBuffer::getSingleton().endFrame();
  391. GpuVisibleTransientMemoryPool::getSingleton().endFrame();
  392. // Update the trace info with some async loader stats
  393. U64 asyncTaskCount = ResourceManager::getSingleton().getAsyncLoader().getCompletedTaskCount();
  394. ANKI_TRACE_INC_COUNTER(RsrcAsyncTasks, asyncTaskCount - m_resourceCompletedAsyncTaskCount);
  395. m_resourceCompletedAsyncTaskCount = asyncTaskCount;
  396. // Now resume the loader
  397. ResourceManager::getSingleton().getAsyncLoader().resume();
  398. // Sleep
  399. const Second endTime = HighRezTimer::getCurrentTime();
  400. const Second frameTime = endTime - startTime;
  401. if(!benchmarkMode) [[likely]]
  402. {
  403. const Second timerTick = 1.0_sec / Second(ConfigSet::getSingleton().getCoreTargetFps());
  404. if(frameTime < timerTick)
  405. {
  406. ANKI_TRACE_SCOPED_EVENT(TimerTickSleep);
  407. HighRezTimer::sleep(timerTick - frameTime);
  408. }
  409. }
  410. // Benchmark stats
  411. else
  412. {
  413. aggregatedCpuTime += frameTime - grTime;
  414. aggregatedGpuTime += MainRenderer::getSingleton().getStats().m_renderingGpuTime;
  415. ++benchmarkFramesGathered;
  416. if(benchmarkFramesGathered >= kBenchmarkFramesToGatherBeforeFlush)
  417. {
  418. aggregatedCpuTime = aggregatedCpuTime / Second(kBenchmarkFramesToGatherBeforeFlush) * 1000.0;
  419. aggregatedGpuTime = aggregatedGpuTime / Second(kBenchmarkFramesToGatherBeforeFlush) * 1000.0;
  420. ANKI_CHECK(benchmarkCsvFile.writeTextf("%f,%f\n", aggregatedCpuTime, aggregatedGpuTime));
  421. benchmarkFramesGathered = 0;
  422. aggregatedCpuTime = 0.0;
  423. aggregatedGpuTime = 0.0;
  424. }
  425. }
  426. // Stats
  427. if(ConfigSet::getSingleton().getCoreDisplayStats() > 0)
  428. {
  429. StatsUiInput in;
  430. in.m_cpuFrameTime = frameTime - grTime;
  431. in.m_rendererTime = MainRenderer::getSingleton().getStats().m_renderingCpuTime;
  432. in.m_sceneUpdateTime = SceneGraph::getSingleton().getStats().m_updateTime;
  433. in.m_visibilityTestsTime = SceneGraph::getSingleton().getStats().m_visibilityTestsTime;
  434. in.m_physicsTime = SceneGraph::getSingleton().getStats().m_physicsUpdate;
  435. in.m_gpuFrameTime = MainRenderer::getSingleton().getStats().m_renderingGpuTime;
  436. if(MaliHwCounters::isAllocated())
  437. {
  438. MaliHwCountersOut out;
  439. MaliHwCounters::getSingleton().sample(out);
  440. in.m_gpuActiveCycles = out.m_gpuActive;
  441. in.m_gpuReadBandwidth = out.m_readBandwidth;
  442. in.m_gpuWriteBandwidth = out.m_writeBandwidth;
  443. }
  444. in.m_cpuAllocatedMemory = m_memStats.m_allocatedMem.load();
  445. in.m_cpuAllocationCount = m_memStats.m_allocCount.load();
  446. in.m_cpuFreeCount = m_memStats.m_freeCount.load();
  447. const GrManagerStats grStats = GrManager::getSingleton().getStats();
  448. UnifiedGeometryBuffer::getSingleton().getStats(in.m_unifiedGometryExternalFragmentation, in.m_unifiedGeometryAllocated,
  449. in.m_unifiedGeometryTotal);
  450. GpuSceneBuffer::getSingleton().getStats(in.m_gpuSceneExternalFragmentation, in.m_gpuSceneAllocated, in.m_gpuSceneTotal);
  451. in.m_gpuDeviceMemoryAllocated = grStats.m_deviceMemoryAllocated;
  452. in.m_gpuDeviceMemoryInUse = grStats.m_deviceMemoryInUse;
  453. in.m_reBar = rebarMemUsed;
  454. in.m_drawableCount = rqueue.countAllRenderables();
  455. in.m_vkCommandBufferCount = grStats.m_commandBufferCount;
  456. StatsUi& statsUi = *static_cast<StatsUi*>(m_statsUi.get());
  457. const StatsUiDetail detail =
  458. (ConfigSet::getSingleton().getCoreDisplayStats() == 1) ? StatsUiDetail::kFpsOnly : StatsUiDetail::kDetailed;
  459. statsUi.setStats(in, detail);
  460. }
  461. #if ANKI_ENABLE_TRACE
  462. if(MainRenderer::getSingleton().getStats().m_renderingGpuTime >= 0.0)
  463. {
  464. ANKI_TRACE_CUSTOM_EVENT(Gpu, MainRenderer::getSingleton().getStats().m_renderingGpuSubmitTimestamp,
  465. MainRenderer::getSingleton().getStats().m_renderingGpuTime);
  466. }
  467. #endif
  468. ++GlobalFrameIndex::getSingleton().m_value;
  469. if(benchmarkMode) [[unlikely]]
  470. {
  471. if(GlobalFrameIndex::getSingleton().m_value >= ConfigSet::getSingleton().getCoreBenchmarkModeFrameCount())
  472. {
  473. quit = true;
  474. }
  475. }
  476. }
  477. #if ANKI_ENABLE_TRACE
  478. static U64 frame = 1;
  479. CoreTracer::getSingleton().flushFrame(frame++);
  480. #endif
  481. }
  482. if(benchmarkMode) [[unlikely]]
  483. {
  484. ANKI_CORE_LOGI("Benchmark file saved in: %s", benchmarkCsvFileFilename.cstr());
  485. }
  486. return Error::kNone;
  487. }
  488. void App::injectUiElements(CoreDynamicArray<UiQueueElement>& newUiElementArr, RenderQueue& rqueue)
  489. {
  490. const U32 originalCount = rqueue.m_uis.getSize();
  491. if(ConfigSet::getSingleton().getCoreDisplayStats() > 0 || m_consoleEnabled)
  492. {
  493. const U32 extraElements = (ConfigSet::getSingleton().getCoreDisplayStats() > 0) + (m_consoleEnabled != 0);
  494. newUiElementArr.resize(originalCount + extraElements);
  495. if(originalCount > 0)
  496. {
  497. memcpy(&newUiElementArr[0], &rqueue.m_uis[0], rqueue.m_uis.getSizeInBytes());
  498. }
  499. rqueue.m_uis = WeakArray<UiQueueElement>(newUiElementArr);
  500. }
  501. U32 count = originalCount;
  502. if(ConfigSet::getSingleton().getCoreDisplayStats() > 0)
  503. {
  504. newUiElementArr[count].m_userData = m_statsUi.get();
  505. newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
  506. static_cast<StatsUi*>(userData)->build(canvas);
  507. };
  508. ++count;
  509. }
  510. if(m_consoleEnabled)
  511. {
  512. newUiElementArr[count].m_userData = m_console.get();
  513. newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
  514. static_cast<DeveloperConsole*>(userData)->build(canvas);
  515. };
  516. ++count;
  517. }
  518. }
  519. void App::initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserData)
  520. {
  521. if(ConfigSet::getSingleton().getCoreDisplayStats() > 1)
  522. {
  523. allocCb = MemStats::allocCallback;
  524. allocCbUserData = this;
  525. }
  526. else
  527. {
  528. // Leave the default
  529. }
  530. }
  531. void App::setSignalHandlers()
  532. {
  533. auto handler = [](int signum) -> void {
  534. const char* name = nullptr;
  535. switch(signum)
  536. {
  537. case SIGABRT:
  538. name = "SIGABRT";
  539. break;
  540. case SIGSEGV:
  541. name = "SIGSEGV";
  542. break;
  543. #if ANKI_POSIX
  544. case SIGBUS:
  545. name = "SIGBUS";
  546. break;
  547. #endif
  548. case SIGILL:
  549. name = "SIGILL";
  550. break;
  551. case SIGFPE:
  552. name = "SIGFPE";
  553. break;
  554. }
  555. if(name)
  556. printf("Caught signal %d (%s)\n", signum, name);
  557. else
  558. printf("Caught signal %d\n", signum);
  559. U32 count = 0;
  560. printf("Backtrace:\n");
  561. backtrace([&count](CString symbol) {
  562. printf("%.2u: %s\n", count++, symbol.cstr());
  563. });
  564. ANKI_DEBUG_BREAK();
  565. };
  566. signal(SIGSEGV, handler);
  567. signal(SIGILL, handler);
  568. signal(SIGFPE, handler);
  569. #if ANKI_POSIX
  570. signal(SIGBUS, handler);
  571. #endif
  572. // Ignore for now: signal(SIGABRT, handler);
  573. }
  574. } // end namespace anki