diff --git a/.gitignore b/.gitignore index 3443096..5eb2a57 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,6 @@ test_doc.vkn *keybinds *.rdi -.vscode \ No newline at end of file +.vscode + +google_trace.json \ No newline at end of file diff --git a/build.c b/build.c index 64306c1..150e60b 100644 --- a/build.c +++ b/build.c @@ -7,6 +7,8 @@ // This is only for people developing oogabooga! #define OOGABOOGA_DEV 1 +#define ENABLE_PROFILING 0 + // When we need very debug // #define CONFIGURATION VERY_DEBUG @@ -24,6 +26,6 @@ typedef struct Context_Extra { // // Comment & Uncomment to swap projects -// #include "entry_engine_test.c" +// #include "entry_engine_test.c" // #include "entry_minimal_example.c" -#include "entry_randygame.c" \ No newline at end of file + #include "entry_randygame.c" \ No newline at end of file diff --git a/build_dissassembly.bat b/build_dissassembly.bat new file mode 100644 index 0000000..135a9a5 --- /dev/null +++ b/build_dissassembly.bat @@ -0,0 +1,14 @@ + +@echo off +rmdir /S /Q build +mkdir build + +pushd build + +mkdir release +pushd release + +clang -o cgame.asm ../../build.c -Ofast -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -Wno-builtin-requires-header -ffast-math -funroll-loops -finline-functions -fvectorize -fslp-vectorize -fomit-frame-pointer -fno-exceptions -fno-rtti -S -masm=intel + +popd +popd \ No newline at end of file diff --git a/entry_engine_test.c b/entry_engine_test.c index 22d8295..3a57583 100644 --- a/entry_engine_test.c +++ b/entry_engine_test.c @@ -2,17 +2,17 @@ int entry(int argc, char **argv) { - window.title = fixed_string("Engine Testing Example"); + window.title = STR("My epic game"); window.width = 1280; window.height = 720; window.x = 200; - window.y = 200; + window.y = 0; window.clear_color = hex_to_rgba(0x2a2d3aff); - Gfx_Image *bush_image = load_image_from_disk(fixed_string("berry_bush.png"), get_heap_allocator()); + Gfx_Image *bush_image = load_image_from_disk(STR("berry_bush.png"), get_heap_allocator()); assert(bush_image, "Failed loading berry_bush.png"); - Gfx_Image *hammer_image = load_image_from_disk(fixed_string("hammer.png"), get_heap_allocator()); + Gfx_Image *hammer_image = load_image_from_disk(STR("hammer.png"), get_heap_allocator()); assert(hammer_image, "Failed loading hammer.png"); seed_for_random = os_get_current_cycle_count(); @@ -23,7 +23,7 @@ int entry(int argc, char **argv) { Matrix4 camera_view = m4_scalar(1.0); float64 last_time = os_get_current_time_in_seconds(); - while (!window.should_close) { + while (!window.should_close) tm_scope_cycles("Frame") { reset_temporary_storage(); float64 now = os_get_current_time_in_seconds(); @@ -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(fixed_string("berry_bush.png"), get_heap_allocator()); + bush_image = load_image_from_disk(STR("berry_bush.png"), get_heap_allocator()); assert(bush_image, "Failed loading berry_bush.png"); } @@ -70,11 +70,25 @@ int entry(int argc, char **argv) { } Vector2 cam_move = v2_mulf(cam_move_axis, delta * cam_move_speed); - camera_view = m4_translate(camera_view, v3(v2_expand(cam_move), 0)); - draw_frame.view = camera_view; + seed_for_random = 69; + for (u64 i = 0; i < 100000; i++) { + float32 aspect = (float32)window.width/(float32)window.height; + float min_x = -aspect; + float max_x = aspect; + float min_y = -1; + float max_y = 1; + + float x = get_random_float32() * (max_x-min_x) + min_x; + float y = get_random_float32() * (max_y-min_y) + min_y; + + draw_image(bush_image, v2(x, y), v2(0.1, 0.1), COLOR_WHITE); + } + seed_for_random = os_get_current_cycle_count(); + + Matrix4 hammer_xform = m4_scalar(1.0); hammer_xform = m4_rotate_z(hammer_xform, (f32)now); hammer_xform = m4_translate(hammer_xform, v3(-.25f, -.25f, 0)); diff --git a/entry_minimal_example.c b/entry_minimal_example.c index 6d8fb15..f40e4e3 100644 --- a/entry_minimal_example.c +++ b/entry_minimal_example.c @@ -1,26 +1,26 @@ - -int entry(int argc, char **argv) { - - window.title = fixed_string("Minimal Game Example"); - window.width = 1280; - window.height = 720; - window.x = 200; - window.y = 200; - window.clear_color = v4(1, 1, 1, 1); - - while (!window.should_close) { - reset_temporary_storage(); - - os_update(); - - float64 now = os_get_current_time_in_seconds(); - Matrix4 hammer_xform = m4_scalar(1.0); - hammer_xform = m4_rotate_z(hammer_xform, (f32)now); - hammer_xform = m4_translate(hammer_xform, v3(-.25f, -.25f, 0)); - draw_rect_xform(hammer_xform, v2(.5f, .5f), COLOR_RED); - - gfx_update(); - } - - return 0; + +int entry(int argc, char **argv) { + + window.title = STR("Minimal Game Example"); + window.width = 1280; + window.height = 720; + window.x = 200; + window.y = 200; + window.clear_color = v4(1, 1, 1, 1); + + while (!window.should_close) { + reset_temporary_storage(); + + os_update(); + + float64 now = os_get_current_time_in_seconds(); + Matrix4 hammer_xform = m4_scalar(1.0); + hammer_xform = m4_rotate_z(hammer_xform, (f32)now); + hammer_xform = m4_translate(hammer_xform, v3(-.25f, -.25f, 0)); + draw_rect_xform(hammer_xform, v2(.5f, .5f), COLOR_RED); + + gfx_update(); + } + + return 0; } \ No newline at end of file diff --git a/entry_randygame.c b/entry_randygame.c index 2324875..089d2c5 100644 --- a/entry_randygame.c +++ b/entry_randygame.c @@ -1,64 +1,64 @@ - -int entry(int argc, char **argv) { - - window.title = fixed_string("Randy's Game"); - window.width = 1280; - window.height = 720; - window.x = 200; - window.y = 200; - window.clear_color = hex_to_rgba(0x2a2d3aff); - - Gfx_Image* player = load_image_from_disk(fixed_string("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; - - float64 last_time = os_get_current_time_in_seconds(); - while (!window.should_close) { - reset_temporary_storage(); - - float64 now = os_get_current_time_in_seconds(); - float64 delta_t = now - last_time; - last_time = now; - - os_update(); - - if (is_key_just_pressed(KEY_ESCAPE)) { - window.should_close = true; - } - - Vector2 input_axis = v2(0, 0); - if (is_key_down('A')) { - input_axis.x -= 1.0; - } - if (is_key_down('D')) { - input_axis.x += 1.0; - } - if (is_key_down('S')) { - input_axis.y -= 1.0; - } - if (is_key_down('W')) { - input_axis.y += 1.0; - } - input_axis = v2_normalize(input_axis); - - player_pos = v2_add(player_pos, v2_mulf(input_axis, 5.0 * delta_t)); - - Matrix4 xform = m4_scalar(1.0); - xform = m4_translate(xform, v3(player_pos.x, player_pos.y, 0)); - draw_image_xform(player, xform, v2(.5f, .5f), COLOR_RED); - - gfx_update(); - seconds_counter += delta_t; - frame_count += 1; - if (seconds_counter > 1.0) { - log("fps: %i", frame_count); - seconds_counter = 0.0; - frame_count = 0; - } - } - - return 0; + +int entry(int argc, char **argv) { + + window.title = STR("Randy's Game"); + window.width = 1280; + window.height = 720; + 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; + + float64 last_time = os_get_current_time_in_seconds(); + while (!window.should_close) { + reset_temporary_storage(); + + float64 now = os_get_current_time_in_seconds(); + float64 delta_t = now - last_time; + last_time = now; + + os_update(); + + if (is_key_just_pressed(KEY_ESCAPE)) { + window.should_close = true; + } + + Vector2 input_axis = v2(0, 0); + if (is_key_down('A')) { + input_axis.x -= 1.0; + } + if (is_key_down('D')) { + input_axis.x += 1.0; + } + if (is_key_down('S')) { + input_axis.y -= 1.0; + } + if (is_key_down('W')) { + input_axis.y += 1.0; + } + input_axis = v2_normalize(input_axis); + + player_pos = v2_add(player_pos, v2_mulf(input_axis, 5.0 * delta_t)); + + Matrix4 xform = m4_scalar(1.0); + xform = m4_translate(xform, v3(player_pos.x, player_pos.y, 0)); + draw_image_xform(player, xform, v2(.5f, .5f), COLOR_RED); + + gfx_update(); + seconds_counter += delta_t; + frame_count += 1; + if (seconds_counter > 1.0) { + log("fps: %i", frame_count); + seconds_counter = 0.0; + frame_count = 0; + } + } + + return 0; } \ No newline at end of file diff --git a/oogabooga/base.c b/oogabooga/base.c index 8fcb01d..fa3d573 100644 --- a/oogabooga/base.c +++ b/oogabooga/base.c @@ -42,11 +42,13 @@ typedef u8 bool; void printf(const char* fmt, ...); -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) -#define assert_line(line, cond, ...) if(!(cond)) { printf("Assertion failed in file " __FILE__ " on line " STR(line) "\nFailed Condition: " #cond ". Message: " __VA_ARGS__); os_break(); } +#define ASSERT_STR_HELPER(x) #x +#define ASSERT_STR(x) ASSERT_STR_HELPER(x) +#define assert_line(line, cond, ...) if(!(cond)) { printf("Assertion failed in file " __FILE__ " on line " ASSERT_STR(line) "\nFailed Condition: " #cond ". Message: " __VA_ARGS__); os_break(); } #define assert(cond, ...) assert_line(__LINE__, cond, __VA_ARGS__); +#define DEFER(start, end) for(int _i_ = ((start), 0); _i_ == 0; _i_ += 1, (end)) + #if CONFIGURATION == RELEASE #undef assert #define assert(...) @@ -65,35 +67,73 @@ void printf(const char* fmt, ...); // Microsoft Visual C++ #define inline __forceinline #define COMPILER_HAS_MEMCPY_INTRINSICS 1 + #include + #pragma intrinsic(__rdtsc) + inline u64 rdtsc() { + return __rdtsc(); + } #elif defined(__GNUC__) || defined(__GNUG__) // GNU GCC/G++ #define inline __attribute__((always_inline)) inline #define COMPILER_HAS_MEMCPY_INTRINSICS 1 + inline u64 rdtsc() { + unsigned int lo, hi; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return ((u64)hi << 32) | lo; + } #elif defined(__clang__) // Clang/LLVM #define inline __attribute__((always_inline)) inline #define COMPILER_HAS_MEMCPY_INTRINSICS 1 + inline u64 rdtsc() { + unsigned int lo, hi; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return ((u64)hi << 32) | lo; + } #elif defined(__INTEL_COMPILER) || defined(__ICC) // Intel C++ Compiler #define inline __forceinline #define COMPILER_HAS_MEMCPY_INTRINSICS 1 + inline u64 rdtsc() { + return __rdtsc(); + } #elif defined(__BORLANDC__) // Borland C++ #define inline __inline -#elif defined(__MINGW32__) || defined(__MINGW64__) - // MinGW (Minimalist GNU for Windows) - #define inline __attribute__((always_inline)) inline - #define COMPILER_HAS_MEMCPY_INTRINSICS 1 + inline u64 rdtsc() { + unsigned int lo, hi; + __asm { + rdtsc + mov lo, eax + mov hi, edx + } + return ((u64)hi << 32) | lo; + } #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) // Oracle Solaris Studio #define inline inline __attribute__((always_inline)) + inline u64 rdtsc() { + unsigned int lo, hi; + asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); + return ((u64)hi << 32) | lo; + } #elif defined(__IBMC__) || defined(__IBMCPP__) // IBM XL C/C++ Compiler #define inline __attribute__((always_inline)) inline #define COMPILER_HAS_MEMCPY_INTRINSICS 1 + inline u64 rdtsc() { + unsigned int lo, hi; + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); + return ((u64)hi << 32) | lo; + } #elif defined(__PGI) // Portland Group Compiler #define inline inline __attribute__((always_inline)) + inline u64 rdtsc() { + unsigned int lo, hi; + asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); + return ((u64)hi << 32) | lo; + } #else // Fallback for unknown compilers #define inline inline diff --git a/oogabooga/d3d11_image_shader_bytecode.c b/oogabooga/d3d11_image_shader_bytecode.c index 28407e2..2692a84 100644 --- a/oogabooga/d3d11_image_shader_bytecode.c +++ b/oogabooga/d3d11_image_shader_bytecode.c @@ -1,5 +1,5 @@ /* -<<<<<< Bytecode compiled from HLSL code below: >>>>>> +<<<<<< Bytecode compiled fro HLSL code below: >>>>>> struct VS_INPUT { @@ -78,7 +78,7 @@ float4 ps_main(PS_INPUT input) : SV_TARGET } */ -const u8 IMAGE_SHADER_VERTEX_BLOB_BYTES[] = { +const u8 IMAGE_SHADER_VERTEX_BLOB_BYTES[]= { 0x44, 0x58, 0x42, 0x43, 0xdd, 0x02, 0x55, 0xb0, 0x7b, 0x83, 0x6c, 0x34, 0x45, 0xe8, 0x51, 0xd4, 0x76, 0xbf, 0x66, 0x77, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0xd4, 0x01, @@ -136,7 +136,7 @@ const u8 IMAGE_SHADER_VERTEX_BLOB_BYTES[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const u8 IMAGE_SHADER_PIXEL_BLOB_BYTES[] = { +const u8 IMAGE_SHADER_PIXEL_BLOB_BYTES[]= { 0x44, 0x58, 0x42, 0x43, 0xa6, 0x92, 0xe1, 0x1e, 0x36, 0x1d, 0x06, 0x3b, 0xbf, 0x5b, 0xfa, 0x13, 0xd8, 0xd2, 0xd3, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x74, 0x18, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x64, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x34, 0x07, diff --git a/oogabooga/drawing.c b/oogabooga/drawing.c index be5c3a0..582cc9f 100644 --- a/oogabooga/drawing.c +++ b/oogabooga/drawing.c @@ -64,6 +64,7 @@ typedef struct Draw_Quad { Vector4 uv; } Draw_Quad; + typedef struct Draw_Quad_Block { Draw_Quad quad_buffer[QUADS_PER_BLOCK]; u64 num_quads; @@ -71,8 +72,12 @@ typedef struct Draw_Quad_Block { struct Draw_Quad_Block *next; } Draw_Quad_Block; +// I made these blocks part of the frame at first so they were temp allocated BUT I think +// that was a mistake because these blocks are accessed a lot so we want it to just be +// persistent memory that's super hot all the time. +Draw_Quad_Block first_block = {0}; + typedef struct Draw_Frame { - Draw_Quad_Block first_block; Draw_Quad_Block *current; u64 num_blocks; @@ -89,6 +94,9 @@ Draw_Frame draw_frame = ZERO(Draw_Frame); void reset_draw_frame(Draw_Frame *frame) { *frame = (Draw_Frame){0}; + frame->current = &first_block; + frame->current->num_quads = 0; + float32 aspect = (float32)window.width/(float32)window.height; frame->projection = m4_make_orthographic_projection(-aspect, aspect, -1, 1, -1, 10); @@ -101,17 +109,20 @@ Draw_Quad *draw_quad_projected(Draw_Quad quad, Matrix4 world_to_clip) { quad.top_right = m4_transform(world_to_clip, v4(v2_expand(quad.top_right), 0, 1)).xy; quad.bottom_right = m4_transform(world_to_clip, v4(v2_expand(quad.bottom_right), 0, 1)).xy; - if (!draw_frame.current) draw_frame.current = &draw_frame.first_block; + if (!draw_frame.current) draw_frame.current = &first_block; - if (draw_frame.current == &draw_frame.first_block) draw_frame.num_blocks = 1; + if (draw_frame.current == &first_block) draw_frame.num_blocks = 1; assert(draw_frame.current->num_quads <= QUADS_PER_BLOCK); if (draw_frame.current->num_quads == QUADS_PER_BLOCK) { - draw_frame.current->next = cast(Draw_Quad_Block*)talloc(sizeof(Draw_Quad_Block)); - draw_frame.current = draw_frame.current->next; - draw_frame.current->next = 0; + if (!draw_frame.current->next) { + draw_frame.current->next = cast(Draw_Quad_Block*)alloc(get_heap_allocator(), sizeof(Draw_Quad_Block)); + *draw_frame.current->next = ZERO(Draw_Quad_Block); + } + + draw_frame.current = draw_frame.current->next; draw_frame.current->num_quads = 0; draw_frame.num_blocks += 1; diff --git a/oogabooga/gfx_impl_d3d11.c b/oogabooga/gfx_impl_d3d11.c index 7bedb0d..250a04f 100644 --- a/oogabooga/gfx_impl_d3d11.c +++ b/oogabooga/gfx_impl_d3d11.c @@ -44,6 +44,53 @@ ID3D11InputLayout *d3d11_image_vertex_layout = 0; ID3D11Buffer *d3d11_quad_vbo = 0; u32 d3d11_quad_vbo_size = 0; +void *d3d11_staging_quad_buffer = 0; + +const char* d3d11_stringify_category(D3D11_MESSAGE_CATEGORY category) { + switch (category) { + case D3D11_MESSAGE_CATEGORY_APPLICATION_DEFINED: return "Application Defined"; + case D3D11_MESSAGE_CATEGORY_MISCELLANEOUS: return "Miscellaneous"; + case D3D11_MESSAGE_CATEGORY_INITIALIZATION: return "Initialization"; + case D3D11_MESSAGE_CATEGORY_CLEANUP: return "Cleanup"; + case D3D11_MESSAGE_CATEGORY_COMPILATION: return "Compilation"; + case D3D11_MESSAGE_CATEGORY_STATE_CREATION: return "State Creation"; + case D3D11_MESSAGE_CATEGORY_STATE_SETTING: return "State Setting"; + case D3D11_MESSAGE_CATEGORY_STATE_GETTING: return "State Getting"; + case D3D11_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: return "Resource Manipulation"; + case D3D11_MESSAGE_CATEGORY_EXECUTION: return "Execution"; + default: return "Unknown"; + } +} + +const char* d3d11_stringify_severity(D3D11_MESSAGE_SEVERITY severity) { + switch (severity) { + case D3D11_MESSAGE_SEVERITY_CORRUPTION: return "Corruption"; + case D3D11_MESSAGE_SEVERITY_ERROR: return "Error"; + case D3D11_MESSAGE_SEVERITY_WARNING: return "Warning"; + case D3D11_MESSAGE_SEVERITY_INFO: return "Info"; + case D3D11_MESSAGE_SEVERITY_MESSAGE: return "Message"; + default: return "Unknown"; + } +} + +void CALLBACK d3d11_debug_callback(D3D11_MESSAGE_CATEGORY category, D3D11_MESSAGE_SEVERITY severity, D3D11_MESSAGE_ID id, const char* description) +{ + string msg = tprint("D3D11 MESSAGE [Category: %cs, Severity: %cs, id: %d]: %cs", d3d11_stringify_category(category), d3d11_stringify_severity(severity), id, description); + + switch (severity) { + case D3D11_MESSAGE_SEVERITY_CORRUPTION: + case D3D11_MESSAGE_SEVERITY_ERROR: + log_error(msg); + case D3D11_MESSAGE_SEVERITY_WARNING: + log_warning(msg); + case D3D11_MESSAGE_SEVERITY_INFO: + log_info(msg); + case D3D11_MESSAGE_SEVERITY_MESSAGE: + log_verbose(msg); + default: + log("Ligma"); + } +} #define win32_check_hr(hr) win32_check_hr_impl(hr, __LINE__, __FILE__); void win32_check_hr_impl(HRESULT hr, u32 line, const char* file_name) { @@ -313,7 +360,7 @@ void gfx_init() { #if OOGABOOGA_DEV string source; - bool source_ok = os_read_entire_file(fxstr("oogabooga/dev/d3d11_image_shader.hlsl"), &source, get_heap_allocator()); // #Leak + bool source_ok = os_read_entire_file("oogabooga/dev/d3d11_image_shader.hlsl", &source, get_heap_allocator()); // #Leak assert(source_ok, "Could not open d3d11_image_shader source"); // Compile vertex shader @@ -336,28 +383,28 @@ void gfx_init() { /// // Dump blobs to the .c - File blob_file = os_file_open(fxstr("oogabooga/d3d11_image_shader_bytecode.c"), O_WRITE | O_CREATE); - os_file_write_string(blob_file, fxstr("/*\n")); - os_file_write_string(blob_file, fxstr("<<<<<< Bytecode compiled from HLSL code below: >>>>>>\n\n")); + File blob_file = os_file_open("oogabooga/d3d11_image_shader_bytecode.c", O_WRITE | O_CREATE); + os_file_write_string(blob_file, STR("/*\n")); + os_file_write_string(blob_file, STR("<<<<<< Bytecode compiled fro HLSL code below: >>>>>>\n\n")); os_file_write_string(blob_file, source); - os_file_write_string(blob_file, fxstr("\n*/\n\n")); + os_file_write_string(blob_file, STR("\n*/\n\n")); - os_file_write_string(blob_file, fxstr("const u8 IMAGE_SHADER_VERTEX_BLOB_BYTES[] = {\n")); + os_file_write_string(blob_file, STR("const u8 IMAGE_SHADER_VERTEX_BLOB_BYTES[]= {\n")); for (u64 i = 0; i < vs_size; i++) { os_file_write_string(blob_file, tprint("0x%02x", (int)((u8*)vs_buffer)[i])); - if (i < vs_size-1) os_file_write_string(blob_file, fxstr(", ")); - if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, fxstr("\n")); - } - os_file_write_string(blob_file, fxstr("\n};\n")); + if (i < vs_size-1) os_file_write_string(blob_file, STR(", ")); + if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, STR("\n")); +} + os_file_write_string(blob_file, STR("\n};\n")); - os_file_write_string(blob_file, fxstr("const u8 IMAGE_SHADER_PIXEL_BLOB_BYTES[] = {\n")); + os_file_write_string(blob_file, STR("const u8 IMAGE_SHADER_PIXEL_BLOB_BYTES[]= {\n")); for (u64 i = 0; i < ps_size; i++) { os_file_write_string(blob_file, tprint("0x%02x", (int)((u8*)ps_buffer)[i])); - if (i < ps_size-1) os_file_write_string(blob_file, fxstr(", ")); - if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, fxstr("\n")); - } - os_file_write_string(blob_file, fxstr("\n};\n")); - os_file_close(blob_file); + if (i < ps_size-1) os_file_write_string(blob_file, STR(", ")); + if (i % 15 == 0 && i != 0) os_file_write_string(blob_file, STR("\n")); +} + os_file_write_string(blob_file, STR("\n};\n")); + os_file_close(blob_file); #else @@ -451,7 +498,6 @@ void gfx_update() { VTABLE(ClearRenderTargetView, d3d11_context, d3d11_window_render_target_view, (float*)&window.clear_color); - f64 rest_before = os_get_current_time_in_seconds(); HRESULT hr; @@ -487,9 +533,11 @@ void gfx_update() { /// // Maybe grow quad vbo u32 required_size = sizeof(D3D11_Vertex) * draw_frame.num_blocks*QUADS_PER_BLOCK*6; + if (required_size > d3d11_quad_vbo_size) { if (d3d11_quad_vbo) { D3D11Release(d3d11_quad_vbo); + dealloc(get_heap_allocator(), d3d11_staging_quad_buffer); } D3D11_BUFFER_DESC desc = ZERO(D3D11_BUFFER_DESC); desc.Usage = D3D11_USAGE_DYNAMIC; @@ -500,126 +548,146 @@ void gfx_update() { assert(SUCCEEDED(hr), "CreateBuffer failed"); d3d11_quad_vbo_size = required_size; + d3d11_staging_quad_buffer = alloc(get_heap_allocator(), d3d11_quad_vbo_size); + log_verbose("Grew quad vbo to %d bytes.", d3d11_quad_vbo_size); } + f64 rest_before = os_get_current_time_in_seconds(); if (draw_frame.num_blocks > 0) { /// // Render geometry from into vbo quad list - D3D11_MAPPED_SUBRESOURCE buffer_mapping; - VTABLE(Map, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0, D3D11_MAP_WRITE_DISCARD, 0, &buffer_mapping); + ID3D11ShaderResourceView *textures[32]; ID3D11ShaderResourceView *last_texture = 0; u64 num_textures = 0; - D3D11_Vertex* head = buffer_mapping.pData; + D3D11_Vertex* head = (D3D11_Vertex*)d3d11_staging_quad_buffer; D3D11_Vertex* pointer = head; u64 number_of_rendered_quads = 0; - Draw_Quad_Block *block = &draw_frame.first_block; - while (block != 0) { - - for (u64 i = 0; i < block->num_quads; i++) { - Draw_Quad *q = &block->quad_buffer[i]; - - int texture_index = -1; - - if (q->image) { - if (!q->image->gfx_handle) { - D3D11_TEXTURE2D_DESC desc = ZERO(D3D11_TEXTURE2D_DESC); - desc.Width = q->image->width; - desc.Height = q->image->height; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; + Draw_Quad_Block *block = &first_block; + + tm_scope_cycles("Quad processing") { + while (block != 0 && block->num_quads > 0) tm_scope_cycles("ad2As") { + for (u64 i = 0; i < block->num_quads; i++) tm_scope_cycles("Single quad") { + + Draw_Quad *q = &block->quad_buffer[i]; + + int texture_index = -1; + + if (q->image) { + if (!q->image->gfx_handle) { + D3D11_TEXTURE2D_DESC desc = ZERO(D3D11_TEXTURE2D_DESC); + desc.Width = q->image->width; + desc.Height = q->image->height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + D3D11_SUBRESOURCE_DATA data = ZERO(D3D11_SUBRESOURCE_DATA); + data.pSysMem = q->image->data; + data.SysMemPitch = q->image->width * 4; // #Magicvalue assuming 4 channels + + ID3D11Texture2D* texture = 0; + HRESULT hr = VTABLE(CreateTexture2D, d3d11_device, &desc, &data, &texture); + win32_check_hr(hr); + + hr = VTABLE(CreateShaderResourceView, d3d11_device, (ID3D11Resource*)texture, 0, &q->image->gfx_handle); + win32_check_hr(hr); + + log_verbose("Created an image of width %d and height %d.", q->image->width, q->image->height); + } - D3D11_SUBRESOURCE_DATA data = ZERO(D3D11_SUBRESOURCE_DATA); - data.pSysMem = q->image->data; - data.SysMemPitch = q->image->width * 4; // #Magicvalue assuming 4 channels - - ID3D11Texture2D* texture = 0; - HRESULT hr = VTABLE(CreateTexture2D, d3d11_device, &desc, &data, &texture); - win32_check_hr(hr); - - hr = VTABLE(CreateShaderResourceView, d3d11_device, (ID3D11Resource*)texture, 0, &q->image->gfx_handle); - win32_check_hr(hr); - - log_verbose("Created an image of width %d and height %d.", q->image->width, q->image->height); + if (last_texture == q->image->gfx_handle) { + texture_index = (int)(num_textures-1); + } else { + // First look if texture is already bound + for (u64 j = 0; j < num_textures; j++) { + if (textures[j] == q->image->gfx_handle) { + texture_index = (int)j; + break; + } + } + // Otherwise use a new slot + if (texture_index <= -1) { + if (num_textures >= 32) { + // If max textures reached, make a draw call and start over + D3D11_MAPPED_SUBRESOURCE buffer_mapping; + VTABLE(Map, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &buffer_mapping); + memcpy(buffer_mapping.pData, d3d11_staging_quad_buffer, number_of_rendered_quads*sizeof(D3D11_Vertex)*6); + VTABLE(Unmap, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0); + d3d11_draw_call(number_of_rendered_quads, textures, num_textures); + head = (D3D11_Vertex*)d3d11_staging_quad_buffer; + num_textures = 0; + texture_index = 0; + number_of_rendered_quads = 0; + pointer = head; + } else { + texture_index = (int)num_textures; + num_textures += 1; + } + } + } + textures[texture_index] = q->image->gfx_handle; + last_texture = q->image->gfx_handle; } - if (last_texture == q->image->gfx_handle) { - texture_index = (int)(num_textures-1); - } else { - // First look if texture is already bound - for (u64 j = 0; j < num_textures; j++) { - if (textures[j] == q->image->gfx_handle) { - texture_index = (int)j; - break; - } - } - // Otherwise use a new slot - if (texture_index <= -1) { - if (num_textures >= 32) { - // If max textures reached, make a draw call and start over - d3d11_draw_call(number_of_rendered_quads, textures, num_textures); - num_textures = 0; - texture_index = 0; - number_of_rendered_quads = 0; - pointer = head; - } else { - texture_index = (int)num_textures; - num_textures += 1; - } - } + // We will write to 6 vertices for the one quad (two tris) + { + + D3D11_Vertex* BL = pointer + 0; + D3D11_Vertex* TL = pointer + 1; + D3D11_Vertex* TR = pointer + 2; + D3D11_Vertex* BL2 = pointer + 3; + D3D11_Vertex* TR2 = pointer + 4; + D3D11_Vertex* BR = pointer + 5; + pointer += 6; + + BL->position = v4(q->bottom_left.x, q->bottom_left.y, 0, 1); + TL->position = v4(q->top_left.x, q->top_left.y, 0, 1); + TR->position = v4(q->top_right.x, q->top_right.y, 0, 1); + BR->position = v4(q->bottom_right.x, q->bottom_right.y, 0, 1); + + BL->uv = v2(q->uv.x1, q->uv.y1); + TL->uv = v2(q->uv.x1, q->uv.y2); + TR->uv = v2(q->uv.x2, q->uv.y2); + BR->uv = v2(q->uv.x2, q->uv.y1); + + BL->color = TL->color = TR->color = BR->color = q->color; + + BL->texture_index=TL->texture_index=TR->texture_index=BR->texture_index = texture_index; + + *BL2 = *BL; + *TR2 = *TR; + + number_of_rendered_quads += 1; } - textures[texture_index] = q->image->gfx_handle; - last_texture = q->image->gfx_handle; } - // We will write to 6 vertices for the one quad (two tris) - D3D11_Vertex* BL = pointer + 0; - D3D11_Vertex* TL = pointer + 1; - D3D11_Vertex* TR = pointer + 2; - D3D11_Vertex* BL2 = pointer + 3; - D3D11_Vertex* TR2 = pointer + 4; - D3D11_Vertex* BR = pointer + 5; - pointer += 6; - BL->position = v4(q->bottom_left.x, q->bottom_left.y, 0, 1); - TL->position = v4(q->top_left.x, q->top_left.y, 0, 1); - TR->position = v4(q->top_right.x, q->top_right.y, 0, 1); - BR->position = v4(q->bottom_right.x, q->bottom_right.y, 0, 1); - - BL->uv = v2(q->uv.x1, q->uv.y1); - TL->uv = v2(q->uv.x1, q->uv.y2); - TR->uv = v2(q->uv.x2, q->uv.y2); - BR->uv = v2(q->uv.x2, q->uv.y1); - - BL->color = TL->color = TR->color = BR->color = q->color; - - BL->texture_index=TL->texture_index=TR->texture_index=BR->texture_index = texture_index; - - *BL2 = *BL; - *TR2 = *TR; - - number_of_rendered_quads += 1; + block = block->next; } - - block = block->next; } - + + D3D11_MAPPED_SUBRESOURCE buffer_mapping; + VTABLE(Map, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &buffer_mapping); + memcpy(buffer_mapping.pData, d3d11_staging_quad_buffer, number_of_rendered_quads*sizeof(D3D11_Vertex)*6); VTABLE(Unmap, d3d11_context, (ID3D11Resource*)d3d11_quad_vbo, 0); /// // Draw call + u64 before_draw = os_get_current_cycle_count(); d3d11_draw_call(number_of_rendered_quads, textures, num_textures); + u64 after_draw = os_get_current_cycle_count(); + //log("Draw call took %llu cycles", after_draw-before_draw); } f64 rest_after = os_get_current_time_in_seconds(); @@ -633,5 +701,27 @@ void gfx_update() { log("Present took %.2fms", (after-before_present)*1000.0); win32_check_hr(hr); +#if CONFIGURATION == DEBUG + /// + // Check debug messages, output to stdout + ID3D11InfoQueue* info_q = 0; + hr = VTABLE(QueryInterface, d3d11_device, &IID_ID3D11InfoQueue, (void**)&info_q); + if (SUCCEEDED(hr)) { + u64 msg_count = VTABLE(GetNumStoredMessagesAllowedByRetrievalFilter, info_q); + for (u64 i = 0; i < msg_count; i++) { + SIZE_T msg_size = 0; + VTABLE(GetMessage, info_q, i, 0, &msg_size); + + D3D11_MESSAGE* msg = (D3D11_MESSAGE*)talloc(msg_size); + if (msg) { + VTABLE(GetMessage, info_q, i, msg, &msg_size); // Get the actual message + + d3d11_debug_callback(msg->Category, msg->Severity, msg->ID, msg->pDescription); + } + } + } +#endif + reset_draw_frame(&draw_frame); + } diff --git a/oogabooga/memory.c b/oogabooga/memory.c index cd0503c..e1f1487 100644 --- a/oogabooga/memory.c +++ b/oogabooga/memory.c @@ -19,7 +19,7 @@ void* initialization_allocator_proc(u64 size, void *p, Allocator_Message message init_memory_head += size; if (init_memory_head >= ((u8*)init_memory_arena+INIT_MEMORY_SIZE)) { - os_write_string_to_stdout(cstr("Out of initialization memory! Please provide more by increasing INIT_MEMORY_SIZE")); + os_write_string_to_stdout(STR("Out of initialization memory! Please provide more by increasing INIT_MEMORY_SIZE")); os_break(); } return p; @@ -478,7 +478,7 @@ void* talloc(u64 size) { if ((u8*)temporary_storage_pointer >= (u8*)temporary_storage+TEMPORARY_STORAGE_SIZE) { if (!has_warned_temporary_storage_overflow) { - os_write_string_to_stdout(cstr("WARNING: temporary storage was overflown, we wrap around at the start.\n")); + os_write_string_to_stdout(STR("WARNING: temporary storage was overflown, we wrap around at the start.\n")); } temporary_storage_pointer = temporary_storage; return talloc(size);; diff --git a/oogabooga/oogabooga.c b/oogabooga/oogabooga.c index 987f560..f29b852 100644 --- a/oogabooga/oogabooga.c +++ b/oogabooga/oogabooga.c @@ -57,24 +57,7 @@ void lodepng_free(void* ptr) { // One day I might write my own png decoder so we don't even need this #include "third_party/lodepng.h" #include "third_party/lodepng.c" -/* - To decode a png file: - - // 1. Read to memory - string path = fixed_string("my_image.png"); - string png; - os_read_entire_file(path, &png); - - // 2. Decode - u8 *image; - u32 width; - u32 height; - u32 error = lodepng_decode32(&image, &width, &height, png.data, png.count); - - // Cleanup - dealloc_string(png); - dealloc(image); -*/ + @@ -100,6 +83,9 @@ void lodepng_free(void* ptr) { #error "Current OS not supported!"; #endif + + + #define GFX_RENDERER_D3D11 0 #define GFX_RENDERER_VULKAN 1 #define GFX_RENDERER_METAL 2 @@ -125,6 +111,58 @@ void lodepng_free(void* ptr) { #include "os_interface.c" #include "gfx_interface.c" + +// #Cleanup #Temporary +// This should be somewhere else +String_Builder _profile_output = {0}; +bool profiler_initted = false; +Spinlock *_profiler_lock = 0; +void dump_profile_result() { + File file = os_file_open("google_trace.json", O_CREATE | O_WRITE); + + os_file_write_string(file, STR("[")); + os_file_write_string(file, _profile_output.result); + os_file_write_string(file, STR("{}]")); + + os_file_close(file); + + log_verbose("Wrote profiling result to google_trace.json"); +} +void _profiler_report_time_cycles(string name, u64 count, u64 start) { + if (!profiler_initted) { + _profiler_lock = os_make_spinlock(get_heap_allocator()); + profiler_initted = true; + + string_builder_init_reserve(&_profile_output, 1024*1000, get_heap_allocator()); + + } + + os_spinlock_lock(_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, GetCurrentThreadId(), start*1000); + + os_spinlock_unlock(_profiler_lock); +} +#if ENABLE_PROFILING +#define tm_scope_cycles(name) \ + for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \ + elapsed_time == 0; \ + elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, _profiler_report_time_cycles(STR(name), elapsed_time, start_time)) +#define tm_scope_cycles_var(name, var) \ + for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \ + elapsed_time == 0; \ + elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, var=elapsed_time) +#define tm_scope_cycles_accum(name, var) \ + for (u64 start_time = os_get_current_cycle_count(), end_time = start_time, elapsed_time = 0; \ + elapsed_time == 0; \ + elapsed_time = (end_time = os_get_current_cycle_count()) - start_time, var+=elapsed_time) +#else + #define tm_scope_cycles(...) + #define tm_scope_cycles_var(...) + #define tm_scope_cycles_accum(...) +#endif + // I hope whoever caused this @ microsoft is fired. #ifdef near #undef near @@ -195,6 +233,12 @@ int main(int argc, char **argv) { int code = ENTRY_PROC(argc, argv); +#if ENABLE_PROFILING + + dump_profile_result(); + +#endif + printf("Ooga booga program exit with code %i\n", code); return code; diff --git a/oogabooga/os_impl_windows.c b/oogabooga/os_impl_windows.c index 2c83e26..15e69fd 100644 --- a/oogabooga/os_impl_windows.c +++ b/oogabooga/os_impl_windows.c @@ -134,6 +134,11 @@ LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wpar void os_init(u64 program_memory_size) { + timeBeginPeriod(1); +#if CONFIGURATION == RELEASE + SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); +#endif + SYSTEM_INFO si; GetSystemInfo(&si); os.granularity = cast(u64)si.dwAllocationGranularity; @@ -163,22 +168,22 @@ void os_init(u64 program_memory_size) { heap_init(); - os.crt = os_load_dynamic_library(const_string("msvcrt.dll")); + os.crt = os_load_dynamic_library(STR("msvcrt.dll")); assert(os.crt != 0, "Could not load win32 crt library. Might be compiled with non-msvc? #Incomplete #Portability"); - os.crt_vsnprintf = (Crt_Vsnprintf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("vsnprintf")); + os.crt_vsnprintf = (Crt_Vsnprintf_Proc)os_dynamic_library_load_symbol(os.crt, STR("vsnprintf")); assert(os.crt_vsnprintf, "Missing vsnprintf in crt"); - os.crt_vprintf = (Crt_Vprintf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("vprintf")); + os.crt_vprintf = (Crt_Vprintf_Proc)os_dynamic_library_load_symbol(os.crt, STR("vprintf")); assert(os.crt_vprintf, "Missing vprintf in crt"); - os.crt_vsprintf = (Crt_Vsprintf_Proc)os_dynamic_library_load_symbol(os.crt, const_string("vsprintf")); + os.crt_vsprintf = (Crt_Vsprintf_Proc)os_dynamic_library_load_symbol(os.crt, STR("vsprintf")); assert(os.crt_vsprintf, "Missing vsprintf in crt"); - os.crt_memcpy = (Crt_Memcpy_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memcpy")); + os.crt_memcpy = (Crt_Memcpy_Proc)os_dynamic_library_load_symbol(os.crt, STR("memcpy")); assert(os.crt_memcpy, "Missing memcpy in crt"); - os.crt_memcmp = (Crt_Memcmp_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memcmp")); + os.crt_memcmp = (Crt_Memcmp_Proc)os_dynamic_library_load_symbol(os.crt, STR("memcmp")); assert(os.crt_memcmp, "Missing crt_memcmp in crt"); - os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memset")); + os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, STR("memset")); assert(os.crt_memset, "Missing memset in crt"); - window.title = fixed_string("Unnamed Window"); + window.title = STR("Unnamed Window"); window.width = 1280; window.height = 720; window.x = 0; @@ -300,6 +305,12 @@ bool os_grow_program_memory(u64 new_size) { // Thread primitive DWORD WINAPI win32_thread_invoker(LPVOID param) { + + timeBeginPeriod(1); +#if CONFIGURATION == RELEASE + SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); +#endif + Thread *t = (Thread*)param; temporary_storage_init(); context = t->initial_context; @@ -447,9 +458,9 @@ void os_high_precision_sleep(f64 ms) { // Time /// -#include // #Cdep + u64 os_get_current_cycle_count() { - return __rdtsc(); + return rdtsc(); } float64 os_get_current_time_in_seconds() { @@ -531,7 +542,7 @@ string temp_win32_null_terminated_wide_to_fixed_utf8(const u16 *utf16) { } -File os_file_open(string path, Os_Io_Open_Flags flags) { +File os_file_open_s(string path, Os_Io_Open_Flags flags) { DWORD access = GENERIC_READ; DWORD creation = 0; @@ -553,7 +564,7 @@ void os_file_close(File f) { CloseHandle(f); } -bool os_file_delete(string path) { +bool os_file_delete_s(string path) { u16 *path_wide = temp_win32_fixed_utf8_to_null_terminated_wide(path); return (bool)DeleteFileW(path_wide); } @@ -583,8 +594,8 @@ bool os_write_entire_file_handle(File f, string data) { return os_file_write_string(f, data); } -bool os_write_entire_file(string path, string data) { - File file = os_file_open(path, O_WRITE | O_CREATE); +bool os_write_entire_file_s(string path, string data) { + File file = os_file_open_s(path, O_WRITE | O_CREATE); if (file == OS_INVALID_FILE) { return false; } @@ -613,8 +624,8 @@ bool os_read_entire_file_handle(File f, string *result, Allocator allocator) { return actual_read == file_size.QuadPart; } -bool os_read_entire_file(string path, string *result, Allocator allocator) { - File file = os_file_open(path, O_READ); +bool os_read_entire_file_s(string path, string *result, Allocator allocator) { + File file = os_file_open_s(path, O_READ); if (file == OS_INVALID_FILE) { return false; } @@ -623,7 +634,7 @@ bool os_read_entire_file(string path, string *result, Allocator allocator) { return res; } -bool os_is_file(string path) { +bool os_is_file_s(string path) { u16 *path_wide = temp_win32_fixed_utf8_to_null_terminated_wide(path); assert(path_wide, "Invalid path string"); if (path_wide == NULL) { @@ -639,7 +650,7 @@ bool os_is_file(string path) { return !(attributes & FILE_ATTRIBUTE_DIRECTORY); } -bool os_is_directory(string path) { +bool os_is_directory_s(string path) { u16 *path_wide = temp_win32_fixed_utf8_to_null_terminated_wide(path); assert(path_wide, "Invalid path string"); if (path_wide == NULL) { diff --git a/oogabooga/os_interface.c b/oogabooga/os_interface.c index 79be3aa..182981a 100644 --- a/oogabooga/os_interface.c +++ b/oogabooga/os_interface.c @@ -199,9 +199,11 @@ typedef enum Os_Io_Open_Flags { // To append, pass WRITE flag without CREATE flag } Os_Io_Open_Flags; -File os_file_open(string path, Os_Io_Open_Flags flags); +File os_file_open_s(string path, Os_Io_Open_Flags flags); void os_file_close(File f); -bool os_file_delete(string path); +bool os_file_delete_s(string path); + +bool os_make_directory_s(string path, bool recursive); bool os_file_write_string(File f, string s); bool os_file_write_bytes(File f, void *buffer, u64 size_in_bytes); @@ -209,12 +211,56 @@ bool os_file_write_bytes(File f, void *buffer, u64 size_in_bytes); bool os_file_read(File f, void* buffer, u64 bytes_to_read, u64 *actual_read_bytes); bool os_write_entire_file_handle(File f, string data); -bool os_write_entire_file(string path, string data); +bool os_write_entire_file_s(string path, string data); bool os_read_entire_file_handle(File f, string *result, Allocator allocator); -bool os_read_entire_file(string path, string *result, Allocator allocator); +bool os_read_entire_file_s(string path, string *result, Allocator allocator); -bool os_is_file(string path); -bool os_is_directory(string path); +bool os_is_file_s(string path); +bool os_is_directory_s(string path); + +// It's a little unfortunate that we need to do this but I can't think of a better solution + +inline File os_file_open_f(const char *path, Os_Io_Open_Flags flags) {return os_file_open_s(STR(path), flags);} +#define os_file_open(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: os_file_open_s, \ + default: os_file_open_f \ + )(__VA_ARGS__) + +inline bool os_file_delete_f(const char *path) {return os_file_delete_s(STR(path));} +#define os_file_delete(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: os_file_delete_s, \ + default: os_file_delete_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, \ + default: os_make_directory_f \ + )(__VA_ARGS__) + +inline bool os_write_entire_file_f(const char *path, string data) {return os_write_entire_file_s(STR(path), data);} +#define os_write_entire_file(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: os_write_entire_file_s, \ + default: os_write_entire_file_f \ + )(__VA_ARGS__) + +inline bool os_read_entire_file_f(const char *path, string *result, Allocator allocator) {return os_read_entire_file_s(STR(path), result, allocator);} +#define os_read_entire_file(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: os_read_entire_file_s, \ + default: os_read_entire_file_f \ + )(__VA_ARGS__) + +inline bool os_is_file_f(const char *path) {return os_is_file_s(STR(path));} +#define os_is_file(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: os_is_file_s, \ + default: os_is_file_f \ + )(__VA_ARGS__) + +inline bool os_is_directory_f(const char *path) {return os_is_directory_s(STR(path));} +#define os_is_directory(...) _Generic((FIRST_ARG(__VA_ARGS__)), \ + string: os_is_directory_s, \ + default: os_is_directory_f \ + )(__VA_ARGS__) void fprints(File f, string fmt, ...); diff --git a/oogabooga/random.c b/oogabooga/random.c index 544f686..a6b30d2 100644 --- a/oogabooga/random.c +++ b/oogabooga/random.c @@ -11,3 +11,7 @@ u64 get_random() { seed_for_random = seed_for_random * MULTIPLIER + INCREMENT; return seed_for_random; } + +f32 get_random_float32() { + return (float32)get_random()/(float32)UINT64_MAX; +} \ No newline at end of file diff --git a/oogabooga/string.c b/oogabooga/string.c index 9a24b00..8a32a0b 100644 --- a/oogabooga/string.c +++ b/oogabooga/string.c @@ -13,11 +13,7 @@ typedef struct string { u8 *data; } string; -// Not sure what to call this lol -#define fxstr fixed_string -#define fixed_string const_string -#define cstr const_string -#define const_string(s) ((string){ length_of_null_terminated_string((const char*)s), (u8*)s }) +#define STR(s) ((string){ length_of_null_terminated_string((const char*)s), (u8*)s }) inline u64 length_of_null_terminated_string(const char* cstring) { u64 len = 0; @@ -102,4 +98,6 @@ s64 string_find_from_right(string s, string sub) { } return -1; -} \ No newline at end of file +} + + diff --git a/oogabooga/string_format.c b/oogabooga/string_format.c index cbd917e..169cad8 100644 --- a/oogabooga/string_format.c +++ b/oogabooga/string_format.c @@ -83,24 +83,24 @@ u64 format_string_to_buffer(char* buffer, u64 count, const char* fmt, va_list ar return bufp - buffer; } -string sprint_null_terminated_string_va_list_to_buffer(const char *fmt, va_list args, void* buffer, u64 count) { - u64 formatted_length = format_string_to_buffer((char*)buffer, count, fmt, args); +string sprint_null_terminated_string_va_list_to_buffer(const char *fmt, va_list args, void* buffer, u64 buffer_size) { + u64 formatted_length = format_string_to_buffer((char*)buffer, buffer_size, fmt, args); string result; result.data = (u8*)buffer; - if (formatted_length >= 0 && formatted_length < count) { + if (formatted_length >= 0 && formatted_length < buffer_size) { result.count = formatted_length; } else { - result.count = count - 1; + result.count = buffer_size - 1; } return result; } -string sprint_va_list_to_buffer(const string fmt, va_list args, void* buffer, u64 count) { +string sprint_va_list_to_buffer(const string fmt, va_list args, void* buffer, u64 buffer_size) { char* fmt_cstring = temp_convert_to_null_terminated_string(fmt); - return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, count); + return sprint_null_terminated_string_va_list_to_buffer(fmt_cstring, args, buffer, buffer_size); } string sprint_va_list(Allocator allocator, const string fmt, va_list args) { @@ -230,4 +230,95 @@ void default_logger(Log_Level level, string s) { case LOG_WARNING: print("[WARNING]: %s\n", s); break; case LOG_ERROR: print("[ERROR]: %s\n", s); break; } -} \ No newline at end of file +} + + +typedef struct String_Builder { + union { + struct {u64 count;u8 *buffer;}; + string result; + }; + u64 buffer_capacity; + Allocator allocator; +} String_Builder; + + +void string_builder_reserve(String_Builder *b, u64 required_capacity) { + if (b->buffer_capacity >= required_capacity) return; + + u64 new_capacity = max(b->buffer_capacity*2, (u64)(required_capacity*1.5)); + u8 *new_buffer = alloc(b->allocator, new_capacity); + if (b->buffer) { + memcpy(new_buffer, b->buffer, b->count); + dealloc(b->allocator, b->buffer); + } + b->buffer = new_buffer; + b->buffer_capacity = new_capacity; +} +void string_builder_init_reserve(String_Builder *b, u64 reserved_capacity, Allocator allocator) { + reserved_capacity = max(reserved_capacity, 128); + b->allocator = allocator; + b->buffer_capacity = 0; + b->buffer = 0; + string_builder_reserve(b, reserved_capacity); + b->count = 0; +} +void string_builder_init(String_Builder *b, Allocator allocator) { + string_builder_init_reserve(b, 128, allocator); +} +void string_builder_append(String_Builder *b, string s) { + assert(b->allocator.proc, "String_Builder is missing allocator"); + string_builder_reserve(b, b->count+s.count); + + memcpy(b->buffer+b->count, s.data, s.count); + b->count += s.count; +} + +void string_builder_prints(String_Builder *b, string fmt, ...) { + assert(b->allocator.proc, "String_Builder is missing allocator"); + + va_list args1 = 0; + va_start(args1, fmt); + va_list args2 = 0; + va_copy(args2, args1); + + u64 formatted_count = format_string_to_buffer(0, 0, temp_convert_to_null_terminated_string(fmt), args1); + + va_end(args1); + + string_builder_reserve(b, b->count+formatted_count+1); + + format_string_to_buffer((char*)b->buffer+b->count, b->count+formatted_count+1, temp_convert_to_null_terminated_string(fmt), args2); + b->count += formatted_count; + + va_end(args2); +} +void string_builder_printf(String_Builder *b, const char *fmt, ...) { + assert(b->allocator.proc, "String_Builder is missing allocator"); + + va_list args1 = 0; + va_start(args1, fmt); + va_list args2 = 0; + va_copy(args2, args1); + + u64 formatted_count = format_string_to_buffer(0, 0, fmt, args1); + + va_end(args1); + + string_builder_reserve(b, b->count+formatted_count+1); + + format_string_to_buffer((char*)b->buffer+b->count, b->buffer_capacity-b->count+1, fmt, args2); + b->count += formatted_count; + + va_end(args2); +} + +#define string_builder_print(...) _Generic((SECOND_ARG(__VA_ARGS__)), \ + string: string_builder_prints, \ + default: string_builder_printf \ + )(__VA_ARGS__) + +string string_builder_get_string(String_Builder *b) { + return b->result; +} + diff --git a/oogabooga/tests.c b/oogabooga/tests.c index 9478c27..2d23b17 100644 --- a/oogabooga/tests.c +++ b/oogabooga/tests.c @@ -1,13 +1,13 @@ void log_heap() { os_spinlock_lock(heap_lock); - printf("\nHEAP:\n"); + print("\nHEAP:\n"); Heap_Block *block = heap_head; while (block != 0) { - printf("\tBLOCK @ 0x%I64x, %llu bytes\n", (u64)block, block->size); + print("\tBLOCK @ 0x%I64x, %llu bytes\n", (u64)block, block->size); Heap_Free_Node *node = block->free_head; @@ -15,14 +15,14 @@ void log_heap() { while (node != 0) { - printf("\t\tFREE NODE @ 0x%I64x, %llu bytes\n", (u64)node, node->size); + print("\t\tFREE NODE @ 0x%I64x, %llu bytes\n", (u64)node, node->size); total_free += node->size; node = node->next; } - printf("\t TOTAL FREE: %llu\n\n", total_free); + print("\t TOTAL FREE: %llu\n\n", total_free); block = block->next; } @@ -179,15 +179,15 @@ void test_allocator(bool do_log_heap) { void test_thread_proc1(Thread* t) { os_sleep(5); - printf("Hello from thread %llu\n", t->id); + print("Hello from thread %llu\n", t->id); os_sleep(5); - printf("Hello from thread %llu\n", t->id); + print("Hello from thread %llu\n", t->id); os_sleep(5); - printf("Hello from thread %llu\n", t->id); + print("Hello from thread %llu\n", t->id); os_sleep(5); - printf("Hello from thread %llu\n", t->id); + print("Hello from thread %llu\n", t->id); os_sleep(5); - printf("Hello from thread %llu\n", t->id); + print("Hello from thread %llu\n", t->id); } void test_threads() { @@ -195,9 +195,9 @@ void test_threads() { Thread* t = os_make_thread(test_thread_proc1, get_heap_allocator()); os_start_thread(t); os_sleep(20); - printf("This should be printed in middle of thread execution\n"); + print("This should be printed in middle of thread execution\n"); os_join_thread(t); - printf("Thread is joined\n"); + print("Thread is joined\n"); Mutex_Handle m = os_make_mutex(); os_lock_mutex(m); @@ -238,111 +238,196 @@ void test_allocator_threaded(Thread *t) { } void test_strings() { - // Test length_of_null_terminated_string - assert(length_of_null_terminated_string("Test") == 4, "Failed: length_of_null_terminated_string"); - assert(length_of_null_terminated_string("") == 0, "Failed: length_of_null_terminated_string"); - Allocator heap = get_heap_allocator(); - - // Test alloc_string and dealloc_string - string alloc_str = alloc_string(heap, 10); - assert(alloc_str.data != NULL, "Failed: alloc_string"); - assert(alloc_str.count == 10, "Failed: alloc_string"); - dealloc_string(heap, alloc_str); - - // Test string_concat - string str1 = fixed_string("Hello, "); - string str2 = fixed_string("World!"); - string concat_str = string_concat(str1, str2, heap); - assert(concat_str.count == str1.count + str2.count, "Failed: string_concat"); - assert(memcmp(concat_str.data, "Hello, World!", concat_str.count) == 0, "Failed: string_concat"); - dealloc_string(heap, concat_str); - - // Test convert_to_null_terminated_string - char* cstr = convert_to_null_terminated_string(str1, heap); - assert(strcmp(cstr, "Hello, ") == 0, "Failed: convert_to_null_terminated_string"); - dealloc(heap, cstr); - - // Test temp_convert_to_null_terminated_string - cstr = temp_convert_to_null_terminated_string(str2); - assert(strcmp(cstr, "World!") == 0, "Failed: temp_convert_to_null_terminated_string"); - - // Test sprint - string format_str = fixed_string("Number: %d"); - string formatted_str = sprint(heap, format_str, 42); - char* formatted_cstr = convert_to_null_terminated_string(formatted_str, heap); - assert(strcmp(formatted_cstr, "Number: 42") == 0, "Failed: sprint"); - dealloc(heap, formatted_str.data); - dealloc(heap, formatted_cstr); - - // Test tprint - string temp_formatted_str = tprint(format_str, 100); - formatted_cstr = temp_convert_to_null_terminated_string(temp_formatted_str); - assert(strcmp(formatted_cstr, "Number: 100") == 0, "Failed: tprint"); - - // Test print and printf (visual inspection) - printf("Expected output: Hello, World!\n"); - print("Hello, %s!\n", fixed_string("World")); - - printf("Expected output: Number: 1234\n"); - print(fixed_string("Number: %d\n"), 1234); + { + // Test length_of_null_terminated_string + assert(length_of_null_terminated_string("Test") == 4, "Failed: length_of_null_terminated_string"); + assert(length_of_null_terminated_string("") == 0, "Failed: length_of_null_terminated_string"); + + + // Test alloc_string and dealloc_string + string alloc_str = alloc_string(heap, 10); + assert(alloc_str.data != NULL, "Failed: alloc_string"); + assert(alloc_str.count == 10, "Failed: alloc_string"); + dealloc_string(heap, alloc_str); + + // Test string_concat + string str1 = STR("Hello, "); + string str2 = STR("World!"); + string concat_str = string_concat(str1, str2, heap); + assert(concat_str.count == str1.count + str2.count, "Failed: string_concat"); + assert(memcmp(concat_str.data, "Hello, World!", concat_str.count) == 0, "Failed: string_concat"); + dealloc_string(heap, concat_str); + + // Test convert_to_null_terminated_string + char* cstr = convert_to_null_terminated_string(str1, heap); + assert(strcmp(cstr, "Hello, ") == 0, "Failed: convert_to_null_terminated_string"); + dealloc(heap, cstr); + + // Test temp_convert_to_null_terminated_string + cstr = temp_convert_to_null_terminated_string(str2); + assert(strcmp(cstr, "World!") == 0, "Failed: temp_convert_to_null_terminated_string"); + + // Test sprint + string format_str = STR("Number: %d"); + string formatted_str = sprint(heap, format_str, 42); + char* formatted_cstr = convert_to_null_terminated_string(formatted_str, heap); + assert(strcmp(formatted_cstr, "Number: 42") == 0, "Failed: sprint"); + dealloc(heap, formatted_str.data); + dealloc(heap, formatted_cstr); + + // Test tprint + string temp_formatted_str = tprint(format_str, 100); + formatted_cstr = temp_convert_to_null_terminated_string(temp_formatted_str); + assert(strcmp(formatted_cstr, "Number: 100") == 0, "Failed: tprint"); + + // Test print and printf (visual inspection) + print("Expected output: Hello, World!\n"); + print("Hello, %s!\n", STR("World")); + + print("Expected output: Number: 1234\n"); + print("Number: %d\n", 1234); + + print("Expected output: Number: 1234\n"); + print("Number: %d\n", 1234); + + print("Expected output: Mixed values: 42 and 3.14\n"); + print("Mixed values: %d and %.2f\n", 42, 3.14); + + // This should fail assert and print descriptive error + //print("Expected output (printf): Hello, World!\n"); + //print("Hello, %cs!\n", 5); + // This should fail assert and print descriptive error + // print("Expected output (printf): Hello, World!\n"); + // print("Hello, %s!\n", "World"); + + print("Expected output (printf): Hello, World!\n"); + print("Hello, %s!\n", STR("World")); + + print("Expected output (printf): Number: 5678\n"); + print("Number: %d\n", 5678); + + print("Expected output (printf): Mixed values: 99 and 2.71\n"); + print("Mixed values: %d and %.2f\n", 99, 2.71); + + // Test handling of empty strings + string empty_str = STR(""); + string concat_empty_str = string_concat(empty_str, empty_str, heap); + assert(concat_empty_str.count == 0, "Failed: string_concat with empty strings"); + dealloc_string(heap, concat_empty_str); + + // Test very large strings (performance test) + string large_str1 = alloc_string(heap, 1024 * 1024); + string large_str2 = alloc_string(heap, 1024 * 1024); + string large_concat_str = string_concat(large_str1, large_str2, heap); + assert(large_concat_str.count == 2 * 1024 * 1024, "Failed: large string_concat"); + dealloc_string(heap, large_str1); + dealloc_string(heap, large_str2); + dealloc_string(heap, large_concat_str); + + // Test string with special characters + string special_char_str = STR("Special chars: \n\t\r"); + cstr = convert_to_null_terminated_string(special_char_str, heap); + assert(strcmp(cstr, "Special chars: \n\t\r") == 0, "Failed: special character string"); + dealloc(heap, cstr); + + string a = tprint("Hello, %cs!\n", "balls"); + string balls1 = string_view(a, 7, 5); + string balls2 = STR("balls"); + + assert(strings_match(balls1, balls2), "String match failed"); + assert(!strings_match(balls1, a), "String match failed"); + + } + // Test string_builder_init + String_Builder builder; + string_builder_init(&builder, heap); + assert(builder.buffer != NULL, "Failed: string_builder_init"); + assert(builder.buffer_capacity >= 128, "Failed: string_builder_init"); + assert(builder.count == 0, "Failed: string_builder_init"); - printf("Expected output: Number: 1234\n"); - print(fixed_string("Number: %d\n"), 1234); - - printf("Expected output: Mixed values: 42 and 3.14\n"); - print(fixed_string("Mixed values: %d and %.2f\n"), 42, 3.14); - - // This should fail assert and print descriptive error - //printf("Expected output (printf): Hello, World!\n"); - //printf("Hello, %cs!\n", 5); - // This should fail assert and print descriptive error - // printf("Expected output (printf): Hello, World!\n"); - // printf("Hello, %s!\n", "World"); + // Test string_builder_reserve + string_builder_reserve(&builder, 256); + assert(builder.buffer_capacity >= 256, "Failed: string_builder_reserve"); - printf("Expected output (printf): Hello, World!\n"); - printf("Hello, %s!\n", cstr("World")); - - printf("Expected output (printf): Number: 5678\n"); - printf("Number: %d\n", 5678); - - printf("Expected output (printf): Mixed values: 99 and 2.71\n"); - printf("Mixed values: %d and %.2f\n", 99, 2.71); - - // Test handling of empty strings - string empty_str = fixed_string(""); - string concat_empty_str = string_concat(empty_str, empty_str, heap); - assert(concat_empty_str.count == 0, "Failed: string_concat with empty strings"); - dealloc_string(heap, concat_empty_str); - - // Test very large strings (performance test) - string large_str1 = alloc_string(heap, 1024 * 1024); - string large_str2 = alloc_string(heap, 1024 * 1024); - string large_concat_str = string_concat(large_str1, large_str2, heap); - assert(large_concat_str.count == 2 * 1024 * 1024, "Failed: large string_concat"); - dealloc_string(heap, large_str1); - dealloc_string(heap, large_str2); - dealloc_string(heap, large_concat_str); - - // Test string with special characters - string special_char_str = fixed_string("Special chars: \n\t\r"); - cstr = convert_to_null_terminated_string(special_char_str, heap); - assert(strcmp(cstr, "Special chars: \n\t\r") == 0, "Failed: special character string"); - dealloc(heap, cstr); + // Test string_builder_append + string str1 = STR("Hello, "); + string_builder_append(&builder, str1); + assert(builder.count == str1.count, "Failed: string_builder_append"); + assert(memcmp(builder.buffer, str1.data, str1.count) == 0, "Failed: string_builder_append"); - string a = tprintf("Hello, %cs!\n", "balls"); - string balls1 = string_view(a, 7, 5); - string balls2 = fixed_string("balls"); + string str2 = STR("World!"); + string_builder_append(&builder, str2); + assert(builder.count == str1.count + str2.count, "Failed: string_builder_append"); + assert(memcmp(builder.buffer, "Hello, World!", builder.count) == 0, "Failed: string_builder_append"); - assert(strings_match(balls1, balls2), "String match failed"); - assert(!strings_match(balls1, a), "String match failed"); + // Test string_builder_prints + string format_str = STR(" Number: %d"); + string_builder_prints(&builder, format_str, 42); + char* expected_result = "Hello, World! Number: 42"; + assert(builder.count == strlen(expected_result), "Failed: string_builder_prints"); + assert(memcmp(builder.buffer, expected_result, builder.count) == 0, "Failed: string_builder_prints"); + + // Test string_builder_printf + string_builder_printf(&builder, " And a float: %.2f", 3.14); + expected_result = "Hello, World! Number: 42 And a float: 3.14"; + assert(builder.count == strlen(expected_result), "Failed: string_builder_printf"); + assert(memcmp(builder.buffer, expected_result, builder.count) == 0, "Failed: string_builder_printf"); + + // Test string_builder_get_string + string result_str = string_builder_get_string(&builder); + assert(result_str.count == builder.count, "Failed: string_builder_get_string"); + assert(memcmp(result_str.data, builder.buffer, result_str.count) == 0, "Failed: string_builder_get_string"); + + // Cleanup + dealloc(heap, builder.buffer); + + // Test handling of empty builder + String_Builder empty_builder; + string_builder_init(&empty_builder, heap); + result_str = string_builder_get_string(&empty_builder); + assert(result_str.count == 0, "Failed: empty builder handling"); + dealloc(heap, empty_builder.buffer); + + // Test appending large strings (performance test) + String_Builder large_builder; + string_builder_init(&large_builder, heap); + string large_str = alloc_string(heap, 1024 * 1024); + memset(large_str.data, 'A', 1024 * 1024); + string_builder_append(&large_builder, large_str); + assert(large_builder.count == 1024 * 1024, "Failed: large string_builder_append"); + dealloc_string(heap, large_str); + dealloc(heap, large_builder.buffer); + + // Test appending special characters + String_Builder special_char_builder; + string_builder_init(&special_char_builder, heap); + string special_char_str = STR("Special chars: \n\t\r"); + string_builder_append(&special_char_builder, special_char_str); + assert(special_char_builder.count == special_char_str.count, "Failed: special character append"); + assert(memcmp(special_char_builder.buffer, special_char_str.data, special_char_str.count) == 0, "Failed: special character append"); + dealloc(heap, special_char_builder.buffer); + + // Test multiple appends + String_Builder multi_append_builder; + string_builder_init(&multi_append_builder, heap); + string str_a = STR("First part"); + string str_b = STR(" and second part"); + string str_c = STR(" and third part."); + string_builder_append(&multi_append_builder, str_a); + string_builder_append(&multi_append_builder, str_b); + string_builder_append(&multi_append_builder, str_c); + expected_result = "First part and second part and third part."; + assert(multi_append_builder.count == strlen(expected_result), "Failed: multiple appends"); + assert(memcmp(multi_append_builder.buffer, expected_result, multi_append_builder.count) == 0, "Failed: multiple appends"); + dealloc(heap, multi_append_builder.buffer); } void test_file_io() { #if TARGET_OS == WINDOWS // Test win32_fixed_utf8_to_null_terminated_wide - string utf8_str = fixed_string("Test"); + string utf8_str = STR("Test"); u16 *wide_str = win32_fixed_utf8_to_null_terminated_wide(utf8_str, get_heap_allocator()); assert(wide_str != NULL, "Failed: win32_fixed_utf8_to_null_terminated_wide"); assert(wide_str[4] == 0, "Failed: win32_fixed_utf8_to_null_terminated_wide"); @@ -358,20 +443,20 @@ void test_file_io() { os_file_close(file); // Test os_file_open and os_file_close - file = os_file_open(fixed_string("test.txt"), O_WRITE | O_CREATE); + file = os_file_open("test.txt", O_WRITE | O_CREATE); assert(file != OS_INVALID_FILE, "Failed: os_file_open (write/create)"); os_file_close(file); // Test os_file_write_string and os_file_read - string hello_world_write = fixed_string("Hello, World!"); - file = os_file_open(fixed_string("test.txt"), O_WRITE | O_CREATE); + string hello_world_write = STR("Hello, World!"); + file = os_file_open("test.txt", O_WRITE | O_CREATE); assert(file != OS_INVALID_FILE, "Failed: os_file_open (write/create)"); bool write_result = os_file_write_string(file, hello_world_write); assert(write_result, "Failed: os_file_write_string"); os_file_close(file); - file = os_file_open(fixed_string("test.txt"), O_READ); + file = os_file_open("test.txt", O_READ); assert(file != OS_INVALID_FILE, "Failed: os_file_open (read)"); string hello_world_read = talloc_string(hello_world_write.count); bool read_result = os_file_read(file, hello_world_read.data, hello_world_read.count, &hello_world_read.count); @@ -380,7 +465,7 @@ void test_file_io() { os_file_close(file); // Test os_file_write_bytes - file = os_file_open(fixed_string("test_bytes.txt"), O_WRITE | O_CREATE); + file = os_file_open("test_bytes.txt", O_WRITE | O_CREATE); assert(file != OS_INVALID_FILE, "Failed: os_file_open (write/create)"); int int_data = 42; write_result = os_file_write_bytes(file, &int_data, sizeof(int)); @@ -388,28 +473,28 @@ void test_file_io() { os_file_close(file); // Test os_read_entire_file and os_write_entire_file - string write_data = fixed_string("Entire file test"); - bool write_entire_result = os_write_entire_file(fixed_string("entire_test.txt"), write_data); + string write_data = STR("Entire file test"); + bool write_entire_result = os_write_entire_file("entire_test.txt", write_data); assert(write_entire_result, "Failed: os_write_entire_file"); Allocator heap = get_heap_allocator(); string read_data; - bool read_entire_result = os_read_entire_file(fixed_string("entire_test.txt"), &read_data, heap); + bool read_entire_result = os_read_entire_file("entire_test.txt", &read_data, heap); assert(read_entire_result, "Failed: os_read_entire_file"); assert(strings_match(read_data, write_data), "Failed: os_read_entire_file write/read mismatch"); assert(memcmp(read_data.data, write_data.data, write_data.count) == 0, "Failed: os_read_entire_file (content mismatch)"); dealloc(heap, read_data.data); // Test fprint - File balls = os_file_open(fixed_string("balls.txt"), O_WRITE | O_CREATE); + File balls = os_file_open("balls.txt", O_WRITE | O_CREATE); assert(balls != OS_INVALID_FILE, "Failed: Could not create balls.txt"); fprint(balls, "Hello, %cs!", "Balls"); os_file_close(balls); string hello_balls; - read_entire_result = os_read_entire_file(fixed_string("balls.txt"), &hello_balls, heap); + read_entire_result = os_read_entire_file("balls.txt", &hello_balls, heap); assert(read_entire_result, "Failed: could not read balls.txt"); - assert(strings_match(hello_balls, fixed_string("Hello, Balls!")), "Failed: balls read/write mismatch. Expected 'Hello, Balls!', got '%s'", hello_balls); + assert(strings_match(hello_balls, STR("Hello, Balls!")), "Failed: balls read/write mismatch. Expected 'Hello, Balls!', got '%s'", hello_balls); u64 integers[4096]; for (u64 i = 0; i < 4096; i++) { @@ -418,11 +503,11 @@ void test_file_io() { string integers_data; integers_data.data = (u8*)integers; integers_data.count = 4096*sizeof(u64); - bool ok = os_write_entire_file(fxstr("integers"), integers_data); + bool ok = os_write_entire_file("integers", integers_data); assert(ok, "write integers fail"); string integers_read; - ok = os_read_entire_file(fxstr("integers"), &integers_read, heap); + ok = os_read_entire_file("integers", &integers_read, heap); assert(ok, "read integers fail"); u64 *new_integers = (u64*)integers_data.data; assert(integers_read.count == integers_data.count, "Failed: big file read/write mismatch. Read was %d and written was %d", integers_read.count, integers_data.count); @@ -430,32 +515,32 @@ void test_file_io() { // Clean up test files bool delete_ok = false; - delete_ok = os_file_delete(fixed_string("test.txt")); + delete_ok = os_file_delete("test.txt"); assert(delete_ok, "Failed: could not delete test.txt"); - delete_ok = os_file_delete(fixed_string("test_bytes.txt")); + delete_ok = os_file_delete("test_bytes.txt"); assert(delete_ok, "Failed: could not delete test_bytes.txt"); - delete_ok = os_file_delete(fixed_string("entire_test.txt")); + delete_ok = os_file_delete("entire_test.txt"); assert(delete_ok, "Failed: could not delete entire_test.txt"); - delete_ok = os_file_delete(fixed_string("balls.txt")); + delete_ok = os_file_delete("balls.txt"); assert(delete_ok, "Failed: could not delete balls.txt"); - delete_ok = os_file_delete(fixed_string("integers.txt")); - assert(delete_ok, "Failed: could not delete integers.txt"); + delete_ok = os_file_delete("integers"); + assert(delete_ok, "Failed: could not delete integers"); } void oogabooga_run_tests() { - printf("Testing allocator... "); + print("Testing allocator... "); test_allocator(true); - printf("OK!\n"); + print("OK!\n"); - printf("Testing threads... "); + print("Testing threads... "); test_threads(); - printf("OK!\n"); + print("OK!\n"); - printf("Testing strings... "); + print("Testing strings... "); test_strings(); - printf("OK!\n"); + print("OK!\n"); - printf("Thread bombing allocator... "); + print("Thread bombing allocator... "); Thread* threads[100]; for (int i = 0; i < 100; i++) { threads[i] = os_make_thread(test_allocator_threaded, get_heap_allocator()); @@ -464,9 +549,9 @@ void oogabooga_run_tests() { for (int i = 0; i < 100; i++) { os_join_thread(threads[i]); } - printf("OK!\n"); + print("OK!\n"); - printf("Testing file IO... "); + print("Testing file IO... "); test_file_io(); - printf("OK!\n"); + print("OK!\n"); } \ No newline at end of file