#include "vg_m.h"
#include "vg_io.h"
#include "vg_log.h"
+ #include "vg_async.h"
#include "vg_steam.h"
//#define VG_SYNC_DEBUG
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();
/* 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)
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 )
/* 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);
--- /dev/null
+/* 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 */