base_math, only has Vec2 and Vec3; memory arena implementation with support for windows right now.
This commit is contained in:
parent
9e1e4c2c5c
commit
8b7af0c1ec
127
src/base/base_arena.c
Normal file
127
src/base/base_arena.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
internal Arena *arena_alloc_(ArenaParams *params) {
|
||||||
|
u64 reserve_size = params->reserve_size;
|
||||||
|
u64 commit_size = params->commit_size;
|
||||||
|
|
||||||
|
if (params->flags & ArenaFlag_LargePages) {
|
||||||
|
reserve_size = AlignPow2(reserve_size, os_get_system_info()->large_page_size);
|
||||||
|
commit_size = AlignPow2(commit_size, os_get_system_info()->large_page_size);
|
||||||
|
} else {
|
||||||
|
reserve_size = AlignPow2(reserve_size, os_get_system_info()->page_size);
|
||||||
|
commit_size = AlignPow2(commit_size, os_get_system_info()->page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reserve/commit initial block of memory
|
||||||
|
void *base = params->optional_backing_buffer;
|
||||||
|
if (base == 0) {
|
||||||
|
if (params->flags & ArenaFlag_LargePages) {
|
||||||
|
base = os_reserve_large(reserve_size);
|
||||||
|
os_commit_large(base, commit_size);
|
||||||
|
} else {
|
||||||
|
base = os_reserve(reserve_size);
|
||||||
|
os_commit(base, commit_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena *arena = (Arena *)base;
|
||||||
|
arena->current = arena; // Current arena in the chain
|
||||||
|
arena->flags = params->flags;
|
||||||
|
arena->commit_size = (u32)params->commit_size;
|
||||||
|
arena->reserve_size = params->reserve_size;
|
||||||
|
arena->base_position = 0;
|
||||||
|
arena->position = ARENA_HEADER_SIZE;
|
||||||
|
arena->commit = commit_size;
|
||||||
|
arena->reserve = reserve_size;
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void arena_release(Arena *arena) {
|
||||||
|
for (Arena *current_arena = arena->current, *previous_arena = 0; current_arena != 0; current_arena = previous_arena) {
|
||||||
|
previous_arena = current_arena->previous;
|
||||||
|
os_release(current_arena, current_arena->reserve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *arena_push(Arena *arena, u64 size_to_push, u64 align) {
|
||||||
|
Arena *current_arena = arena->current;
|
||||||
|
u64 position_pre_push = AlignPow2(current_arena->position, align); // position of arena before push
|
||||||
|
u64 position_post_push = position_pre_push + size_to_push; // position of arena after push
|
||||||
|
|
||||||
|
// ??(tijani): chain, if needed
|
||||||
|
if (current_arena->reserve < position_post_push && !(arena->flags & ArenaFlag_NoChain)) {
|
||||||
|
u64 new_reserve_size = current_arena->reserve_size;
|
||||||
|
u64 new_commit_size = current_arena->commit_size;
|
||||||
|
|
||||||
|
if (size_to_push > new_reserve_size) {
|
||||||
|
new_reserve_size = size_to_push + ARENA_HEADER_SIZE;
|
||||||
|
new_commit_size = size_to_push + ARENA_HEADER_SIZE;
|
||||||
|
}
|
||||||
|
Arena *new_memory_block =
|
||||||
|
arena_alloc(.reserve_size = new_reserve_size, .commit_size = new_commit_size, .flags = current_arena->flags);
|
||||||
|
new_memory_block->base_position = current_arena->base_position + current_arena->reserve;
|
||||||
|
SLLStackPush_N(arena->current, new_memory_block, previous); // `previous` refers to `previous` in `Arena` struct
|
||||||
|
current_arena = new_memory_block;
|
||||||
|
position_pre_push = AlignPow2(current_arena->position, align);
|
||||||
|
position_post_push = position_pre_push + size_to_push;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ??(tijani): commit new page, if needed
|
||||||
|
if (current_arena->commit < position_post_push && !(current_arena->flags & ArenaFlag_LargePages)) {
|
||||||
|
u64 commit_post_aligned = AlignPow2(position_post_push, current_arena->commit_size);
|
||||||
|
u64 commit_post_clamped = ClampTop(commit_post_aligned, current_arena->reserve);
|
||||||
|
u64 new_commit_size = commit_post_clamped - current_arena->commit;
|
||||||
|
os_commit((u8 *)current_arena + current_arena->commit, new_commit_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// push onto the current block
|
||||||
|
void *memory = 0;
|
||||||
|
if (current_arena->commit >= position_post_push) {
|
||||||
|
memory = (u8 *)current_arena + position_pre_push;
|
||||||
|
current_arena->position = position_post_push;
|
||||||
|
// ??(tijani): why need to Asan Unpoision memory
|
||||||
|
}
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal u64 arena_position(Arena *arena) {
|
||||||
|
Arena *current_arena = arena->current;
|
||||||
|
u64 current_position = current_arena->base_position + current_arena->position;
|
||||||
|
return current_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void arena_pop_to(Arena *arena, u64 position) {
|
||||||
|
u64 big_position = ClampBot(ARENA_HEADER_SIZE, position);
|
||||||
|
Arena *current_arena = arena->current;
|
||||||
|
for (Arena *previous_arena = 0; current_arena->base_position >= big_position; current_arena = previous_arena) {
|
||||||
|
previous_arena = current_arena->previous;
|
||||||
|
os_release(current_arena, current_arena->reserve);
|
||||||
|
}
|
||||||
|
arena->current = current_arena;
|
||||||
|
u64 new_position = big_position - current_arena->base_position;
|
||||||
|
// ??(tijani): why need to ASSERT and AsanPoision memory region.
|
||||||
|
current_arena->position = new_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void arena_clear(Arena *arena) { arena_pop_to(arena, 0); }
|
||||||
|
|
||||||
|
// Pops the amount of memory passed off the passed in arena.
|
||||||
|
// The new position of the passed in arena will be the same
|
||||||
|
// memory block minus the amount passed in.
|
||||||
|
internal void arena_pop_off(Arena *arena, u64 amount) {
|
||||||
|
u64 old_position = arena_position(arena);
|
||||||
|
u64 new_position = old_position;
|
||||||
|
|
||||||
|
if (amount < old_position) {
|
||||||
|
new_position = old_position - amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
arena_pop_to(arena, new_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporary memory
|
||||||
|
internal Temp temp_begin(Arena *arena) {
|
||||||
|
u64 position = arena_position(arena);
|
||||||
|
Temp temp = {arena, position};
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void temp_end(Temp temp) { arena_pop_to(temp.arena, temp.position); }
|
78
src/base/base_arena.h
Normal file
78
src/base/base_arena.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef BASE_ARENA_H
|
||||||
|
#define BASE_ARENA_H
|
||||||
|
|
||||||
|
// Arena allocator simulates how stack memory works.
|
||||||
|
// This allows us the ability to allocate a reasonableamount of memory
|
||||||
|
// at startup and only use that allocated amount of memory throughout
|
||||||
|
// the lifetime of the application. Obviously this still uses
|
||||||
|
// "malloc, free, VirtualAlloc, VirtualFree" but instead of having to
|
||||||
|
// request and freeing memory during runtime, we create an environment
|
||||||
|
// where we have as much memory we could ever need and them portion it
|
||||||
|
// out in small chunk as needed. This has multiple benefits that would
|
||||||
|
// make itself glaring throughout the codebase but the gist of it is that
|
||||||
|
// we have one large block of memory throughout the lifetime,
|
||||||
|
// then application specific code that could need memory grab a chunck
|
||||||
|
// memory from the big block of memory we have reserved with the operating
|
||||||
|
// system at startup do whatever operation it needs to do, then return
|
||||||
|
// that block of memory back to the arena.
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
#define ARENA_HEADER_SIZE 64
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
// ArenaFlag_NoChain - Arenas are chained by default, this flag tells it otherwise.
|
||||||
|
// ArenaFlag_LargePages - Use large pages.
|
||||||
|
typedef u32 ArenaFlags;
|
||||||
|
enum {
|
||||||
|
ArenaFlag_NoChain = (1 << 0),
|
||||||
|
ArenaFlag_LargePages = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ArenaParams ArenaParams;
|
||||||
|
struct ArenaParams {
|
||||||
|
ArenaFlags flags;
|
||||||
|
u64 reserve_size;
|
||||||
|
u64 commit_size;
|
||||||
|
void *optional_backing_buffer; // NOTE(tijani): ??
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Arena Arena;
|
||||||
|
struct Arena {
|
||||||
|
Arena *previous; // Previous arena in the chain
|
||||||
|
Arena *current; // Current arena in the chain
|
||||||
|
ArenaFlags flags;
|
||||||
|
u32 commit_size;
|
||||||
|
u64 reserve_size;
|
||||||
|
u64 base_position;
|
||||||
|
u64 position;
|
||||||
|
u64 commit;
|
||||||
|
u64 reserve;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Temp Temp;
|
||||||
|
struct Temp {
|
||||||
|
Arena *arena;
|
||||||
|
u64 position;
|
||||||
|
};
|
||||||
|
|
||||||
|
// creation, destruction
|
||||||
|
internal Arena *arena_alloc_(ArenaParams *params);
|
||||||
|
#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = MB(64), .commit_size = KB(64), __VA_ARGS__})
|
||||||
|
internal void arena_release(Arena *arena);
|
||||||
|
|
||||||
|
// push, pop operations
|
||||||
|
internal void *arena_push(Arena *arena, u64 size_to_push, u64 align);
|
||||||
|
internal u64 arena_position(Arena *arena);
|
||||||
|
internal void arena_pop_to(Arena *arena, u64 position);
|
||||||
|
internal void arena_clear(Arena *arena);
|
||||||
|
internal void arena_pop_off(Arena *arena, u64 amount);
|
||||||
|
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T) * (c), (align))
|
||||||
|
#define push_array_aligned(a, T, c, align) (T *)MemoryZero(push_array_no_zero_aligned(a, T, c, align), sizeof(T) * (c))
|
||||||
|
#define push_array_no_zero(arena, Type, count) push_array_no_zero_aligned(arena, Type, count, Max(8, Align_Of(Type)))
|
||||||
|
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, Align_Of(T)))
|
||||||
|
|
||||||
|
// Temp
|
||||||
|
internal Temp temp_begin(Arena *arena);
|
||||||
|
internal void temp_end(Temp temp);
|
||||||
|
|
||||||
|
#endif // BASE_ARENA_H
|
4
src/base/base_inc.c
Normal file
4
src/base/base_inc.c
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// clang-format off
|
||||||
|
|
||||||
|
|
||||||
|
// clang-format on
|
11
src/base/base_inc.h
Normal file
11
src/base/base_inc.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef BASE_INC_H
|
||||||
|
#define BASE_INC_H
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include "base_context_switching.h"
|
||||||
|
#include "base_core.h"
|
||||||
|
#include "base_math.h"
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // BASE_INC_H
|
23
src/base/base_math.h
Normal file
23
src/base/base_math.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef BASE_MATH_H
|
||||||
|
#define BASE_MATH_H
|
||||||
|
|
||||||
|
typedef struct Vec2F32 Vec2F32;
|
||||||
|
union Vec2F32 {
|
||||||
|
struct {
|
||||||
|
f32 x;
|
||||||
|
f32 y;
|
||||||
|
};
|
||||||
|
f32 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Vec3F32 Vec3F32;
|
||||||
|
union Vec3F32 {
|
||||||
|
struct {
|
||||||
|
f32 x;
|
||||||
|
f32 y;
|
||||||
|
f32 z;
|
||||||
|
};
|
||||||
|
f32 v[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BASE_MATH_H
|
16
src/os/core/os_core.h
Normal file
16
src/os/core/os_core.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef OS_CORE_H
|
||||||
|
#define OS_CORE_H
|
||||||
|
|
||||||
|
// %os_hooks(implemented per-os) Memory allocation
|
||||||
|
|
||||||
|
// NOTE(tijani): For normal page size
|
||||||
|
internal b32 os_commit(void *ptr, u64 size);
|
||||||
|
internal void *os_reserve(u64 size);
|
||||||
|
internal void os_decommit(void *ptr, u64 size);
|
||||||
|
internal void os_release(void *ptr, u64 size);
|
||||||
|
|
||||||
|
// NOTE(tijani): For large page size
|
||||||
|
internal void *os_reserve_large(u64 size);
|
||||||
|
internal b32 os_commit_large(void *ptr, u64 size);
|
||||||
|
|
||||||
|
#endif // OS_CORE_H
|
33
src/os/core/win32/os_core_win32.c
Normal file
33
src/os/core/win32/os_core_win32.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// %os_hooks(implemented per-os) Memory allocation
|
||||||
|
|
||||||
|
// NOTE(tijani): For normal page size
|
||||||
|
internal b32 os_commit(void *ptr, u64 size) {
|
||||||
|
b32 l_memory = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0);
|
||||||
|
return l_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *os_reserve(u64 size) {
|
||||||
|
void *l_memory = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
return l_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void os_decommit(void *ptr, u64 size) { VirtualFree(ptr, size, MEM_DECOMMIT); }
|
||||||
|
|
||||||
|
internal void os_release(void *ptr, u64 size) {
|
||||||
|
// NOTE(tijani): size must be 0 on windows hence it will fail.
|
||||||
|
VirtualFree(ptr, size, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(tijani): For large page size
|
||||||
|
internal void *os_reserve_large(u64 size) {
|
||||||
|
void *l_memory = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||||
|
return l_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(tijani): From my understanding, on windows you cannot
|
||||||
|
// commit large pages as this has to be done during reservation.
|
||||||
|
// see `os_reserve_large` and WIN32 docs on large page support.
|
||||||
|
internal b32 os_commit_large(void *ptr, u64 size) { return -1; }
|
||||||
|
|
||||||
|
// %os_hooks(implemented per-os) Aborting
|
||||||
|
internal void os_abort(s32 exit_code) { ExitProcess(exit_code); }
|
11
src/os/core/win32/os_core_win32.h
Normal file
11
src/os/core/win32/os_core_win32.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef OS_CORE_WIN32_H
|
||||||
|
#define OS_CORE_WIN32_H
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // OS_CORE_WIN32_H
|
6
src/os/os_inc.c
Normal file
6
src/os/os_inc.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#include "core/os_core.c"
|
||||||
|
#include "core/win32/os_core_win32.c"
|
||||||
|
|
||||||
|
// clang-format on
|
11
src/os/os_inc.h
Normal file
11
src/os/os_inc.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef OS_INC_H
|
||||||
|
#define OS_INC_H
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#include "core/os_core.h"
|
||||||
|
#include "core/win32/os_core_win32.h"
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // OS_INC_H
|
Loading…
Reference in New Issue
Block a user