6 #include "vg_platform.h"
11 VG_STATIC
void vg_print_backtrace(void);
13 #define VG_MAX_ALLOCATIONS 128
14 #define VG_FUZZ_ALLOCATIONS
16 typedef struct vg_linear_allocator vg_linear_allocator
;
17 typedef struct vg_allocation_meta vg_allocation_meta
;
30 struct vg_allocation_meta
35 k_allocation_type_block
= 0,
36 k_allocation_type_linear
= 1
41 #define VG_MEMORY_SYSTEM 0x1 /* systems memory, slow and low counts */
42 #define VG_MEMORY_REALTIME 0x2 /* per-frame. no max allocs, only size. fast */
44 /* systems memory cannot be declared inside realtime memory regions */
47 * Stored just behind the array. 32 bytes.
50 struct vg_linear_allocator
76 vg_allocation_meta
*alloc_table
;
86 /* 32 bit pointers! */
92 VG_STATIC
void vg_fatal_exit_loop( const char *error
);
93 VG_STATIC
void vg_error(const char *fmt
, ...);
94 VG_STATIC
void vg_info(const char *fmt
, ...);
96 VG_STATIC u32
vg_align8( u32 s
)
102 VG_STATIC u32
vg_align4( u32 s
)
104 u32 m
= (s
+ 3) >> 2;
108 /* Returns allocator structure from data pointer */
109 static vg_linear_allocator
*vg_linear_header( void *data
)
111 vg_linear_allocator
*ptr
= data
;
117 /* allocate something from a linear allocator */
118 __attribute__((warn_unused_result
))
119 VG_STATIC
void *vg_linear_alloc( void *buffer
, u32 size
)
122 vg_error( "alloc(%u) is not 8 byte aligned\n", size
);
123 vg_print_backtrace();
124 size
= vg_align8( size
);
127 if( ((u32
)buffer
) % 8 ){
129 if( ((u64
)buffer
) % 8 ){
131 vg_error( "buffer: %p\n", buffer
);
132 vg_fatal_exit_loop( "unaligned buffer" );
135 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
137 if( (alloc
->cur
+ size
) > alloc
->size
){
138 vg_error( "%u + %u > %u\n", alloc
->cur
, size
, alloc
->size
);
139 vg_fatal_exit_loop( "linear allocator overflow" );
142 if( alloc
->flags
& VG_MEMORY_SYSTEM
)
143 if( (alloc
->allocation_count
+ 1) > VG_MAX_ALLOCATIONS
)
144 vg_fatal_exit_loop( "Max linear allocations reached" );
148 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
149 data
= malloc( size
);
151 vg_allocation_meta
*meta
= &alloc
->alloc_table
[ alloc
->allocation_count
];
152 meta
->type
= k_allocation_type_block
;
156 data
= buffer
+ alloc
->cur
;
160 for( u32 i
=0; i
<size
; i
++ ){
164 alloc
->allocation_count
++;
165 alloc
->last_alloc
= data
;
166 alloc
->last_alloc_size
= size
;
170 if( ((u32
)data
) % 8 ){
172 if( ((u64
)data
) % 8 ){
174 vg_fatal_exit_loop( "unaligned" );
180 /* resize latest block of memory from linear */
181 __attribute__((warn_unused_result
))
182 VG_STATIC
void *vg_linear_resize( void *buffer
, void *data
, u32 newsize
)
184 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
187 vg_error( "alloc(%u) is not 8 byte aligned\n", newsize
);
188 vg_print_backtrace();
189 newsize
= vg_align8( newsize
);
192 if( alloc
->last_alloc
!= data
)
193 vg_fatal_exit_loop( "This block has been fixed!" );
195 if( (alloc
->cur
- alloc
->last_alloc_size
+ newsize
) > alloc
->size
)
196 vg_fatal_exit_loop( "Cannot resize, overflow" );
198 alloc
->cur
-= alloc
->last_alloc_size
;
199 alloc
->cur
+= newsize
;
200 alloc
->last_alloc_size
= newsize
;
202 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
203 data
= realloc( data
, newsize
);
205 vg_fatal_exit_loop( "realloc failed" );
207 alloc
->alloc_table
[ alloc
->allocation_count
-1 ].data
= data
;
208 alloc
->last_alloc
= data
;
216 /* its possible to delete just the last item */
217 VG_STATIC
void vg_linear_del( void *buffer
, void *data
)
219 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
221 if( alloc
->last_alloc
!= data
)
222 vg_fatal_exit_loop( "This block has been fixed!" );
224 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
225 vg_allocation_meta
*meta
= &alloc
->alloc_table
[alloc
->allocation_count
-1];
226 if( meta
->type
== k_allocation_type_linear
)
227 vg_fatal_exit_loop( "Cannot free a linear allocator in this conext" );
232 alloc
->allocation_count
--;
233 alloc
->cur
-= alloc
->last_alloc_size
;
234 alloc
->last_alloc
= NULL
;
235 alloc
->last_alloc_size
= 0;
238 /* extend latest block of memory from linear */
239 __attribute__((warn_unused_result
))
240 VG_STATIC
void *vg_linear_extend( void *buffer
, void *data
, u32 extra
)
243 return vg_linear_alloc( buffer
, extra
);
245 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
247 if( alloc
->last_alloc
!= data
)
248 vg_fatal_exit_loop( "This block has been fixed!" );
250 u32 new_size
= alloc
->last_alloc_size
+ extra
;
251 return vg_linear_resize( buffer
, data
, new_size
);
254 /* get the current usage of allocator */
255 VG_STATIC u32
vg_linear_get_cur( void *buffer
)
257 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
261 /* get the capacity of allocator. */
262 VG_STATIC u32
vg_linear_get_capacity( void *buffer
)
264 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
268 /* get the remaining size of the allocator */
269 VG_STATIC u32
vg_linear_remaining( void *buffer
)
271 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
272 return alloc
->size
- alloc
->cur
;
275 /* yeet all memory from linear allocator */
276 VG_STATIC
void vg_linear_clear( void *buffer
)
278 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
280 /* libc mode we recursively free any allocations made */
281 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
282 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ ){
283 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
285 if( meta
->type
== k_allocation_type_block
){
289 vg_linear_clear( meta
->data
);
290 vg_linear_allocator
*sub
= vg_linear_header( meta
->data
);
292 free( sub
->alloc_table
);
298 alloc
->last_alloc
= NULL
;
299 alloc
->last_alloc_size
= 0;
300 alloc
->allocation_count
= 0;
304 /* allocate a FIXED SIZE linear allocator */
305 VG_STATIC
void *vg_create_linear_allocator( void *lin_alloc
, u32 size
,
308 assert( sizeof( vg_linear_allocator
) == 32 );
310 vg_linear_allocator
*header
;
311 u32 block_size
= size
+ sizeof(vg_linear_allocator
);
313 /* Creating it inside an existing one */
315 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
317 if( alloc
->cur
+ block_size
> alloc
->size
)
318 vg_fatal_exit_loop( "Out of memory" );
320 if( alloc
->allocation_count
+ 1 > VG_MAX_ALLOCATIONS
)
321 vg_fatal_exit_loop( "Max allocations in linear allocator" );
323 if( (flags
&& VG_MEMORY_SYSTEM
) && (alloc
->flags
& VG_MEMORY_REALTIME
) )
324 vg_fatal_exit_loop( "Cannot declare realtime allocator inside systems"
327 if( vg_mem
.use_libc_malloc
){
328 vg_allocation_meta
*meta
=
329 &alloc
->alloc_table
[ alloc
->allocation_count
];
331 if( flags
& VG_MEMORY_REALTIME
)
332 header
= malloc( block_size
);
334 header
= malloc( sizeof(vg_linear_allocator
) );
336 meta
->data
= header
+1;
337 meta
->type
= k_allocation_type_linear
;
340 header
= lin_alloc
+ alloc
->cur
;
343 alloc
->cur
+= block_size
;
344 alloc
->last_alloc
= NULL
; /* cant resize this block! */
345 alloc
->last_alloc_size
= block_size
;
347 alloc
->allocation_count
++;
350 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
351 header
= malloc( sizeof(vg_linear_allocator
) );
353 header
= malloc( block_size
);
356 header
->allocation_count
= 0;
358 header
->last_alloc
= NULL
;
359 header
->last_alloc_size
= 0;
361 header
->flags
= flags
;
363 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) ){
364 u32 table_size
= sizeof(vg_allocation_meta
)*VG_MAX_ALLOCATIONS
;
365 header
->alloc_table
= malloc( table_size
);
368 header
->alloc_table
= NULL
;
373 /* request all the memory we need in advance */
374 VG_STATIC
void vg_set_mem_quota( u32 size
)
379 VG_STATIC
void vg_alloc_quota(void)
381 u32 size_scratch
= 10*1024*1024;
382 u32 size
= VG_MAX( vg_mem
.quota
, size_scratch
);
384 vg_mem
.rtmemory
= vg_create_linear_allocator( NULL
, size
, VG_MEMORY_SYSTEM
);
385 vg_mem
.scratch
= vg_create_linear_allocator( vg_mem
.rtmemory
,
389 vg_mem
.async
= vg_create_linear_allocator( NULL
, 50*1024*1024,
390 VG_MEMORY_REALTIME
);
393 #endif /* VG_MEM_H */