Ooga'd some boogas
This commit is contained in:
parent
b15c7c6e41
commit
1f2809d23e
12 changed files with 124 additions and 22 deletions
12
build.c
12
build.c
|
@ -2,6 +2,7 @@
|
|||
|
||||
///
|
||||
// Build config stuff
|
||||
|
||||
#define RUN_TESTS 0
|
||||
|
||||
// This is only for people developing oogabooga!
|
||||
|
@ -9,6 +10,8 @@
|
|||
|
||||
#define ENABLE_PROFILING 0
|
||||
|
||||
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
|
||||
|
||||
// When we need very debug
|
||||
// #define CONFIGURATION VERY_DEBUG
|
||||
|
||||
|
@ -20,12 +23,15 @@ typedef struct Context_Extra {
|
|||
|
||||
#define GFX_RENDERER GFX_RENDERER_D3D11
|
||||
|
||||
// This defaults to "entry", but we can set it to anything (except "main" or other existing proc names"
|
||||
#define ENTRY_PROC entry
|
||||
|
||||
#include "oogabooga/oogabooga.c"
|
||||
|
||||
|
||||
//
|
||||
// Comment & Uncomment to swap projects
|
||||
|
||||
// #include "entry_engine_test.c"
|
||||
// #include "entry_minimal_example.c"
|
||||
#include "entry_randygame.c"
|
||||
// #include "oogabooga/examples/renderer_stress_test.c"
|
||||
// #include "oogabooga/examples/minimal_game_loop.c"
|
||||
#include "entry_randygame.c"
|
|
@ -7,10 +7,11 @@ int entry(int argc, char **argv) {
|
|||
window.x = 200;
|
||||
window.y = 200;
|
||||
window.clear_color = hex_to_rgba(0x2a2d3aff);
|
||||
|
||||
|
||||
Gfx_Image* player = load_image_from_disk(STR("player.png"), get_heap_allocator());
|
||||
assert(player, "fuckie wucky happen");
|
||||
|
||||
|
||||
Vector2 player_pos = v2(0, 0);
|
||||
float64 seconds_counter = 0.0;
|
||||
s32 frame_count = 0;
|
||||
|
|
|
@ -196,7 +196,15 @@ thread_local u64 num_contexts = 0;
|
|||
|
||||
forward_global thread_local Allocator temp;
|
||||
|
||||
void* memset(void* dest, int value, size_t amount);
|
||||
void* alloc(Allocator allocator, u64 size) {
|
||||
void *p = allocator.proc(size, 0, ALLOCATOR_ALLOCATE, allocator.data);
|
||||
#if DO_ZERO_INITIALIZATION
|
||||
memset(p, 0, size);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
void* alloc_uninitialized(Allocator allocator, u64 size) {
|
||||
return allocator.proc(size, 0, ALLOCATOR_ALLOCATE, allocator.data);
|
||||
}
|
||||
void dealloc(Allocator allocator, void *p) {
|
||||
|
|
Before Width: | Height: | Size: 556 B After Width: | Height: | Size: 556 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
|
@ -10,9 +10,9 @@ int entry(int argc, char **argv) {
|
|||
|
||||
window.clear_color = hex_to_rgba(0x2a2d3aff);
|
||||
|
||||
Gfx_Image *bush_image = load_image_from_disk(STR("berry_bush.png"), get_heap_allocator());
|
||||
Gfx_Image *bush_image = load_image_from_disk(STR("oogabooga/examples/berry_bush.png"), get_heap_allocator());
|
||||
assert(bush_image, "Failed loading berry_bush.png");
|
||||
Gfx_Image *hammer_image = load_image_from_disk(STR("hammer.png"), get_heap_allocator());
|
||||
Gfx_Image *hammer_image = load_image_from_disk(STR("oogabooga/examples/hammer.png"), get_heap_allocator());
|
||||
assert(hammer_image, "Failed loading hammer.png");
|
||||
|
||||
seed_for_random = os_get_current_cycle_count();
|
||||
|
@ -50,7 +50,7 @@ int entry(int argc, char **argv) {
|
|||
|
||||
if (is_key_just_released('Q')) {
|
||||
delete_image(bush_image);
|
||||
bush_image = load_image_from_disk(STR("berry_bush.png"), get_heap_allocator());
|
||||
bush_image = load_image_from_disk(STR("oogabooga/examples/berry_bush.png"), get_heap_allocator());
|
||||
assert(bush_image, "Failed loading berry_bush.png");
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
|
||||
|
||||
#define KB(x) (x*1024ull)
|
||||
#define MB(x) ((KB(x))*1024ull)
|
||||
#define GB(x) ((MB(x))*1024ull)
|
||||
|
||||
|
||||
void* program_memory = 0;
|
||||
u64 program_memory_size = 0;
|
||||
|
||||
#ifndef INIT_MEMORY_SIZE
|
||||
#define INIT_MEMORY_SIZE (1024*50)
|
||||
#define INIT_MEMORY_SIZE KB(50)
|
||||
#endif
|
||||
// We may need to allocate stuff in initialization time before the heap is ready.
|
||||
// That's what this is for.
|
||||
|
@ -50,7 +54,8 @@ Allocator get_initialization_allocator() {
|
|||
// We could fix it by merging free nodes every now and then
|
||||
// BUT: We aren't really supposed to allocate/deallocate directly on the heap too much anyways...
|
||||
|
||||
#define DEFAULT_HEAP_BLOCK_SIZE min((os.page_size * 1024ULL * 50ULL), program_memory_size)
|
||||
#define MAX_HEAP_BLOCK_SIZE ((MB(500)+os.page_size)& ~(os.page_size-1))
|
||||
#define DEFAULT_HEAP_BLOCK_SIZE (min(MAX_HEAP_BLOCK_SIZE, program_memory_size))
|
||||
#define HEAP_ALIGNMENT (sizeof(Heap_Free_Node))
|
||||
typedef struct Heap_Free_Node Heap_Free_Node;
|
||||
typedef struct Heap_Block Heap_Block;
|
||||
|
@ -187,7 +192,7 @@ Heap_Block *make_heap_block(Heap_Block *parent, u64 size) {
|
|||
// #Speed #Cleanup
|
||||
if (((u8*)block)+size >= ((u8*)program_memory)+program_memory_size) {
|
||||
u64 minimum_size = ((u8*)block+size) - (u8*)program_memory + 1;
|
||||
u64 new_program_size = (cast(u64)(minimum_size * 1.5));
|
||||
u64 new_program_size = max((cast(u64)(minimum_size*2)), program_memory_size*2);
|
||||
assert(new_program_size >= minimum_size, "Bröd");
|
||||
const u64 ATTEMPTS = 1000;
|
||||
for (u64 i = 0; i <= ATTEMPTS; i++) {
|
||||
|
@ -226,7 +231,7 @@ void *heap_alloc(u64 size) {
|
|||
|
||||
size = (size+HEAP_ALIGNMENT) & ~(HEAP_ALIGNMENT-1);
|
||||
|
||||
assert(size < DEFAULT_HEAP_BLOCK_SIZE, "Past Charlie has been lazy and did not handle large allocations like this. I apologize on behalf of past Charlie. A quick fix could be to increase the heap block size for now.");
|
||||
assert(size < MAX_HEAP_BLOCK_SIZE, "Past Charlie has been lazy and did not handle large allocations like this. I apologize on behalf of past Charlie. A quick fix could be to increase the heap block size for now.");
|
||||
|
||||
Heap_Block *block = heap_head;
|
||||
Heap_Block *last_block = 0;
|
||||
|
@ -237,6 +242,13 @@ void *heap_alloc(u64 size) {
|
|||
// #Speed
|
||||
// Maybe instead of going through EVERY free node to find best fit we do a good-enough fit
|
||||
while (block != 0) {
|
||||
|
||||
if (block->size < size) {
|
||||
last_block = block;
|
||||
block = block->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
Heap_Search_Result result = search_heap_block(block, size);
|
||||
Heap_Free_Node *node = result.best_fit;
|
||||
if (node) {
|
||||
|
@ -263,7 +275,7 @@ void *heap_alloc(u64 size) {
|
|||
}
|
||||
|
||||
if (!best_fit) {
|
||||
block = make_heap_block(last_block, DEFAULT_HEAP_BLOCK_SIZE);
|
||||
block = make_heap_block(last_block, max(DEFAULT_HEAP_BLOCK_SIZE, size));
|
||||
previous = 0;
|
||||
best_fit = block->free_head;
|
||||
best_fit_block = block;
|
||||
|
@ -423,7 +435,7 @@ Allocator get_heap_allocator() {
|
|||
///
|
||||
|
||||
#ifndef TEMPORARY_STORAGE_SIZE
|
||||
#define TEMPORARY_STORAGE_SIZE (1024ULL*1024ULL*16ULL) // 16mb
|
||||
#define TEMPORARY_STORAGE_SIZE (1024ULL*1024ULL*2ULL) // 2mb
|
||||
#endif
|
||||
|
||||
void* talloc(u64);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
|
||||
#define DEBUG 0
|
||||
#define VERY_DEBUG 1
|
||||
#define RELEASE 2
|
||||
|
@ -17,6 +18,10 @@
|
|||
#define ENTRY_PROC entry
|
||||
#endif
|
||||
|
||||
#ifndef DO_ZERO_INITIALIZATION
|
||||
#define DO_ZERO_INITIALIZATION 1
|
||||
#endif
|
||||
|
||||
#define WINDOWS 0
|
||||
#define LINUX 1
|
||||
#define MACOS 2
|
||||
|
@ -213,7 +218,7 @@ void oogabooga_init(u64 program_memory_size) {
|
|||
}
|
||||
|
||||
#ifndef INITIAL_PROGRAM_MEMORY_SIZE
|
||||
#define INITIAL_PROGRAM_MEMORY_SIZE (1024ULL * 1024ULL * 100ULL) // Start with 100mb program memory
|
||||
#define INITIAL_PROGRAM_MEMORY_SIZE (max((1024ULL * 1024ULL * 100ULL), TEMPORARY_STORAGE_SIZE*2))
|
||||
#endif
|
||||
#ifndef RUN_TESTS
|
||||
#define RUN_TESTS 0
|
||||
|
@ -223,8 +228,12 @@ void oogabooga_init(u64 program_memory_size) {
|
|||
int ENTRY_PROC(int argc, char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
oogabooga_init(INITIAL_PROGRAM_MEMORY_SIZE);
|
||||
|
||||
|
||||
printf("Ooga booga program started\n");
|
||||
oogabooga_init(INITIAL_PROGRAM_MEMORY_SIZE);
|
||||
|
||||
assert(main != ENTRY_PROC, "You've ooga'd your last booga");
|
||||
|
||||
// This can be disabled in build.c
|
||||
#if RUN_TESTS
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
|
||||
#define VIRTUAL_MEMORY_BASE ((void*)0x0000010000000000ULL)
|
||||
#define VIRTUAL_MEMORY_BASE ((void*)0x0000690000000000ULL)
|
||||
|
||||
void* heap_alloc(u64);
|
||||
void heap_dealloc(void*);
|
||||
|
@ -238,6 +238,48 @@ void os_init(u64 program_memory_size) {
|
|||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void s64_to_null_terminated_string_reverse(char str[], int length)
|
||||
{
|
||||
int start = 0;
|
||||
int end = length - 1;
|
||||
while (start < end) {
|
||||
char temp = str[start];
|
||||
str[start] = str[end];
|
||||
str[end] = temp;
|
||||
end--;
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
void s64_to_null_terminated_string(s64 num, char* str, int base)
|
||||
{
|
||||
int i = 0;
|
||||
bool neg = false;
|
||||
|
||||
if (num == 0) {
|
||||
str[i++] = '0';
|
||||
str[i] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (num < 0 && base == 10) {
|
||||
neg = true;
|
||||
num = -num;
|
||||
}
|
||||
|
||||
while (num != 0) {
|
||||
int rem = num % base;
|
||||
str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0';
|
||||
num = num / base;
|
||||
}
|
||||
|
||||
if (neg)
|
||||
str[i++] = '-';
|
||||
|
||||
str[i] = '\0';
|
||||
s64_to_null_terminated_string_reverse(str, i);
|
||||
}
|
||||
|
||||
bool os_grow_program_memory(u64 new_size) {
|
||||
|
@ -275,6 +317,10 @@ bool os_grow_program_memory(u64 new_size) {
|
|||
assert(m == 0, "amount_to_allocate is not aligned to granularity!");
|
||||
// Just keep allocating at the tail of the current chunk
|
||||
void* result = VirtualAlloc(tail, amount_to_allocate, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
assert(result == tail);
|
||||
#if CONFIGURATION == DEBUG
|
||||
volatile u8 a = *(u8*)tail = 69;
|
||||
#endif
|
||||
memset(result, 0xBA, amount_to_allocate);
|
||||
if (result == 0) {
|
||||
os_unlock_mutex(program_memory_mutex); // #Sync
|
||||
|
@ -289,7 +335,12 @@ bool os_grow_program_memory(u64 new_size) {
|
|||
}
|
||||
|
||||
|
||||
char size_str[32];
|
||||
s64_to_null_terminated_string(program_memory_size/1024, size_str, 10);
|
||||
|
||||
os_write_string_to_stdout(STR("Program memory grew to "));
|
||||
os_write_string_to_stdout(STR(size_str));
|
||||
os_write_string_to_stdout(STR(" kb\n"));
|
||||
os_unlock_mutex(program_memory_mutex); // #Sync
|
||||
return true;
|
||||
}
|
||||
|
@ -440,7 +491,7 @@ void os_high_precision_sleep(f64 ms) {
|
|||
|
||||
f64 start = os_get_current_time_in_seconds();
|
||||
f64 end = start + (f64)s;
|
||||
u32 sleep_time = (u32)((end-start)-1.0);
|
||||
s32 sleep_time = (s32)((end-start)-1.0);
|
||||
bool do_sleep = sleep_time >= 1;
|
||||
|
||||
timeBeginPeriod(1); // I don't see a reason to reset this
|
||||
|
|
|
@ -91,6 +91,8 @@ inline int crt_vprintf(const char* fmt, va_list args) {
|
|||
}
|
||||
#endif
|
||||
|
||||
inline bool bytes_match(void *a, void *b, u64 count) { return memcmp(a, b, count) == 0; }
|
||||
|
||||
inline int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args) {
|
||||
return os.crt_vsnprintf(buffer, n, fmt, args);
|
||||
}
|
||||
|
|
|
@ -47,15 +47,23 @@ void test_allocator(bool do_log_heap) {
|
|||
assert(*c == 1337, "Test failed: Memory corrupted");
|
||||
|
||||
// Test growing memory
|
||||
os_grow_program_memory(1024 * 1024 * 1000);
|
||||
//os_grow_program_memory(1024 * 1024 * 1000);
|
||||
|
||||
assert(*a == 69, "Test failed: Memory corrupted");
|
||||
assert(*b == 420, "Test failed: Memory corrupted");
|
||||
assert(*c == 1337, "Test failed: Memory corrupted");
|
||||
|
||||
|
||||
u8 check_bytes[1024];
|
||||
for (u64 i = 0; i < 1024; i += 4) {
|
||||
*((int*)&check_bytes[i]) = (int)get_random();
|
||||
}
|
||||
u8 *check_bytes_copy = (u8*)alloc(heap, 1024);
|
||||
memcpy(check_bytes_copy, check_bytes, 1024);
|
||||
|
||||
|
||||
// Allocate and free large block
|
||||
void* large_block = alloc(heap, 1024 * 1024 * 100);
|
||||
dealloc(heap, large_block);
|
||||
//void* large_block = alloc(heap, 1024 * 1024 * 100);
|
||||
//dealloc(heap, large_block);
|
||||
|
||||
// Allocate multiple small blocks
|
||||
void* blocks[100];
|
||||
|
@ -75,6 +83,7 @@ void test_allocator(bool do_log_heap) {
|
|||
dealloc(heap, p);
|
||||
}
|
||||
|
||||
|
||||
// Free in reverse order
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
blocks[i] = alloc(heap, 128);
|
||||
|
@ -93,7 +102,7 @@ void test_allocator(bool do_log_heap) {
|
|||
nums[i][j] = i * 10 + j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
assert(nums[i][j] == i * 10 + j, "Memory corruption detected");
|
||||
|
@ -102,8 +111,10 @@ void test_allocator(bool do_log_heap) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
reset_temporary_storage();
|
||||
|
||||
|
||||
int* foo = (int*)alloc(temp, 72);
|
||||
*foo = 1337;
|
||||
void* bar = alloc(temp, 69);
|
||||
|
@ -174,6 +185,8 @@ void test_allocator(bool do_log_heap) {
|
|||
dealloc(heap, blocks[i]);
|
||||
}
|
||||
|
||||
assert(bytes_match(check_bytes, check_bytes_copy, 1024), "Memory corrupt");
|
||||
|
||||
if (do_log_heap) log_heap();
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue