// Copyright (c) Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) global U64 global_update_tick_idx = 0; global CondVar async_tick_start_cond_var = {0}; global CondVar async_tick_stop_cond_var = {0}; global Mutex async_tick_start_mutex = {0}; global Mutex async_tick_stop_mutex = {0}; global U64 async_wait_timeout = 0; global B32 global_async_exit = 0; internal void main_thread_base_entry_point(int arguments_count, char **arguments) { ThreadNameF("main_thread"); Temp scratch = scratch_begin(0, 0); //- rjf: set up async thread group info async_tick_start_cond_var = cond_var_alloc(); async_tick_start_mutex = mutex_alloc(); async_tick_stop_cond_var = cond_var_alloc(); async_tick_stop_mutex = mutex_alloc(); //- rjf: set up telemetry #if PROFILE_TELEMETRY local_persist char tm_data[MB(64)]; tmLoadLibrary(TM_RELEASE); tmSetMaxThreadCount(256); tmInitialize(sizeof(tm_data), tm_data); #endif //- rjf: set up spall #if PROFILE_SPALL spall_profile = spall_init_file_ex("spall_capture", 1, 0); #endif //- rjf: parse command line String8List command_line_argument_strings = {0}; { for EachIndex(idx, arguments_count) { str8_list_push(scratch.arena, &command_line_argument_strings, str8_cstring(arguments[idx])); } } CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings); //- rjf: begin captures B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture")); if(capture) { ProfBeginCapture(arguments[0]); ProfMsg(BUILD_TITLE); } //- rjf: initialize all included layers #if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL) async_init(&cmdline); #endif #if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL) hs_init(); #endif #if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL) fs_init(); #endif #if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL) txt_init(); #endif #if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL) mtx_init(); #endif #if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL) dasm_init(); #endif #if defined(DBGI_H) && !defined(DI_INIT_MANUAL) di_init(); #endif #if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) dmn_init(); #endif #if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL) ctrl_init(); #endif #if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL) os_gfx_init(); #endif #if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL) fp_init(); #endif #if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL) r_init(&cmdline); #endif #if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL) tex_init(); #endif #if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL) geo_init(); #endif #if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL) fnt_init(); #endif #if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL) d_init(); #endif #if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL) rd_init(&cmdline); #endif //- rjf: launch async threads Thread *async_threads = 0; U64 async_threads_count = 0; { U64 num_main_threads = 1; #if defined(CTRL_CORE_H) num_main_threads += 1; #endif U64 num_async_threads = os_get_system_info()->logical_processor_count; U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads); num_async_threads -= num_main_threads_clamped; num_async_threads = Max(1, num_async_threads); Barrier barrier = barrier_alloc(num_async_threads); LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads); async_threads_count = num_async_threads; async_threads = push_array(scratch.arena, Thread, async_threads_count); for EachIndex(idx, num_async_threads) { lane_ctxs[idx].lane_idx = idx; lane_ctxs[idx].lane_count = num_async_threads; lane_ctxs[idx].barrier = barrier; async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]); } } //- rjf: call into entry point entry_point(&cmdline); //- rjf: join async threads ins_atomic_u32_inc_eval(&global_async_exit); cond_var_broadcast(async_tick_start_cond_var); for EachIndex(idx, async_threads_count) { thread_join(async_threads[idx], max_U64); } //- rjf: end captures if(capture) { ProfEndCapture(); } scratch_end(scratch); } internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params) { TCTX *tctx = tctx_alloc(); tctx_select(tctx); entry_point(params); tctx_release(tctx); } internal U64 update_tick_idx(void) { U64 result = ins_atomic_u64_eval(&global_update_tick_idx); return result; } internal B32 update(void) { ProfTick(0); ins_atomic_u64_inc_eval(&global_update_tick_idx); #if defined(FONT_CACHE_H) fnt_frame(); #endif #if OS_FEATURE_GRAPHICAL B32 result = frame(); #else B32 result = 0; #endif return result; } internal void async_thread_entry_point(void *params) { LaneCtx lctx = *(LaneCtx *)params; lane_ctx(lctx); ThreadNameF("async_thread_%I64u", lane_idx()); for(;!ins_atomic_u32_eval(&global_async_exit);) { MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000); #if defined(HASH_STORE_H) hs_tick(); #endif #if defined(FILE_STREAM_H) fs_tick(); #endif #if defined(DASM_CACHE_H) dasm_tick(); #endif cond_var_broadcast(async_tick_stop_cond_var); } }