Allocators
There are multiple different allocators available for use and also already in use by the engine itself. This document explains all available allocators and when to use which.
Linear allocator
The linear allocator is mostly used as a per-frame allocator. It works by allocating a configured amount of bytes up front and when the allocate function is called, it just assignes and returns the requested amount from the already allocated memory pool. This is very handy for a per-frame allocation system, because in the beginning of each frame the memory is reset by zeroing out the entire pool, and the next frame can use the same pool without any re-allocation.
Use cases
One use case is the per-frame allocator, but that's already in place and the client is not required to make another use of this allocator, as he can already just use the existing one.
Another use case might be, if the amount of bytes needed is already known up-front, in case of loading documents or regular binary files for example. In these cases the client could make use of a linear allocator, reducing the calls to the OS and basically only requesting memory of the OS once.
Example usage
General usage
void foo()
{
// Creation
fake_linear_allocator allocator = {0};
// The entire size of the pool
// |
if (!fake_linear_allocator_create(MEGABYTES(512), &allocator))
{
// Error: Failed to create allocator, might not have enough space on the system
return;
}
// Requesting memory
void *assigned_memory_block = fake_linear_allocator_allocate(&allocator, MEGABYTES(10));
// Resetting the memory pool, by zeroing out the entire pool and not freeing it
fake_linear_allocator_free_all(&allocator, true);
// Destroying the entire pool, freeing the entire pool
fake_linear_allocator_destroy(&allocator);
}
Usage of the existing allocator in the client application
b8 application_boot(struct fake_application *app_inst)
{
// This sets the entire size of the memory pool for the linear allocator.
config->frame_allocator_size = MEBIBYTES(64);
// ...
return true;
}
// In each of those functions you can use:
// void *assigned_memory_block = fake_engine_frame_allocator_allocate(<size>);
b8 application_update(struct fake_application *app_inst, struct fake_frame_data *p_frame_data)
{
// ...
return true;
}
b8 application_prepare_frame(struct fake_application *app_inst, struct fake_frame_data *p_frame_data)
{
// ...
return true;
}
b8 application_render_frame(struct fake_application *app_inst, struct fake_frame_data *p_frame_data)
{
// ...
return true;
}
In the client application you are not allowed to call fake_linear_allocator_free_all, as this is already called by the engine in the game loop at the beginning of each frame.
If you call it anyway, it will result in some errors in the log, as other subsystems also use this allocator and require the data.
Dynamic allocator
The dynamic allocator makes use of a Freelist, to maintain a list of available memory blocks. It can also allocate in an aligned matter