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 // Build config stuff
#define RUN_TESTS 1
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5) #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. // 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/text_rendering.c"
// #include "oogabooga/examples/custom_logger.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/tile_game.c"
// #include "oogabooga/examples/audio_test.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! // This is where you swap in your own project!
// #include "entry_yourepicgamename.c" // #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 ## v0.01.001 - Spacial audio, custom shading, scissor boxing
- Audio - Audio
- Implemented spacial audio playback - 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 #define local_persist static
@ -9,10 +9,10 @@
#define null 0 #define null 0
ogb_instance void void
printf(const char* fmt, ...); printf(const char* fmt, ...);
ogb_instance void void
dump_stack_trace(); dump_stack_trace();
#define ASSERT_STR_HELPER(x) #x #define ASSERT_STR_HELPER(x) #x
@ -81,7 +81,7 @@ typedef struct Allocator {
void *data; void *data;
} Allocator; } Allocator;
ogb_instance Allocator Allocator
get_heap_allocator(); get_heap_allocator();
ogb_instance Allocator ogb_instance Allocator
@ -95,15 +95,15 @@ typedef struct Context {
CONTEXT_EXTRA extra; CONTEXT_EXTRA extra;
} Context; } Context;
forward_global thread_local Allocator temp;
#define CONTEXT_STACK_MAX 512 #define CONTEXT_STACK_MAX 512
// //
// // #Global
thread_local ogb_instance Context context; //thread_local ogb_instance Context context;
thread_local ogb_instance Context context_stack[CONTEXT_STACK_MAX]; //thread_local ogb_instance Context context_stack[CONTEXT_STACK_MAX];
thread_local ogb_instance u64 num_contexts; //thread_local ogb_instance u64 num_contexts;
ogb_instance
Context get_context();
ogb_instance void* ogb_instance void*
alloc(Allocator allocator, u64 size); alloc(Allocator allocator, u64 size);
@ -166,7 +166,10 @@ pop_context() {
context = context_stack[num_contexts]; context = context_stack[num_contexts];
} }
ogb_instance
Context get_context() {
return context;
}
#endif // NOT OOGABOOGA_LINK_EXTERNAL_INSTANCE #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" // Spinlock "primitive"
// Like a mutex but it eats up the entire core while waiting. // Like a mutex but it eats up the entire core while waiting.
// Beneficial if contention is low or sync speed is important // Beneficial if contention is low or sync speed is important
void spinlock_init(Spinlock *l); typedef struct Spinlock {
void spinlock_acquire_or_wait(Spinlock* l); 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. // This returns true if successfully acquired or false if timeout reached.
bool spinlock_acquire_or_wait_timeout(Spinlock* l, f64 timeout_seconds); bool ogb_instance
void spinlock_release(Spinlock* l); 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) // High-level mutex primitive (short spinlock then OS mutex lock)
// Just spins for a few (configurable) microseconds with a spinlock, // Just spins for a few (configurable) microseconds with a spinlock,
// and if acquiring fails it falls back to a OS mutex. // and if acquiring fails it falls back to a OS mutex.
void mutex_init(Mutex *m); #define MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS 100
void mutex_destroy(Mutex *m); typedef struct Mutex {
void mutex_acquire_or_wait(Mutex *m); Spinlock spinlock;
void mutex_release(Mutex *m); 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 // Binary semaphore
void binary_semaphore_init(Binary_Semaphore *sem, bool initial_state); typedef struct Binary_Semaphore {
void binary_semaphore_destroy(Binary_Semaphore *sem); bool signaled;
void binary_semaphore_wait(Binary_Semaphore *sem); Mutex mutex;
void binary_semaphore_signal(Binary_Semaphore *sem); } Binary_Semaphore;
typedef struct Spinlock { void ogb_instance
bool locked; binary_semaphore_init(Binary_Semaphore *sem, bool initial_state);
} Spinlock;
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) { void spinlock_init(Spinlock *l) {
memset(l, 0, sizeof(*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) // 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) { void mutex_init(Mutex *m) {
spinlock_init(&m->spinlock); spinlock_init(&m->spinlock);
m->spin_time_microseconds = MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS; m->spin_time_microseconds = MUTEX_DEFAULT_SPIN_TIME_MICROSECONDS;
@ -134,10 +167,7 @@ void mutex_release(Mutex *m) {
MEMORY_BARRIER; MEMORY_BARRIER;
} }
typedef struct Binary_Semaphore {
bool signaled;
Mutex mutex;
} Binary_Semaphore;
void binary_semaphore_init(Binary_Semaphore *sem, bool initial_state) { void binary_semaphore_init(Binary_Semaphore *sem, bool initial_state) {
sem->signaled = initial_state; sem->signaled = initial_state;
@ -164,3 +194,5 @@ void binary_semaphore_signal(Binary_Semaphore *sem) {
sem->signaled = true; sem->signaled = true;
mutex_release(&sem->mutex); mutex_release(&sem->mutex);
} }
#endif

View file

@ -106,6 +106,8 @@ typedef struct Cpu_Capabilities {
#define MEMORY_BARRIER _ReadWriteBarrier() #define MEMORY_BARRIER _ReadWriteBarrier()
#define thread_local __declspec(thread)
#define SHARED_EXPORT __declspec(dllexport) #define SHARED_EXPORT __declspec(dllexport)
#define SHARED_IMPORT __declspec(dllimport) #define SHARED_IMPORT __declspec(dllimport)
@ -223,8 +225,15 @@ typedef struct Cpu_Capabilities {
#define MEMORY_BARRIER __asm__ __volatile__("" ::: "memory") #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_EXPORT __attribute__((visibility("default")))
#define SHARED_IMPORT #define SHARED_IMPORT
#endif
#else #else
#define inline inline #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 bool
d3d11_compile_shader(string source) { 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("$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), temp); source = string_replace_all(source, STR("$VERTEX_2D_USER_DATA_COUNT"), tprint("%d", VERTEX_2D_USER_DATA_COUNT), get_temporary_allocator());
// #Leak on recompile // #Leak on recompile
@ -921,7 +921,7 @@ bool
shader_recompile_with_extension(string ext_source, u64 cbuffer_size) { 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; if (!d3d11_compile_shader(source)) return false;

View file

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

View file

@ -536,28 +536,41 @@ Allocator get_heap_allocator() {
#define TEMPORARY_STORAGE_SIZE (1024ULL*1024ULL*2ULL) // 2mb #define TEMPORARY_STORAGE_SIZE (1024ULL*1024ULL*2ULL) // 2mb
#endif #endif
void* talloc(u64); ogb_instance void* talloc(u64);
void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void*); ogb_instance void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void*);
// #Global // #Global
thread_local ogb_instance void * temporary_storage; ogb_instance Allocator
thread_local ogb_instance bool temporary_storage_initted; get_temporary_allocator();
thread_local ogb_instance void * temporary_storage_pointer;
thread_local ogb_instance bool has_warned_temporary_storage_overflow;
thread_local ogb_instance Allocator temp;
#if !OOGABOOGA_LINK_EXTERNAL_INSTANCE #if !OOGABOOGA_LINK_EXTERNAL_INSTANCE
thread_local void * temporary_storage = 0; thread_local void * temporary_storage = 0;
thread_local bool temporary_storage_initted = false; thread_local bool temporary_storage_initted = false;
thread_local void * temporary_storage_pointer = 0; thread_local void * temporary_storage_pointer = 0;
thread_local bool has_warned_temporary_storage_overflow = false; 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 #endif
Allocator get_temporary_allocator() { ogb_instance void*
return temp; 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) { void* temp_allocator_proc(u64 size, void *p, Allocator_Message message, void* data) {
switch (message) { switch (message) {
case ALLOCATOR_ALLOCATE: { case ALLOCATOR_ALLOCATE: {
@ -581,12 +594,12 @@ void temporary_storage_init() {
assert(temporary_storage, "Failed allocating temporary storage"); assert(temporary_storage, "Failed allocating temporary storage");
temporary_storage_pointer = temporary_storage; temporary_storage_pointer = temporary_storage;
temp.proc = temp_allocator_proc; temp_allocator.proc = temp_allocator_proc;
temp.data = 0; temp_allocator.data = 0;
temporary_storage_initted = true; temporary_storage_initted = true;
temp.proc = temp_allocator_proc; temp_allocator.proc = temp_allocator_proc;
} }
void* talloc(u64 size) { void* talloc(u64 size) {
@ -617,3 +630,4 @@ void reset_temporary_storage() {
has_warned_temporary_storage_overflow = true; 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 #define ENABLE_SIMD 1
#endif #endif
#ifndef INITIAL_PROGRAM_MEMORY_SIZE
#define INITIAL_PROGRAM_MEMORY_SIZE MB(5)
#endif
#if ENABLE_SIMD && !defined(SIMD_ENABLE_SSE2) #if ENABLE_SIMD && !defined(SIMD_ENABLE_SSE2)
#if COMPILER_CAN_DO_SSE2 #if COMPILER_CAN_DO_SSE2
#define SIMD_ENABLE_SSE2 1 #define SIMD_ENABLE_SSE2 1
@ -246,10 +250,13 @@ typedef u8 bool;
#if OOGABOOGA_LINK_EXTERNAL_INSTANCE #if OOGABOOGA_LINK_EXTERNAL_INSTANCE
#define ogb_instance SHARED_IMPORT extern #define ogb_instance SHARED_IMPORT extern
#else #elif OOGABOOGA_BUILD_SHARED_LIBRARY
#define ogb_instance SHARED_EXPORT #define ogb_instance SHARED_EXPORT
#else
#define ogb_instance
#endif #endif
// This needs to be included before dependencies // This needs to be included before dependencies
#include "base.c" #include "base.c"
@ -367,9 +374,12 @@ void default_logger(Log_Level level, string s) {
mutex_release(&_default_logger_mutex); 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) { void oogabooga_init(u64 program_memory_size) {
context.logger = default_logger; context.logger = default_logger;
temp = get_initialization_allocator(); temp_allocator = get_initialization_allocator();
Cpu_Capabilities features = query_cpu_capabilities(); Cpu_Capabilities features = query_cpu_capabilities();
os_init(program_memory_size); os_init(program_memory_size);
heap_init(); 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 avx2: %cs", features.avx2 ? "true" : "false");
log_verbose("CPU has avx512: %cs", features.avx512 ? "true" : "false"); log_verbose("CPU has avx512: %cs", features.avx512 ? "true" : "false");
} }
#endif
int ENTRY_PROC(int argc, char **argv); 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) { int main(int argc, char **argv) {
#endif
print("Ooga booga program started\n"); print("Ooga booga program started\n");
@ -421,6 +438,8 @@ int main(int argc, char **argv) {
return code; return code;
} }
#endif

View file

@ -588,8 +588,10 @@ float64 os_get_current_time_in_seconds() {
// Dynamic Libraries // Dynamic Libraries
/// ///
u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8);
Dynamic_Library_Handle os_load_dynamic_library(string path) { 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) { void *os_dynamic_library_load_symbol(Dynamic_Library_Handle l, string identifier) {
return GetProcAddress(l, temp_convert_to_null_terminated_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; return utf16_str;
} }
u16 *temp_win32_fixed_utf8_to_null_terminated_wide(string utf8) { 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) { 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); 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) { 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); 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) { bool os_make_directory_s(string path, bool recursive) {
wchar_t *wide_path = temp_win32_fixed_utf8_to_null_terminated_wide(path); 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) { bool os_get_relative_path(string from, string to, string *result, Allocator allocator) {
if (!os_is_path_absolute(from)) { 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 (!abs_ok) return false;
} }
if (!os_is_path_absolute(to)) { 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; 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 // Dynamic Libraries
/// ///
// #Cleanup this naming is bleh
Dynamic_Library_Handle ogb_instance Dynamic_Library_Handle ogb_instance
os_load_dynamic_library(string path); os_load_dynamic_library(string path);
@ -208,6 +211,9 @@ os_file_close(File f);
bool ogb_instance bool ogb_instance
os_file_delete_s(string path); os_file_delete_s(string path);
bool ogb_instance
os_file_copy_s(string from, string to, bool replace_if_exists);
bool ogb_instance bool ogb_instance
os_make_directory_s(string path, bool recursive); 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 \ default: os_file_delete_f \
)(__VA_ARGS__) )(__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); } 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__)), \ #define os_make_directory(...) _Generic((FIRST_ARG(__VA_ARGS__)), \
string: os_make_directory_s, \ string: os_make_directory_s, \

View file

@ -52,3 +52,15 @@ string get_file_name_excluding_extension(string file_path) {
} }
return file_name; 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); spinlock_acquire_or_wait(&_profiler_lock);
string fmt = STR("{\"cat\":\"function\",\"dur\":%.3f,\"name\":\"%s\",\"ph\":\"X\",\"pid\":0,\"tid\":%zu,\"ts\":%lld},"); 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); spinlock_release(&_profiler_lock);
} }

View file

@ -5,7 +5,7 @@
*/ */
void* talloc(u64); ogb_instance void* talloc(u64);
typedef struct string { typedef struct string {
u64 count; u64 count;
@ -41,7 +41,7 @@ dealloc_string(Allocator allocator, string s) {
} }
string string
talloc_string(u64 count) { talloc_string(u64 count) {
string s = alloc_string(temp, count); string s = alloc_string(get_temporary_allocator(), count);
return s; return s;
} }
@ -69,7 +69,7 @@ convert_to_null_terminated_string(const string s, Allocator allocator) {
char * char *
temp_convert_to_null_terminated_string(const string s) { 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; return c;
} }
bool 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, ...); inline int crt_sprintf(char *str, const char *format, ...);
int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args); int vsnprintf(char* buffer, size_t n, const char* fmt, va_list args);
bool is_pointer_valid(void *p); bool is_pointer_valid(void *p);
@ -135,7 +135,7 @@ string sprints(Allocator allocator, const string fmt, ...) {
string tprints(const string fmt, ...) { string tprints(const string fmt, ...) {
va_list args = 0; va_list args = 0;
va_start(args, fmt); 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); va_end(args);
return s; return s;
} }
@ -161,7 +161,7 @@ string tprintf(const char *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); 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); va_end(args);
return s; return s;
@ -220,7 +220,7 @@ void printf(const char* fmt, ...) {
typedef void(*Logger_Proc)(Log_Level level, string s); 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__) #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(); reset_temporary_storage();
int* foo = (int*)alloc(temp, 72); int* foo = (int*)alloc(get_temporary_allocator(), 72);
*foo = 1337; *foo = 1337;
void* bar = alloc(temp, 69); void* bar = alloc(get_temporary_allocator(), 69);
(void)bar; (void)bar;
void* baz = alloc(temp, 420); void* baz = alloc(get_temporary_allocator(), 420);
(void)baz; (void)baz;
assert(*foo == 1337, "Temp memory corruptada"); assert(*foo == 1337, "Temp memory corruptada");
@ -135,7 +135,7 @@ void test_allocator(bool do_log_heap) {
reset_temporary_storage(); reset_temporary_storage();
foo = (int*)alloc(temp, 72); foo = (int*)alloc(get_temporary_allocator(), 72);
assert(old_foo == foo, "Temp allocator goof"); assert(old_foo == foo, "Temp allocator goof");