From 5324992ccec2857770963843fcdb6e44ce2c1a37 Mon Sep 17 00:00:00 2001 From: hgn Date: Sun, 23 Apr 2023 10:34:58 +0100 Subject: [PATCH] basic async mechanism --- submodules/SDL | 2 +- vg.h | 14 ++++- vg_async.h | 138 +++++++++++++++++++++++++++++++++++++++++++++++++ vg_log.h | 4 -- vg_mem.h | 6 +-- 5 files changed, 152 insertions(+), 12 deletions(-) create mode 100644 vg_async.h diff --git a/submodules/SDL b/submodules/SDL index eef4d3c..06492c5 160000 --- a/submodules/SDL +++ b/submodules/SDL @@ -1 +1 @@ -Subproject commit eef4d3c86a653f91b7221c80809ba8ab56f94cf1 +Subproject commit 06492c598158cf825a18aececaf7511d7fd04f48 diff --git a/vg.h b/vg.h index f6c5bb6..7ddd04e 100644 --- a/vg.h +++ b/vg.h @@ -106,6 +106,7 @@ VG_STATIC void vg_print_backtrace(void) #include "vg_m.h" #include "vg_io.h" #include "vg_log.h" + #include "vg_async.h" #include "vg_steam.h" //#define VG_SYNC_DEBUG @@ -398,6 +399,11 @@ VG_STATIC void vg_bake_shaders(void) vg_release_thread_sync(); } +void test_async_runner( void *payload, u32 size ) +{ + vg_success( "Async call test (%p, %u)\n", payload, size ); +} + VG_STATIC void _vg_load_full(void) { vg_preload(); @@ -410,6 +416,9 @@ VG_STATIC void _vg_load_full(void) /* client */ vg_load(); + + vg_async_item *test_async = vg_async_alloc( 0 ); + vg_async_dispatch( test_async, test_async_runner ); } VG_STATIC void _vg_process_events(void) @@ -671,6 +680,7 @@ VG_STATIC void _vg_gameloop(void) vg.time_delta = vg.time_frame_delta * vg.time_rate; vg.time += vg.time_delta; + vg_run_async_checked(); _vg_process_events(); if( vg.window_should_close ) @@ -868,12 +878,12 @@ VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name ) /* Systems init */ vg_alloc_quota(); - _vg_log_init(); _vg_console_init(); vg_console_reg_var( "fps_limit", &vg.fps_limit, k_var_dtype_i32, 0 ); - _vg_init_window( window_name ); + + vg_async_init(); SDL_SetRelativeMouseMode(1); vg.thread_id_main = SDL_GetThreadID(NULL); diff --git a/vg_async.h b/vg_async.h new file mode 100644 index 0000000..366f448 --- /dev/null +++ b/vg_async.h @@ -0,0 +1,138 @@ +/* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved + * + * primateves that you use when you need to run something from another thread + * back in the main loop of vg, at the start of each frame + */ + +#ifndef VG_ASYNC_H +#define VG_ASYNC_H + +#include "vg/vg.h" + +typedef struct vg_async_item vg_async_item; + +struct vg_async_item{ + vg_async_item *next; + + void *payload; + u32 size; + + void (*fn_runner)( void *payload, u32 size ); +}; + +struct vg_async{ + void *buffer; + + vg_async_item *start, *end; + + SDL_sem *sem_wait_for_flush; + SDL_SpinLock sl_index; +} +static vg_async; + +/* + * Allocate an asynchronous call with a bit of memory + */ +VG_STATIC vg_async_item *vg_async_alloc( u32 size ) +{ + SDL_AtomicLock( &vg_async.sl_index ); + + u32 total_allocation = vg_align8(size) + vg_align8(sizeof(vg_async_item)), + remaining = vg_linear_remaining( vg_async.buffer ), + capacity = vg_linear_get_capacity( vg_async.buffer ); + + if( total_allocation > capacity ){ + SDL_AtomicUnlock( &vg_async.sl_index ); + vg_error( "Requested: %umb. Buffer size: %umb\n", + (total_allocation/1024)/1024, + (capacity/1024)/1024 ); + vg_fatal_exit_loop( "async alloc invalid size\n" ); + } + + if( total_allocation > remaining ){ + SDL_AtomicUnlock( &vg_async.sl_index ); + SDL_SemWait( vg_async.sem_wait_for_flush ); + SDL_AtomicLock( &vg_async.sl_index ); + + remaining = vg_linear_remaining( vg_async.buffer ); + capacity = vg_linear_get_capacity( vg_async.buffer ); + + assert( remaining == capacity ); + assert( vg_async.start == NULL ); + assert( vg_async.end == NULL ); + } + + void *block = vg_linear_alloc( vg_async.buffer, total_allocation ); + + vg_async_item *entry = block; + entry->next = NULL; + entry->payload = ((u8*)block) + vg_align8(sizeof(vg_async_item)); + entry->size = size; + entry->fn_runner = NULL; + + if( vg_async.end ){ + vg_async.end->next = entry; + vg_async.end = entry; + }else{ + vg_async.start = entry; + vg_async.end = entry; + } + + SDL_AtomicUnlock( &vg_async.sl_index ); + + return entry; +} + +/* + * Mark the call as being filled and ready to go + */ +VG_STATIC void vg_async_dispatch( vg_async_item *item, + void (*runner)( void *payload, u32 size ) ) +{ + SDL_AtomicLock( &vg_async.sl_index ); + item->fn_runner = runner; + SDL_AtomicUnlock( &vg_async.sl_index ); +} + +/* + * Run as much of the async buffer as possible + */ +VG_STATIC void vg_run_async_checked(void) +{ + SDL_AtomicLock( &vg_async.sl_index ); + + while( vg_async.start ){ + vg_async_item *entry = vg_async.start; + + if( entry->fn_runner ){ + entry->fn_runner( entry->payload, entry->size ); + vg_async.start = entry->next; + + if( vg_async.start == NULL ){ + vg_async.end = NULL; + + vg_linear_clear( vg_async.buffer ); + + if( !SDL_SemValue( vg_async.sem_wait_for_flush ) ){ + SDL_SemPost( vg_async.sem_wait_for_flush ); + } + } + } + else{ + break; + } + + /* TODO: if exceed max frametime.... */ + } + + SDL_AtomicUnlock( &vg_async.sl_index ); +} + +VG_STATIC void vg_async_init(void) +{ + vg_async.sem_wait_for_flush = SDL_CreateSemaphore(0); + vg_async.buffer = vg_create_linear_allocator( NULL, 50*1024*1024, + VG_MEMORY_REALTIME ); +} + +#endif /* VG_ASYNC_H */ diff --git a/vg_log.h b/vg_log.h index 7c6ea43..0439069 100644 --- a/vg_log.h +++ b/vg_log.h @@ -79,10 +79,6 @@ VG_STATIC void _vg_log_write( FILE *file, const char *prefix, #endif } -VG_STATIC void _vg_log_init(void) -{ -} - #define VG_LOGX( NAME, PIPE, PFX ) \ VG_STATIC void NAME(const char *fmt, ...) \ { \ diff --git a/vg_mem.h b/vg_mem.h index 8f3da63..49d9e37 100644 --- a/vg_mem.h +++ b/vg_mem.h @@ -19,8 +19,7 @@ typedef struct vg_allocation_meta vg_allocation_meta; struct { void *rtmemory, - *scratch, - *async; + *scratch; int use_libc_malloc; u32 quota; @@ -385,9 +384,6 @@ VG_STATIC void vg_alloc_quota(void) vg_mem.scratch = vg_create_linear_allocator( vg_mem.rtmemory, size_scratch, VG_MEMORY_SYSTEM ); - - vg_mem.async = vg_create_linear_allocator( NULL, 50*1024*1024, - VG_MEMORY_REALTIME ); } #endif /* VG_MEM_H */ -- 2.25.1