X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_async.h;fp=vg_async.h;h=e0a252806b6dbdf02bf583e10d6cfce151f173ab;hp=b3c8a0af09fecd21c28f505c7bdc4d46e05c0426;hb=3b14f3dcd5bf9dd3c85144f2123d667bfa4bb63f;hpb=fce86711735b15bff37de0f70716808410fcf269 diff --git a/vg_async.h b/vg_async.h index b3c8a0a..e0a2528 100644 --- a/vg_async.h +++ b/vg_async.h @@ -1,18 +1,15 @@ -/* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved +/* Copyright (C) 2021-2024 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 +#pragma once +#include "vg_engine.h" -#define VG_GAME -#include "vg/vg.h" static void vg_assert_thread( enum vg_thread_purpose required ); typedef struct vg_async_item vg_async_item; - struct vg_async_item{ vg_async_item *next; @@ -22,7 +19,8 @@ struct vg_async_item{ void (*fn_runner)( void *payload, u32 size ); }; -struct vg_async{ +struct vg_async +{ void *buffer; vg_async_item *start, *end; @@ -30,157 +28,23 @@ struct vg_async{ SDL_sem *sem_wait_for_flush; SDL_SpinLock sl_index; } -static vg_async; - -static enum vg_thread_purpose vg_thread_purpose(void); -static enum engine_status _vg_engine_status(void); - -/* - * Allocate an asynchronous call with a bit of memory - */ -static 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 ){ - assert( vg_thread_purpose() == k_thread_purpose_loader ); - longjmp( vg.env_loader_exit, 1 ); - } - - 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_error( "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 ); +extern vg_async; - remaining = vg_linear_remaining( vg_async.buffer ); - capacity = vg_linear_get_capacity( vg_async.buffer ); +/* TODO: Docu */ - 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; - - if( size ) entry->payload = ((u8*)block) + vg_align8(sizeof(vg_async_item)); - else entry->payload = NULL; - - 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; -} - -/* - * Wait until the current stack of async calls is completely flushed out - */ -static void vg_async_stall(void){ - vg_assert_thread(k_thread_purpose_loader); -#if 0 - vg_info( "async_stall: %d\n", SDL_SemValue( vg_async.sem_wait_for_flush ) ); -#endif - SDL_SemWait( vg_async.sem_wait_for_flush ); -} +void vg_async_call( void (*runner)( void *payload, u32 size ), + void *payload, u32 size ); +void vg_run_async_checked(void); +void vg_async_init(void); +vg_async_item *vg_async_alloc( u32 size ); /* * Mark the call as being filled and ready to go */ -static void vg_async_dispatch( vg_async_item *item, - void (*runner)( void *payload, u32 size ) ) -{ - vg_assert_thread(k_thread_purpose_loader); - if( SDL_SemValue(vg_async.sem_wait_for_flush) ) - SDL_SemWait(vg_async.sem_wait_for_flush); - - SDL_AtomicLock( &vg_async.sl_index ); - item->fn_runner = runner; - SDL_AtomicUnlock( &vg_async.sl_index ); -} - -/* - * Make a simple async call without allocating extra. - */ -static void vg_async_call( void (*runner)( void *payload, u32 size ), - void *payload, u32 size ) -{ - vg_assert_thread(k_thread_purpose_loader); - vg_async_item *call = vg_async_alloc(0); - call->payload = payload; - call->size = size; - vg_async_dispatch( call, runner ); -} +void vg_async_dispatch( vg_async_item *item, + void (*runner)( void *payload, u32 size ) ); /* - * Run as much of the async buffer as possible + * Wait until the current stack of async calls is completely flushed out */ -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{ - SDL_AtomicUnlock( &vg_async.sl_index ); - return; - } - - /* TODO: if exceed max frametime.... */ - } - - if( !SDL_SemValue( vg_async.sem_wait_for_flush ) ){ - SDL_SemPost( vg_async.sem_wait_for_flush ); - } - - SDL_AtomicUnlock( &vg_async.sl_index ); -} - -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_SYSTEM ); -} - -#endif /* VG_ASYNC_H */ +void vg_async_stall(void);