basic async mechanism
authorhgn <hgodden00@gmail.com>
Sun, 23 Apr 2023 09:34:58 +0000 (10:34 +0100)
committerhgn <hgodden00@gmail.com>
Sun, 23 Apr 2023 09:34:58 +0000 (10:34 +0100)
submodules/SDL
vg.h
vg_async.h [new file with mode: 0644]
vg_log.h
vg_mem.h

index eef4d3c86a653f91b7221c80809ba8ab56f94cf1..06492c598158cf825a18aececaf7511d7fd04f48 160000 (submodule)
@@ -1 +1 @@
-Subproject commit eef4d3c86a653f91b7221c80809ba8ab56f94cf1
+Subproject commit 06492c598158cf825a18aececaf7511d7fd04f48
diff --git a/vg.h b/vg.h
index f6c5bb672566578023264c95afd256627a14a0fa..7ddd04ef839871dc19b845c60a23d7a02043ec78 100644 (file)
--- 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 (file)
index 0000000..366f448
--- /dev/null
@@ -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 */
index 7c6ea43c79dd47f6b60a7494eed00aaaaa66db39..04390697f06be444833a5574651c43ef41674ab1 100644 (file)
--- 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, ...)    \
 {                                            \
index 8f3da6361396d97577c1334e401bf1b251462206..49d9e37e86b8af8d515a64a164d64873e6d6f59f 100644 (file)
--- 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 */