1 /* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved
3 * primateves that you use when you need to run something from another thread
4 * back in the main loop of vg, at the start of each frame
12 typedef struct vg_async_item vg_async_item
;
20 void (*fn_runner
)( void *payload
, u32 size
);
26 vg_async_item
*start
, *end
;
28 SDL_sem
*sem_wait_for_flush
;
29 SDL_SpinLock sl_index
;
34 * Allocate an asynchronous call with a bit of memory
36 VG_STATIC vg_async_item
*vg_async_alloc( u32 size
)
38 SDL_AtomicLock( &vg_async
.sl_index
);
40 u32 total_allocation
= vg_align8(size
) + vg_align8(sizeof(vg_async_item
)),
41 remaining
= vg_linear_remaining( vg_async
.buffer
),
42 capacity
= vg_linear_get_capacity( vg_async
.buffer
);
44 if( total_allocation
> capacity
){
45 SDL_AtomicUnlock( &vg_async
.sl_index
);
46 vg_error( "Requested: %umb. Buffer size: %umb\n",
47 (total_allocation
/1024)/1024,
48 (capacity
/1024)/1024 );
49 vg_fatal_exit_loop( "async alloc invalid size\n" );
52 if( total_allocation
> remaining
){
53 SDL_AtomicUnlock( &vg_async
.sl_index
);
54 SDL_SemWait( vg_async
.sem_wait_for_flush
);
55 SDL_AtomicLock( &vg_async
.sl_index
);
57 remaining
= vg_linear_remaining( vg_async
.buffer
);
58 capacity
= vg_linear_get_capacity( vg_async
.buffer
);
60 assert( remaining
== capacity
);
61 assert( vg_async
.start
== NULL
);
62 assert( vg_async
.end
== NULL
);
65 void *block
= vg_linear_alloc( vg_async
.buffer
, total_allocation
);
67 vg_async_item
*entry
= block
;
69 entry
->payload
= ((u8
*)block
) + vg_align8(sizeof(vg_async_item
));
71 entry
->fn_runner
= NULL
;
74 vg_async
.end
->next
= entry
;
77 vg_async
.start
= entry
;
81 SDL_AtomicUnlock( &vg_async
.sl_index
);
87 * Mark the call as being filled and ready to go
89 VG_STATIC
void vg_async_dispatch( vg_async_item
*item
,
90 void (*runner
)( void *payload
, u32 size
) )
92 SDL_AtomicLock( &vg_async
.sl_index
);
93 item
->fn_runner
= runner
;
94 SDL_AtomicUnlock( &vg_async
.sl_index
);
98 * Run as much of the async buffer as possible
100 VG_STATIC
void vg_run_async_checked(void)
102 SDL_AtomicLock( &vg_async
.sl_index
);
104 while( vg_async
.start
){
105 vg_async_item
*entry
= vg_async
.start
;
107 if( entry
->fn_runner
){
108 entry
->fn_runner( entry
->payload
, entry
->size
);
109 vg_async
.start
= entry
->next
;
111 if( vg_async
.start
== NULL
){
114 vg_linear_clear( vg_async
.buffer
);
116 if( !SDL_SemValue( vg_async
.sem_wait_for_flush
) ){
117 SDL_SemPost( vg_async
.sem_wait_for_flush
);
125 /* TODO: if exceed max frametime.... */
128 SDL_AtomicUnlock( &vg_async
.sl_index
);
131 VG_STATIC
void vg_async_init(void)
133 vg_async
.sem_wait_for_flush
= SDL_CreateSemaphore(0);
134 vg_async
.buffer
= vg_create_linear_allocator( NULL
, 50*1024*1024,
135 VG_MEMORY_REALTIME
);
138 #endif /* VG_ASYNC_H */