Refactor more to be able to build as dll and link a single global oogabooga instance, and made an example for a hot loaded game

This commit is contained in:
Charlie Malmqvist 2024-07-23 17:33:11 +02:00
parent fe3fea0c29
commit 4aa832a822
29 changed files with 549 additions and 112 deletions

View file

@ -3,6 +3,8 @@
///
// Build config stuff
#define RUN_TESTS 1
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
// You might want to increase this if you get a log warning saying the temporary storage was overflown.
@ -37,10 +39,10 @@ typedef struct Context_Extra {
// #include "oogabooga/examples/text_rendering.c"
// #include "oogabooga/examples/custom_logger.c"
// #include "oogabooga/examples/renderer_stress_test.c"
#include "oogabooga/examples/renderer_stress_test.c"
// #include "oogabooga/examples/tile_game.c"
// #include "oogabooga/examples/audio_test.c"
#include "oogabooga/examples/custom_shader.c"
// #include "oogabooga/examples/custom_shader.c"
// This is where you swap in your own project!
// #include "entry_yourepicgamename.c"

79
build_engine.c Normal file
View file

@ -0,0 +1,79 @@
///
// Build config stuff
#define OOGABOOGA_BUILD_SHARED_LIBRARY 1
#include "oogabooga/oogabooga.c"
///
///
// This is the "engine" part of your game, which will call into your game.dll
typedef void (*Game_Update_Proc)(f64);
Game_Update_Proc game_update;
Dynamic_Library_Handle dll = 0;
void load_game_dll(char **argv) {
// Here we load all the game symbols
if (dll) {
os_unload_dynamic_library(dll);
}
string exe_path = STR(argv[0]);
string exe_dir = get_directory_of(exe_path);
// We need to copy the original and open the copy, so we can recompile the original and then close & replace
// the copy.
string dll_path = string_concat(exe_dir, STR("/game.dll"), get_temporary_allocator());
string used_dll_path = string_concat(exe_dir, STR("/game-in-use.dll"), get_temporary_allocator());
bool ok = os_file_copy(dll_path, used_dll_path, true);
assert(ok, "Could not copy %s to %s", dll_path, used_dll_path);
dll = os_load_dynamic_library(used_dll_path);
assert(dll, "Failed loading game dll");
game_update = os_dynamic_library_load_symbol(dll, STR("game_update"));
assert(game_update, "game is missing game_update()");
log("Loaded game procedures");
}
int entry(int argc, char **argv) {
load_game_dll(argv);
window.title = STR("Minimal Game Example");
window.scaled_width = 1280; // We need to set the scaled size if we want to handle system scaling (DPI)
window.scaled_height = 720;
window.x = 200;
window.y = 90;
window.clear_color = hex_to_rgba(0x6495EDff);
float64 last_time = os_get_current_time_in_seconds();
while (!window.should_close) {
float64 now = os_get_current_time_in_seconds();
float64 delta = now-last_time;
if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(delta), (delta)*1000);
last_time = now;
reset_temporary_storage();
game_update(delta);
if (is_key_just_pressed('R')) {
load_game_dll(argv);
play_one_audio_clip(STR("oogabooga/examples/bruh.wav"));
}
os_update();
gfx_update();
}
return 0;
}

30
build_game.c Normal file
View file

@ -0,0 +1,30 @@
// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c
#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1
#include "oogabooga/oogabooga.c"
///
///
// This is the game module which is what can be recompiled in the engine runtime
// For the engine to be able to detect a symbol, it needs to be marked with SHARED_EXPORT
void SHARED_EXPORT
game_update(f64 delta_time) {
float64 now = os_get_current_time_in_seconds();
Matrix4 rect_xform = m4_scalar(1.0);
rect_xform = m4_rotate_z(rect_xform, (f32)now);
rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0));
draw_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN);
draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED);
float aspect = (f32)window.width/(f32)window.height;
float mx = (input_frame.mouse_x/(f32)window.width * 2.0 - 1.0)*aspect;
float my = input_frame.mouse_y/(f32)window.height * 2.0 - 1.0;
draw_line(v2(-.75, -.75), v2(mx, my), 0.005, COLOR_WHITE);
}

