ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

Commit: f08977594719b224db2710dd3f575bcda35bafeb
Parent: 2236c1d733d7fca11793307b2680239c8084a080
Author: Randy Palamar
Date:   Tue,  1 Sep 2026 19:42:40 -0700

base_platform: move thread/barrier functions into platform layer

This way they can be used from tests/other code.

Diffstat:
Mbase_linux.c | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mbase_platform.h | 23++++++++++++++++++++++-
Mbase_win32.c | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mbeamformer.h | 4----
Mbeamformer_internal.h | 3+--
Mlib/ogl_beamformer_lib.c | 1-
Mmain_linux.c | 154++++++++-----------------------------------------------------------------------
Mmain_w32.c | 176++++++++-----------------------------------------------------------------------
Mutil.c | 22++++++++++++++++++++++
Dutil_os.c | 43-------------------------------------------
Mutil_os_ui.c | 17+++++++++++++++++
11 files changed, 374 insertions(+), 368 deletions(-)

diff --git a/base_linux.c b/base_linux.c @@ -24,7 +24,76 @@ #include <sys/sysinfo.h> #include <unistd.h> -global OSSystemInfo linux_system_info; +typedef struct OSLinuxEntity OSLinuxEntity; +typedef struct { + void *handle; + OSLinuxEntity *prev, *next; +} OSLinuxWindow; + +typedef enum { + OSLinuxFileWatchKind_Platform, + OSLinuxFileWatchKind_User, +} OSLinuxFileWatchKind; + +typedef struct OSLinuxFileWatchDirectory OSLinuxFileWatchDirectory; +typedef struct OSLinuxFileWatch OSLinuxFileWatch; +struct OSLinuxFileWatch { + OSLinuxFileWatchKind kind; + u64 hash; + u64 update_time; + void *user_context; + + OSLinuxFileWatchDirectory *parent; + OSLinuxFileWatch *prev, *next; +}; + +struct OSLinuxFileWatchDirectory { + u64 hash; + i64 handle; + str8 name; + + OSLinuxFileWatch *first_child; + OSLinuxFileWatch *last_child; + OSLinuxFileWatchDirectory *prev, *next; +}; + +typedef enum { + OSLinuxEntityKind_Window, + OSLinuxEntityKind_FileWatch, + OSLinuxEntityKind_FileWatchDirectory, +} OSLinuxEntityKind; + +struct OSLinuxEntity { + OSLinuxEntityKind kind; + union { + OSLinuxFileWatch file_watch; + OSLinuxFileWatchDirectory file_watch_directory; + OSLinuxWindow window; + } as; + OSLinuxEntity *next; +}; + +typedef struct { + OSSystemInfo system_info; + + Arena *arena; + i32 arena_lock; + + i32 inotify_handle; + + struct { + OSLinuxFileWatchDirectory *first; + OSLinuxFileWatchDirectory *last; + } file_watch_directories; + + struct { + OSLinuxEntity *first; + OSLinuxEntity *last; + } windows; + + OSLinuxEntity *entity_freelist; +} OSLinux_Context; +global OSLinux_Context os_linux_context; function b32 os_write_file(i32 file, void *data, i64 length) @@ -75,20 +144,20 @@ os_number_of_processors(void) function void os_system_info_init(void) { - linux_system_info.timer_frequency = os_timer_frequency(); - linux_system_info.logical_processor_count = os_number_of_processors(); - linux_system_info.page_size = ARCH_X64? KB(4) : getauxval(AT_PAGESZ); - linux_system_info.path_separator_byte = '/'; + os_linux_context.system_info.timer_frequency = os_timer_frequency(); + os_linux_context.system_info.logical_processor_count = os_number_of_processors(); + os_linux_context.system_info.page_size = ARCH_X64? KB(4) : getauxval(AT_PAGESZ); + os_linux_context.system_info.path_separator_byte = '/'; } BASE_EXPORT OSSystemInfo * os_system_info(void) { #if BASE_PLATFORM_NO_MAIN - if unlikely(linux_system_info.path_separator_byte == 0) + if unlikely(os_linux_context.system_info.path_separator_byte == 0) os_system_info_init(); #endif - return &linux_system_info; + return &os_linux_context.system_info; } BASE_EXPORT void * @@ -195,6 +264,60 @@ os_copy_file(char *name, char *new) return result; } +function OSLinuxEntity * +os_entity_allocate(OSLinuxEntityKind kind) +{ + OSLinuxEntity *result = 0; + DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock)) + { + result = SLLPopFreelist(os_linux_context.entity_freelist); + if (!result) result = push_struct_no_zero(os_linux_context.arena, OSLinuxEntity); + } + + zero_struct(result); + result->kind = kind; + return result; +} + +BASE_EXPORT OSThread +os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn) +{ + pthread_t thread; + pthread_create(&thread, 0, (void *)fn, (void *)user_context); + + if (name) { + char buffer[16]; + str8 name_str = str8_from_c_str((char *)name); + u64 length = (u64)Clamp(name_str.length, 0, countof(buffer) - 1); + memory_copy(buffer, (char *)name, length); + buffer[length] = 0; + pthread_setname_np(thread, buffer); + } + + OSThread result = {(u64)thread}; + return result; +} + +BASE_EXPORT OSBarrier +os_barrier_alloc(u32 count) +{ + OSBarrier result = {0}; + DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock)) + { + pthread_barrier_t *barrier = push_struct(os_linux_context.arena, pthread_barrier_t); + pthread_barrier_init(barrier, 0, count); + result.value[0] = (u64)barrier; + } + return result; +} + +BASE_EXPORT void +os_barrier_enter(OSBarrier barrier) +{ + pthread_barrier_t *b = (pthread_barrier_t *)barrier.value[0]; + if (b) pthread_barrier_wait(b); +} + BASE_EXPORT b32 os_wait_on_address(i32 *value, i32 current, u32 timeout_ms) { @@ -223,6 +346,7 @@ extern i32 main(i32 argc, char *argv[]) { os_system_info_init(); + os_linux_context.arena = arena_create(.name = "Platform Arena"); entry_point(argc, argv); diff --git a/base_platform.h b/base_platform.h @@ -2,6 +2,21 @@ #ifndef BASE_PLATFORM_H #define BASE_PLATFORM_H +/* + * CONFIGURATION + * + * BASE_EXPORT + * the attributes for functions defined by the platfom layer. for example + * `#define BASE_EXPORT static` in a single translation unit build + * + * BASE_IMPORT + * the attributes to apply on the entry_point() called from main() + * + * BASE_PLATFORM_NO_MAIN: + * define if you do not want a main() function (useful for library code) + * + */ + #ifndef BASE_EXPORT #define BASE_EXPORT #endif @@ -12,6 +27,9 @@ #ifndef BASE_PLATFORM_NO_MAIN #define BASE_PLATFORM_NO_MAIN 0 +#else +#undef BASE_PLATFORM_NO_MAIN +#define BASE_PLATFORM_NO_MAIN 1 #endif #include "base_types.h" @@ -50,12 +68,15 @@ BASE_EXPORT u64 os_timer_count(void); BASE_EXPORT str8 os_read_entire_file(Arena *arena, const char *file); +BASE_EXPORT OSThread os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn); +BASE_EXPORT OSBarrier os_barrier_alloc(u32 thread_count); +BASE_EXPORT void os_barrier_enter(OSBarrier); + /* NOTE(rnp): memory watch timed waiting functions. (-1) is an infinite timeout. * Used with the intention of yielding the thread back to the OS. */ BASE_EXPORT u32 os_wait_on_address(i32 *lock, i32 current, u32 timeout_ms); BASE_EXPORT void os_wake_all_waiters(i32 *lock); - /* NOTE(rnp): this functionality is only needed on win32 to provide cross process * synchronization. While posix has equivalent functionality there is no reason to * use it over a value located in shared memory. */ diff --git a/base_win32.c b/base_win32.c @@ -87,6 +87,14 @@ typedef struct { iptr event_handle; } w32_overlapped; +typedef struct { + u32 reserved1; + u32 reserved2; + u64 Reserved3[2]; + u32 reserved4; + u32 reserved5; +} w32_synchronization_barrier; + typedef enum { W32IOEvent_FileWatch, } W32IOEvent; @@ -96,11 +104,6 @@ typedef struct { iptr context; } w32_io_completion_event; -typedef struct { - iptr *semaphores; - u32 reserved_count; -} w32_shared_memory_context; - #define W32(r) __declspec(dllimport) r __stdcall W32(b32) CloseHandle(iptr); W32(b32) CopyFileA(c8 *, c8 *, b32); @@ -108,7 +111,9 @@ W32(iptr) CreateFileA(c8 *, u32, u32, void *, u32, u32, void *); W32(iptr) CreateFileMappingA(iptr, void *, u32, u32, u32, c8 *); W32(iptr) CreateIoCompletionPort(iptr, iptr, uptr, u32); W32(iptr) CreateSemaphoreA(iptr, i32, i32, c8 *); +W32(u64) CreateThread(iptr, u64, iptr, iptr, u32, u32 *); W32(b32) DeleteFileA(c8 *); +W32(b32) EnterSynchronizationBarrier(w32_synchronization_barrier *, u32); W32(void) ExitProcess(i32); W32(i32) GetFileAttributesA(c8 *); W32(b32) GetFileInformationByHandle(iptr, void *); @@ -116,12 +121,14 @@ W32(i32) GetLastError(void); W32(b32) GetQueuedCompletionStatus(iptr, u32 *, uptr *, w32_overlapped **, u32); W32(iptr) GetStdHandle(i32); W32(void) GetSystemInfo(w32_system_info *); +W32(b32) InitializeSynchronizationBarrier(w32_synchronization_barrier *, i32, i32); W32(void *) MapViewOfFile(iptr, u32, u32, u32, u64); W32(b32) QueryPerformanceCounter(u64 *); W32(b32) QueryPerformanceFrequency(u64 *); W32(b32) ReadDirectoryChangesW(iptr, u8 *, u32, b32, u32, u32 *, void *, void *); W32(b32) ReadFile(iptr, u8 *, i32, i32 *, void *); W32(b32) ReleaseSemaphore(iptr, i32, i32 *); +W32(i32) SetThreadDescription(u64, u16 *); W32(u32) WaitForSingleObject(iptr, u32); W32(b32) WaitOnAddress(void *, void *, u64, u32); W32(i32) WakeByAddressAll(void *); @@ -130,7 +137,83 @@ W32(void *) VirtualAlloc(u8 *, i64, u32, u32); W32(b32) VirtualFree(void *, u64, u32); W32(b32) VirtualProtect(void *, u64, u32, u32 *); -global OSSystemInfo win32_system_info; +enum {OSW32_FileWatchDirectoryBufferSize = KB(4)}; + +typedef struct OSW32Entity OSW32Entity; +typedef struct { + void *handle; + OSW32Entity *prev, *next; +} OSW32Window; + +typedef enum { + OSW32FileWatchKind_Platform, + OSW32FileWatchKind_User, +} OSW32FileWatchKind; + +typedef struct OSW32FileWatchDirectory OSW32FileWatchDirectory; +typedef struct OSW32FileWatch OSW32FileWatch; +struct OSW32FileWatch { + OSW32FileWatchKind kind; + u64 hash; + u64 update_time; + void *user_context; + + OSW32FileWatchDirectory *parent; + OSW32FileWatch *prev, *next; +}; + +struct OSW32FileWatchDirectory { + u64 hash; + i64 handle; + str8 name; + + OSW32FileWatch *first_child; + OSW32FileWatch *last_child; + OSW32FileWatchDirectory *prev, *next; + + w32_overlapped overlapped; + w32_io_completion_event event; + + void *buffer; +}; + +typedef enum { + OSW32EntityKind_Window, + OSW32EntityKind_FileWatch, + OSW32EntityKind_FileWatchDirectory, +} OSW32EntityKind; + +struct OSW32Entity { + OSW32EntityKind kind; + union { + OSW32FileWatch file_watch; + OSW32FileWatchDirectory file_watch_directory; + OSW32Window window; + } as; + OSW32Entity *next; +}; + +typedef struct { + OSSystemInfo system_info; + + Arena *arena; + i32 arena_lock; + i64 error_handle; + i64 io_completion_handle; + + struct { + OSW32FileWatchDirectory *first; + OSW32FileWatchDirectory *last; + } file_watch_directories; + + struct { + OSW32Entity *first; + OSW32Entity *last; + } windows; + + OSW32Entity *entity_freelist; +} OSW32_Context; +global OSW32_Context os_w32_context; function b32 os_write_file(iptr file, void *data, i64 length) @@ -169,20 +252,20 @@ os_system_info_init(void) w32_system_info info = {0}; GetSystemInfo(&info); - win32_system_info.timer_frequency = os_timer_frequency(); - win32_system_info.logical_processor_count = info.number_of_processors; - win32_system_info.page_size = info.page_size; - win32_system_info.path_separator_byte = '\\'; + os_w32_context.system_info.timer_frequency = os_timer_frequency(); + os_w32_context.system_info.logical_processor_count = info.number_of_processors; + os_w32_context.system_info.page_size = info.page_size; + os_w32_context.system_info.path_separator_byte = '\\'; } BASE_EXPORT OSSystemInfo * os_system_info(void) { #if BASE_PLATFORM_NO_MAIN - if unlikely(win32_system_info.path_separator_byte == 0) + if unlikely(os_w32_context.system_info.path_separator_byte == 0) os_system_info_init(); #endif - return &win32_system_info; + return &os_w32_context.system_info; } BASE_EXPORT void * @@ -291,6 +374,58 @@ os_copy_file(char *name, char *new) return CopyFileA(name, new, 0); } +function OSW32Entity * +os_entity_allocate(OSW32EntityKind kind) +{ + OSW32Entity *result = 0; + DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) + { + result = SLLPopFreelist(os_w32_context.entity_freelist); + if (!result) result = push_struct_no_zero(os_w32_context.arena, OSW32Entity); + } + + zero_struct(result); + result->kind = kind; + return result; +} + +BASE_EXPORT OSThread +os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn) +{ + OSThread result = {(u64)CreateThread(0, 0, (iptr)fn, (iptr)user_context, 0, 0)}; + if (result.value[0]) { + Temp scratch; + DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) + DeferLoop(scratch = temp_begin(os_w32_context.arena), temp_end(scratch)) + { + SetThreadDescription(result.value[0], str16_from_str8(scratch.arena, str8_from_c_str((c8 *)name)).data); + } + } else { + result.value[0] = OSInvalidHandleValue; + } + return result; +} + +BASE_EXPORT OSBarrier +os_barrier_alloc(u32 count) +{ + OSBarrier result = {0}; + DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) + { + w32_synchronization_barrier *barrier = push_struct(os_w32_context.arena, w32_synchronization_barrier); + InitializeSynchronizationBarrier(barrier, (i32)count, -1); + result.value[0] = (u64)barrier; + } + return result; +} + +BASE_EXPORT void +os_barrier_enter(OSBarrier barrier) +{ + w32_synchronization_barrier *b = (w32_synchronization_barrier *)barrier.value[0]; + if (b) EnterSynchronizationBarrier(b, 0); +} + BASE_EXPORT b32 os_wait_on_address(i32 *value, i32 current, u32 timeout_ms) { @@ -313,6 +448,8 @@ extern i32 main(i32 argc, char *argv[]) { os_system_info_init(); + os_w32_context.arena = arena_create(.name = "Platform Arena"); + os_w32_context.error_handle = GetStdHandle(STD_ERROR_HANDLE); entry_point(argc, argv); diff --git a/beamformer.h b/beamformer.h @@ -72,10 +72,6 @@ BEAMFORMER_IMPORT void os_add_file_watch(const char *path, int64_t pat BEAMFORMER_IMPORT void * os_lookup_symbol(OSLibrary library, const char *symbol); -BEAMFORMER_IMPORT OSThread os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn); -BEAMFORMER_IMPORT OSBarrier os_barrier_alloc(u32 thread_count); -BEAMFORMER_IMPORT void os_barrier_enter(OSBarrier); - // NOTE(rnp): currently beamformer will only create one window. // once raylib is removed it may request multiple BEAMFORMER_IMPORT OSWindow os_window_create(uint8_t *title, int64_t title_length, int32_t width, int32_t height); diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -131,7 +131,6 @@ typedef struct { } RenderModel; #include "threads.c" -#include "util_os_ui.c" /////////////////////////// // NOTE: vulkan layer API @@ -223,7 +222,7 @@ DEBUG_IMPORT renderdoc_end_frame_capture_fn *end_frame_capture; #define renderdoc_attached(...) (0) #endif -#include "util_os.c" +#include "util_os_ui.c" /////////////////////////////// // NOTE: CUDA Library Bindings diff --git a/lib/ogl_beamformer_lib.c b/lib/ogl_beamformer_lib.c @@ -22,7 +22,6 @@ W32(iptr) OpenFileMappingA(u32, b32, c8 *); #error Unsupported Platform #endif -#include "../util_os.c" #include "../beamformer_compute_stats.c" #include "../beamformer_shared_memory.c" diff --git a/main_linux.c b/main_linux.c @@ -32,130 +32,7 @@ #include <dlfcn.h> -typedef struct OSLinuxEntity OSLinuxEntity; -typedef struct { - void *handle; - OSLinuxEntity *prev, *next; -} OSLinuxWindow; - -typedef enum { - OSLinuxFileWatchKind_Platform, - OSLinuxFileWatchKind_User, -} OSLinuxFileWatchKind; - -typedef struct OSLinuxFileWatchDirectory OSLinuxFileWatchDirectory; -typedef struct OSLinuxFileWatch OSLinuxFileWatch; -struct OSLinuxFileWatch { - OSLinuxFileWatchKind kind; - u64 hash; - u64 update_time; - void *user_context; - - OSLinuxFileWatchDirectory *parent; - OSLinuxFileWatch *prev, *next; -}; - -struct OSLinuxFileWatchDirectory { - u64 hash; - i64 handle; - str8 name; - - OSLinuxFileWatch *first_child; - OSLinuxFileWatch *last_child; - OSLinuxFileWatchDirectory *prev, *next; -}; - -typedef enum { - OSLinuxEntityKind_Window, - OSLinuxEntityKind_FileWatch, - OSLinuxEntityKind_FileWatchDirectory, -} OSLinuxEntityKind; - -struct OSLinuxEntity { - OSLinuxEntityKind kind; - union { - OSLinuxFileWatch file_watch; - OSLinuxFileWatchDirectory file_watch_directory; - OSLinuxWindow window; - } as; - OSLinuxEntity *next; -}; - -typedef struct { - Arena *arena; - i32 arena_lock; - - i32 inotify_handle; - - BeamformerInput *input; - - struct { - OSLinuxFileWatchDirectory *first; - OSLinuxFileWatchDirectory *last; - } file_watch_directories; - - struct { - OSLinuxEntity *first; - OSLinuxEntity *last; - } windows; - - OSLinuxEntity *entity_freelist; -} OSLinux_Context; -global OSLinux_Context os_linux_context; - -function OSLinuxEntity * -os_entity_allocate(OSLinuxEntityKind kind) -{ - OSLinuxEntity *result = 0; - DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock)) - { - result = SLLPopFreelist(os_linux_context.entity_freelist); - if (!result) result = push_struct_no_zero(os_linux_context.arena, OSLinuxEntity); - } - - zero_struct(result); - result->kind = kind; - return result; -} - -BEAMFORMER_IMPORT OSThread -os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn) -{ - pthread_t thread; - pthread_create(&thread, 0, (void *)fn, (void *)user_context); - - if (name) { - char buffer[16]; - str8 name_str = str8_from_c_str((char *)name); - u64 length = (u64)Clamp(name_str.length, 0, countof(buffer) - 1); - memory_copy(buffer, (char *)name, length); - buffer[length] = 0; - pthread_setname_np(thread, buffer); - } - - OSThread result = {(u64)thread}; - return result; -} - -BEAMFORMER_IMPORT OSBarrier -os_barrier_alloc(u32 count) -{ - OSBarrier result = {0}; - DeferLoop(take_lock(&os_linux_context.arena_lock, -1), release_lock(&os_linux_context.arena_lock)) - { - pthread_barrier_t *barrier = push_struct(os_linux_context.arena, pthread_barrier_t); - pthread_barrier_init(barrier, 0, count); - result.value[0] = (u64)barrier; - } - return result; -} - -BEAMFORMER_IMPORT void -os_barrier_enter(OSBarrier barrier) -{ - pthread_barrier_t *b = (pthread_barrier_t *)barrier.value[0]; - if (b) pthread_barrier_wait(b); -} +global BeamformerInput beamformer_input_main; BEAMFORMER_IMPORT void os_console_log(u8 *data, i64 length) @@ -189,7 +66,7 @@ os_lookup_symbol(OSLibrary library, const char *symbol) function void * allocate_shared_memory(char *name, i64 requested_capacity, u64 *capacity) { - u64 rounded_capacity = round_up_to(requested_capacity, ARCH_X64? KB(4) : linux_system_info.page_size); + u64 rounded_capacity = round_up_to(requested_capacity, ARCH_X64? KB(4) : os_linux_context.system_info.page_size); void *result = 0; i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (fd > 0 && ftruncate(fd, rounded_capacity) != -1) { @@ -295,7 +172,7 @@ os_window_create(u8 *title, i64 title_length, i32 width, i32 height) } we->as.window.handle = GetPlatformWindowHandle(); - os_window_equip_common(os_linux_context.input, we->as.window.handle); + os_window_equip_common(&beamformer_input_main, we->as.window.handle); raylib_window_resize = glfwSetWindowSizeCallback(we->as.window.handle, os_window_resize_callback); /* NOTE: do this after initing so that the window starts out floating in tiling wm */ @@ -341,12 +218,12 @@ load_library(char *name, char *temp_name, u32 flags) #if BEAMFORMER_DEBUG function void -debug_library_reload(void *beamformer, BeamformerInput *input) +debug_library_reload(void *beamformer) { local_persist OSLibrary beamformer_library_handle = {OSInvalidHandleValue}; if ValidHandle(beamformer_library_handle) { - beamformer_debug_hot_release(beamformer, input); + beamformer_debug_hot_release(beamformer, &beamformer_input_main); dlclose((void *)beamformer_library_handle.value[0]); beamformer_library_handle = (OSLibrary){OSInvalidHandleValue}; } @@ -361,18 +238,19 @@ debug_library_reload(void *beamformer, BeamformerInput *input) } } #else -#define debug_library_reload(a, b) (void)(a), (void)(b) +#define debug_library_reload(a) (void)(a) #endif /* BEAMFORMER_DEBUG */ function void -load_platform_libraries(BeamformerInput *input) +load_platform_libraries(void) { #if BEAMFORMER_DEBUG - debug_library_reload(0, input); + debug_library_reload(0); os_linux_add_file_watch(str8(OS_DEBUG_LIB_NAME), (void *)BeamformerInputEventKind_ExecutableReload, OSLinuxFileWatchKind_Platform); #endif + BeamformerInput *input = &beamformer_input_main; input->vulkan_library_handle = (OSLibrary){OSInvalidHandleValue}; #define X(name) \ if InvalidHandle(input->vulkan_library_handle) \ @@ -393,7 +271,7 @@ load_platform_libraries(BeamformerInput *input) } function void -dispatch_file_watch_events(void *beamformer, BeamformerInput *input) +dispatch_file_watch_events(void *beamformer) { local_persist alignas(16) u8 mem[KB(4)]; struct inotify_event *event; @@ -417,13 +295,13 @@ dispatch_file_watch_events(void *beamformer, BeamformerInput *input) if (fw->kind == OSLinuxFileWatchKind_Platform) { assert((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload); if ((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload) - debug_library_reload(beamformer, input); + debug_library_reload(beamformer); input_event.kind = (u64)fw->user_context; } else { input_event.kind = BeamformerInputEventKind_FileEvent; input_event.file_watch_user_context = fw->user_context; } - os_push_input_event(input, input_event); + os_push_input_event(&beamformer_input_main, input_event); } fw->update_time = current_time; break; @@ -436,11 +314,9 @@ dispatch_file_watch_events(void *beamformer, BeamformerInput *input) BASE_IMPORT void entry_point(i32 argc, char *argv[]) { - os_linux_context.arena = arena_create(.name = "Platform Arena"); os_linux_context.inotify_handle = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); - BeamformerInput *input = push_struct(os_linux_context.arena, BeamformerInput); - os_linux_context.input = input; + BeamformerInput *input = &beamformer_input_main; input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, OS_SHARED_MEMORY_SIZE, &input->shared_memory_size); if (input->shared_memory) { @@ -452,7 +328,7 @@ entry_point(i32 argc, char *argv[]) .kind = BeamformerInputEventKind_ExecutableReload, }); - load_platform_libraries(input); + load_platform_libraries(); void *beamformer = beamformer_init(input); @@ -465,7 +341,7 @@ entry_point(i32 argc, char *argv[]) poll(fds, countof(fds), 0); if (fds[0].revents & POLLIN) - dispatch_file_watch_events(beamformer, input); + dispatch_file_watch_events(beamformer); beamformer_frame_step(beamformer, input); diff --git a/main_w32.c b/main_w32.c @@ -32,22 +32,10 @@ #include "beamformer.c" #include "base_win32.c" -typedef struct { - u32 reserved1; - u32 reserved2; - u64 Reserved3[2]; - u32 reserved4; - u32 reserved5; -} w32_synchronization_barrier; - -W32(u64) CreateThread(iptr, u64, iptr, iptr, u32, u32 *); -W32(b32) EnterSynchronizationBarrier(w32_synchronization_barrier *, u32); W32(b32) FreeLibrary(u64); W32(void *) GetModuleHandleA(const c8 *); W32(void *) GetProcAddress(u64, const c8 *); -W32(b32) InitializeSynchronizationBarrier(w32_synchronization_barrier *, i32, i32); W32(void *) LoadLibraryA(const c8 *); -W32(i32) SetThreadDescription(u64, u16 *); #define OS_SHARED_MEMORY_SIZE GB(2) @@ -62,135 +50,7 @@ W32(i32) SetThreadDescription(u64, u16 *); #define OS_VULKAN_SONAME_LIST \ X("vulkan-1.dll") \ -enum {OSW32_FileWatchDirectoryBufferSize = KB(4)}; - -typedef struct OSW32Entity OSW32Entity; -typedef struct { - void *handle; - OSW32Entity *prev, *next; -} OSW32Window; - -typedef enum { - OSW32FileWatchKind_Platform, - OSW32FileWatchKind_User, -} OSW32FileWatchKind; - -typedef struct OSW32FileWatchDirectory OSW32FileWatchDirectory; -typedef struct OSW32FileWatch OSW32FileWatch; -struct OSW32FileWatch { - OSW32FileWatchKind kind; - u64 hash; - u64 update_time; - void *user_context; - - OSW32FileWatchDirectory *parent; - OSW32FileWatch *prev, *next; -}; - -struct OSW32FileWatchDirectory { - u64 hash; - i64 handle; - str8 name; - - OSW32FileWatch *first_child; - OSW32FileWatch *last_child; - OSW32FileWatchDirectory *prev, *next; - - w32_overlapped overlapped; - w32_io_completion_event event; - - void *buffer; -}; - -typedef enum { - OSW32EntityKind_Window, - OSW32EntityKind_FileWatch, - OSW32EntityKind_FileWatchDirectory, -} OSW32EntityKind; - -struct OSW32Entity { - OSW32EntityKind kind; - union { - OSW32FileWatch file_watch; - OSW32FileWatchDirectory file_watch_directory; - OSW32Window window; - } as; - OSW32Entity *next; -}; - -typedef struct { - Arena *arena; - i32 arena_lock; - i64 error_handle; - i64 io_completion_handle; - - BeamformerInput *input; - - struct { - OSW32FileWatchDirectory *first; - OSW32FileWatchDirectory *last; - } file_watch_directories; - - struct { - OSW32Entity *first; - OSW32Entity *last; - } windows; - - OSW32Entity *entity_freelist; -} OSW32_Context; -global OSW32_Context os_w32_context; - -function OSW32Entity * -os_entity_allocate(OSW32EntityKind kind) -{ - OSW32Entity *result = 0; - DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) - { - result = SLLPopFreelist(os_w32_context.entity_freelist); - if (!result) result = push_struct_no_zero(os_w32_context.arena, OSW32Entity); - } - - zero_struct(result); - result->kind = kind; - return result; -} - -BEAMFORMER_IMPORT OSThread -os_create_thread(const char *name, void *user_context, os_thread_entry_point_fn *fn) -{ - OSThread result = {(u64)CreateThread(0, 0, (iptr)fn, (iptr)user_context, 0, 0)}; - if (result.value[0]) { - Temp scratch; - DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) - DeferLoop(scratch = temp_begin(os_w32_context.arena), temp_end(scratch)) - { - SetThreadDescription(result.value[0], str16_from_str8(scratch.arena, str8_from_c_str((c8 *)name)).data); - } - } else { - result.value[0] = OSInvalidHandleValue; - } - return result; -} - -BEAMFORMER_IMPORT OSBarrier -os_barrier_alloc(u32 count) -{ - OSBarrier result = {0}; - DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) - { - w32_synchronization_barrier *barrier = push_struct(os_w32_context.arena, w32_synchronization_barrier); - InitializeSynchronizationBarrier(barrier, (i32)count, -1); - result.value[0] = (u64)barrier; - } - return result; -} - -BEAMFORMER_IMPORT void -os_barrier_enter(OSBarrier barrier) -{ - w32_synchronization_barrier *b = (w32_synchronization_barrier *)barrier.value[0]; - if (b) EnterSynchronizationBarrier(b, 0); -} +global BeamformerInput beamformer_input_main; BEAMFORMER_IMPORT void os_console_log(u8 *data, i64 length) @@ -224,7 +84,7 @@ os_lookup_symbol(OSLibrary library, const char *symbol) function void * allocate_shared_memory(char *name, i64 requested_capacity, u64 *capacity) { - u64 rounded_capacity = round_up_to(requested_capacity, win32_system_info.page_size); + u64 rounded_capacity = round_up_to(requested_capacity, os_w32_context.system_info.page_size); void *result = 0; iptr h = CreateFileMappingA(-1, 0, PAGE_READWRITE, (rounded_capacity >> 32u), (rounded_capacity & 0xFFFFFFFFul), name); @@ -337,7 +197,7 @@ os_window_create(u8 *title, i64 title_length, i32 width, i32 height) } we->as.window.handle = GetPlatformWindowHandle(); - os_window_equip_common(os_w32_context.input, we->as.window.handle); + os_window_equip_common(&beamformer_input_main, we->as.window.handle); raylib_window_resize = glfwSetWindowSizeCallback(we->as.window.handle, os_window_resize_callback); /* NOTE: do this after initing so that the window starts out floating in tiling wm */ @@ -393,12 +253,12 @@ load_library(char *name, char *temp_name) #if BEAMFORMER_DEBUG function void -debug_library_reload(void *beamformer, BeamformerInput *input) +debug_library_reload(void *beamformer) { local_persist OSLibrary beamformer_library_handle = {OSInvalidHandleValue}; if ValidHandle(beamformer_library_handle) { - beamformer_debug_hot_release(beamformer, input); + beamformer_debug_hot_release(beamformer, &beamformer_input_main); FreeLibrary(beamformer_library_handle.value[0]); beamformer_library_handle = (OSLibrary){OSInvalidHandleValue}; } @@ -413,18 +273,19 @@ debug_library_reload(void *beamformer, BeamformerInput *input) } } #else -#define debug_library_reload(a, b) (void)(a), (void)(b) +#define debug_library_reload(a) (void)(a) #endif /* BEAMFORMER_DEBUG */ function void -load_platform_libraries(BeamformerInput *input) +load_platform_libraries(void) { #if BEAMFORMER_DEBUG - debug_library_reload(0, input); + debug_library_reload(0); os_w32_add_file_watch(str8(OS_DEBUG_LIB_NAME), (void *)BeamformerInputEventKind_ExecutableReload, OSW32FileWatchKind_Platform); #endif + BeamformerInput *input = &beamformer_input_main; input->vulkan_library_handle = (OSLibrary){OSInvalidHandleValue}; #define X(name) \ if InvalidHandle(input->vulkan_library_handle) \ @@ -445,7 +306,7 @@ load_platform_libraries(BeamformerInput *input) } function void -dispatch_file_watch(void *beamformer, BeamformerInput *input, u64 current_time, OSW32FileWatchDirectory *fw_dir, Arena *scratch) +dispatch_file_watch(void *beamformer, u64 current_time, OSW32FileWatchDirectory *fw_dir, Arena *scratch) { i64 offset = 0; w32_file_notify_info *fni = (w32_file_notify_info *)fw_dir->buffer; @@ -468,13 +329,13 @@ dispatch_file_watch(void *beamformer, BeamformerInput *input, u64 current_time, if (fw->kind == OSW32FileWatchKind_Platform) { assert((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload); if ((u64)fw->user_context == BeamformerInputEventKind_ExecutableReload) - debug_library_reload(beamformer, input); + debug_library_reload(beamformer); input_event.kind = (u64)fw->user_context; } else { input_event.kind = BeamformerInputEventKind_FileEvent; input_event.file_watch_user_context = fw->user_context; } - os_push_input_event(input, input_event); + os_push_input_event(&beamformer_input_main, input_event); } fw->update_time = current_time; break; @@ -486,7 +347,7 @@ dispatch_file_watch(void *beamformer, BeamformerInput *input, u64 current_time, } function void -clear_io_queue(void *beamformer, BeamformerInput *input, Arena *scratch) +clear_io_queue(void *beamformer, Arena *scratch) { iptr handle = os_w32_context.io_completion_handle; w32_overlapped *overlapped; @@ -500,7 +361,7 @@ clear_io_queue(void *beamformer, BeamformerInput *input, Arena *scratch) switch (event->tag) { case W32IOEvent_FileWatch:{ OSW32FileWatchDirectory *dir = (OSW32FileWatchDirectory *)event->context; - dispatch_file_watch(beamformer, input, current_time, dir, scratch); + dispatch_file_watch(beamformer, current_time, dir, scratch); zero_struct(&dir->overlapped); ReadDirectoryChangesW(dir->handle, dir->buffer, OSW32_FileWatchDirectoryBufferSize, 0, FILE_NOTIFY_CHANGE_LAST_WRITE, 0, &dir->overlapped, 0); @@ -512,12 +373,9 @@ clear_io_queue(void *beamformer, BeamformerInput *input, Arena *scratch) BASE_IMPORT void entry_point(i32 argc, char *argv[]) { - os_w32_context.arena = arena_create(.name = "Platform Arena"); - os_w32_context.error_handle = GetStdHandle(STD_ERROR_HANDLE); os_w32_context.io_completion_handle = CreateIoCompletionPort(INVALID_FILE, 0, 0, 0); - BeamformerInput *input = push_struct(os_w32_context.arena, BeamformerInput); - os_w32_context.input = input; + BeamformerInput *input = &beamformer_input_main; input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, OS_SHARED_MEMORY_SIZE, &input->shared_memory_size); if (input->shared_memory) { @@ -529,7 +387,7 @@ entry_point(i32 argc, char *argv[]) .kind = BeamformerInputEventKind_ExecutableReload, }); - load_platform_libraries(input); + load_platform_libraries(); void *beamformer = beamformer_init(input); @@ -540,7 +398,7 @@ entry_point(i32 argc, char *argv[]) DeferLoop(take_lock(&os_w32_context.arena_lock, -1), release_lock(&os_w32_context.arena_lock)) DeferLoop(scratch = temp_begin(os_w32_context.arena), temp_end(scratch)) { - clear_io_queue(beamformer, input, scratch.arena); + clear_io_queue(beamformer, scratch.arena); } beamformer_frame_step(beamformer, input); diff --git a/util.c b/util.c @@ -1092,3 +1092,25 @@ number_from_str8(str8 s) } return result; } + +function b32 +take_lock(i32 *lock, i32 timeout_ms) +{ + b32 result = 0; + for (;;) { + i32 current = 0; + if (atomic_cas_u32(lock, &current, 1)) + result = 1; + if (result || !timeout_ms || (!os_wait_on_address(lock, current, (u32)timeout_ms) && timeout_ms != -1)) + break; + } + return result; +} + +function void +release_lock(i32 *lock) +{ + assert(atomic_load_u32(lock)); + atomic_store_u32(lock, 0); + os_wake_all_waiters(lock); +} diff --git a/util_os.c b/util_os.c @@ -1,43 +0,0 @@ -/* See LICENSE for license details. */ - -// NOTE(rnp): functions which require platform layer support but -// otherwise share implementation - -function b32 -take_lock(i32 *lock, i32 timeout_ms) -{ - b32 result = 0; - for (;;) { - i32 current = 0; - if (atomic_cas_u32(lock, &current, 1)) - result = 1; - if (result || !timeout_ms || (!os_wait_on_address(lock, current, (u32)timeout_ms) && timeout_ms != -1)) - break; - } - return result; -} - -function void -release_lock(i32 *lock) -{ - assert(atomic_load_u32(lock)); - atomic_store_u32(lock, 0); - os_wake_all_waiters(lock); -} - -#if BEAMFORMER_RENDERDOC_HOOKS -function void -load_renderdoc_functions(BeamformerInput *input, OSLibrary rdoc) -{ - if ValidHandle(rdoc) { - renderdoc_get_api_fn *get_api = os_lookup_symbol(rdoc, "RENDERDOC_GetAPI"); - if (get_api) { - RenderDocAPI *api = 0; - if (get_api(10600, (void **)&api)) { - input->renderdoc_start_frame_capture = RENDERDOC_START_FRAME_CAPTURE(api); - input->renderdoc_end_frame_capture = RENDERDOC_END_FRAME_CAPTURE(api); - } - } - } -} -#endif diff --git a/util_os_ui.c b/util_os_ui.c @@ -227,3 +227,20 @@ os_build_frame_input(BeamformerInput *input) input->mouse_x = new_mouse.x; input->mouse_y = new_mouse.y; } + +#if BEAMFORMER_RENDERDOC_HOOKS +function void +load_renderdoc_functions(BeamformerInput *input, OSLibrary rdoc) +{ + if ValidHandle(rdoc) { + renderdoc_get_api_fn *get_api = os_lookup_symbol(rdoc, "RENDERDOC_GetAPI"); + if (get_api) { + RenderDocAPI *api = 0; + if (get_api(10600, (void **)&api)) { + input->renderdoc_start_frame_capture = RENDERDOC_START_FRAME_CAPTURE(api); + input->renderdoc_end_frame_capture = RENDERDOC_END_FRAME_CAPTURE(api); + } + } + } +} +#endif