ogl_beamforming

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

Commit: 91ee977d233f5d7d8323b1dc7ac4be6cb6abbe83
Parent: f36c234cb479149684a81c52f870cf7b80b1d440
Author: Randy Palamar
Date:   Sat, 26 Jul 2025 20:02:08 -0600

lib: move global variables into a single global context

Also fix a pipeline validation mistake that was spotted while
switching this.

Diffstat:
Mhelpers/ogl_beamformer_lib.c | 142++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 79 insertions(+), 63 deletions(-)

diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c @@ -18,10 +18,12 @@ W32(iptr) OpenFileMappingA(u32, b32, c8 *); #include "../beamformer_work_queue.c" -global int32_t g_timeout_ms; -global SharedMemoryRegion g_shared_memory; -global BeamformerSharedMemory *g_bp; -global BeamformerLibErrorKind g_lib_last_error; +global struct { + SharedMemoryRegion shared_memory; + BeamformerSharedMemory *bp; + i32 timeout_ms; + BeamformerLibErrorKind last_error; +} g_beamformer_library_context; #if OS_LINUX @@ -77,46 +79,49 @@ function b32 check_shared_memory(void) { b32 result = 1; - if (!g_shared_memory.region) { - g_shared_memory = os_open_shared_memory_area(OS_SHARED_MEMORY_NAME); - if (!g_shared_memory.region) { - g_lib_last_error = BF_LIB_ERR_KIND_SHARED_MEMORY; + if (!g_beamformer_library_context.shared_memory.region) { + g_beamformer_library_context.shared_memory = os_open_shared_memory_area(OS_SHARED_MEMORY_NAME); + if (!g_beamformer_library_context.shared_memory.region) { + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_SHARED_MEMORY; result = 0; - } else if (((BeamformerSharedMemory *)g_shared_memory.region)->version != + } else if (((BeamformerSharedMemory *)g_beamformer_library_context.shared_memory.region)->version != BEAMFORMER_SHARED_MEMORY_VERSION) { - g_lib_last_error = BF_LIB_ERR_KIND_VERSION_MISMATCH; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_VERSION_MISMATCH; result = 0; } } - if (result && ((BeamformerSharedMemory *)g_shared_memory.region)->invalid) { - g_lib_last_error = BF_LIB_ERR_KIND_INVALID_ACCESS; + if (result && ((BeamformerSharedMemory *)g_beamformer_library_context.shared_memory.region)->invalid) { + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_INVALID_ACCESS; result = 0; } - if (result) g_bp = g_shared_memory.region; + if (result) g_beamformer_library_context.bp = g_beamformer_library_context.shared_memory.region; return result; } function BeamformWork * try_push_work_queue(void) { - BeamformWork *result = beamform_work_queue_push(&g_bp->external_work_queue); - if (!result) g_lib_last_error = BF_LIB_ERR_KIND_WORK_QUEUE_FULL; + BeamformWork *result = beamform_work_queue_push(&g_beamformer_library_context.bp->external_work_queue); + if (!result) g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_WORK_QUEUE_FULL; return result; } function b32 lib_try_lock(BeamformerSharedMemoryLockKind lock, i32 timeout_ms) { - b32 result = os_shared_memory_region_lock(&g_shared_memory, g_bp->locks, (i32)lock, (u32)timeout_ms); - if (!result) g_lib_last_error = BF_LIB_ERR_KIND_SYNC_VARIABLE; + b32 result = os_shared_memory_region_lock(&g_beamformer_library_context.shared_memory, + g_beamformer_library_context.bp->locks, + (i32)lock, (u32)timeout_ms); + if (!result) g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_SYNC_VARIABLE; return result; } function void lib_release_lock(BeamformerSharedMemoryLockKind lock) { - os_shared_memory_region_unlock(&g_shared_memory, g_bp->locks, (i32)lock); + os_shared_memory_region_unlock(&g_beamformer_library_context.shared_memory, + g_beamformer_library_context.bp->locks, (i32)lock); } u32 @@ -137,7 +142,7 @@ beamformer_error_string(BeamformerLibErrorKind kind) BeamformerLibErrorKind beamformer_get_last_error(void) { - return g_lib_last_error; + return g_beamformer_library_context.last_error; } const char * @@ -149,23 +154,25 @@ beamformer_get_last_error_string(void) function b32 validate_pipeline(i32 *shaders, i32 shader_count, BeamformerDataKind data_kind) { - b32 result = shader_count <= countof(g_bp->shaders); + b32 result = shader_count <= countof(g_beamformer_library_context.bp->shaders); if (result) { for (i32 i = 0; i < shader_count; i++) result &= BETWEEN(shaders[i], 0, BeamformerShaderKind_ComputeCount); if (!result) { - g_lib_last_error = BF_LIB_ERR_KIND_INVALID_COMPUTE_STAGE; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_INVALID_COMPUTE_STAGE; } else if (shaders[0] != BeamformerShaderKind_Demodulate && shaders[0] != BeamformerShaderKind_Decode) { - result = BF_LIB_ERR_KIND_INVALID_START_SHADER; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_INVALID_START_SHADER; + result = 0; } else if (shaders[0] == BeamformerShaderKind_Demodulate && !(data_kind == BeamformerDataKind_Int16 || data_kind == BeamformerDataKind_Float32)) { - result = BF_LIB_ERR_KIND_INVALID_DEMOD_DATA_KIND; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_INVALID_DEMOD_DATA_KIND; + result = 0; } } else { - g_lib_last_error = BF_LIB_ERR_KIND_COMPUTE_STAGE_OVERFLOW; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_COMPUTE_STAGE_OVERFLOW; } return result; } @@ -175,10 +182,12 @@ beamformer_set_pipeline_stage_parameters(i32 stage_index, i32 parameter) { b32 result = 0; BeamformerSharedMemoryLockKind lock = BeamformerSharedMemoryLockKind_ComputePipeline; - if (check_shared_memory() && g_bp->shader_count != 0 && lib_try_lock(lock, g_timeout_ms)) { - stage_index %= (i32)g_bp->shader_count; - g_bp->shader_parameters[stage_index].filter_slot = (u8)parameter; - atomic_or_u32(&g_bp->dirty_regions, 1 << (lock - 1)); + if (check_shared_memory() && g_beamformer_library_context.bp->shader_count != 0 && + lib_try_lock(lock, g_beamformer_library_context.timeout_ms)) + { + stage_index %= (i32)g_beamformer_library_context.bp->shader_count; + g_beamformer_library_context.bp->shader_parameters[stage_index].filter_slot = (u8)parameter; + atomic_or_u32(&g_beamformer_library_context.bp->dirty_regions, 1 << (lock - 1)); lib_release_lock(lock); } return result; @@ -190,12 +199,12 @@ beamformer_push_pipeline(i32 *shaders, i32 shader_count, BeamformerDataKind data b32 result = 0; if (validate_pipeline(shaders, shader_count, data_kind) && check_shared_memory()) { BeamformerSharedMemoryLockKind lock = BeamformerSharedMemoryLockKind_ComputePipeline; - if (lib_try_lock(lock, g_timeout_ms)) { - g_bp->shader_count = shader_count; - g_bp->data_kind = data_kind; + if (lib_try_lock(lock, g_beamformer_library_context.timeout_ms)) { + g_beamformer_library_context.bp->shader_count = shader_count; + g_beamformer_library_context.bp->data_kind = data_kind; for (i32 i = 0; i < shader_count; i++) - g_bp->shaders[i] = (BeamformerShaderKind)shaders[i]; - atomic_or_u32(&g_bp->dirty_regions, 1 << (lock - 1)); + g_beamformer_library_context.bp->shaders[i] = (BeamformerShaderKind)shaders[i]; + atomic_or_u32(&g_beamformer_library_context.bp->dirty_regions, 1 << (lock - 1)); lib_release_lock(lock); result = 1; } @@ -218,7 +227,7 @@ beamformer_create_kaiser_low_pass_filter(f32 beta, f32 cutoff_frequency, i16 len ctx->beta = beta; ctx->length = length; ctx->slot = slot % BEAMFORMER_FILTER_SLOTS; - beamform_work_queue_push_commit(&g_bp->external_work_queue); + beamform_work_queue_push_commit(&g_beamformer_library_context.bp->external_work_queue); } } return result; @@ -249,9 +258,10 @@ locked_region_upload(void *region, void *data, u32 size, BeamformerSharedMemoryL { b32 result = lib_try_lock(lock, timeout_ms); if (result) { - if (dirty) *dirty = atomic_load_u32(&g_bp->dirty_regions) & (1 << (lock - 1)); + if (dirty) + *dirty = atomic_load_u32(&g_beamformer_library_context.bp->dirty_regions) & (1 << (lock - 1)); mem_copy(region, data, size); - atomic_or_u32(&g_bp->dirty_regions, (1 << (lock - 1))); + atomic_or_u32(&g_beamformer_library_context.bp->dirty_regions, (1 << (lock - 1))); lib_release_lock(lock); } return result; @@ -265,14 +275,15 @@ beamformer_upload_buffer(void *data, u32 size, i32 store_offset, BeamformerUploa if (check_shared_memory()) { BeamformWork *work = try_push_work_queue(); b32 dirty = 0; - result = work && locked_region_upload((u8 *)g_bp + store_offset, data, size, lock, &dirty, timeout_ms); + result = work && locked_region_upload((u8 *)g_beamformer_library_context.bp + store_offset, + data, size, lock, &dirty, timeout_ms); if (result && !dirty) { work->upload_context.shared_memory_offset = store_offset; work->upload_context.kind = kind; work->upload_context.size = size; work->kind = BeamformerWorkKind_UploadBuffer; work->lock = lock; - beamform_work_queue_push_commit(&g_bp->external_work_queue); + beamform_work_queue_push_commit(&g_beamformer_library_context.bp->external_work_queue); } } return result; @@ -286,13 +297,14 @@ beamformer_upload_buffer(void *data, u32 size, i32 store_offset, BeamformerUploa #define X(name, dtype, elements, lock_name) \ b32 beamformer_push_##name (dtype *data, u32 count) { \ b32 result = 0; \ - if (count <= countof(g_bp->name)) { \ + if (count <= countof(g_beamformer_library_context.bp->name)) { \ result = beamformer_upload_buffer(data, count * elements * sizeof(dtype), \ offsetof(BeamformerSharedMemory, name), \ BeamformerUploadKind_##lock_name, \ - BeamformerSharedMemoryLockKind_##lock_name, g_timeout_ms); \ + BeamformerSharedMemoryLockKind_##lock_name, \ + g_beamformer_library_context.timeout_ms); \ } else { \ - g_lib_last_error = BF_LIB_ERR_KIND_BUFFER_OVERFLOW; \ + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_BUFFER_OVERFLOW; \ } \ return result; \ } @@ -307,9 +319,10 @@ beamformer_push_data_base(void *data, u32 data_size, i32 timeout_ms, b32 start_f result = beamformer_upload_buffer(data, data_size, BEAMFORMER_SCRATCH_OFF, BeamformerUploadKind_RFData, BeamformerSharedMemoryLockKind_ScratchSpace, timeout_ms); - if (result && start_from_main) atomic_store_u32(&g_bp->start_compute_from_main, 1); + if (result && start_from_main) + atomic_store_u32(&g_beamformer_library_context.bp->start_compute_from_main, 1); } else { - g_lib_last_error = BF_LIB_ERR_KIND_BUFFER_OVERFLOW; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_BUFFER_OVERFLOW; } return result; } @@ -317,13 +330,13 @@ beamformer_push_data_base(void *data, u32 data_size, i32 timeout_ms, b32 start_f b32 beamformer_push_data(void *data, u32 data_size) { - return beamformer_push_data_base(data, data_size, g_timeout_ms, 1); + return beamformer_push_data_base(data, data_size, g_beamformer_library_context.timeout_ms, 1); } b32 beamformer_push_data_with_compute(void *data, u32 data_size, u32 image_plane_tag) { - b32 result = beamformer_push_data_base(data, data_size, g_timeout_ms, 0); + b32 result = beamformer_push_data_base(data, data_size, g_beamformer_library_context.timeout_ms, 0); if (result) { result = image_plane_tag < BeamformerViewPlaneTag_Count; if (result) { @@ -331,11 +344,11 @@ beamformer_push_data_with_compute(void *data, u32 data_size, u32 image_plane_tag if (work) { work->kind = BeamformerWorkKind_ComputeIndirect; work->compute_indirect_plane = image_plane_tag; - beamform_work_queue_push_commit(&g_bp->external_work_queue); + beamform_work_queue_push_commit(&g_beamformer_library_context.bp->external_work_queue); result = beamformer_start_compute(0); } } else { - g_lib_last_error = BF_LIB_ERR_KIND_INVALID_IMAGE_PLANE; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_INVALID_IMAGE_PLANE; } } return result; @@ -344,27 +357,30 @@ beamformer_push_data_with_compute(void *data, u32 data_size, u32 image_plane_tag b32 beamformer_push_parameters(BeamformerParameters *bp) { - b32 result = locked_region_upload((u8 *)g_bp + offsetof(BeamformerSharedMemory, parameters), + b32 result = locked_region_upload((u8 *)g_beamformer_library_context.bp + + offsetof(BeamformerSharedMemory, parameters), bp, sizeof(*bp), BeamformerSharedMemoryLockKind_Parameters, - 0, g_timeout_ms); + 0, g_beamformer_library_context.timeout_ms); return result; } b32 beamformer_push_parameters_ui(BeamformerUIParameters *bp) { - b32 result = locked_region_upload((u8 *)g_bp + offsetof(BeamformerSharedMemory, parameters_ui), + b32 result = locked_region_upload((u8 *)g_beamformer_library_context.bp + + offsetof(BeamformerSharedMemory, parameters_ui), bp, sizeof(*bp), BeamformerSharedMemoryLockKind_Parameters, - 0, g_timeout_ms); + 0, g_beamformer_library_context.timeout_ms); return result; } b32 beamformer_push_parameters_head(BeamformerParametersHead *bp) { - b32 result = locked_region_upload((u8 *)g_bp + offsetof(BeamformerSharedMemory, parameters_head), + b32 result = locked_region_upload((u8 *)g_beamformer_library_context.bp + + offsetof(BeamformerSharedMemory, parameters_head), bp, sizeof(*bp), BeamformerSharedMemoryLockKind_Parameters, - 0, g_timeout_ms); + 0, g_beamformer_library_context.timeout_ms); return result; } @@ -377,7 +393,7 @@ beamformer_export_buffer(BeamformerExportContext export_context) work->export_context = export_context; work->kind = BeamformerWorkKind_ExportBuffer; work->lock = BeamformerSharedMemoryLockKind_ScratchSpace; - beamform_work_queue_push_commit(&g_bp->external_work_queue); + beamform_work_queue_push_commit(&g_beamformer_library_context.bp->external_work_queue); } return result; } @@ -389,7 +405,7 @@ beamformer_read_output(void *out, uz size, i32 timeout_ms) if (lib_try_lock(BeamformerSharedMemoryLockKind_ExportSync, timeout_ms)) { lib_release_lock(BeamformerSharedMemoryLockKind_ExportSync); if (lib_try_lock(BeamformerSharedMemoryLockKind_ScratchSpace, 0)) { - mem_copy(out, (u8 *)g_bp + BEAMFORMER_SCRATCH_OFF, size); + mem_copy(out, (u8 *)g_beamformer_library_context.bp + BEAMFORMER_SCRATCH_OFF, size); lib_release_lock(BeamformerSharedMemoryLockKind_ScratchSpace); result = 1; } @@ -406,9 +422,9 @@ beamform_data_synchronized(void *data, u32 data_size, i32 output_points[3], f32 output_points[1] = MAX(1, output_points[1]); output_points[2] = MAX(1, output_points[2]); - g_bp->parameters.output_points[0] = output_points[0]; - g_bp->parameters.output_points[1] = output_points[1]; - g_bp->parameters.output_points[2] = output_points[2]; + g_beamformer_library_context.bp->parameters.output_points[0] = output_points[0]; + g_beamformer_library_context.bp->parameters.output_points[1] = output_points[1]; + g_beamformer_library_context.bp->parameters.output_points[2] = output_points[2]; uz output_size = (u32)output_points[0] * (u32)output_points[1] * (u32)output_points[2] * sizeof(f32) * 2; if (output_size <= BEAMFORMER_SCRATCH_SIZE && beamformer_push_data_with_compute(data, data_size, 0)) @@ -425,7 +441,7 @@ beamform_data_synchronized(void *data, u32 data_size, i32 output_points[3], f32 result = beamformer_read_output(out_data, output_size, timeout_ms); } } else { - g_lib_last_error = BF_LIB_ERR_KIND_EXPORT_SPACE_OVERFLOW; + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_EXPORT_SPACE_OVERFLOW; } } return result; @@ -451,9 +467,9 @@ beamformer_live_parameters_get_dirty_flag(void) { i32 result = -1; if (check_shared_memory()) { - u32 flag = ctz_u32(g_bp->live_imaging_dirty_flags); + u32 flag = ctz_u32(g_beamformer_library_context.bp->live_imaging_dirty_flags); if (flag != 32) { - atomic_and_u32(&g_bp->live_imaging_dirty_flags, ~(1 << flag)); + atomic_and_u32(&g_beamformer_library_context.bp->live_imaging_dirty_flags, ~(1 << flag)); result = (i32)flag; } } @@ -464,7 +480,7 @@ BeamformerLiveImagingParameters * beamformer_get_live_parameters(void) { BeamformerLiveImagingParameters *result = 0; - if (check_shared_memory()) result = &g_bp->live_imaging_parameters; + if (check_shared_memory()) result = &g_beamformer_library_context.bp->live_imaging_parameters; return result; } @@ -473,7 +489,7 @@ beamformer_set_live_parameters(BeamformerLiveImagingParameters *new) { b32 result = 0; if (check_shared_memory()) { - mem_copy(&g_bp->live_imaging_parameters, new, sizeof(*new)); + mem_copy(&g_beamformer_library_context.bp->live_imaging_parameters, new, sizeof(*new)); memory_write_barrier(); result = 1; }