36
build_launcher.c Normal file
View file

@ -0,0 +1,36 @@
// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c
#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1
#include "oogabooga/oogabooga.c"
// All we do with the launcher is to launch the engine
// We need to be careful to use oogabooga things because it has not yet been initialized.
// We can use get_temporary_allocator() because that actually gives us the initialization allocator.
// We cannot use log() but we can use print()
int main(int argc, char **argv) {
string exe_path = STR(argv[0]);
string exe_dir = get_directory_of(exe_path);
Allocator a = get_initialization_allocator();
string dll_path = string_concat(exe_dir, STR("/engine.dll"), a);
Dynamic_Library_Handle dll = os_load_dynamic_library(dll_path);
if (!dll) {
os_write_string_to_stdout(STR("Failed loading engine dll from "));
os_write_string_to_stdout(dll_path);
os_write_string_to_stdout(STR("\n"));
return -1;
}
int (*engine_main)(int, char**) = os_dynamic_library_load_symbol(dll, STR("main"));
if (!engine_main) {
os_write_string_to_stdout(STR("Failed loading engine main\n"));
return -1;
}
print("Launcher found engine main(), running...\n");
return engine_main(argc, argv);
}

View file

@ -1,3 +1,6 @@
## v0.01.002 -
## v0.01.001 - Spacial audio, custom shading, scissor boxing
- Audio
- Implemented spacial audio playback

16
hotload_build_all.bat Normal file
View file

@ -0,0 +1,16 @@
@echo on
if exist build (
rmdir /s /q build
)
mkdir build
pushd build
clang ../build_engine.c -g -shared -o engine.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -fuse-ld=lld -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -ldbghelp -femit-all-decls -Xlinker /IMPLIB:engine.lib -Xlinker /MACHINE:X64 -Xlinker /SUBSYSTEM:CONSOLE
clang ../build_launcher.c -g -o launcher.exe -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE
clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE
popd

8
hotload_build_game.bat Normal file
View file

@ -0,0 +1,8 @@
@echo on
pushd build
clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE
popd

View file

@ -1,5 +1,5 @@
#define thread_local _Thread_local
#define local_persist static
@ -9,10 +9,10 @@
#define null 0
ogb_instance void
void
printf(const char* fmt, ...);
ogb_instance void
void
dump_stack_trace();
#define ASSERT_STR_HELPER(x) #x
@ -81,7 +81,7 @@ typedef struct Allocator {
void *data;
} Allocator;
ogb_instance Allocator
Allocator
get_heap_allocator();
ogb_instance Allocator
@ -95,15 +95,15 @@ typedef struct Context {
CONTEXT_EXTRA extra;
} Context;
forward_global thread_local Allocator temp;
#define CONTEXT_STACK_MAX 512
//
//
thread_local ogb_instance Context context;
thread_local ogb_instance Context context_stack[CONTEXT_STACK_MAX];
thread_local ogb_instance u64 num_contexts;
// #Global
//thread_local ogb_instance Context context;
//thread_local ogb_instance Context context_stack[CONTEXT_STACK_MAX];
//thread_local ogb_instance u64 num_contexts;
ogb_instance
Context get_context();
ogb_instance void*
alloc(Allocator allocator, u64 size);
@ -166,7 +166,10 @@ pop_context() {
context = context_stack[num_contexts];
}
ogb_instance
Context get_context() {
return context;
}
#endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE

View file

@ -1,27 +0,0 @@
typedef struct Bucket_Array {
u64 _block_size;
u64 _bucket_count;
} Bucket_Array;
typedef struct Bucket_Array_Free_Node {
struct Bucket_Array_Free_Node *next;
} Bucket_Array_Free_Node;
typedef struct Bucket_Array_Bucket {
Bucket_Array_Free_Node *first_free;
void *data;
Bucket *next;
} Bucket_Array_Bucket;
Bucket_Array make_bucket_array(u64 block_size, u64 bucket_count) {
Bucket_Array ba;
ba._block_size = block_size;
ba._bucket_count = bucket_count;
}

View file

