struct vg_async vg_async;
-enum vg_thread_purpose vg_thread_purpose(void);
-enum engine_status _vg_engine_status(void);
+u32 vg_thread_purpose(void);
vg_async_item *vg_async_alloc( u32 size )
{
/* ditch out here if engine crashed. this serves as the 'quit checking' */
- if( _vg_engine_status() == k_engine_status_crashed ){
+ if( SDL_AtomicGet( &vg.engine_status ) == k_engine_status_crashed )
longjmp( vg.env_loader_exit, 1 );
- }
- SDL_AtomicLock( &vg_async.sl_index );
+ SDL_LockMutex( vg_async.lock );
u32 total_allocation = vg_align8(size) + vg_align8(sizeof(vg_async_item)),
remaining = vg_linear_remaining( vg_async.buffer ),
if( total_allocation > capacity )
{
- SDL_AtomicUnlock( &vg_async.sl_index );
+ SDL_UnlockMutex( vg_async.lock );
vg_fatal_condition();
vg_info( "async alloc invalid size\n" );
vg_info( "Requested: %umb. Buffer size: %umb\n",
if( total_allocation > remaining )
{
- SDL_AtomicUnlock( &vg_async.sl_index );
+ SDL_UnlockMutex( vg_async.lock );
SDL_SemWait( vg_async.sem_wait_for_flush );
- SDL_AtomicLock( &vg_async.sl_index );
+ SDL_LockMutex( vg_async.lock );
remaining = vg_linear_remaining( vg_async.buffer );
capacity = vg_linear_get_capacity( vg_async.buffer );
vg_async.end = entry;
}
- SDL_AtomicUnlock( &vg_async.sl_index );
+ SDL_UnlockMutex( vg_async.lock );
return entry;
}
if( SDL_SemValue(vg_async.sem_wait_for_flush) )
SDL_SemWait(vg_async.sem_wait_for_flush);
- SDL_AtomicLock( &vg_async.sl_index );
+ SDL_LockMutex( vg_async.lock );
item->fn_runner = runner;
- SDL_AtomicUnlock( &vg_async.sl_index );
+ SDL_UnlockMutex( vg_async.lock );
}
void vg_async_call( void (*runner)( void *payload, u32 size ),
void vg_run_async_checked(void)
{
- SDL_AtomicLock( &vg_async.sl_index );
+ SDL_LockMutex( vg_async.lock );
while( vg_async.start )
{
}
else
{
- SDL_AtomicUnlock( &vg_async.sl_index );
+ SDL_UnlockMutex( vg_async.lock );
return;
}
}
SDL_SemPost( vg_async.sem_wait_for_flush );
}
- SDL_AtomicUnlock( &vg_async.sl_index );
+ SDL_UnlockMutex( vg_async.lock );
}
void vg_async_init(void)
{
+ vg_async.lock = SDL_CreateMutex();
+ VG_ASSERT( vg_async.lock );
+
vg_async.sem_wait_for_flush = SDL_CreateSemaphore(0);
- vg_async.buffer = vg_create_linear_allocator( NULL, 50*1024*1024,
- VG_MEMORY_SYSTEM );
+ VG_ASSERT( vg_async.sem_wait_for_flush );
+
+ vg_async.buffer = vg_create_linear_allocator( NULL, 50*1024*1024, VG_MEMORY_SYSTEM );
}
-/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved
+/* Copyright (C) 2021-2025 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
+ *
+ * TODO: Replace this with async2 in the future.
*/
#pragma once
#include "vg_engine.h"
-static void vg_assert_thread( enum vg_thread_purpose required );
+static void vg_assert_thread( u32 required );
typedef struct vg_async_item vg_async_item;
struct vg_async_item
vg_async_item *start, *end;
SDL_sem *sem_wait_for_flush;
- SDL_SpinLock sl_index;
+ SDL_mutex *lock;
}
extern vg_async;
/*
* Make a simple async call without allocating extra.
*/
-void vg_async_call( void (*runner)( void *payload, u32 size ),
- void *payload, u32 size );
+void vg_async_call( void (*runner)( void *payload, u32 size ), void *payload, u32 size );
/*
* Run as much of the async buffer as possible
/*
* Mark the call as being filled and ready to go
*/
-void vg_async_dispatch( vg_async_item *item,
- void (*runner)( void *payload, u32 size ) );
+void vg_async_dispatch( vg_async_item *item, void (*runner)( void *payload, u32 size ) );
/*
* Wait until the current stack of async calls is completely flushed out
static void vg_console_write_persistent(void)
{
- SDL_AtomicLock( &vg.sl_status );
- enum engine_status status = vg.engine_status;
- SDL_AtomicUnlock( &vg.sl_status );
+ enum engine_status status = SDL_AtomicGet( &vg.engine_status );
if( status < k_engine_status_running )
{
.time_fixed_delta = VG_TIMESTEP_FIXED,
};
-#include <string.h>
-#include "vg/vg_ui/imgui.c"
-#include "vg/vg_ui/imgui_impl_opengl.c"
-#include "vg/vg_default_font.gc"
+const u32 k_thread_purpose_nothing = 0x00;
+const u32 k_thread_purpose_main = 0x01;
+const u32 k_thread_purpose_loader = 0x02;
-enum engine_status _vg_engine_status(void)
+u32 vg_thread_purpose(void)
{
- SDL_AtomicLock( &vg.sl_status );
- enum engine_status status = vg.engine_status;
- SDL_AtomicUnlock( &vg.sl_status );
-
- return status;
+ return *((u32 *)SDL_TLSGet( vg.thread_purpose ));
}
-enum vg_thread_purpose vg_thread_purpose(void)
-{
- SDL_AtomicLock( &vg.sl_status );
-
- SDL_threadID id = SDL_GetThreadID(NULL);
- if( vg.thread_id_main == id )
- {
- SDL_AtomicUnlock( &vg.sl_status );
- return k_thread_purpose_main;
- }
- else if( vg.thread_id_loader == id )
- {
- SDL_AtomicUnlock( &vg.sl_status );
- return k_thread_purpose_loader;
- }
- else
- {
- SDL_AtomicUnlock( &vg.sl_status );
- return k_thread_purpose_nothing;
- }
-}
-
-static void _vg_opengl_sync_init(void)
-{
- vg.sem_loader = SDL_CreateSemaphore(1);
-}
+#include <string.h>
+#include "vg/vg_ui/imgui.c"
+#include "vg/vg_ui/imgui_impl_opengl.c"
+#include "vg/vg_default_font.gc"
#include "vg_console.h"
#include "vg_profiler.h"
{
vg_success( "Internal async setup complete\n" );
- SDL_AtomicLock( &vg.sl_status );
- if( vg.engine_status == k_engine_status_crashed )
- {
- SDL_AtomicUnlock( &vg.sl_status );
+ if( SDL_AtomicGet( &vg.engine_status ) == k_engine_status_crashed )
return;
- }
else
- vg.engine_status = k_engine_status_running;
- SDL_AtomicUnlock( &vg.sl_status );
+ SDL_AtomicSet( &vg.engine_status, k_engine_status_running );
vg_magi_restore();
}
vg_changevsync();
- enum engine_status status = _vg_engine_status();
+ enum engine_status status = SDL_AtomicGet( &vg.engine_status );
if( status == k_engine_status_running )
vg_profile_begin( &vg_prof_swap );
vg_magi_save();
vg_console_write_persistent();
- SDL_AtomicLock( &vg.sl_status );
- vg.engine_status = k_engine_status_none;
- SDL_AtomicUnlock( &vg.sl_status );
-
+ SDL_AtomicSet( &vg.engine_status, k_engine_status_none );
vg_loader_atexit();
SDL_GL_DeleteContext( vg.gl_context );
SDL_Quit();
-
- vg_success( "The program has terminated 'correctly'\n" );
exit(0);
}
static int cmd_vg_settings_toggle( int argc, const char *argv[] );
void vg_enter( int argc, char *argv[], const char *window_name )
{
+ vg.thread_purpose = SDL_TLSCreate();
+ VG_ASSERT( vg.thread_purpose );
+ SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_nothing, NULL );
+
vg_rand_seed( &vg.rand, 461 );
_vg_process_launch_opts_internal( argc, argv );
vg_async_init();
SDL_SetRelativeMouseMode(1);
- vg.thread_id_main = SDL_GetThreadID(NULL);
+ /* multi-threaded loading phase */
+ vg.sem_loader = SDL_CreateSemaphore(1);
+ VG_ASSERT( vg.sem_loader );
+ SDL_AtomicSet( &vg.engine_status, k_engine_status_load_internal );
+ SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_main, NULL );
/* Opengl-required systems */
vg_ui_init();
- vg.engine_status = k_engine_status_load_internal;
vg_loader_step( vg_loader_init, vg_loader_free );
- _vg_opengl_sync_init();
vg_loader_start( _vg_load_full, NULL );
_vg_gameloop();
_vg_terminate();
free( strings );
#endif
- SDL_AtomicLock( &vg.sl_status );
- vg.engine_status = k_engine_status_crashed;
- SDL_AtomicUnlock( &vg.sl_status );
+ SDL_AtomicSet( &vg.engine_status, k_engine_status_crashed );
if( vg_thread_purpose() == k_thread_purpose_loader )
{
k_quality_profile_min = 2
};
-enum vg_thread_purpose
+enum engine_status
{
- k_thread_purpose_nothing,
- k_thread_purpose_main,
- k_thread_purpose_loader
+ k_engine_status_none,
+ k_engine_status_load_internal,
+ k_engine_status_running,
+ k_engine_status_crashed
};
-
struct vg_engine
{
/* Engine sync */
SDL_GLContext gl_context;
SDL_sem *sem_loader; /* allows only one loader at a time */
- SDL_threadID thread_id_main,
- thread_id_loader;
+ SDL_TLSID thread_purpose;
- SDL_SpinLock sl_status;
+ //SDL_threadID thread_id_main,
+ // thread_id_loader;
jmp_buf env_loader_exit;
- void *thread_data;
+ void *thread_data;
- enum engine_status{
- k_engine_status_none,
- k_engine_status_load_internal,
- k_engine_status_running,
- k_engine_status_crashed
- }
- engine_status;
+ SDL_atomic_t engine_status;
/* Window information */
int window_x,
ui_rect inout_panel, bool validated );
enum engine_status _vg_engine_status(void);
-enum vg_thread_purpose vg_thread_purpose(void);
+
+
+extern const u32 k_thread_purpose_nothing;
+extern const u32 k_thread_purpose_main;
+extern const u32 k_thread_purpose_loader;
+u32 vg_thread_purpose(void);
void vg_checkgl( const char *src_info );
#define VG_STRINGIT( X ) #X
static int _vg_loader_thread( void *pfn )
{
- vg.thread_id_loader = SDL_GetThreadID(NULL);
+ SDL_TLSSet( vg.thread_purpose, &k_thread_purpose_loader, NULL );
if( setjmp( vg.env_loader_exit ) )
- {
- vg.thread_id_loader = 0;
return 0;
- }
/* Run client loader */
void (*call_func)(void *data) = pfn;
call_func( vg.thread_data );
SDL_SemPost( vg.sem_loader );
- vg.thread_id_loader = 0;
-
return 0;
}
vg_loader.step_buffer[ vg_loader.step_count ++ ] = step;
}
- SDL_AtomicLock( &vg.sl_status );
- enum engine_status status = vg.engine_status;
- SDL_AtomicUnlock( &vg.sl_status );
+ enum engine_status status = SDL_AtomicGet( &vg.engine_status );
if( status != k_engine_status_load_internal )
{
#include "vg_log.h"
#include "vg_string.h"
+#ifndef VG_ENGINE
+#include <pthread.h>
+#endif
+
struct vg_log vg_log;
static void _vg_log_append_line( const char *str )
printf( "SDL2 Error: %s\n", SDL_GetError() );
exit(-1);
}
+#else
+ if( pthread_mutex_init( &vg_log.lock, NULL ) )
+ exit(-1);
#endif
}
#ifdef VG_ENGINE
if( SDL_LockMutex( vg_log.mutex ) )
vg_fatal_error( "" );
+#else
+ pthread_mutex_lock( &vg_log.lock );
#endif
char buffer[4096], line[96];
- static char last_buffer[4096];
vsnprintf( buffer, VG_ARRAY_LEN(buffer), fmt, args );
int line_length = snprintf( line, 90, "%s%7s" KNRM "|%s ", colour, prefix, colour );
- strcpy( last_buffer, buffer );
for( u32 i=0; i<VG_ARRAY_LEN(buffer); i ++ )
{
#ifdef VG_ENGINE
if( SDL_UnlockMutex( vg_log.mutex ) )
vg_fatal_error( "" );
+#else
+ pthread_mutex_unlock( &vg_log.lock );
#endif
}
bool initialized;
#ifdef VG_ENGINE
SDL_mutex *mutex;
+#else
+ pthread_mutex_t lock;
#endif
}
extern vg_log;
* this should then only be checked and turned on in debugging.
*
*/
-void *_vg_create_linear_allocator( void *lin_alloc, u32 size,
- u16 flags, const char *constr_name)
+void *_vg_create_linear_allocator( void *lin_alloc, u32 size, u16 flags, const char *constr_name)
{
VG_ASSERT( sizeof( vg_linear_allocator ) == 32 );
vg_linear_allocator *alloc = vg_linear_header( lin_alloc );
if( alloc->cur + block_size > alloc->size )
- vg_fatal_error( "Out of memory (%u + %u > %u)\n",
- alloc->cur, block_size, alloc->size );
+ vg_fatal_error( "Out of memory (%u + %u > %u)\n", alloc->cur, block_size, alloc->size );
if( alloc->allocation_count + 1 > VG_MAX_ALLOCATIONS )
- vg_fatal_error( "Exceeded max allocations in linear allocator (%u)\n",
- VG_MAX_ALLOCATIONS );
+ vg_fatal_error( "Exceeded max allocations in linear allocator (%u)\n", VG_MAX_ALLOCATIONS );
if( (flags && VG_MEMORY_SYSTEM) && (alloc->flags & VG_MEMORY_REALTIME) )
- vg_fatal_error( "Cannot declare realtime allocator inside systems "
- "allocator");
+ vg_fatal_error( "Cannot declare realtime allocator inside systems allocator");
if( vg_mem.use_libc_malloc ){
vg_allocation_meta *meta =
tail->prev_size = 0;
}
+u32 vg_queue_item_size( vg_queue *q, u32 item_id )
+{
+ vg_queue_item *item = q->buffer + item_id;
+ return item->alloc_size;
+}
+
bool vg_queue_previous( vg_queue *q, u32 item_id, u32 *out_prev )
{
vg_queue_item *item = q->buffer + item_id;
else return 0;
}
-u32 vg_queue_item_size( vg_queue *q, u32 item_id )
-{
- vg_queue_item *item = q->buffer + item_id;
- return item->alloc_size;
-}
-
bool vg_queue_next( vg_queue *q, u32 item_id, u32 *out_next )
{
if( item_id != q->head_offset )
else
return 0;
}
+
+void vg_queue_clear( vg_queue *q )
+{
+ q->head_offset = 0;
+ q->tail_offset = 0;
+ q->allocation_count = 0;
+}
void vg_queue_memcpy( vg_queue *q, void *dst, u32 start, u32 size );
u32 vg_queue_usage( vg_queue *q );
+void vg_queue_clear( vg_queue *q );