From: hgn Date: Sat, 19 Apr 2025 08:34:58 +0000 (+0100) Subject: admin stuff X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=d30c5d2a3bf58da81b6c22343650235561a5d7c1;p=vg.git admin stuff --- diff --git a/vg_async2.c b/vg_async2.c index 926cce6..57e76ae 100644 --- a/vg_async2.c +++ b/vg_async2.c @@ -129,6 +129,9 @@ void vg_async_queue_end( vg_async_queue *queue, enum async_quit quit ) VG_SEMAPHORE_POST( queue->work_semaphore ); } +/* + * simple functions + * ------------------------------------------------------------------------------------------------------------------ */ struct simple_function_info { void (*fn)(void *userdata); @@ -149,3 +152,97 @@ void vg_async_call( vg_async_queue *queue, void(*fn)(void *userdata), void *user info->userdata = userdata; vg_async_task_dispatch( task, simple_function_call ); } + +/* + * Coroutines + * ------------------------------------------------------------------------------------------------------------------ */ + +bool co_begin( vg_coroutine *co ) +{ + co->i = 0; + if( co->state == k_coroutine_state_none ) + { + co->state = k_coroutine_state_init; + return 1; + } + else + { + co->state = k_coroutine_state_run; + return 0; + } +} + +void co_thread( vg_coroutine *co, i32 thread_id, vg_async_queue *queue ) +{ + co->worker_queues[thread_id] = queue; +} + +void *co_storage( vg_coroutine *co, u16 size ) +{ + co->data_size = size; + co->task = vg_allocate_async_task( co->worker_queues[0], sizeof(vg_coroutine) + size, 1 ); + vg_coroutine *next_co = (void *)co->task->data; + memcpy( next_co, co, sizeof(vg_coroutine) ); + memset( next_co->data, 0, size ); + return next_co->data; +} + +static void co_internal_call( vg_async_task *task ) +{ + vg_coroutine *co = (void *)task->data; + co->userdata = NULL; + co->task = NULL; + co->fn( co ); +} + +bool co_step( vg_coroutine *co, i32 thread_id ) +{ + if( co->state == k_coroutine_state_run ) + { + if( co->i == co->step ) + { + if( thread_id == co->thread ) + { + co->step ++; + co->i ++; + return 1; + } + else + { + co->thread = thread_id; + u32 size = sizeof(vg_coroutine) + co->data_size; + co->task = vg_allocate_async_task( co->worker_queues[ thread_id ], size, 1 ); + vg_coroutine *co_copy = (void *)co->task->data; + memcpy( co_copy, co, size ); + co->state = k_coroutine_state_orphan; + return 0; + } + } + else + co->i ++; + } + + return 0; +} + +void co_end( vg_coroutine *co ) +{ + if( co->state == k_coroutine_state_init ) + { + if( !co->task ) + co_storage( co, 0 ); + } + + if( co->task ) + vg_async_task_dispatch( co->task, co_internal_call ); +} + +void co_run( void(*fn)(vg_coroutine *co), void *userdata ) +{ + vg_coroutine bootstrap = {0}; + bootstrap.userdata = userdata; + bootstrap.state = k_coroutine_state_none; + bootstrap.thread = 0xffff; + bootstrap.fn = fn; + fn( &bootstrap ); +} diff --git a/vg_async2.h b/vg_async2.h index 22c0e6c..80c2c53 100644 --- a/vg_async2.h +++ b/vg_async2.h @@ -5,6 +5,7 @@ typedef struct vg_async_queue vg_async_queue; typedef struct vg_async_task vg_async_task; +typedef struct vg_coroutine vg_coroutine; struct vg_async_queue { @@ -35,6 +36,35 @@ struct vg_async_task u8 data[]; }; +struct vg_coroutine +{ + void *userdata; + vg_async_task *task; + vg_async_queue *worker_queues[2]; + void (*fn)(vg_coroutine *co); + + u16 step, i, thread; + + enum + { + k_coroutine_state_none, + k_coroutine_state_init, + k_coroutine_state_run, + k_coroutine_state_orphan + } + state; + + u16 data_size; + u8 data[]; +}; + +void *co_storage( vg_coroutine *co, u16 size ); +bool co_begin( vg_coroutine *co ); +void co_thread( vg_coroutine *co, i32 thread_id, vg_async_queue *queue ); +bool co_step( vg_coroutine *co, i32 thread_id ); +void co_run( void(*fn)(vg_coroutine *co), void *userdata ); +void co_end( vg_coroutine *co ); + bool vg_init_async_queue( vg_async_queue *queue ); void vg_free_async_queue( vg_async_queue *queue ); diff --git a/vg_console.c b/vg_console.c index 19937be..e4e41dd 100644 --- a/vg_console.c +++ b/vg_console.c @@ -9,7 +9,7 @@ struct vg_console vg_console; void vg_console_reg_var( const char *alias, void *ptr, enum vg_var_dtype type, u32 flags ) { - VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main ); + THREAD_1; VG_ASSERT( vg_console.var_count < VG_ARRAY_LEN(vg_console.vars) ); vg_var *var = &vg_console.vars[ vg_console.var_count ++ ]; @@ -25,7 +25,7 @@ void vg_console_reg_cmd( const char *alias, int (*function)(int argc, const char *argv[]), void (*poll_suggest)(int argc, const char *argv[]) ) { - VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main ); + THREAD_1; VG_ASSERT( vg_console.function_count < VG_ARRAY_LEN(vg_console.functions) ); vg_cmd *cmd = &vg_console.functions[ vg_console.function_count ++ ]; diff --git a/vg_engine.c b/vg_engine.c index af6f137..fe16c7b 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -16,9 +16,8 @@ struct vg_engine vg = } }; -const u32 k_thread_purpose_nothing = 0x00; -const u32 k_thread_purpose_main = 0x01; -const u32 k_thread_purpose_loader = 0x02; +u32 _thread_purpose_main = 0x01; +u32 _thread_purpose_loader = 0x01; u32 vg_thread_purpose(void) { @@ -81,75 +80,62 @@ void vg_bake_shaders(void) void vg_auto_shader_register(void); /* created from codegen */ #endif -static void _vg_load_step0(void *_); -static void _vg_load_step1(void *_); -static void _vg_load_step2(void *_); -static void _vg_load_step_complete(void *_); - -static void _vg_load_step0(void *_) +static void vg_load_co( vg_coroutine *co ) { - THREAD_1; -vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" ); -vg_info(" 2021-2025 |\\ /| | / | | | | /| \n" ); -vg_info(" | \\ / | +-- / +----- +---' | / | \n" ); -vg_info(" | \\ / | | / | | \\ | / | \n" ); -vg_info(" | \\/ | | / | | \\ | / | \n" ); -vg_info(" ' ' '--' [] '----- '----- ' ' '---' " - "SOFTWARE\n" ); - - vg_preload(); - vg_tex2d_replace_with_error_async( 0, &vg.tex_missing ); - vg_async_call( &vg.main_tasks, _vg_load_step1, NULL ); -} + if( co_begin( co ) ) + { + co_thread( co, 0, &vg.main_tasks ); + co_thread( co, 1, &vg.loader_tasks ); + } -static void _vg_load_step1(void *_) -{ - THREAD_0; - vg_async_call( &vg.loader_tasks, _vg_load_step2, NULL ); -} + if( co_step( co, 1 ) ) + { + vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" ); + vg_info(" 2021-2025 |\\ /| | / | | | | /| \n" ); + vg_info(" | \\ / | +-- / +----- +---' | / | \n" ); + vg_info(" | \\ / | | / | | \\ | / | \n" ); + vg_info(" | \\/ | | / | | \\ | / | \n" ); + vg_info(" ' ' '--' [] '----- '----- ' ' '---' " + "SOFTWARE\n" ); + + vg_tex2d_replace_with_error_async( 0, &vg.tex_missing ); + } -static void _vg_load_step2(void *_) -{ - THREAD_1; - vg_ui.tex_bg = vg.tex_missing; + if( co_step( co, 0 ) ) + { + vg_ui.tex_bg = vg.tex_missing; + } - /* internal */ - vg_loader_step( vg_framebuffer_init, NULL ); - vg_loader_step( vg_render_init, NULL ); - vg_loader_step( vg_input_init, vg_input_free ); - vg_loader_step( vg_lines_init, NULL ); - vg_loader_step( vg_rb_view_init, NULL ); - _vg_profile_reg_set( &_vg_prof_gameloop ); + if( co_step( co, 1 ) ) + { + /* internal */ + vg_loader_step( vg_framebuffer_init, NULL ); + vg_loader_step( vg_render_init, NULL ); + vg_loader_step( vg_input_init, vg_input_free ); + vg_loader_step( vg_lines_init, NULL ); + vg_loader_step( vg_rb_view_init, NULL ); + _vg_profile_reg_set( &_vg_prof_gameloop ); #ifndef VG_NO_AUDIO - vg_loader_step( vg_audio_init, vg_audio_free ); + vg_loader_step( vg_audio_init, vg_audio_free ); #endif - vg_loader_step( vg_profiler_init, NULL ); - vg_loader_step( vg_mem_view_init, NULL ); + vg_loader_step( vg_profiler_init, NULL ); + vg_loader_step( vg_mem_view_init, NULL ); - /* client */ + /* client */ #ifdef VG_CUSTOM_SHADERS - vg_auto_shader_register(); + vg_auto_shader_register(); #endif - vg_load(); -} - -void _vg_load_temp_end(void) -{ - vg_async_call( &vg.main_tasks, _vg_load_step_complete, NULL ); - vg_success( "Client loaded in %fs\n", vg.time_real ); -} - -static void _vg_load_step_complete(void *_) -{ - vg_success( "Internal async setup complete\n" ); + //vg_success( "Client loaded in %fs\n", vg.time_real ); + } - if( SDL_AtomicGet( &vg.engine_status ) == k_engine_status_crashed ) - return; - else + if( co_step( co, 0 ) ) + { SDL_AtomicSet( &vg.engine_status, k_engine_status_running ); + _vg_tower_set_flag( vg.sig_engine, 1 ); + } - vg_magi_restore(); + co_end( co ); } static void _vg_process_events(void) @@ -511,39 +497,6 @@ static void _vg_gameloop(void) } } -static void _vg_process_launch_opts_internal( int argc, char *argv[] ) -{ - char *arg; - while( vg_argp( argc, argv ) ) - { - if( (arg = vg_opt_arg( 'w', "Render output width" )) ) - vg.window_x = atoi( arg ); - - if( (arg = vg_opt_arg( 'h', "Render output height" )) ) - vg.window_y = atoi( arg ); - - if( (arg = vg_long_opt_arg( "samples", "Rendering samples per pixel" )) ) - vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) ); - - if( vg_long_opt( "use-libc-malloc", "Use standard libc allocator" ) ) - vg_mem.use_libc_malloc = 1; - - if( vg_long_opt( "high-performance", "Turn graphics to lowest quality" ) ) - vg.quality_profile = k_quality_profile_low; - - if( (arg = vg_long_opt_arg( "load-step-delay", "Loader step delay (ms)" )) ) - vg.load_step_delay = atoi(arg); - - vg_launch_opt(); - - if( vg_long_opt( "help", "Helps you" ) ) - { - _vg_print_options(); - exit(0); - } - } -} - static void _vg_init_window( const char *window_name ) { vg_info( "SDL_INIT\n" ); @@ -715,7 +668,7 @@ static int cmd_log_memory( int argc, const char *argv[] ) static int _vg_loader_thread( void *pfn ) { - SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_loader, NULL ); + SDL_TLSSet( vg.thread_purpose, &_thread_purpose_loader, NULL ); if( setjmp( vg.env_loader_exit ) ) return 0; @@ -725,21 +678,52 @@ static int _vg_loader_thread( void *pfn ) } static int cmd_vg_settings_toggle( int argc, const char *argv[] ); -void vg_enter( int argc, char *argv[], const char *window_name ) +void vg_init( int argc, const char *argv[], const char *window_name ) { + vg.thread_purpose = SDL_TLSCreate(); + VG_ASSERT( vg.thread_purpose ); + SDL_TLSSet( vg.thread_purpose, &_thread_purpose_main, NULL ); + + vg_log_init(); + + vg.sig_engine = _vg_tower_create_signal( "Engine" ); + vg.sig_client = _vg_tower_create_signal( "Client" ); + if( !vg_init_async_queue( &vg.main_tasks ) ) return; if( !vg_init_async_queue( &vg.loader_tasks ) ) return; - vg.thread_purpose = SDL_TLSCreate(); - VG_ASSERT( vg.thread_purpose ); + vg_rand_seed( &vg.rand, 461 ); - /* we pretend to be loader thread while it doesn't exist */ - SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_loader, NULL ); + /* launch options */ + _vg_opt_init( argc, argv ); + const char *arg; + if( (arg = vg_opt_arg( 'w', "Render output width" )) ) + vg.window_x = atoi( arg ); - vg_rand_seed( &vg.rand, 461 ); - _vg_process_launch_opts_internal( argc, argv ); + if( (arg = vg_opt_arg( 'h', "Render output height" )) ) + vg.window_y = atoi( arg ); + + if( (arg = vg_long_opt_arg( "samples", "Rendering samples per pixel" )) ) + vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) ); + + if( vg_long_opt( "use-libc-malloc", "Use standard libc allocator" ) ) + vg_mem.use_libc_malloc = 1; + + if( vg_long_opt( "high-performance", "Turn graphics to lowest quality" ) ) + vg.quality_profile = k_quality_profile_low; + + if( (arg = vg_long_opt_arg( "load-step-delay", "Loader step delay (ms)" )) ) + vg.load_step_delay = atoi(arg); + + vg.window_name = window_name; +} + +void vg_run(void) +{ + if( !_vg_opt_check() ) + exit(0); /* Systems init */ vg_alloc_quota(); @@ -756,19 +740,17 @@ void vg_enter( int argc, char *argv[], const char *window_name ) vg_console_reg_cmd( "vg_settings", cmd_vg_settings_toggle, NULL ); vg_console_reg_cmd( "vg_rtmemory", cmd_log_memory, NULL ); - _vg_init_window( window_name ); - + _vg_init_window( vg.window_name ); SDL_SetRelativeMouseMode(1); - - /* multi-threaded loading phase */ - SDL_AtomicSet( &vg.engine_status, k_engine_status_load_internal ); /* Opengl-required systems */ vg_ui_init(); vg_loader_step( vg_loader_init, vg_loader_free ); - vg_async_call( &vg.loader_tasks, _vg_load_step0, NULL ); - SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_main, NULL ); + SDL_AtomicSet( &vg.engine_status, k_engine_status_load_internal ); + co_run( vg_load_co, NULL ); + + _thread_purpose_loader = 0x2; SDL_CreateThread( _vg_loader_thread, "vg: loader", NULL ); _vg_gameloop(); _vg_terminate(); @@ -802,7 +784,7 @@ void vg_fatal_exit(void) SDL_AtomicSet( &vg.engine_status, k_engine_status_crashed ); - if( vg_thread_purpose() == k_thread_purpose_loader ) + if( vg_thread_purpose() == _thread_purpose_loader ) { longjmp( vg.env_loader_exit, 1 ); } @@ -1336,6 +1318,7 @@ __attribute__((used)) int AmdPowerXpressRequestHighPerformance = 1; #include "vg_render.c" #include "vg_opengl.c" #include "vg_mem_view.c" +#include "vg_tower.c" #ifdef VG_CUSTOM_SHADERS #include "shaders/impl.c" diff --git a/vg_engine.h b/vg_engine.h index 1b977ca..2cc8b6d 100644 --- a/vg_engine.h +++ b/vg_engine.h @@ -1,58 +1,6 @@ #pragma once -/* Copyright (C) 2021-2024 Mt.Zero Software - All Rights Reserved */ -/* - .-. VG Event loop -| 0 | -| | .---------------------------------------------------------. -|API| | vg_enter( int argc, char *argv[], const char *window_name | -| | '---------------------------------------------------------' -| | | -| | v -|IMP| vg_launch_opt(void) <--. -| | | | -| | |'---------------' -| | | .-. -| | |'-----------------------------------| 1 |------. -| | | | | | -| | | | | v -| | | |IMP| vg_preload(void) -| | | | | | -| | .-----+. | | v -| | | | |IMP| vg_load(void) -| | | v '___' | -|IMP| | vg_framebuffer_resize(void) | -| | | | | -|IMP| | |.--------------------------------------------' -| | | | -| | | v -|IMP| | vg_pre_update(void) -| | | | -| | | .-----+. -| | | | | called 0x to 8x -| | | | v -|IMP| | '- vg_fixed_update(void) -| | | | -| | | .-' -| | | | -| | | v -|IMP| | vg_post_update(void) -| | | | -| | | v -|IMP| | vg_render(void) -| | | | -| | | v -|IMP| | vg_gui(void) -| | | | -| | | v -|IMP| | vg_game_settings_init(void) -|IMP| | vg_game_settings_gui( ui_rect panel ) -| | | | (optional: #define VG_GAME_SETTINGS) -| | | | -| | '----' -'___' - -*/ +/* Copyright (C) 2021-2025 Mt.Zero Software - All Rights Reserved */ /* configuration warnings */ @@ -81,20 +29,18 @@ #include "vg_string.h" #include "vg_ui/imgui.h" #include "vg_async2.h" +#include "vg_tower.h" #include /* API */ -void vg_enter( int argc, char *argv[], const char *window_name ); +void vg_init( int argc, const char *argv[], const char *window_name ); +void vg_run(void); /* Thread 1 */ void vg_bake_shaders(void); -extern void vg_preload(void); -extern void vg_load(void); - /* Main thread */ -extern void vg_launch_opt(void); extern void vg_framebuffer_resize(int w, int h); extern void vg_pre_update(void); extern void vg_fixed_update(void); @@ -125,20 +71,21 @@ struct vg_engine /* Engine sync */ SDL_Window *window; SDL_GLContext gl_context; - SDL_TLSID thread_purpose; vg_async_queue main_tasks, loader_tasks; jmp_buf env_loader_exit; /* for deep fatal error handling */ - SDL_atomic_t engine_status; + vg_signal_id sig_engine, sig_client; + /* Window information */ int window_x, window_y, samples, window_should_close; - const char *base_path; + const char *base_path; + const char *window_name; int display_refresh_rate, fps_limit, @@ -242,24 +189,17 @@ struct vg_setting_ranged_i32 void ui_settings_ranged_i32_init( struct vg_setting_ranged_i32 *prop ); void ui_settings_enum_init( struct vg_setting_enum *prop ); bool vg_settings_enum_diff( struct vg_setting_enum *prop ); -bool vg_settings_enum( ui_context *ctx, - struct vg_setting_enum *prop, ui_rect rect ); -void vg_settings_ui_header( ui_context *ctx, - ui_rect inout_panel, const char *name ); -bool vg_settings_apply_button( ui_context *ctx, - ui_rect inout_panel, bool validated ); - +bool vg_settings_enum( ui_context *ctx, struct vg_setting_enum *prop, ui_rect rect ); +void vg_settings_ui_header( ui_context *ctx, ui_rect inout_panel, const char *name ); +bool vg_settings_apply_button( ui_context *ctx, ui_rect inout_panel, bool validated ); enum engine_status _vg_engine_status(void); - -extern const u32 k_thread_purpose_nothing; -extern const u32 k_thread_purpose_main; -extern const u32 k_thread_purpose_loader; +extern u32 _thread_purpose_main; +extern u32 _thread_purpose_loader; u32 vg_thread_purpose(void); -void _vg_load_temp_end(void); -#define THREAD_0 VG_ASSERT( vg_thread_purpose() == k_thread_purpose_main ) -#define THREAD_1 VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader ) +#define THREAD_0 VG_ASSERT( vg_thread_purpose() == _thread_purpose_main ) +#define THREAD_1 VG_ASSERT( vg_thread_purpose() == _thread_purpose_loader ) void vg_checkgl( const char *src_info ); #define VG_STRINGIT( X ) #X diff --git a/vg_loader.c b/vg_loader.c index f22a826..bbd134d 100644 --- a/vg_loader.c +++ b/vg_loader.c @@ -1,6 +1,7 @@ #include "vg_engine.h" #include "vg_loader.h" #include "vg_shader.h" +#include "vg_async2.h" struct vg_loader vg_loader; @@ -108,7 +109,7 @@ void async_loader_set_user_information( vg_async_task *task ) void vg_loader_set_user_information( const char *information ) { - if( vg_thread_purpose() == k_thread_purpose_loader ) + if( vg_thread_purpose() == _thread_purpose_loader ) { vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct async_set_information_args), 1 ); struct async_set_information_args *args = (void *)task->data; @@ -193,9 +194,9 @@ void _vg_loader_step( void( *fn_load )(void), void( *fn_free )(void), const char enum engine_status status = SDL_AtomicGet( &vg.engine_status ); - if( status != k_engine_status_load_internal ) + if( status == k_engine_status_crashed ) { - vg_info( "Joining loader thread.\n" ); longjmp( vg.env_loader_exit, 1 ); } } + diff --git a/vg_loader.h b/vg_loader.h index 8f43b3a..9dfb600 100644 --- a/vg_loader.h +++ b/vg_loader.h @@ -13,6 +13,12 @@ #include "vg_platform.h" #include "vg_engine.h" +#define VG_ENGINE_READY 0x1 +#define VG_CLIENT_READY 0x2 +#define VG_ALL_READY (VG_ENGINE_READY|VG_CLIENT_READY) +#define VG_READYNESS_MAX 0x8000 +#define VG_CLIENT_READYNESS_MAX 0x80000000 + struct vg_loader { /* Shutdown steps */ @@ -24,8 +30,9 @@ struct vg_loader u32 step_count, step_action; GLuint vao, vbo; - const char *information_for_user; + + u32 readyness; } extern vg_loader; diff --git a/vg_opt.c b/vg_opt.c index 80b3146..ce224e3 100644 --- a/vg_opt.c +++ b/vg_opt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved + * Copyright (C) 2021-2025 Mt.ZERO Software, Harry Godden - All Rights Reserved */ #include "vg_opt.h" @@ -18,263 +18,252 @@ * standard agument | regular_thing */ -static int vg_argi = 1; -static int vg_argj = 1; -static int vg_argc = 0; -static int vg_consume_next = 0; -static char **vg_argv; - -enum vg_opt_type -{ - k_vg_opt_type_standard, - k_vg_opt_type_flag, - k_vg_opt_type_arg, - k_vg_opt_type_long_flag, - k_vg_opt_type_long_arg -}; - -struct _vg_opt_reg -{ - const char *alias, *desc; - char alias_c; - u8 type; -} -static _vg_all_opts[32]; -static u32 _vg_opt_count = 0; - -static void _vg_opt_observe( const char *alias, char alias_c, const char *desc, - enum vg_opt_type type ) +struct { - for( u32 i=0; i<_vg_opt_count; i ++ ) + struct vg_opt_reg { - struct _vg_opt_reg *reg = &_vg_all_opts[i]; - if( (type == k_vg_opt_type_flag || type == k_vg_opt_type_arg) - && reg->alias_c == alias_c ) - { - return; - } - - if( (type == k_vg_opt_type_long_flag || type == k_vg_opt_type_long_arg) - && reg->alias == alias ) - { - return; - } + const char *alias, *desc; + char alias_c; - if( (type == k_vg_opt_type_standard) - && (reg->alias == NULL && reg->alias_c == 0) ) + enum opt_type { - return; + k_opt_flag, + k_opt_opt, + k_opt_long_flag, + k_opt_long_opt } + type; } + infos[32]; + u32 info_count; - if( _vg_opt_count < VG_ARRAY_LEN( _vg_all_opts ) ) + struct vg_arg { - struct _vg_opt_reg *reg = &_vg_all_opts[ _vg_opt_count ++ ]; - reg->alias = alias; - reg->alias_c = alias_c; - reg->desc = desc; - reg->type = type; + enum arg_type + { + k_arg_singles, + k_arg_long, + k_arg_assign, + k_arg_regular + } + type; + + u32 arg_len; + const char *arg, *value; + u32 used; } + args[32]; + u32 arg_count; } +_vg_opt; -void _vg_print_options(void) +static void _vg_opt_reg( struct vg_opt_reg reg ) { - for( u32 i=0; i<_vg_opt_count; i ++ ) - { - struct _vg_opt_reg *reg = &_vg_all_opts[i]; - - if( reg->type == k_vg_opt_type_flag ) - printf( "-%c %s\n", reg->alias_c, reg->desc ); - - if( reg->type == k_vg_opt_type_arg ) - printf( "-%c %s\n", reg->alias_c, reg->desc ); + if( _vg_opt.info_count < VG_ARRAY_LEN( _vg_opt.infos ) ) + _vg_opt.infos[ _vg_opt.info_count ++ ] = reg; +} - if( reg->type == k_vg_opt_type_long_flag ) - printf( "--%-21s %s\n", reg->alias, reg->desc ); +void _vg_opt_init( int argc, const char *argv[] ) +{ + if( argc+1 >= VG_ARRAY_LEN( _vg_opt.args ) ) + { + vg_error( "Too many arguments!\n" ); + exit(-1); + } - if( reg->type == k_vg_opt_type_long_arg ) + _vg_opt.arg_count = 0; + for( u32 i=1; iarg = NULL; + arg->value = NULL; + arg->arg_len = 0; + arg->used = 0; + if( v[0] == '-' ) { - char temp[32]; - snprintf( temp, 32, "--%s=", reg->alias ); - printf( "%-23s %s\n", temp, reg->desc ); + if( v[1] == '-' ) + { + arg->arg = v+2; + arg->type = k_arg_long; + u32 k=2; + while( v[ k ] ) + { + if( v[ k ] == '=' ) + { + arg->arg_len = k-2; + arg->value = v + k + 1; + arg->type = k_arg_assign; + goto next; + } + k ++; + } + } + else + { + arg->arg = v+1; + arg->type = k_arg_singles; + u32 k=1; + while( v[k] ) + k ++; + arg->arg_len = k-1; + arg->used = ~((0x1<arg_len)-1); + } } - - if( reg->type == k_vg_opt_type_standard ) + else { - printf( " %s\n", reg->desc ); + arg->type = k_arg_regular; + arg->value = v; + arg->arg = v; } +next:; } } -/* Will return 0 if exhausted */ -int vg_argp( int argc, char *argv[] ) +bool _vg_opt_check(void) { - vg_argv = argv; - vg_argc = argc; - - static int delta_i = 0; - static int delta_j = 0; - - if( vg_argj != 1 && !vg_argv[ vg_argi ][ vg_argj ] ) + if( vg_long_opt( "help", "Helps you" ) ) { - vg_argj = 1; - vg_argi ++; - } + for( u32 i=0; i<_vg_opt.info_count; i ++ ) + { + struct vg_opt_reg *reg = &_vg_opt.infos[i]; + const char *desc = reg->desc? reg->desc: ""; - if( vg_consume_next ) - { - vg_consume_next = 0; - vg_argi ++; - } + if( reg->type == k_opt_flag ) + printf( "-%c %s\n", reg->alias_c, desc ); - if( vg_argi >= argc ) - return 0; + if( reg->type == k_opt_opt ) + printf( "-%c %s\n", reg->alias_c, desc ); - if( (delta_i == vg_argi) && (delta_j == vg_argj) ) - { - char *cur = &vg_argv[ vg_argi ][ vg_argj ]; - - if( *cur != '-' ) - { - vg_error( "Unknown opt '-%c'\n", *cur ); + if( reg->type == k_opt_long_flag ) + printf( "--%-21s %s\n", reg->alias, desc ); + + if( reg->type == k_opt_long_opt ) + { + char temp[32]; + snprintf( temp, 32, "--%s=", reg->alias ); + printf( "%-23s %s\n", temp, desc ); + } } - else + exit(0); + } + + bool errors = 0; + for( u32 i=0; i<_vg_opt.arg_count; i ++ ) + { + struct vg_arg *arg = &_vg_opt.args[ i ]; + if( arg->used != 0xffffffff ) { - vg_error( "Unknown opt '--%s'\n", cur + 1 ); + if( arg->type == k_arg_singles ) + { + for( u32 j=0; j<32; j ++ ) + { + if( !(arg->used & (0x1<arg[j] ); + } + } + else + vg_error( "Unknown option '%s'\n", arg->arg ); + errors = 1; } - - exit(0); } - - delta_i = vg_argi; - delta_j = vg_argj; - return 1; + return errors == 0; } -/* Example: see if -c is set */ -int vg_opt( char c, const char *desc ) +bool vg_opt( char c, const char *desc ) { - _vg_opt_observe( NULL, c, desc, k_vg_opt_type_flag ); - - char *carg = vg_argv[ vg_argi ]; - - if( carg[0] == '-' ) + _vg_opt_reg( (struct vg_opt_reg){ .alias=NULL, .alias_c=c, .desc=desc, .type=k_opt_flag } ); + for( u32 i=0; i<_vg_opt.arg_count; i ++ ) { - if( carg[1] == '-' ) - return 0; - - if( carg[ vg_argj ] == c ) + struct vg_arg *arg = &_vg_opt.args[ i ]; + if( arg->type == k_arg_singles ) { - vg_argj ++; - - return 1; + for( u32 j=0; jarg_len; j ++ ) + { + if( arg->arg[j] == c ) + { + arg->used |= 0x1 << j; + return 1; + } + } } } - return 0; } -/* Example: get -c *value* */ -char *vg_opt_arg( char c, const char *desc ) -{ - _vg_opt_observe( NULL, c, desc, k_vg_opt_type_arg ); - - if( vg_opt( c, NULL ) ) +const char *vg_opt_arg( char c, const char *desc ) +{ + _vg_opt_reg( (struct vg_opt_reg){ .alias=NULL, .alias_c=c, .desc=desc, .type=k_opt_opt } ); + for( u32 i=0; i+1<_vg_opt.arg_count; i ++ ) { - if( vg_argi < vg_argc-1 ) + struct vg_arg *arg = &_vg_opt.args[ i ]; + if( arg->type == k_arg_singles ) { - if( vg_argv[ vg_argi + 1 ][0] != '-' ) + for( u32 j=0; jarg_len; j ++ ) { - vg_consume_next = 1; - return vg_argv[ vg_argi + 1 ]; + if( arg->arg[j] == c ) + { + arg->used |= 0x1 << j; + return _vg_opt.args[ i + 1 ].value; + } } } - - vg_error( "Option '%c' requires argument!\n", c ); - exit(0); } - return NULL; } -/* Example see if --big is set */ -int vg_long_opt( char *name, const char *desc ) -{ - _vg_opt_observe( name, 0, desc, k_vg_opt_type_long_flag ); - - char *carg = vg_argv[ vg_argi ]; - - if( carg[0] == '-' ) +bool vg_long_opt( char *name, const char *desc ) +{ + _vg_opt_reg( (struct vg_opt_reg){ .alias=name, .alias_c=0, .desc=desc, .type=k_opt_long_flag } ); + for( u32 i=0; i<_vg_opt.arg_count; i ++ ) { - if( carg[1] == '-' ) + struct vg_arg *arg = &_vg_opt.args[ i ]; + if( arg->type == k_arg_long ) { - if( !strcmp( name, carg+2 ) ) + if( !strcmp( arg->arg, name ) ) { - vg_consume_next = 1; + arg->used = 0xffffffff; return 1; } } } - return 0; } -/* Example: get --big=value */ -char *vg_long_opt_arg( char *name, const char *desc ) -{ - _vg_opt_observe( name, 0, desc, k_vg_opt_type_long_arg ); - - char *carg = vg_argv[ vg_argi ]; - - if( carg[0] == '-' ) +const char *vg_long_opt_arg( char *name, const char *desc ) +{ + _vg_opt_reg( (struct vg_opt_reg){ .alias=name, .alias_c=0, .desc=desc, .type=k_opt_long_opt } ); + for( u32 i=0; i<_vg_opt.arg_count; i ++ ) { - if( carg[1] == '-' ) + struct vg_arg *arg = &_vg_opt.args[ i ]; + if( arg->type == k_arg_assign ) { - int k = 2; int set = 0; - while( carg[ k ] ) + if( !strncmp( arg->arg, name, arg->arg_len ) ) { - if( carg[ k ] == '=' ) - { - set = 1; - break; - } - - k ++; + arg->used = 0xffffffff; + return arg->value; } - - if( !strncmp( name, carg+2, k-2 ) ) - { - vg_consume_next = 1; - - // the rest - if( set ) - { - return carg + k + 1; - } - else - { - vg_error( "Long option '%s' requires argument\n", name ); - } - } } } - return NULL; } -/* Example: get regular_thing */ -char *vg_arg( const char *desc ) -{ - _vg_opt_observe( NULL, 0, desc, k_vg_opt_type_standard ); - - char *carg = vg_argv[ vg_argi ]; - - if( carg[0] != '-' ) +const char *vg_arg( u32 index ) +{ + u32 count = 0; + for( u32 i=0; i<_vg_opt.arg_count; i ++ ) { - vg_consume_next = 1; - return carg; + struct vg_arg *arg = &_vg_opt.args[ i ]; + if( arg->type == k_arg_regular ) + { + count ++; + if( index+1 == count ) + { + arg->used = 0xffffffff; + return arg->value; + } + } } - return NULL; } diff --git a/vg_opt.h b/vg_opt.h index 0dac45c..12e6187 100644 --- a/vg_opt.h +++ b/vg_opt.h @@ -1,26 +1,24 @@ /* - * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved + * Copyright (C) 2021-2025 Mt.ZERO Software - All Rights Reserved */ #pragma once +#include "vg_platform.h" -/* Will return 0 if exhausted */ -int vg_argp( int argc, char *argv[] ); +void _vg_opt_init( int argc, const char *argv[] ); +bool _vg_opt_check(void); /* Example: see if -c is set */ -int vg_opt( char c, const char *desc ); +bool vg_opt( char c, const char *desc ); /* Example: get -c *value* */ -char *vg_opt_arg( char c, const char *desc ); +const char *vg_opt_arg( char c, const char *desc ); /* Example see if --big is set */ -int vg_long_opt( char *name, const char *desc ); +bool vg_long_opt( char *name, const char *desc ); /* Example: get --big=value */ -char *vg_long_opt_arg( char *name, const char *desc ); +const char *vg_long_opt_arg( char *name, const char *desc ); /* Example: get regular_thing */ -char *vg_arg( const char *desc ); - -/* You should probably bind this to --help (and call it last!) */ -void _vg_print_options(void); +const char *vg_arg( u32 index ); diff --git a/vg_tex.c b/vg_tex.c index 7db6171..e82fa31 100644 --- a/vg_tex.c +++ b/vg_tex.c @@ -298,9 +298,7 @@ void vg_tex2d_load_qoi_async( const u8 *bytes, u32 size, u32 flags, GLuint *dest void vg_tex2d_load_qoi_async_file( const char *path, u32 flags, GLuint *dest ) { - if( vg_thread_purpose() != k_thread_purpose_loader ) - vg_fatal_error( "Called aync texture load from wrong thread (main)\n" ); - + THREAD_1; vg_linear_clear( vg_mem.scratch ); u32 size; diff --git a/vg_tower.c b/vg_tower.c new file mode 100644 index 0000000..96d0a63 --- /dev/null +++ b/vg_tower.c @@ -0,0 +1,87 @@ +#pragma once +#include "vg_tower.h" + +struct _vg_tower _vg_tower; + +vg_signal_id _vg_tower_create_signal( const char *name ) +{ + THREAD_0; + VG_ASSERT( _vg_tower.signal_count < VG_ARRAY_LEN( _vg_tower.signals ) ); + vg_signal_id id = _vg_tower.signal_count; + struct signal_info *inf = &_vg_tower.signals[ id ]; + inf->name = name; + _vg_tower.signal_count ++; + return id; +} + +void _vg_tower_register_trigger( u64 mask, void(*fn)( vg_signal_id id, bool state ) ) +{ + THREAD_0; + VG_ASSERT( _vg_tower.trigger_count < VG_ARRAY_LEN( _vg_tower.triggers ) ); + struct tower_trigger *trigger = &_vg_tower.triggers[ _vg_tower.trigger_count ++ ]; + trigger->mask = mask; + trigger->fn = fn; +} + +struct async_tower_info +{ + vg_signal_id id; + bool state; +}; +static void _vg_tower_set_flag_recall( vg_async_task *task ) +{ + struct async_tower_info *info = (void *)task->data; + _vg_tower_set_flag( info->id, info->state ); +} +void _vg_tower_set_flag( vg_signal_id id, bool state ) +{ + if( vg_thread_purpose() == _thread_purpose_loader ) + { + vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct async_tower_info), 1 ); + struct async_tower_info *info = (void *)task->data; + info->id = id; + info->state = state; + vg_async_task_dispatch( task, _vg_tower_set_flag_recall ); + return; + } + + THREAD_0; + + u64 bit = 0x1lu << (u64)id; + if( state ) _vg_tower.state |= bit; + else _vg_tower.state &= ~bit; + vg_info( "[tower] %s:%s [%lx]\n", _vg_tower.signals[id].name, state? "true": "false", _vg_tower.state ); + + for( u32 i=0; i<_vg_tower.trigger_count; i ++ ) + { + struct tower_trigger *trig = &_vg_tower.triggers[i]; + if( trig->mask & bit ) + { + trig->fn( id, state ); + } + } + +#if 0 + // TODO: Make subscription + if( (flag == VG_ENGINE_READY) && state ) + { + vg_load(); + } + + if( (flag == VG_CLIENT_READY) && state ) + { + vg_magi_restore(); + } +#endif +} +bool _vg_tower_clearence( u64 mask ) +{ + THREAD_0; + return (_vg_tower.state & mask) == mask; +} + +u64 _vg_tower_mask( vg_signal_id id ) +{ + u64 bit = 0x1lu << (u64)id; + return bit; +} diff --git a/vg_tower.h b/vg_tower.h new file mode 100644 index 0000000..b3b9cae --- /dev/null +++ b/vg_tower.h @@ -0,0 +1,30 @@ +#pragma once +#include "vg_async2.h" + +typedef u8 vg_signal_id; + +struct _vg_tower +{ + struct tower_trigger + { + u64 mask; + void( *fn )( vg_signal_id id, bool state ); + } + triggers[ 64 ]; + + struct signal_info + { + const char *name; + } + signals[ 64 ]; + + u32 trigger_count, signal_count; + u64 state; +} +extern _vg_tower; + +vg_signal_id _vg_tower_create_signal( const char *name ); +void _vg_tower_register_trigger( u64 mask, void(*fn)( vg_signal_id id, bool state ) ); +void _vg_tower_set_flag( vg_signal_id id, bool state ); +bool _vg_tower_clearence( u64 mask ); +u64 _vg_tower_mask( vg_signal_id id );