@ -14,31 +14,71 @@ inline bool compare_and_swap_bool(bool *a, bool b, bool old);
// Spinlock "primitive"
// Like a mutex but it eats up the entire core while waiting.
// Beneficial if contention is low or sync speed is important
void spinlock_init(Spinlock *l);
void spinlock_acquire_or_wait(Spinlock* l);
typedef struct Spinlock {
bool locked;
} Spinlock;
void ogb_instance
spinlock_init(Spinlock *l);
void ogb_instance
spinlock_acquire_or_wait(Spinlock* l);
// This returns true if successfully acquired or false if timeout reached.
bool spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds);
void spinlock_release(Spinlock* l);
bool ogb_instance
spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds);
void ogb_instance
spinlock_release(Spinlock* l);
///
// High-level mutex primitive (short spinlock then OS mutex lock)
// Just spins for a few (configurable) microseconds with a spinlock,
// and if acquiring fails it falls back to a OS mutex.
void mutex_init(Mutex *m);
void mutex_destroy(Mutex *m);
void mutex_acquire_or_wait(Mutex *m);
void mutex_release(Mutex *m);
#define MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS 100
typedef struct Mutex {
Spinlock spinlock;
f64 spin_time_microseconds;
Mutex_Handle os_handle;
volatile bool spinlock_acquired;
volatile u64 acquiring_thread;
} Mutex;
void ogb_instance
mutex_init(Mutex *m);
void ogb_instance
mutex_destroy(Mutex *m);
void ogb_instance
mutex_acquire_or_wait(Mutex *m);
void ogb_instance
mutex_release(Mutex *m);
///
// Binary semaphore
void binary_semaphore_init(Binary_Semaphore *sem, bool initial_state);
void binary_semaphore_destroy(Binary_Semaphore *sem);
void binary_semaphore_wait(Binary_Semaphore *sem);
void binary_semaphore_signal(Binary_Semaphore *sem);
typedef struct Binary_Semaphore {
bool signaled;
Mutex mutex;
} Binary_Semaphore;
typedef struct Spinlock {
bool locked;
} Spinlock;
void ogb_instance
binary_semaphore_init(Binary_Semaphore *sem, bool initial_state);
void ogb_instance
binary_semaphore_destroy(Binary_Semaphore *sem);
void ogb_instance
binary_semaphore_wait(Binary_Semaphore *sem);
void ogb_instance
binary_semaphore_signal(Binary_Semaphore *sem);
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
void spinlock_init(Spinlock *l) {
memset(l, 0, sizeof(*l));
@ -87,14 +127,7 @@ void spinlock_release(Spinlock* l) {
///
// High-level mutex primitive (short spinlock then OS mutex lock)
#define MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS 100
typedef struct Mutex {
Spinlock spinlock;
f64 spin_time_microseconds;
Mutex_Handle os_handle;
volatile bool spinlock_acquired;
volatile u64 acquiring_thread;
} Mutex;
void mutex_init(Mutex *m) {
spinlock_init(&m->spinlock);
m->spin_time_microseconds = MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS;
@ -134,10 +167,7 @@ void mutex_release(Mutex *m) {
MEMORY_BARRIER;
}
typedef struct Binary_Semaphore {
bool signaled;
Mutex mutex;
} Binary_Semaphore;
void binary_semaphore_init(Binary_Semaphore *sem, bool initial_state) {
sem->signaled = initial_state;
@ -164,3 +194,5 @@ void binary_semaphore_signal(Binary_Semaphore *sem) {
sem->signaled = true;
mutex_release(&sem->mutex);
}
#endif

View file

@ -106,6 +106,8 @@ typedef struct Cpu_Capabilities {
#define MEMORY_BARRIER _ReadWriteBarrier()
#define thread_local __declspec(thread)
#define SHARED_EXPORT __declspec(dllexport)
#define SHARED_IMPORT __declspec(dllimport)
@ -223,8 +225,15 @@ typedef struct Cpu_Capabilities {
#define MEMORY_BARRIER __asm__ __volatile__("" ::: "memory")
#define thread_local __thread
#if TARGET_OS == WINDOWS
#define SHARED_EXPORT __attribute__((visibility("default"))) __declspec(dllexport)
#define SHARED_IMPORT __declspec(dllimport)
#else
#define SHARED_EXPORT __attribute__((visibility("default")))
#define SHARED_IMPORT
#endif
#else
#define inline inline

View file

@ -0,0 +1,12 @@
# !!! THIS VERY EXPERIMENTAL !!!
This is an example how how we can set up a oogabooga project where some code can be recompiled while the engine is still running.
To try this:
1. Copy the files in this directory into the root project directory
2. Compile with `hotload_build_all.bat`
3. Run `build/launcher.exe`
4. Modify `build_game.c`
5. Recompile the game code only with `hotload_build_game.bat`
6. Go back to the application and press 'R'

View file

@ -0,0 +1,79 @@
///
// Build config stuff
#define OOGABOOGA_BUILD_SHARED_LIBRARY 1
#include "oogabooga/oogabooga.c"
///
///
// This is the "engine" part of your game, which will call into your game.dll
typedef void (*Game_Update_Proc)(f64);
Game_Update_Proc game_update;
Dynamic_Library_Handle dll = 0;
void load_game_dll(char **argv) {
// Here we load all the game symbols
if (dll) {
os_unload_dynamic_library(dll);
}
string exe_path = STR(argv[0]);
string exe_dir = get_directory_of(exe_path);
// We need to copy the original and open the copy, so we can recompile the original and then close & replace
// the copy.
string dll_path = string_concat(exe_dir, STR("/game.dll"), get_temporary_allocator());
string used_dll_path = string_concat(exe_dir, STR("/game-in-use.dll"), get_temporary_allocator());
bool ok = os_file_copy(dll_path, used_dll_path, true);
assert(ok, "Could not copy %s to %s", dll_path, used_dll_path);
dll = os_load_dynamic_library(used_dll_path);
assert(dll, "Failed loading game dll");
game_update = os_dynamic_library_load_symbol(dll, STR("game_update"));
assert(game_update, "game is missing game_update()");
log("Loaded game procedures");
}
int entry(int argc, char **argv) {
load_game_dll(argv);
window.title = STR("Minimal Game Example");
window.scaled_width = 1280; // We need to set the scaled size if we want to handle system scaling (DPI)
window.scaled_height = 720;
window.x = 200;
window.y = 90;
window.clear_color = hex_to_rgba(0x6495EDff);
float64 last_time = os_get_current_time_in_seconds();
while (!window.should_close) {
float64 now = os_get_current_time_in_seconds();
float64 delta = now-last_time;
if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(delta), (delta)*1000);
last_time = now;
reset_temporary_storage();
game_update(delta);
if (is_key_just_pressed('R')) {
load_game_dll(argv);
play_one_audio_clip(STR("oogabooga/examples/bruh.wav"));
}
os_update();
gfx_update();
}
return 0;
}

View file

@ -0,0 +1,30 @@
// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c
#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1
#include "oogabooga/oogabooga.c"
///
///
// This is the game module which is what can be recompiled in the engine runtime
// For the engine to be able to detect a symbol, it needs to be marked with SHARED_EXPORT
void SHARED_EXPORT
game_update(f64 delta_time) {
float64 now = os_get_current_time_in_seconds();
Matrix4 rect_xform = m4_scalar(1.0);
rect_xform = m4_rotate_z(rect_xform, (f32)now);
rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0));
draw_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN);
draw_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED);
float aspect = (f32)window.width/(f32)window.height;
float mx = (input_frame.mouse_x/(f32)window.width * 2.0 - 1.0)*aspect;
float my = input_frame.mouse_y/(f32)window.height * 2.0 - 1.0;
draw_line(v2(-.75, -.75), v2(mx, my), 0.005, COLOR_WHITE);
}

View file

@ -0,0 +1,36 @@
// !!!!!!!! BUILD CONFIG SHOULD BE DONE IN build_engine.c
#define OOGABOOGA_LINK_EXTERNAL_INSTANCE 1
#include "oogabooga/oogabooga.c"
// All we do with the launcher is to launch the engine
// We need to be careful to use oogabooga things because it has not yet been initialized.
// We can use get_temporary_allocator() because that actually gives us the initialization allocator.
// We cannot use log() but we can use print()
int main(int argc, char **argv) {
string exe_path = STR(argv[0]);
string exe_dir = get_directory_of(exe_path);
Allocator a = get_initialization_allocator();
string dll_path = string_concat(exe_dir, STR("/engine.dll"), a);
Dynamic_Library_Handle dll = os_load_dynamic_library(dll_path);
if (!dll) {
os_write_string_to_stdout(STR("Failed loading engine dll from "));
os_write_string_to_stdout(dll_path);
os_write_string_to_stdout(STR("\n"));
return -1;
}
int (*engine_main)(int, char**) = os_dynamic_library_load_symbol(dll, STR("main"));
if (!engine_main) {
os_write_string_to_stdout(STR("Failed loading engine main\n"));
return -1;
}
print("Launcher found engine main(), running...\n");
return engine_main(argc, argv);
}

View file

@ -0,0 +1,16 @@
@echo on
if exist build (
rmdir /s /q build
)
mkdir build
pushd build
clang ../build_engine.c -g -shared -o engine.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -fuse-ld=lld -lkernel32 -lgdi32 -luser32 -lruntimeobject -lwinmm -ld3d11 -ldxguid -ld3dcompiler -lshlwapi -lole32 -lavrt -lksuser -ldbghelp -femit-all-decls -Xlinker /IMPLIB:engine.lib -Xlinker /MACHINE:X64 -Xlinker /SUBSYSTEM:CONSOLE
clang ../build_launcher.c -g -o launcher.exe -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE
clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE
popd

View file

@ -0,0 +1,8 @@
@echo on
pushd build
clang ../build_game.c -g -shared -o game.dll -O0 -std=c11 -D_CRT_SECURE_NO_WARNINGS -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -femit-all-decls -luser32 -fuse-ld=lld -L. -lengine -Xlinker /SUBSYSTEM:CONSOLE
popd

View file

@ -231,8 +231,8 @@ void d3d11_update_swapchain() {
bool
d3d11_compile_shader(string source) {
source = string_replace_all(source, STR("$INJECT_PIXEL_POST_PROCESS"), STR("float4 pixel_shader_extension(PS_INPUT input, float4 color) { return color; }"), temp);
source = string_replace_all(source, STR("$VERTEX_2D_USER_DATA_COUNT"), tprint("%d", VERTEX_2D_USER_DATA_COUNT), temp);
source = string_replace_all(source, STR("$INJECT_PIXEL_POST_PROCESS"), STR("float4 pixel_shader_extension(PS_INPUT input, float4 color) { return color; }"), get_temporary_allocator());
source = string_replace_all(source, STR("$VERTEX_2D_USER_DATA_COUNT"), tprint("%d", VERTEX_2D_USER_DATA_COUNT), get_temporary_allocator());
// #Leak on recompile
@ -921,7 +921,7 @@ bool
shader_recompile_with_extension(string ext_source, u64 cbuffer_size) {
string source = string_replace_all(STR(d3d11_image_shader_source), STR("$INJECT_PIXEL_POST_PROCESS"), ext_source, temp);
string source = string_replace_all(STR(d3d11_image_shader_source), STR("$INJECT_PIXEL_POST_PROCESS"), ext_source, get_temporary_allocator());
if (!d3d11_compile_shader(source)) return false;

View file

@ -37,11 +37,11 @@ typedef struct Gfx_Image {
Allocator allocator;
} Gfx_Image;
ogb_instance Gfx_Image *
Gfx_Image *
make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator);
ogb_instance Gfx_Image *
Gfx_Image *
load_image_from_disk(string path, Allocator allocator);
ogb_instance void
void
delete_image(Gfx_Image *image);
// Implemented per renderer
@ -61,7 +61,7 @@ ogb_instance bool
shader_recompile_with_extension(string ext_source, u64 cbuffer_size);
// initial_data can be null to leave image data uninitialized
ogb_instance Gfx_Image *
Gfx_Image *
make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator allocator) {
Gfx_Image *image = alloc(allocator, sizeof(Gfx_Image) + width*height*channels);
@ -78,7 +78,7 @@ make_image(u32 width, u32 height, u32 channels, void *initial_data, Allocator al
return image;
}
ogb_instance Gfx_Image *
Gfx_Image *
load_image_from_disk(string path, Allocator allocator) {
string png;
bool ok = os_read_entire_file(path, &png, allocator);
@ -115,7 +115,7 @@ load_image_from_disk(string path, Allocator allocator) {
return image;
}
ogb_instance void
void
delete_image(Gfx_Image *image) {
// Free the image data allocated by stb_image
image->width = 0;

View file

@ -536,28 +536,41 @@ Allocator get_heap_allocator() {
#define TEMPORARY_STORAGE_SIZE (1024ULL*1024ULL*2ULL) // 2mb
#endif
void* talloc(u64);
void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void*);
ogb_instance void* talloc(u64);
ogb_instance void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void*);
// #Global
thread_local ogb_instance void * temporary_storage;
thread_local ogb_instance bool temporary_storage_initted;
thread_local ogb_instance void * temporary_storage_pointer;
thread_local ogb_instance bool has_warned_temporary_storage_overflow;
thread_local ogb_instance Allocator temp;
ogb_instance Allocator
get_temporary_allocator();
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
thread_local void * temporary_storage = 0;
thread_local bool temporary_storage_initted = false;
thread_local void * temporary_storage_pointer = 0;
thread_local bool has_warned_temporary_storage_overflow = false;
thread_local Allocator temp;
thread_local Allocator temp_allocator;
ogb_instance Allocator
get_temporary_allocator() {
if (!temporary_storage_initted) return get_initialization_allocator();
return temp_allocator;
}
#endif
Allocator get_temporary_allocator() {
return temp;
}
ogb_instance void*
temp_allocator_proc(u64 size, void *p, Allocator_Message message, void* data);
ogb_instance void
temporary_storage_init();
ogb_instance void*
talloc(u64 size);
ogb_instance void
reset_temporary_storage();
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void* data) {
switch (message) {
case ALLOCATOR_ALLOCATE: {
@ -581,12 +594,12 @@ void temporary_storage_init() {
assert(temporary_storage, "Failed allocating temporary storage");
temporary_storage_pointer = temporary_storage;
temp.proc = temp_allocator_proc;
temp.data = 0;
temp_allocator.proc = temp_allocator_proc;
temp_allocator.data = 0;
temporary_storage_initted = true;
temp.proc = temp_allocator_proc;
temp_allocator.proc = temp_allocator_proc;
}
void* talloc(u64 size) {
@ -617,3 +630,4 @@ void reset_temporary_storage() {
has_warned_temporary_storage_overflow = true;
}
#endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE

View file

@ -197,6 +197,10 @@ typedef u8 bool;
#define ENABLE_SIMD 1
#endif
#ifndef INITIAL_PROGRAM_MEMORY_SIZE
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
#endif
#if ENABLE_SIMD && !defined(SIMD_ENABLE_SSE2)
#if COMPILER_CAN_DO_SSE2
#define SIMD_ENABLE_SSE2 1
@ -246,10 +250,13 @@ typedef u8 bool;
#if OOGABOOGA_LINK_EXTERNAL_INSTANCE
#define ogb_instance SHARED_IMPORT extern
#else
#elif OOGABOOGA_BUILD_SHARED_LIBRARY
#define ogb_instance SHARED_EXPORT
#else
#define ogb_instance
#endif
// This needs to be included before dependencies
#include "base.c"
@ -367,9 +374,12 @@ void default_logger(Log_Level level, string s) {
mutex_release(&_default_logger_mutex);
}
ogb_instance void oogabooga_init(u64 program_memory_size);
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
void oogabooga_init(u64 program_memory_size) {
context.logger = default_logger;
temp = get_initialization_allocator();
temp_allocator = get_initialization_allocator();
Cpu_Capabilities features = query_cpu_capabilities();
os_init(program_memory_size);
heap_init();
@ -390,10 +400,17 @@ void oogabooga_init(u64 program_memory_size) {
log_verbose("CPU has avx2: %cs", features.avx2 ? "true" : "false");
log_verbose("CPU has avx512: %cs", features.avx512 ? "true" : "false");
}
#endif
int ENTRY_PROC(int argc, char **argv);
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
#if OOGABOOGA_BUILD_SHARED_LIBRARY
int SHARED_EXPORT main(int argc, char **argv) {
#else
int main(int argc, char **argv) {
#endif
print("Ooga booga program started\n");
@ -421,6 +438,8 @@ int main(int argc, char **argv) {
return code;
}
#endif

View file

@ -588,8 +588,10 @@ float64 os_get_current_time_in_seconds() {
// Dynamic Libraries
///
u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8);
Dynamic_Library_Handle os_load_dynamic_library(string path) {
return LoadLibraryA(temp_convert_to_null_terminated_string(path));
return LoadLibraryW(temp_win32_fixed_utf8_to_null_terminated_wide(path));
}
void *os_dynamic_library_load_symbol(Dynamic_Library_Handle l, string identifier) {
return GetProcAddress(l, temp_convert_to_null_terminated_string(identifier));
@ -635,7 +637,7 @@ u16 *win32_fixed_utf8_to_null_terminated_wide(string utf8, Allocator allocator)
return utf16_str;
}
u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8) {
return win32_fixed_utf8_to_null_terminated_wide(utf8, temp);
return win32_fixed_utf8_to_null_terminated_wide(utf8, get_temporary_allocator());
}
string win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16, Allocator allocator) {
u64 utf8_length = WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)utf16, -1, 0, 0, 0, 0);
@ -663,7 +665,7 @@ string win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16, Allocator allo
}
string temp_win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16) {
return win32_null_terminated_wide_to_fixed_utf8(utf16, temp);
return win32_null_terminated_wide_to_fixed_utf8(utf16, get_temporary_allocator());
}
@ -694,6 +696,12 @@ bool os_file_delete_s(string path) {
return (bool)DeleteFileW(path_wide);
}
bool os_file_copy_s(string from, string to, bool replace_if_exists) {
u16 *from_wide = temp_win32_fixed_utf8_to_null_terminated_wide(from);
u16 *to_wide = temp_win32_fixed_utf8_to_null_terminated_wide(to);
return (bool)CopyFileW(from_wide, to_wide, !replace_if_exists);
}
bool os_make_directory_s(string path, bool recursive) {
wchar_t *wide_path = temp_win32_fixed_utf8_to_null_terminated_wide(path);
@ -946,11 +954,11 @@ bool os_get_absolute_path(string path, string *result, Allocator allocator) {
bool os_get_relative_path(string from, string to, string *result, Allocator allocator) {
if (!os_is_path_absolute(from)) {
bool abs_ok = os_get_absolute_path(from, &from, temp);
bool abs_ok = os_get_absolute_path(from, &from, get_temporary_allocator());
if (!abs_ok) return false;
}
if (!os_is_path_absolute(to)) {
bool abs_ok = os_get_absolute_path(to, &to, temp);
bool abs_ok = os_get_absolute_path(to, &to, get_temporary_allocator());
if (!abs_ok) return false;
}

View file

@ -89,7 +89,8 @@ inline int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args) {
bool os_grow_program_memory(size_t new_size);
bool ogb_instance
os_grow_program_memory(size_t new_size);
///
///
@ -172,6 +173,8 @@ os_get_current_time_in_seconds();
// Dynamic Libraries
///
// #Cleanup this naming is bleh
Dynamic_Library_Handle ogb_instance
os_load_dynamic_library(string path);
@ -208,6 +211,9 @@ os_file_close(File f);
bool ogb_instance
os_file_delete_s(string path);
bool ogb_instance
os_file_copy_s(string from, string to, bool replace_if_exists);
bool ogb_instance
os_make_directory_s(string path, bool recursive);
@ -290,6 +296,12 @@ inline bool os_file_delete_f(const char *path) {return os_file_delete_s(STR(path
default: os_file_delete_f \
)(__VA_ARGS__)
inline bool os_file_copy_f(const char *from, const char *to, bool replace_if_exists) {return os_file_copy_s(STR(from), STR(to), replace_if_exists);}
#define os_file_copy(...) _Generic((FIRST_ARG(__VA_ARGS__)), \
string: os_file_copy_s, \
default: os_file_copy_f \
)(__VA_ARGS__)
inline bool os_make_directory_f(const char *path, bool recursive) { return os_make_directory_s(STR(path), recursive); }
#define os_make_directory(...) _Generic((FIRST_ARG(__VA_ARGS__)), \
string: os_make_directory_s, \

View file

@ -52,3 +52,15 @@ string get_file_name_excluding_extension(string file_path) {
}
return file_name;
}
string get_directory_of(string path) {
if (path.count <= 0) return ZERO(string);
for (u64 i = path.count; i >= 0; i--) {
if (path.data[i] == '/' || path.data[i] == '\\' || path.data[i] == ':') {
return string_view(path, 0, i);
}
}
return ZERO(string);
}

View file

@ -34,7 +34,7 @@ void _profiler_report_time_cycles(string name, u64 count, u64 start) {
spinlock_acquire_or_wait(&_profiler_lock);
string fmt = STR("{\"cat\":\"function\",\"dur\":%.3f,\"name\":\"%s\",\"ph\":\"X\",\"pid\":0,\"tid\":%zu,\"ts\":%lld},");
string_builder_print(&_profile_output, fmt, (float64)count*1000, name, context.thread_id, start*1000);
string_builder_print(&_profile_output, fmt, (float64)count*1000, name, get_context().thread_id, start*1000);
spinlock_release(&_profiler_lock);
}

View file

@ -5,7 +5,7 @@
*/
void* talloc(u64);
ogb_instance void* talloc(u64);
typedef struct string {
u64 count;
@ -41,7 +41,7 @@ dealloc_string(Allocator allocator, string s) {
}
string
talloc_string(u64 count) {
string s = alloc_string(temp, count);
string s = alloc_string(get_temporary_allocator(), count);
return s;
}
@ -69,7 +69,7 @@ convert_to_null_terminated_string(const string s, Allocator allocator) {
char *
temp_convert_to_null_terminated_string(const string s) {
char *c = convert_to_null_terminated_string(s, temp);
char *c = convert_to_null_terminated_string(s, get_temporary_allocator());
return c;
}
bool

View file

@ -1,5 +1,5 @@
void os_write_string_to_stdout(string s);
ogb_instance void os_write_string_to_stdout(string s);
inline int crt_sprintf(char *str, const char *format, ...);
int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args);
bool is_pointer_valid(void *p);
@ -135,7 +135,7 @@ string sprints(Allocator allocator, const string fmt, ...) {
string tprints(const string fmt, ...) {
va_list args = 0;
va_start(args, fmt);
string s = sprint_va_list(temp, fmt, args);
string s = sprint_va_list(get_temporary_allocator(), fmt, args);
va_end(args);
return s;
}
@ -161,7 +161,7 @@ string tprintf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
string s = sprint_va_list(temp, sfmt, args);
string s = sprint_va_list(get_temporary_allocator(), sfmt, args);
va_end(args);
return s;
@ -220,7 +220,7 @@ void printf(const char* fmt, ...) {
typedef void(*Logger_Proc)(Log_Level level, string s);
#define LOG_BASE(level, ...) if (context.logger) ((Logger_Proc)context.logger)(level, tprint(__VA_ARGS__))
#define LOG_BASE(level, ...) if (get_context().logger) ((Logger_Proc)get_context().logger)(level, tprint(__VA_ARGS__))
#define log_verbose(...) LOG_BASE(LOG_VERBOSE, __VA_ARGS__)

View file

@ -122,11 +122,11 @@ void test_allocator(bool do_log_heap) {
reset_temporary_storage();
int* foo = (int*)alloc(temp, 72);
int* foo = (int*)alloc(get_temporary_allocator(), 72);
*foo = 1337;
void* bar = alloc(temp, 69);
void* bar = alloc(get_temporary_allocator(), 69);
(void)bar;
void* baz = alloc(temp, 420);
void* baz = alloc(get_temporary_allocator(), 420);
(void)baz;
assert(*foo == 1337, "Temp memory corruptada");
@ -135,7 +135,7 @@ void test_allocator(bool do_log_heap) {
reset_temporary_storage();
foo = (int*)alloc(temp, 72);
foo = (int*)alloc(get_temporary_allocator(), 72);
assert(old_foo == foo, "Temp allocator goof");