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
;
29 struct vg_allocation_meta
34 k_allocation_type_block
= 0,
35 k_allocation_type_linear
= 1
40 #define VG_MEMORY_SYSTEM 0x1 /* systems memory, slow and low counts */
41 #define VG_MEMORY_REALTIME 0x2 /* per-frame. no max allocs, only size. fast */
43 /* systems memory cannot be declared inside realtime memory regions */
46 * Stored just behind the array. 32 bytes.
49 struct vg_linear_allocator
57 vg_allocation_meta
*alloc_table
;
60 /* 32 bit pointers! */
66 VG_STATIC
void vg_fatal_error( const char *fmt
, ... );
67 VG_STATIC
void vg_error(const char *fmt
, ...);
68 VG_STATIC
void vg_info(const char *fmt
, ...);
70 VG_STATIC u32
vg_align8( u32 s
)
76 VG_STATIC u32
vg_align4( u32 s
)
82 /* Returns allocator structure from data pointer */
83 static vg_linear_allocator
*vg_linear_header( void *data
)
85 vg_linear_allocator
*ptr
= data
;
91 /* allocate something from a linear allocator */
92 __attribute__((warn_unused_result
))
93 VG_STATIC
void *vg_linear_alloc( void *buffer
, u32 size
)
96 vg_error( "alloc(%u) is not 8 byte aligned\n", size
);
98 size
= vg_align8( size
);
101 if( ((u32
)buffer
) % 8 ){
103 if( ((u64
)buffer
) % 8 ){
105 vg_fatal_error( "unaligned buffer (%p)", buffer
);
108 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
110 if( (alloc
->cur
+ size
) > alloc
->size
){
111 vg_fatal_error( "linear allocator overflow (%u + %u > %u)\n",
112 alloc
->cur
, size
, alloc
->size
);
115 if( alloc
->flags
& VG_MEMORY_SYSTEM
)
116 if( (alloc
->allocation_count
+ 1) > VG_MAX_ALLOCATIONS
)
117 vg_fatal_error( "Max linear allocations reached" );
121 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
122 data
= malloc( size
);
124 vg_allocation_meta
*meta
= &alloc
->alloc_table
[ alloc
->allocation_count
];
125 meta
->type
= k_allocation_type_block
;
129 data
= buffer
+ alloc
->cur
;
133 for( u32 i
=0; i
<size
; i
++ ){
137 alloc
->allocation_count
++;
138 alloc
->last_alloc
= data
;
139 alloc
->last_alloc_size
= size
;
143 if( ((u32
)data
) % 8 ){
145 if( ((u64
)data
) % 8 ){
147 vg_fatal_error( "unaligned" );
153 /* resize latest block of memory from linear */
154 __attribute__((warn_unused_result
))
155 VG_STATIC
void *vg_linear_resize( void *buffer
, void *data
, u32 newsize
)
157 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
160 vg_error( "alloc(%u) is not 8 byte aligned\n", newsize
);
161 vg_print_backtrace();
162 newsize
= vg_align8( newsize
);
165 if( alloc
->last_alloc
!= data
)
166 vg_fatal_error( "This block has been fixed!" );
168 if( (alloc
->cur
- alloc
->last_alloc_size
+ newsize
) > alloc
->size
)
169 vg_fatal_error( "Cannot resize, overflow" );
171 alloc
->cur
-= alloc
->last_alloc_size
;
172 alloc
->cur
+= newsize
;
173 alloc
->last_alloc_size
= newsize
;
175 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
176 data
= realloc( data
, newsize
);
178 vg_fatal_error( "realloc failed" );
180 alloc
->alloc_table
[ alloc
->allocation_count
-1 ].data
= data
;
181 alloc
->last_alloc
= data
;
189 /* its possible to delete just the last item */
190 VG_STATIC
void vg_linear_del( void *buffer
, void *data
)
192 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
194 if( alloc
->last_alloc
!= data
){
195 vg_fatal_error( "This block has been fixed! Last alloc: %p, this: %p\n",
196 alloc
->last_alloc
, data
);
199 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
200 vg_allocation_meta
*meta
= &alloc
->alloc_table
[alloc
->allocation_count
-1];
201 if( meta
->type
== k_allocation_type_linear
)
202 vg_fatal_error( "Cannot free a linear allocator in this conext" );
207 alloc
->allocation_count
--;
208 alloc
->cur
-= alloc
->last_alloc_size
;
209 alloc
->last_alloc
= NULL
;
210 alloc
->last_alloc_size
= 0;
213 /* extend latest block of memory from linear */
214 __attribute__((warn_unused_result
))
215 VG_STATIC
void *vg_linear_extend( void *buffer
, void *data
, u32 extra
)
218 return vg_linear_alloc( buffer
, extra
);
220 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
222 if( alloc
->last_alloc
!= data
)
223 vg_fatal_error( "This block has been fixed!" );
225 u32 new_size
= alloc
->last_alloc_size
+ extra
;
226 return vg_linear_resize( buffer
, data
, new_size
);
229 /* get the current usage of allocator */
230 VG_STATIC u32
vg_linear_get_cur( void *buffer
)
232 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
236 /* get the capacity of allocator. */
237 VG_STATIC u32
vg_linear_get_capacity( void *buffer
)
239 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
243 /* get the remaining size of the allocator */
244 VG_STATIC u32
vg_linear_remaining( void *buffer
)
246 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
247 return alloc
->size
- alloc
->cur
;
250 /* yeet all memory from linear allocator */
251 VG_STATIC
void vg_linear_clear( void *buffer
)
253 vg_linear_allocator
*alloc
= vg_linear_header( buffer
);
255 /* libc mode we recursively free any allocations made */
256 if( vg_mem
.use_libc_malloc
&& (alloc
->flags
& VG_MEMORY_SYSTEM
) ){
257 for( u32 i
=0; i
<alloc
->allocation_count
; i
++ ){
258 vg_allocation_meta
*meta
= &alloc
->alloc_table
[i
];
260 if( meta
->type
== k_allocation_type_block
){
264 vg_linear_clear( meta
->data
);
265 vg_linear_allocator
*sub
= vg_linear_header( meta
->data
);
267 free( sub
->alloc_table
);
273 alloc
->last_alloc
= NULL
;
274 alloc
->last_alloc_size
= 0;
275 alloc
->allocation_count
= 0;
279 /* allocate a FIXED SIZE linear allocator */
280 VG_STATIC
void *vg_create_linear_allocator( void *lin_alloc
, u32 size
,
283 assert( sizeof( vg_linear_allocator
) == 32 );
285 vg_linear_allocator
*header
;
286 u32 block_size
= size
+ sizeof(vg_linear_allocator
);
288 /* Creating it inside an existing one */
290 vg_linear_allocator
*alloc
= vg_linear_header( lin_alloc
);
292 if( alloc
->cur
+ block_size
> alloc
->size
)
293 vg_fatal_error( "Out of memory" );
295 if( alloc
->allocation_count
+ 1 > VG_MAX_ALLOCATIONS
)
296 vg_fatal_error( "Max allocations in linear allocator" );
298 if( (flags
&& VG_MEMORY_SYSTEM
) && (alloc
->flags
& VG_MEMORY_REALTIME
) )
299 vg_fatal_error( "Cannot declare realtime allocator inside systems"
302 if( vg_mem
.use_libc_malloc
){
303 vg_allocation_meta
*meta
=
304 &alloc
->alloc_table
[ alloc
->allocation_count
];
306 if( flags
& VG_MEMORY_REALTIME
)
307 header
= malloc( block_size
);
309 header
= malloc( sizeof(vg_linear_allocator
) );
311 meta
->data
= header
+1;
312 meta
->type
= k_allocation_type_linear
;
315 header
= lin_alloc
+ alloc
->cur
;
318 alloc
->cur
+= block_size
;
319 alloc
->last_alloc
= header
;
320 alloc
->last_alloc_size
= block_size
;
321 alloc
->allocation_count
++;
324 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) )
325 header
= malloc( sizeof(vg_linear_allocator
) );
327 header
= malloc( block_size
);
330 header
->allocation_count
= 0;
332 header
->last_alloc
= NULL
;
333 header
->last_alloc_size
= 0;
335 header
->flags
= flags
;
337 if( vg_mem
.use_libc_malloc
&& (flags
& VG_MEMORY_SYSTEM
) ){
338 u32 table_size
= sizeof(vg_allocation_meta
)*VG_MAX_ALLOCATIONS
;
339 header
->alloc_table
= malloc( table_size
);
342 header
->alloc_table
= NULL
;
347 /* request all the memory we need in advance */
348 VG_STATIC
void vg_set_mem_quota( u32 size
)
353 VG_STATIC
void vg_alloc_quota(void)
355 u32 size_scratch
= 10*1024*1024;
356 u32 size
= VG_MAX( vg_mem
.quota
, size_scratch
);
358 vg_mem
.rtmemory
= vg_create_linear_allocator( NULL
, size
, VG_MEMORY_SYSTEM
);
359 vg_mem
.scratch
= vg_create_linear_allocator( vg_mem
.rtmemory
,
364 #endif /* VG_MEM_H */