App.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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/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/ThreadHive.h>
  12. #include <AnKi/Util/Tracer.h>
  13. #include <AnKi/Util/HighRezTimer.h>
  14. #include <AnKi/Core/CoreTracer.h>
  15. #include <AnKi/Core/DeveloperConsole.h>
  16. #include <AnKi/Core/StatsUi.h>
  17. #include <AnKi/Window/NativeWindow.h>
  18. #include <AnKi/Core/MaliHwCounters.h>
  19. #include <AnKi/Window/Input.h>
  20. #include <AnKi/Scene/SceneGraph.h>
  21. #include <AnKi/Renderer/RenderQueue.h>
  22. #include <AnKi/Resource/ResourceManager.h>
  23. #include <AnKi/Physics/PhysicsWorld.h>
  24. #include <AnKi/Renderer/MainRenderer.h>
  25. #include <AnKi/Script/ScriptManager.h>
  26. #include <AnKi/Resource/ResourceFilesystem.h>
  27. #include <AnKi/Resource/AsyncLoader.h>
  28. #include <AnKi/Core/GpuMemoryPools.h>
  29. #include <AnKi/Ui/UiManager.h>
  30. #include <AnKi/Ui/Canvas.h>
  31. #include <csignal>
  32. #if ANKI_OS_ANDROID
  33. # include <android_native_app_glue.h>
  34. #endif
  35. namespace anki {
  36. #if ANKI_OS_ANDROID
  37. /// The one and only android hack
  38. android_app* g_androidApp = nullptr;
  39. #endif
  40. void* App::MemStats::allocCallback(void* userData, void* ptr, PtrSize size, [[maybe_unused]] PtrSize alignment)
  41. {
  42. ANKI_ASSERT(userData);
  43. constexpr PtrSize kMaxAlignment = 64;
  44. struct alignas(kMaxAlignment) Header
  45. {
  46. PtrSize m_allocatedSize;
  47. Array<U8, kMaxAlignment - sizeof(PtrSize)> _m_padding;
  48. };
  49. static_assert(sizeof(Header) == kMaxAlignment, "See file");
  50. static_assert(alignof(Header) == kMaxAlignment, "See file");
  51. void* out = nullptr;
  52. if(ptr == nullptr)
  53. {
  54. // Need to allocate
  55. ANKI_ASSERT(size > 0);
  56. ANKI_ASSERT(alignment > 0 && alignment <= kMaxAlignment);
  57. const PtrSize newAlignment = kMaxAlignment;
  58. const PtrSize newSize = sizeof(Header) + size;
  59. // Allocate
  60. App* self = static_cast<App*>(userData);
  61. Header* allocation = static_cast<Header*>(
  62. self->m_originalAllocCallback(self->m_originalAllocUserData, nullptr, newSize, newAlignment));
  63. allocation->m_allocatedSize = size;
  64. ++allocation;
  65. out = static_cast<void*>(allocation);
  66. // Update stats
  67. self->m_memStats.m_allocatedMem.fetchAdd(size);
  68. self->m_memStats.m_allocCount.fetchAdd(1);
  69. }
  70. else
  71. {
  72. // Need to free
  73. App* self = static_cast<App*>(userData);
  74. Header* allocation = static_cast<Header*>(ptr);
  75. --allocation;
  76. ANKI_ASSERT(allocation->m_allocatedSize > 0);
  77. // Update stats
  78. self->m_memStats.m_freeCount.fetchAdd(1);
  79. self->m_memStats.m_allocatedMem.fetchSub(allocation->m_allocatedSize);
  80. // Free
  81. self->m_originalAllocCallback(self->m_originalAllocUserData, allocation, 0, 0);
  82. }
  83. return out;
  84. }
  85. App::App(AllocAlignedCallback allocCb, void* allocCbUserData)
  86. {
  87. m_originalAllocCallback = allocCb;
  88. m_originalAllocUserData = allocCbUserData;
  89. // Config set is a bit special so init it ASAP
  90. ConfigSet::allocateSingleton(allocCb, allocCbUserData);
  91. }
  92. App::~App()
  93. {
  94. ANKI_CORE_LOGI("Destroying application");
  95. cleanup();
  96. }
  97. void App::cleanup()
  98. {
  99. m_statsUi.reset(nullptr);
  100. m_console.reset(nullptr);
  101. SceneGraph::freeSingleton();
  102. ScriptManager::freeSingleton();
  103. MainRenderer::freeSingleton();
  104. UiManager::freeSingleton();
  105. GpuSceneMicroPatcher::freeSingleton();
  106. ResourceManager::freeSingleton();
  107. PhysicsWorld::freeSingleton();
  108. RebarStagingGpuMemoryPool::freeSingleton();
  109. UnifiedGeometryMemoryPool::freeSingleton();
  110. GpuSceneMemoryPool::freeSingleton();
  111. CoreThreadHive::freeSingleton();
  112. MaliHwCounters::freeSingleton();
  113. GrManager::freeSingleton();
  114. Input::freeSingleton();
  115. NativeWindow::freeSingleton();
  116. #if ANKI_ENABLE_TRACE
  117. CoreTracer::freeSingleton();
  118. #endif
  119. GlobalFrameIndex::freeSingleton();
  120. ConfigSet::freeSingleton();
  121. m_settingsDir.destroy();
  122. m_cacheDir.destroy();
  123. CoreMemoryPool::freeSingleton();
  124. DefaultMemoryPool::freeSingleton();
  125. }
  126. Error App::init()
  127. {
  128. const Error err = initInternal();
  129. if(err)
  130. {
  131. ANKI_CORE_LOGE("App initialization failed. Shutting down");
  132. cleanup();
  133. }
  134. return err;
  135. }
  136. Error App::initInternal()
  137. {
  138. Logger::getSingleton().enableVerbosity(ConfigSet::getSingleton().getCoreVerboseLog());
  139. setSignalHandlers();
  140. AllocAlignedCallback allocCb = m_originalAllocCallback;
  141. void* allocCbUserData = m_originalAllocUserData;
  142. initMemoryCallbacks(allocCb, allocCbUserData);
  143. DefaultMemoryPool::allocateSingleton(allocCb, allocCbUserData);
  144. CoreMemoryPool::allocateSingleton(allocCb, allocCbUserData);
  145. ANKI_CHECK(initDirs());
  146. // Print a message
  147. const char* buildType =
  148. #if ANKI_OPTIMIZE
  149. "optimized, "
  150. #else
  151. "NOT optimized, "
  152. #endif
  153. #if ANKI_DEBUG_SYMBOLS
  154. "dbg symbols, "
  155. #else
  156. "NO dbg symbols, "
  157. #endif
  158. #if ANKI_EXTRA_CHECKS
  159. "extra checks, "
  160. #else
  161. "NO extra checks, "
  162. #endif
  163. #if ANKI_ENABLE_TRACE
  164. "built with tracing";
  165. #else
  166. "NOT built with tracing";
  167. #endif
  168. ANKI_CORE_LOGI("Initializing application ("
  169. "version %u.%u, "
  170. "%s, "
  171. "compiler %s, "
  172. "build date %s, "
  173. "commit %s)",
  174. ANKI_VERSION_MAJOR, ANKI_VERSION_MINOR, buildType, ANKI_COMPILER_STR, __DATE__, ANKI_REVISION);
  175. // Check SIMD support
  176. #if ANKI_SIMD_SSE && ANKI_COMPILER_GCC_COMPATIBLE
  177. if(!__builtin_cpu_supports("sse4.2"))
  178. {
  179. ANKI_CORE_LOGF(
  180. "AnKi is built with sse4.2 support but your CPU doesn't support it. Try bulding without SSE support");
  181. }
  182. #endif
  183. ANKI_CORE_LOGI("Number of job threads: %u", ConfigSet::getSingleton().getCoreJobThreadCount());
  184. if(ConfigSet::getSingleton().getCoreBenchmarkMode() && ConfigSet::getSingleton().getGrVsync())
  185. {
  186. ANKI_CORE_LOGW("Vsync is enabled and benchmark mode as well. Will turn vsync off");
  187. ConfigSet::getSingleton().setGrVsync(false);
  188. }
  189. GlobalFrameIndex::allocateSingleton();
  190. //
  191. // Core tracer
  192. //
  193. #if ANKI_ENABLE_TRACE
  194. ANKI_CHECK(CoreTracer::allocateSingleton().init(m_settingsDir));
  195. #endif
  196. //
  197. // Window
  198. //
  199. NativeWindowInitInfo nwinit;
  200. nwinit.m_width = ConfigSet::getSingleton().getWidth();
  201. nwinit.m_height = ConfigSet::getSingleton().getHeight();
  202. nwinit.m_depthBits = 0;
  203. nwinit.m_stencilBits = 0;
  204. nwinit.m_fullscreenDesktopRez = ConfigSet::getSingleton().getWindowFullscreen() > 0;
  205. nwinit.m_exclusiveFullscreen = ConfigSet::getSingleton().getWindowFullscreen() == 2;
  206. nwinit.m_targetFps = ConfigSet::getSingleton().getCoreTargetFps();
  207. NativeWindow::allocateSingleton();
  208. ANKI_CHECK(NativeWindow::getSingleton().init(nwinit));
  209. //
  210. // Input
  211. //
  212. Input::allocateSingleton();
  213. ANKI_CHECK(Input::getSingleton().init());
  214. //
  215. // ThreadPool
  216. //
  217. const Bool pinThreads = !ANKI_OS_ANDROID;
  218. CoreThreadHive::allocateSingleton(ConfigSet::getSingleton().getCoreJobThreadCount(), pinThreads);
  219. //
  220. // Graphics API
  221. //
  222. GrManagerInitInfo grInit;
  223. grInit.m_allocCallback = allocCb;
  224. grInit.m_allocCallbackUserData = allocCbUserData;
  225. grInit.m_cacheDirectory = m_cacheDir.toCString();
  226. ANKI_CHECK(GrManager::allocateSingleton().init(grInit));
  227. //
  228. // Mali HW counters
  229. //
  230. if(GrManager::getSingleton().getDeviceCapabilities().m_gpuVendor == GpuVendor::kArm
  231. && ConfigSet::getSingleton().getCoreMaliHwCounters())
  232. {
  233. MaliHwCounters::allocateSingleton();
  234. }
  235. //
  236. // GPU mem
  237. //
  238. UnifiedGeometryMemoryPool::allocateSingleton().init();
  239. GpuSceneMemoryPool::allocateSingleton().init();
  240. RebarStagingGpuMemoryPool::allocateSingleton().init();
  241. //
  242. // Physics
  243. //
  244. PhysicsWorld::allocateSingleton();
  245. ANKI_CHECK(PhysicsWorld::getSingleton().init(allocCb, allocCbUserData));
  246. //
  247. // Resources
  248. //
  249. #if !ANKI_OS_ANDROID
  250. // Add the location of the executable where the shaders are supposed to be
  251. String executableFname;
  252. ANKI_CHECK(getApplicationPath(executableFname));
  253. ANKI_CORE_LOGI("Executable path is: %s", executableFname.cstr());
  254. String shadersPath;
  255. getParentFilepath(executableFname, shadersPath);
  256. shadersPath += ":";
  257. shadersPath += ConfigSet::getSingleton().getRsrcDataPaths();
  258. ConfigSet::getSingleton().setRsrcDataPaths(shadersPath);
  259. #endif
  260. ANKI_CHECK(ResourceManager::allocateSingleton().init(allocCb, allocCbUserData));
  261. //
  262. // UI
  263. //
  264. ANKI_CHECK(UiManager::allocateSingleton().init(allocCb, allocCbUserData));
  265. //
  266. // GPU scene
  267. //
  268. ANKI_CHECK(GpuSceneMicroPatcher::allocateSingleton().init());
  269. //
  270. // Renderer
  271. //
  272. MainRendererInitInfo renderInit;
  273. renderInit.m_swapchainSize =
  274. 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
  369. || benchmarkMode
  370. #if ANKI_ENABLE_TRACE
  371. || Tracer::getSingleton().getEnabled()
  372. #endif
  373. );
  374. ANKI_CHECK(MainRenderer::getSingleton().render(rqueue, presentableTex));
  375. // Pause and sync async loader. That will force all tasks before the pause to finish in this frame.
  376. ResourceManager::getSingleton().getAsyncLoader().pause();
  377. // If we get stats exclude the time of GR because it forces some GPU-CPU serialization. We don't want to
  378. // count that
  379. Second grTime = 0.0;
  380. if(benchmarkMode || ConfigSet::getSingleton().getCoreDisplayStats() > 0) [[unlikely]]
  381. {
  382. grTime = HighRezTimer::getCurrentTime();
  383. }
  384. GrManager::getSingleton().swapBuffers();
  385. if(benchmarkMode || ConfigSet::getSingleton().getCoreDisplayStats() > 0) [[unlikely]]
  386. {
  387. grTime = HighRezTimer::getCurrentTime() - grTime;
  388. }
  389. const PtrSize rebarMemUsed = RebarStagingGpuMemoryPool::getSingleton().endFrame();
  390. UnifiedGeometryMemoryPool::getSingleton().endFrame();
  391. GpuSceneMemoryPool::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. UnifiedGeometryMemoryPool::getSingleton().getStats(
  449. in.m_unifiedGometryExternalFragmentation, in.m_unifiedGeometryAllocated, in.m_unifiedGeometryTotal);
  450. GpuSceneMemoryPool::getSingleton().getStats(in.m_gpuSceneExternalFragmentation, in.m_gpuSceneAllocated,
  451. in.m_gpuSceneTotal);
  452. in.m_gpuDeviceMemoryAllocated = grStats.m_deviceMemoryAllocated;
  453. in.m_gpuDeviceMemoryInUse = grStats.m_deviceMemoryInUse;
  454. in.m_reBar = rebarMemUsed;
  455. in.m_drawableCount = rqueue.countAllRenderables();
  456. in.m_vkCommandBufferCount = grStats.m_commandBufferCount;
  457. StatsUi& statsUi = *static_cast<StatsUi*>(m_statsUi.get());
  458. const StatsUiDetail detail = (ConfigSet::getSingleton().getCoreDisplayStats() == 1)
  459. ? StatsUiDetail::kFpsOnly
  460. : StatsUiDetail::kDetailed;
  461. statsUi.setStats(in, detail);
  462. }
  463. #if ANKI_ENABLE_TRACE
  464. if(m_renderer->getStats().m_renderingGpuTime >= 0.0)
  465. {
  466. ANKI_TRACE_CUSTOM_EVENT(Gpu, m_renderer->getStats().m_renderingGpuSubmitTimestamp,
  467. m_renderer->getStats().m_renderingGpuTime);
  468. }
  469. #endif
  470. ++GlobalFrameIndex::getSingleton().m_value;
  471. if(benchmarkMode) [[unlikely]]
  472. {
  473. if(GlobalFrameIndex::getSingleton().m_value
  474. >= ConfigSet::getSingleton().getCoreBenchmarkModeFrameCount())
  475. {
  476. quit = true;
  477. }
  478. }
  479. }
  480. #if ANKI_ENABLE_TRACE
  481. static U64 frame = 1;
  482. CoreTracer::getSingleton().flushFrame(frame++);
  483. #endif
  484. }
  485. if(benchmarkMode) [[unlikely]]
  486. {
  487. ANKI_CORE_LOGI("Benchmark file saved in: %s", benchmarkCsvFileFilename.cstr());
  488. }
  489. return Error::kNone;
  490. }
  491. void App::injectUiElements(CoreDynamicArray<UiQueueElement>& newUiElementArr, RenderQueue& rqueue)
  492. {
  493. const U32 originalCount = rqueue.m_uis.getSize();
  494. if(ConfigSet::getSingleton().getCoreDisplayStats() > 0 || m_consoleEnabled)
  495. {
  496. const U32 extraElements = (ConfigSet::getSingleton().getCoreDisplayStats() > 0) + (m_consoleEnabled != 0);
  497. newUiElementArr.resize(originalCount + extraElements);
  498. if(originalCount > 0)
  499. {
  500. memcpy(&newUiElementArr[0], &rqueue.m_uis[0], rqueue.m_uis.getSizeInBytes());
  501. }
  502. rqueue.m_uis = WeakArray<UiQueueElement>(newUiElementArr);
  503. }
  504. U32 count = originalCount;
  505. if(ConfigSet::getSingleton().getCoreDisplayStats() > 0)
  506. {
  507. newUiElementArr[count].m_userData = m_statsUi.get();
  508. newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
  509. static_cast<StatsUi*>(userData)->build(canvas);
  510. };
  511. ++count;
  512. }
  513. if(m_consoleEnabled)
  514. {
  515. newUiElementArr[count].m_userData = m_console.get();
  516. newUiElementArr[count].m_drawCallback = [](CanvasPtr& canvas, void* userData) -> void {
  517. static_cast<DeveloperConsole*>(userData)->build(canvas);
  518. };
  519. ++count;
  520. }
  521. }
  522. void App::initMemoryCallbacks(AllocAlignedCallback& allocCb, void*& allocCbUserData)
  523. {
  524. if(ConfigSet::getSingleton().getCoreDisplayStats() > 1)
  525. {
  526. allocCb = MemStats::allocCallback;
  527. allocCbUserData = this;
  528. }
  529. else
  530. {
  531. // Leave the default
  532. }
  533. }
  534. void App::setSignalHandlers()
  535. {
  536. auto handler = [](int signum) -> void {
  537. const char* name = nullptr;
  538. switch(signum)
  539. {
  540. case SIGABRT:
  541. name = "SIGABRT";
  542. break;
  543. case SIGSEGV:
  544. name = "SIGSEGV";
  545. break;
  546. #if ANKI_POSIX
  547. case SIGBUS:
  548. name = "SIGBUS";
  549. break;
  550. #endif
  551. case SIGILL:
  552. name = "SIGILL";
  553. break;
  554. case SIGFPE:
  555. name = "SIGFPE";
  556. break;
  557. }
  558. if(name)
  559. printf("Caught signal %d (%s)\n", signum, name);
  560. else
  561. printf("Caught signal %d\n", signum);
  562. U32 count = 0;
  563. printf("Backtrace:\n");
  564. backtrace([&count](CString symbol) {
  565. printf("%.2u: %s\n", count++, symbol.cstr());
  566. });
  567. ANKI_DEBUG_BREAK();
  568. };
  569. signal(SIGSEGV, handler);
  570. signal(SIGILL, handler);
  571. signal(SIGFPE, handler);
  572. #if ANKI_POSIX
  573. signal(SIGBUS, handler);
  574. #endif
  575. // Ignore for now: signal(SIGABRT, handler);
  576. }
  577. } // end namespace anki