ogl_beamforming

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

Commit: 829bc0d2e17aab601e9d10d03a67dda84807b7c3
Parent: 080cc8333beaad77e1f9cfe6477acbc0efdc2199
Author: Randy Palamar
Date:   Tue, 31 Mar 2026 11:31:45 -0600

core: eliminate remaining places assuming fixed size shared memory

This was old legacy, now the shared memory size is provided by the
platform and cannot be assumed anywhere in the beamformer.

For the library we query its size after we open it, which is
probably what should have been done anyways.

Diffstat:
Mbeamformer.c | 17++++++++++-------
Mbeamformer_core.c | 7++++---
Mbeamformer_internal.h | 10++++++----
Mbeamformer_shared_memory.c | 9++-------
Mlib/ogl_beamformer_lib.c | 69++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mmain_linux.c | 4+++-
Mmain_w32.c | 4+++-
7 files changed, 72 insertions(+), 48 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -323,8 +323,10 @@ beamformer_init(BeamformerInput *input) ctx->compute_shader_stats = push_struct(&memory, ComputeShaderStats); ctx->compute_timing_table = push_struct(&memory, ComputeTimingTable); - ctx->shared_memory = input->shared_memory; - if (!ctx->shared_memory) fatal(s8("Get more ram lol\n")); + ctx->shared_memory = input->shared_memory; + ctx->shared_memory_size = input->shared_memory_size; + if (ctx->shared_memory_size < (i64)sizeof(*ctx->shared_memory)) + fatal(s8("Get more ram lol\n")); zero_struct(ctx->shared_memory); ctx->shared_memory->version = BEAMFORMER_SHARED_MEMORY_VERSION; @@ -366,13 +368,14 @@ beamformer_init(BeamformerInput *input) GLWorkerThreadContext *upload = &ctx->upload_worker; BeamformerUploadThreadContext *upctx = push_struct(&memory, typeof(*upctx)); - upload->user_context = (iptr)upctx; - upctx->rf_buffer = &cs->rf_buffer; - upctx->shared_memory = ctx->shared_memory; + upload->user_context = (iptr)upctx; + upctx->rf_buffer = &cs->rf_buffer; + upctx->shared_memory = ctx->shared_memory; + upctx->shared_memory_size = ctx->shared_memory_size; upctx->compute_timing_table = ctx->compute_timing_table; upctx->compute_worker_sync = &ctx->compute_worker.sync_variable; - upload->window_handle = glfwCreateWindow(1, 1, "", 0, raylib_window_handle); - upload->handle = os_create_thread("[upload]", upload, beamformer_upload_entry_point); + upload->window_handle = glfwCreateWindow(1, 1, "", 0, raylib_window_handle); + upload->handle = os_create_thread("[upload]", upload, beamformer_upload_entry_point); glfwMakeContextCurrent(raylib_window_handle); diff --git a/beamformer_core.c b/beamformer_core.c @@ -1067,7 +1067,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena, iptr gl_c u32 out_size = (u32)dim.x * (u32)dim.y * (u32)dim.z * 2 * sizeof(f32); if (out_size <= ec->size) { glGetTextureImage(texture, 0, GL_RG, GL_FLOAT, (i32)out_size, - beamformer_shared_memory_scratch_arena(sm).beg); + beamformer_shared_memory_scratch_arena(sm, ctx->shared_memory_size).beg); } } }break; @@ -1077,7 +1077,8 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena, iptr gl_c spin_wait(table->write_index != atomic_load_u32(&table->read_index)); ComputeShaderStats *stats = ctx->compute_shader_stats; if (sizeof(stats->table) <= ec->size) - mem_copy(beamformer_shared_memory_scratch_arena(sm).beg, &stats->table, sizeof(stats->table)); + mem_copy(beamformer_shared_memory_scratch_arena(sm, ctx->shared_memory_size).beg, + &stats->table, sizeof(stats->table)); }break; InvalidDefaultCase; } @@ -1342,7 +1343,7 @@ DEBUG_EXPORT BEAMFORMER_RF_UPLOAD_FN(beamformer_rf_upload) } u32 size = bp->channel_count * bp->acquisition_count * bp->sample_count * beamformer_data_kind_byte_size[data_kind]; - u8 *data = beamformer_shared_memory_scratch_arena(sm).beg; + u8 *data = beamformer_shared_memory_scratch_arena(sm, ctx->shared_memory_size).beg; if (nvidia) glNamedBufferSubData(rf->ssbo, slot * rf->active_rf_size, (i32)size, data); else memory_copy_non_temporal(rf->buffer + slot * rf->active_rf_size, data, size); diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -255,10 +255,11 @@ typedef struct { } ComputeTimingTable; typedef struct { - BeamformerRFBuffer * rf_buffer; - BeamformerSharedMemory * shared_memory; - ComputeTimingTable * compute_timing_table; - i32 * compute_worker_sync; + BeamformerRFBuffer *rf_buffer; + BeamformerSharedMemory *shared_memory; + i64 shared_memory_size; + ComputeTimingTable *compute_timing_table; + i32 *compute_worker_sync; } BeamformerUploadThreadContext; struct BeamformerFrame { @@ -327,6 +328,7 @@ typedef struct { ComputeTimingTable *compute_timing_table; BeamformerSharedMemory *shared_memory; + i64 shared_memory_size; BeamformerFrame beamform_frames[BeamformerMaxSavedFrames]; BeamformerFrame *latest_frame; diff --git a/beamformer_shared_memory.c b/beamformer_shared_memory.c @@ -71,11 +71,6 @@ typedef struct { BeamformWork work_items[1 << 6]; } BeamformWorkQueue; -#define BEAMFORMER_SHARED_MEMORY_SIZE (GB(2)) -#define BEAMFORMER_SHARED_MEMORY_MAX_SCRATCH_SIZE (BEAMFORMER_SHARED_MEMORY_SIZE - \ - sizeof(BeamformerSharedMemory) - \ - sizeof(BeamformerParameterBlock)) - #define X(name, id) BeamformerLiveImagingDirtyFlags_##name = (1 << id), typedef enum {BEAMFORMER_LIVE_IMAGING_DIRTY_FLAG_LIST} BeamformerLiveImagingDirtyFlags; #undef X @@ -274,11 +269,11 @@ beamformer_parameter_block_unlock(BeamformerSharedMemory *sm, u32 block) } function Arena -beamformer_shared_memory_scratch_arena(BeamformerSharedMemory *sm) +beamformer_shared_memory_scratch_arena(BeamformerSharedMemory *sm, i64 shared_memory_size) { assert(sm->reserved_parameter_blocks > 0); BeamformerParameterBlock *last = beamformer_parameter_block(sm, sm->reserved_parameter_blocks); - Arena result = {.beg = (u8 *)(last + 1), .end = (u8 *)sm + BEAMFORMER_SHARED_MEMORY_SIZE}; + Arena result = {.beg = (u8 *)(last + 1), .end = (u8 *)sm + shared_memory_size}; result.beg = arena_aligned_start(result, KB(4)); return result; } diff --git a/lib/ogl_beamformer_lib.c b/lib/ogl_beamformer_lib.c @@ -29,31 +29,39 @@ global struct { BeamformerSharedMemory *bp; i32 timeout_ms; BeamformerLibErrorKind last_error; + i64 shared_memory_size; } g_beamformer_library_context; #if OS_LINUX -function void * +function s8 os_open_shared_memory_area(char *name) { - void *result = 0; + s8 result = {0}; i32 fd = shm_open(name, O_RDWR, S_IRUSR|S_IWUSR); if (fd > 0) { - void *new = mmap(0, BEAMFORMER_SHARED_MEMORY_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (new != MAP_FAILED) result = new; + struct stat sb; + if (fstat(fd, &sb) != -1) { + void *new = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (new != MAP_FAILED) { + result.data = new; + result.len = sb.st_size; + } + } close(fd); } return result; } function void -os_close_shared_memory_area(void *memory) +os_close_shared_memory_area(void *memory, i64 size) { - munmap(memory, BEAMFORMER_SHARED_MEMORY_SIZE); + munmap(memory, size); } #elif OS_WINDOWS +W32(b32) GetFileSizeEx(iptr, i64 *); W32(b32) UnmapViewOfFile(void *); function b32 @@ -84,24 +92,29 @@ os_reserve_region_locks(void) return result; } -function void * +function s8 os_open_shared_memory_area(char *name) { + s8 result = {0}; iptr h = OpenFileMappingA(FILE_MAP_ALL_ACCESS, 0, name); - void *result = 0; if (h != INVALID_FILE) { - void *new = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, BEAMFORMER_SHARED_MEMORY_SIZE); - if (new && os_reserve_region_locks()) - result = new; - if (new && !result) - UnmapViewOfFile(new); + i64 size; + if (GetFileSizeEx(h, &size)) { + void *new = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, size); + if (new && os_reserve_region_locks()) { + result.data = new; + result.len = size; + } + if (new && !result.data) + UnmapViewOfFile(new); + } CloseHandle(h); } return result; } function void -os_close_shared_memory_area(void *memory) +os_close_shared_memory_area(void *memory, i64 size) { UnmapViewOfFile(memory); } @@ -123,11 +136,16 @@ check_shared_memory(void) { b32 result = g_beamformer_library_context.bp != 0; if unlikely(!g_beamformer_library_context.bp) { - BeamformerSharedMemory *bp = os_open_shared_memory_area(OS_SHARED_MEMORY_NAME); - if (lib_error_check(bp != 0, SharedMemory)) { + s8 shared_memory = os_open_shared_memory_area(OS_SHARED_MEMORY_NAME); + if (lib_error_check(shared_memory.data != 0, SharedMemory)) { + BeamformerSharedMemory *bp = (BeamformerSharedMemory *)shared_memory.data; result = lib_error_check(bp->version == BEAMFORMER_SHARED_MEMORY_VERSION, VersionMismatch); - if (result) g_beamformer_library_context.bp = bp; - else os_close_shared_memory_area(bp); + if (result) { + g_beamformer_library_context.bp = bp; + g_beamformer_library_context.shared_memory_size = shared_memory.len; + } else { + os_close_shared_memory_area(shared_memory.data, shared_memory.len); + } } } @@ -388,7 +406,8 @@ function b32 beamformer_push_data_base(void *data, u32 data_size, i32 timeout_ms, u32 block) { b32 result = 0; - Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp); + Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp, + g_beamformer_library_context.shared_memory_size); BeamformerParameterBlock *b = beamformer_parameter_block(g_beamformer_library_context.bp, block); BeamformerParameters *bp = &b->parameters; BeamformerDataKind data_kind = b->pipeline.data_kind; @@ -545,7 +564,8 @@ beamformer_export(BeamformerExportContext export, void *out, i32 timeout_ms) if (lib_try_lock(BeamformerSharedMemoryLockKind_ExportSync, timeout_ms)) { if (lib_try_lock(BeamformerSharedMemoryLockKind_ScratchSpace, 0)) { - Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp); + Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp, + g_beamformer_library_context.shared_memory_size); mem_copy(out, scratch.beg, export.size); lib_release_lock(BeamformerSharedMemoryLockKind_ScratchSpace); result = 1; @@ -576,7 +596,8 @@ beamformer_beamform_data(BeamformerSimpleParameters *bp, void *data, uint32_t da iz output_size = output_points.x * output_points.y * output_points.z * (i32)sizeof(f32); if (complex) output_size *= 2; - Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp); + Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp, + g_beamformer_library_context.shared_memory_size); if (out_data) result &= lib_error_check(output_size <= arena_capacity(&scratch, u8), ExportSpaceOverflow); if (result) { @@ -595,12 +616,10 @@ beamformer_beamform_data(BeamformerSimpleParameters *bp, void *data, uint32_t da b32 beamformer_compute_timings(BeamformerComputeStatsTable *output, i32 timeout_ms) { - static_assert(sizeof(*output) <= BEAMFORMER_SHARED_MEMORY_MAX_SCRATCH_SIZE, - "timing table size exceeds scratch space"); - b32 result = 0; if (check_shared_memory()) { - Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp); + Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp, + g_beamformer_library_context.shared_memory_size); if (lib_error_check((iz)sizeof(*output) <= arena_capacity(&scratch, u8), ExportSpaceOverflow)) { BeamformerExportContext export; export.kind = BeamformerExportKind_Stats; diff --git a/main_linux.c b/main_linux.c @@ -13,6 +13,8 @@ #include "beamformer.c" #include "os_linux.c" +#define OS_SHARED_MEMORY_SIZE GB(2) + #define OS_DEBUG_LIB_NAME "./beamformer.so" #define OS_DEBUG_LIB_TEMP_NAME "./beamformer_temp.so" @@ -314,7 +316,7 @@ main(void) BeamformerInput *input = push_struct(&program_memory, BeamformerInput); input->memory = program_memory.beg; input->memory_size = program_memory.end - program_memory.beg; - input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, BEAMFORMER_SHARED_MEMORY_SIZE, + input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, OS_SHARED_MEMORY_SIZE, &input->shared_memory_size); if (input->shared_memory) { input->shared_memory_name = s8(OS_SHARED_MEMORY_NAME).data; diff --git a/main_w32.c b/main_w32.c @@ -45,6 +45,8 @@ W32(b32) InitializeSynchronizationBarrier(w32_synchronization_barrier *, i32, W32(void *) LoadLibraryA(const c8 *); W32(i32) SetThreadDescription(u64, u16 *); +#define OS_SHARED_MEMORY_SIZE GB(2) + #define OS_DEBUG_LIB_NAME ".\\beamformer.dll" #define OS_DEBUG_LIB_TEMP_NAME ".\\beamformer_temp.dll" @@ -396,7 +398,7 @@ main(void) BeamformerInput *input = push_struct(&program_memory, BeamformerInput); input->memory = program_memory.beg; input->memory_size = program_memory.end - program_memory.beg; - input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, BEAMFORMER_SHARED_MEMORY_SIZE, + input->shared_memory = allocate_shared_memory(OS_SHARED_MEMORY_NAME, OS_SHARED_MEMORY_SIZE, &input->shared_memory_size); if (input->shared_memory) { input->shared_memory_name = s8(OS_SHARED_MEMORY_NAME).data;