diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-04-06 23:04:02 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-04-06 23:04:02 +0200 |
commit | e2ad36c4cd9f757b3843ac59c5c436819b70f442 (patch) | |
tree | e445f1d412dd10c67bca17424c382cadd11540ef | |
parent | 7ecc024796fc2e63c4e1731691d36817edc14916 (diff) | |
download | reduced_system_layer-e2ad36c4cd9f757b3843ac59c5c436819b70f442.zip |
Dynamic libraries; Refactor
-rwxr-xr-x | graphics.c | 36 | ||||
-rwxr-xr-x | reduced_system_layer.c | 573 |
2 files changed, 365 insertions, 244 deletions
@@ -141,6 +141,7 @@ typedef struct graphics_request_ { f64 width; } line; struct { + i32 font; vec4_f32 color; Box area; vec2 max_size; @@ -148,6 +149,7 @@ typedef struct graphics_request_ { c32 * text; } text_area; struct { + i32 font; vec4_f32 color; Box area; vec2 max_size; @@ -218,8 +220,8 @@ void fill_triangles_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 position, void fill_quad_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 vertices[4]); void fill_ellipse_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area); void fill_line_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 vertices[2], f64 width); -void draw_text_area_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); -void draw_text_cursor_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); +void draw_text_area_to_buffer (Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); +void draw_text_cursor_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); void draw_pixels_cached (Box area, Pixel_Buffer src); void fill_rectangle_cached (vec4_f32 color, Box area); @@ -228,8 +230,8 @@ void fill_triangles_cached (vec4_f32 color, vec2 position, vec2 scale, i64 num_ void fill_quad_cached (vec4_f32 color, vec2 vertices[4]); void fill_ellipse_cached (vec4_f32 color, Box area); void fill_line_cached (vec4_f32 color, vec2 vertices[2], f64 width); -void draw_text_area_cached (vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); -void draw_text_cursor_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); +void draw_text_area_cached (i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); +void draw_text_cursor_cached(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); void draw_pixels (Box area, Pixel_Buffer src); void fill_rectangle (vec4_f32 color, Box area); @@ -238,8 +240,8 @@ void fill_triangles (vec4_f32 color, vec2 position, vec2 scale, i64 num_triangl void fill_quad (vec4_f32 color, vec2 vertices[4]); void fill_ellipse (vec4_f32 color, Box area); void fill_line (vec4_f32 color, vec2 vertices[2], f64 width); -void draw_text_area (vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); -void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); +void draw_text_area (i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); +void draw_text_cursor(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); void perform_graphics_request(Graphics_Context context, Graphics_Request req); @@ -809,7 +811,7 @@ void external_font_render_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, } #endif // !defined(GRAPHICS_ENABLE_EXTERNAL_FONT) -void draw_text_area_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { +void draw_text_area_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { if (text == NULL || num_chars <= 0 || max_size.x < EPSILON || max_size.y < EPSILON) return; @@ -830,7 +832,7 @@ void draw_text_area_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 m draw_text_(dst, color, area.x, area.y, kx, ky, num_chars, text); } -void draw_text_cursor_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { +void draw_text_cursor_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { if (max_size.x < EPSILON || max_size.y < EPSILON) return; @@ -1361,12 +1363,13 @@ void fill_line_cached(vec4_f32 color, vec2 vertices[2], f64 width) { ); } -void draw_text_area_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { +void draw_text_area_cached(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { .op = GRAPHICS_DRAW_TEXT_AREA, .text_area = { + .font = font, .color = color, .area = area, .max_size = max_size, @@ -1377,12 +1380,13 @@ void draw_text_area_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_char ); } -void draw_text_cursor_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { +void draw_text_cursor_cached(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { .op = GRAPHICS_DRAW_TEXT_CURSOR, .text_cursor = { + .font = font, .color = color, .area = area, .max_size = max_size, @@ -1499,12 +1503,13 @@ void fill_line(vec4_f32 color, vec2 vertices[2], f64 width) { ); } -void draw_text_area(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { +void draw_text_area(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { perform_graphics_request( (Graphics_Context) { .disable_cache = 1, }, (Graphics_Request) { .op = GRAPHICS_DRAW_TEXT_AREA, .text_area = { + .font = font, .color = color, .area = area, .max_size = max_size, @@ -1515,12 +1520,13 @@ void draw_text_area(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 ); } -void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { +void draw_text_cursor(i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { perform_graphics_request( (Graphics_Context) { .disable_cache = 1, }, (Graphics_Request) { .op = GRAPHICS_DRAW_TEXT_CURSOR, .text_cursor = { + .font = font, .color = color, .area = area, .max_size = max_size, @@ -1586,6 +1592,7 @@ static void graphics_request_hash_(Blake2b_State *S, Graphics_Request req) { break; case GRAPHICS_DRAW_TEXT_AREA: + blake2b_update(S, (u8 *) &req.text_area.font, sizeof req.text_area.font); blake2b_update(S, (u8 *) &req.text_area.color, sizeof req.text_area.color); blake2b_update(S, (u8 *) &req.text_area.area, sizeof req.text_area.area); blake2b_update(S, (u8 *) &req.text_area.max_size, sizeof req.text_area.max_size); @@ -1598,6 +1605,7 @@ static void graphics_request_hash_(Blake2b_State *S, Graphics_Request req) { break; case GRAPHICS_DRAW_TEXT_CURSOR: + blake2b_update(S, (u8 *) &req.text_cursor.font, sizeof req.text_cursor.font); blake2b_update(S, (u8 *) &req.text_cursor.color, sizeof req.text_cursor.color); blake2b_update(S, (u8 *) &req.text_cursor.area, sizeof req.text_cursor.area); blake2b_update(S, (u8 *) &req.text_cursor.max_size, sizeof req.text_cursor.max_size); @@ -1927,6 +1935,7 @@ static void perform_graphics_request_to_buffer_(Pixel_Buffer dst, Graphics_Reque case GRAPHICS_DRAW_TEXT_AREA: draw_text_area_to_buffer( dst, + req.text_area.font, req.text_area.color, req.text_area.area, req.text_area.max_size, @@ -1938,6 +1947,7 @@ static void perform_graphics_request_to_buffer_(Pixel_Buffer dst, Graphics_Reque case GRAPHICS_DRAW_TEXT_CURSOR: draw_text_cursor_to_buffer( dst, + req.text_cursor.font, req.text_cursor.color, req.text_cursor.area, req.text_cursor.max_size, @@ -2244,7 +2254,7 @@ BENCHMARK("draw text area") { BENCHMARK_BEGIN; { c32 text[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'S', 'a', 'i', 'l', 'o', 'r', '!', }; - draw_text_area_to_buffer(_test_pixels, _test_color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, }, (vec2) { 100, 200 }, sizeof text / sizeof *text, text); + draw_text_area_to_buffer(_test_pixels, 0, _test_color, (Box) { .x = 100, .y = 100, .width = 300, .height = 200, }, (vec2) { 100, 200 }, sizeof text / sizeof *text, text); } BENCHMARK_END; } diff --git a/reduced_system_layer.c b/reduced_system_layer.c index cf7db67..f083ec8 100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -41,9 +41,6 @@ #/ To-Do list #/ #/ - Work in progress -#/ - Clipboard -#/ - Images - BMP, PPM -#/ - Sound - WAV #/ - Graphics perf - request cache #/ Requires: #/ + [ ] Graphics tests @@ -63,6 +60,18 @@ #/ - UI #/ - Icons #/ - Folder widget +#/ - Clipboard +#/ - Images - BMP, PPM +#/ - Sound - WAV +#/ - Clipboard +#/ - Images - BMP, PPM +#/ - Sound - WAV +#/ - Dynamic libraries - load dependencies conditionally +#/ - X11 +#/ - Wayland +#/ - ALSA +#/ - Sockets +#/ - Windows #/ - Cross-platform networking - UDP + TCP + WebSocket #/ Requires: #/ - [ ] Sockets - UDP, TCP @@ -102,12 +111,6 @@ #/ - Windows sockets #/ - fetch - via libcurl on native platforms #/ - Lattice-based cipher suite -#/ - dlopen - load libraries conditionally -#/ - X11 -#/ - Wayland -#/ - ALSA -#/ - Sockets -#/ - Windows #/ - Switching canvas - Web #/ - File system #/ - Secure random @@ -705,7 +708,12 @@ b8 network_open(u16 slot, Network_Address address, u16 *local_port); i64 network_recv(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port, Network_Address *remote_address); i64 network_send(u16 slot, Network_Address address, i64 size, u8 *data, u16 *local_port); -// NOTE: This will shutdown main window, networking and audio. +// Dynamic libraries +void dynamic_library_open (u16 slot, c8 *name); +void *dynamic_library_get_proc_address(u16 slot, c8 *proc); + +// NOTE: This will shutdown main window, networking, audio, +// and close all opened dynamic libraries. // If g_platform.graceful_shutdown is 0, this does nothing. void shutdown_all_systems(void); @@ -736,23 +744,7 @@ extern Platform g_platform; #ifndef REDUCED_SYSTEM_LAYER_IMPL_GUARD_ #define REDUCED_SYSTEM_LAYER_IMPL_GUARD_ -Platform g_platform = {0}; - -static i64 _sound_clock_time = 0; -static i64 _sound_clock_carry = 0; -static i64 _sound_position = 0; -static i64 _frame_index = 0; - -static f32 _sound_ring [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0}; -static i64 _frame_duration [NUM_FRAMES_AVERAGED] = {0}; - -void run_main_window_event_loop(void) { - init_main_window(); -#if !defined(__wasm__) - while (!g_platform.done) update_and_render_frame(); - shutdown_all_systems(); -#endif -} +// ---------------------------------------------------------------- static void mem_set_(void *dst, u8 x, i64 size) { for (i64 i = 0; i < size; ++i) @@ -803,199 +795,6 @@ void log_error_impl(i32 file_len, c8 const *file, i32 line, i32 func_len, c8 con // ================================================================ // -// Memory buffer allocator -// -// ================================================================ - -static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0}; - -static i64 align_(i64 x, i64 alignment) { - return ((x + (alignment - 1)) / alignment) * alignment; -} - -static i64 memory_buffer_occupied_len_(i64 buffer_size) { - return (buffer_size + 64 * MEMORY_CHUNK_SIZE - 1) / (64 * MEMORY_CHUNK_SIZE); -} - -void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) { - if (g_platform.memory_buffer_size < 0) { - LOG_ERROR("Invalid memory buffer size."); - return NULL; - } - - if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0) { - LOG_ERROR("Invalid memory buffer."); - return NULL; - } - - if (g_platform.memory_buffer == NULL || g_platform.memory_buffer_size <= 0) { - g_platform.memory_buffer_size = sizeof memory_buffer_; - g_platform.memory_buffer = memory_buffer_; - } - - i64 occupied_len = memory_buffer_occupied_len_(g_platform.memory_buffer_size); - i64 occupied_len_bytes = occupied_len * 8; - i64 occupied_len_bits = occupied_len * 64; - - u64 *occupied = (u64 *) g_platform.memory_buffer; - - if (g_platform.memory_buffer_size <= occupied_len_bytes) { - LOG_ERROR("Memory buffer too small."); - return NULL; - } - - if (alignment <= 0) { - LOG_ERROR("Invalid alignment: %lld", alignment); - return NULL; - } - - if (size < 0) { - LOG_ERROR("Invalid size: %lld", size); - return NULL; - } - - if (previous_size < 0) { - LOG_ERROR("Invalid previous size: %lld", previous_size); - return NULL; - } - - if (previous_size > 0 && previous_data == NULL) { - LOG_ERROR("Invalid previous data."); - return NULL; - } - - u8 *data = g_platform.memory_buffer + occupied_len_bytes; - - i64 prev_num_chunks = 0; - i64 prev_chunk = 0; - - if (previous_size > 0) { - prev_num_chunks = (align_(previous_size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; - prev_chunk = ((u8 *) previous_data - data) / MEMORY_CHUNK_SIZE; - } - - i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; - i64 chunk = (g_platform.memory_buffer_size + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; - - if (num_chunks == prev_num_chunks) - return previous_data; - - u8 *dst = NULL; - - if (num_chunks < prev_num_chunks) { - // Reuse previously allocated space. - chunk = prev_chunk; - dst = data + chunk * MEMORY_CHUNK_SIZE; - } else { - // Search free space - for (i64 i = 0;; ++i) { - while ((i % 64) == 0 - && i < occupied_len_bits - && (i + 64 <= prev_chunk || i >= prev_chunk + prev_num_chunks) - && occupied[i / 64] == ~0ull) - i += 64; - while ((i % 8) == 0 - && i < occupied_len_bits - && (i + 8 <= prev_chunk || i >= prev_chunk + prev_num_chunks) - && ((u8 *) occupied)[i / 8] == 255u) - i += 8; - if (i >= occupied_len_bits) break; - b8 is_occupied = 0; - for (i64 j = i; j < i + num_chunks; ++j) { - if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue; - if ((occupied[j / 64] & (1ull << (j % 64))) == 0) continue; - is_occupied = 1; - break; - } - if (!is_occupied) { - chunk = i; - break; - } - } - - // Check if out of memory - dst = data + chunk * MEMORY_CHUNK_SIZE; - if (dst + size > g_platform.memory_buffer + g_platform.memory_buffer_size) { - LOG_ERROR("Out of memory: %lld bytes", size - previous_size); - return NULL; - } - - // Claim required space - for (i64 j = chunk; j < chunk + num_chunks; ++j) - occupied[j / 64] |= 1ull << (j % 64); - } - - if (chunk != prev_chunk) { - // Copy data - i64 len = size < previous_size ? size : previous_size; - u8 *s0 = data + prev_chunk * MEMORY_CHUNK_SIZE; - u8 *s1 = s0 + len - 1; - u8 *d0 = dst; - u8 *d1 = dst + len - 1; - if (d0 > s0) - for (u8 *d = d1, *s = s1; d >= d0; --d, --s) - *d = *s; - else - for (u8 *d = d0, *s = s0; d <= d1; ++d, ++s) - *d = *s; - } - - // Free previous space - for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) { - if (j >= chunk && j < chunk + num_chunks) continue; - occupied[j / 64] &= ~(1ull << (j % 64)); - } - - if (num_chunks == 0) - return NULL; - - return dst; -} - -void resize_dynamic_array_exact(i64 *num, void **data, i64 element_size, i64 new_num) { - if (num == NULL || data == NULL) { - LOG_ERROR("Sanity"); - return; - } - - if (*num == new_num) - return; - - i64 alignment = max2_i64_(8, element_size); - - void *new_data = memory_buffer_allocate( - new_num * element_size, - alignment, - *num * element_size, - *data - ); - - if (new_data == NULL && new_num > 0) - // Out of memory. - return; - - *num = new_num; - *data = new_data; -} - -void resize_dynamic_array_capacity(i64 *num, i64 *capacity, void **data, i64 element_size, i64 new_num) { - if (num == NULL || capacity == NULL || data == NULL) { - LOG_ERROR("Sanity"); - return; - } - - if (*num == new_num) - return; - - if (new_num > *capacity) - resize_dynamic_array_exact(capacity, data, element_size, new_num); - - if (new_num <= *capacity) - *num = new_num; -} - -// ================================================================ -// // BLAKE2B // // ================================================================ @@ -1331,7 +1130,7 @@ i32 blake2b(u8 *out, void *in, void *key, u8 outlen, u64 inlen, u8 keylen) { // ================================================================ // -// Utilities +// UTF-8 // // ================================================================ @@ -1434,6 +1233,228 @@ static vec3_f32 rgb_f32_from_u32_(u32 c) { } // ================================================================ + +// TODO: Move this to separate sections. + +Platform g_platform = {0}; + +static i64 _sound_clock_time = 0; +static i64 _sound_clock_carry = 0; +static i64 _sound_position = 0; +static i64 _frame_index = 0; + +static f32 _sound_ring [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0}; +static i64 _frame_duration [NUM_FRAMES_AVERAGED] = {0}; + +void run_main_window_event_loop(void) { + init_main_window(); +#if !defined(__wasm__) + while (!g_platform.done) update_and_render_frame(); + shutdown_all_systems(); +#endif +} + +// ================================================================ +// +// Memory buffer allocator +// +// ================================================================ + +static i64 align_(i64 x, i64 alignment) { + return ((x + (alignment - 1)) / alignment) * alignment; +} + +static i64 memory_buffer_occupied_len_(i64 buffer_size) { + return (buffer_size + 64 * MEMORY_CHUNK_SIZE - 1) / (64 * MEMORY_CHUNK_SIZE); +} + +static void *memory_buffer_allocate_from_(i64 memory_buffer_size, u8 *memory_buffer, i64 size, i64 alignment, i64 previous_size, void *previous_data) { + if (memory_buffer_size <= 0) { + LOG_ERROR("Invalid memory buffer size."); + return NULL; + } + + if (memory_buffer == NULL) { + LOG_ERROR("Invalid memory buffer."); + return NULL; + } + + i64 occupied_len = memory_buffer_occupied_len_(memory_buffer_size); + i64 occupied_len_bytes = occupied_len * 8; + i64 occupied_len_bits = occupied_len * 64; + + u64 *occupied = (u64 *) memory_buffer; + + if (memory_buffer_size <= occupied_len_bytes) { + LOG_ERROR("Memory buffer too small."); + return NULL; + } + + if (alignment <= 0) { + LOG_ERROR("Invalid alignment: %lld", alignment); + return NULL; + } + + if (size < 0) { + LOG_ERROR("Invalid size: %lld", size); + return NULL; + } + + if (previous_size < 0) { + LOG_ERROR("Invalid previous size: %lld", previous_size); + return NULL; + } + + if (previous_size > 0 && previous_data == NULL) { + LOG_ERROR("Invalid previous data."); + return NULL; + } + + u8 *data = memory_buffer + occupied_len_bytes; + + i64 prev_num_chunks = 0; + i64 prev_chunk = 0; + + if (previous_size > 0) { + prev_num_chunks = (align_(previous_size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; + prev_chunk = ((u8 *) previous_data - data) / MEMORY_CHUNK_SIZE; + } + + i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; + i64 chunk = (memory_buffer_size + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE; + + if (num_chunks == prev_num_chunks) + return previous_data; + + u8 *dst = NULL; + + if (num_chunks < prev_num_chunks) { + // Reuse previously allocated space. + chunk = prev_chunk; + dst = data + chunk * MEMORY_CHUNK_SIZE; + } else { + // Search free space + for (i64 i = 0;; ++i) { + while ((i % 64) == 0 + && i < occupied_len_bits + && (i + 64 <= prev_chunk || i >= prev_chunk + prev_num_chunks) + && occupied[i / 64] == ~0ull) + i += 64; + while ((i % 8) == 0 + && i < occupied_len_bits + && (i + 8 <= prev_chunk || i >= prev_chunk + prev_num_chunks) + && ((u8 *) occupied)[i / 8] == 255u) + i += 8; + if (i >= occupied_len_bits) break; + b8 is_occupied = 0; + for (i64 j = i; j < i + num_chunks; ++j) { + if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue; + if ((occupied[j / 64] & (1ull << (j % 64))) == 0) continue; + is_occupied = 1; + break; + } + if (!is_occupied) { + chunk = i; + break; + } + } + + // Check if out of memory + dst = data + chunk * MEMORY_CHUNK_SIZE; + if (dst + size > memory_buffer + memory_buffer_size) { + LOG_ERROR("Out of memory: %lld bytes", size - previous_size); + return NULL; + } + + // Claim required space + for (i64 j = chunk; j < chunk + num_chunks; ++j) + occupied[j / 64] |= 1ull << (j % 64); + } + + if (chunk != prev_chunk) { + // Copy data + i64 len = size < previous_size ? size : previous_size; + u8 *s0 = data + prev_chunk * MEMORY_CHUNK_SIZE; + u8 *s1 = s0 + len - 1; + u8 *d0 = dst; + u8 *d1 = dst + len - 1; + if (d0 > s0) + for (u8 *d = d1, *s = s1; d >= d0; --d, --s) + *d = *s; + else + for (u8 *d = d0, *s = s0; d <= d1; ++d, ++s) + *d = *s; + } + + // Free previous space + for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) { + if (j >= chunk && j < chunk + num_chunks) continue; + occupied[j / 64] &= ~(1ull << (j % 64)); + } + + if (num_chunks == 0) + return NULL; + + return dst; +} + +static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0}; + +void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) { + if (g_platform.memory_buffer == NULL || g_platform.memory_buffer_size <= 0) { + g_platform.memory_buffer_size = sizeof memory_buffer_; + g_platform.memory_buffer = memory_buffer_; + } + + return memory_buffer_allocate_from_(g_platform.memory_buffer_size, g_platform.memory_buffer, size, alignment, previous_size, previous_data); +} + +void resize_dynamic_array_exact(i64 *num, void **data, i64 element_size, i64 new_num) { + if (num == NULL || data == NULL) { + LOG_ERROR("Sanity"); + return; + } + + if (*num == new_num) + return; + + i64 alignment = max2_i64_(8, element_size); + + void *new_data = memory_buffer_allocate( + new_num * element_size, + alignment, + *num * element_size, + *data + ); + + if (new_data == NULL && new_num > 0) + // Out of memory. + return; + + if (new_num > *num) + mem_set_(*data, 0, new_num - *num); + + *num = new_num; + *data = new_data; +} + +void resize_dynamic_array_capacity(i64 *num, i64 *capacity, void **data, i64 element_size, i64 new_num) { + if (num == NULL || capacity == NULL || data == NULL) { + LOG_ERROR("Sanity"); + return; + } + + if (*num == new_num) + return; + + if (new_num > *capacity) + resize_dynamic_array_exact(capacity, data, element_size, new_num); + + if (new_num <= *capacity) + *num = new_num; +} + +// ================================================================ // // Platform // @@ -1502,12 +1523,7 @@ static void drop_files_set_num_(i64 num) { return; } - i64 prev_num = g_platform.num_drop_files; - resize_dynamic_array_exact(&g_platform.num_drop_files, (void **) &g_platform.drop_files, sizeof *g_platform.drop_files, num); - - if (prev_num < g_platform.num_drop_files) - mem_set_(g_platform.drop_files + prev_num, 0, sizeof *g_platform.drop_files * (g_platform.num_drop_files - prev_num)); } static void drop_files_set_name_(i64 index, i64 name_len, c8 *name) { @@ -1738,6 +1754,102 @@ static void store_clipboard_text_(i64 size, c8 *data) { // ================================================================ // +// Dynamic libraries +// +// ================================================================ + +#if defined(__unix__) +#include <dlfcn.h> + +typedef struct { + void *handle; +} Dynamic_Library_Slot_; + +typedef struct { + i64 num_slots; + Dynamic_Library_Slot_ *slots; +} Dynamic_Libraries_; + +static Dynamic_Libraries_ dynamic_libraries_ = {0}; + +void dynamic_library_open(u16 slot, c8 *name) { + if (name == NULL) { + LOG_ERROR("Sanity"); + return; + } + + if (slot >= dynamic_libraries_.num_slots) + resize_dynamic_array_exact(&dynamic_libraries_.num_slots, (void **) &dynamic_libraries_.slots, sizeof *dynamic_libraries_.slots, (i64) slot + 1); + + if (dynamic_libraries_.slots[slot].handle != NULL) { + dlclose(dynamic_libraries_.slots[slot].handle); + dynamic_libraries_.slots[slot].handle = NULL; + } + + void *h = dlopen(name, RTLD_LAZY); + + if (h == NULL) { + LOG_ERROR("Failed to open: %s", name); + LOG_ERROR("%s", dlerror()); + return; + } + + dynamic_libraries_.slots[slot].handle = h; +} + +void *dynamic_library_get_proc_address(u16 slot, c8 *proc) { + if (slot >= dynamic_libraries_.num_slots) { + LOG_ERROR("Invalid slot: %d", (i32) slot); + return NULL; + } + + if (proc == NULL) { + LOG_ERROR("Sanity"); + return NULL; + } + + if (dynamic_libraries_.slots[slot].handle == NULL) { + LOG_ERROR("Slot is closed: %d", (i32) slot); + return NULL; + } + + void *proc_address = dlsym(dynamic_libraries_.slots[slot].handle, proc); + + if (proc_address == NULL) { + LOG_ERROR("Failed to get: %s", proc); + LOG_ERROR("%s", dlerror()); + } + + return proc_address; +} + +static void close_all_dynamic_libraries_(void) { + for (i64 i = 0; i < dynamic_libraries_.num_slots; ++i) + if (dynamic_libraries_.slots[i].handle != NULL) + dlclose(dynamic_libraries_.slots[i].handle); + resize_dynamic_array_exact(&dynamic_libraries_.num_slots, (void **) &dynamic_libraries_.slots, sizeof *dynamic_libraries_.slots, 0); +} +#endif // defined(__unix__) + +#if defined(__wasm__) +void dynamic_library_open(u16 slot, c8 *name) { + (void) slot; + (void) name; + + LOG_ERROR("Dynamic library not found: %s", name); +} + +void *dynamic_library_get_proc_address(u16 slot, c8 *proc) { + (void) slot; + (void) proc; + + LOG_ERROR("Proc address not found: %s", proc); + return NULL; +} +#endif // defined(__wasm__) + +// ================================================================ +// // Unix // // ================================================================ @@ -1816,10 +1928,8 @@ static void network_init_(u16 slot) { i64 num = (i64) (u64) slot; i64 prev_num = _num_sockets; - if (num > prev_num) { + if (num > prev_num) resize_dynamic_array_exact(&_num_sockets, (void **) &_sockets, sizeof *_sockets, num); - mem_set_(_sockets + prev_num, 0, num - prev_num); - } } static void network_cleanup_(void) { @@ -3069,6 +3179,7 @@ void shutdown_all_systems(void) { cleanup_pixel_buffers_(); network_cleanup_(); sound_cleanup_(); + close_all_dynamic_libraries_(); g_platform.input_len = 0; resize_dynamic_array_exact(&g_platform.input_capacity, (void **) &g_platform.input, sizeof *g_platform.input, 0); @@ -3313,7 +3424,7 @@ i32 handle_main_window_events(void) { ev.xselection.requestor, _dnd_selection, 0, - g_platform.memory_buffer_size, + STATIC_MEMORY_BUFFER_SIZE, // FIXME False, ev.xselection.target, &(Atom) {0}, @@ -3368,7 +3479,7 @@ i32 handle_main_window_events(void) { _window, _clipboard, 0, - g_platform.memory_buffer_size, + STATIC_MEMORY_BUFFER_SIZE, // FIXME False, AnyPropertyType, &(Atom) {0}, |