ogl_beamforming

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

Commit: efe2a5e361719985a9adf0233d8092a8584bea6e
Parent: 9130418de20f2674c3152ae6ef4bafaba43b6a00
Author: Randy Palamar
Date:   Sun, 22 Jun 2025 21:26:41 -0600

core: don't flicker ui when frames are in progress

got a little too zealous and removed the gaurd against this.
instead of going back we can just push a pointer to the last frame
to complete beamforming into context

Diffstat:
Mbeamformer.c | 32+++++++++-----------------------
Mbeamformer.h | 2++
Mintrinsics.c | 4+++-
Mstatic.c | 1+
Mui.c | 2+-
5 files changed, 16 insertions(+), 25 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -160,20 +160,6 @@ push_compute_timing_info(ComputeTimingTable *t, ComputeTimingInfo info) t->buffer[index] = info; } -function BeamformComputeFrame * -beamformer_get_newest_frame(BeamformerCtx *ctx, b32 average_frame) -{ - BeamformComputeFrame *result = 0; - if (average_frame) { - u32 a_index = !(ctx->averaged_frame_index % countof(ctx->averaged_frames)); - result = ctx->averaged_frames + a_index; - } else { - u32 index = (ctx->next_render_frame_index - 1) % countof(ctx->beamform_frames); - result = ctx->beamform_frames + index; - } - return result; -} - function b32 fill_frame_compute_work(BeamformerCtx *ctx, BeamformWork *work, ImagePlaneTag plane) { @@ -526,8 +512,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co if (success && ctx->csctx.raw_data_ssbo) { /* TODO(rnp): this check seems off */ can_commit = 0; - BeamformComputeFrame *frame = beamformer_get_newest_frame(ctx, bp->output_points[3] > 1); - fill_frame_compute_work(ctx, work, frame->image_plane_tag); + fill_frame_compute_work(ctx, work, ctx->latest_frame->image_plane_tag); } }break; case BeamformerWorkKind_ExportBuffer:{ @@ -538,7 +523,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co BeamformerExportContext *ec = &work->export_context; switch (ec->kind) { case BeamformerExportKind_BeamformedData:{ - BeamformComputeFrame *frame = beamformer_get_newest_frame(ctx, bp->output_points[3] > 1); + BeamformComputeFrame *frame = ctx->latest_frame; assert(frame->ready_to_present); u32 texture = frame->frame.texture; uv3 dim = frame->frame.dim; @@ -681,13 +666,16 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co push_compute_timing_info(ctx->compute_timing_table, info); } + frame->ready_to_present = 1; if (did_sum_shader) { u32 aframe_index = (ctx->averaged_frame_index % countof(ctx->averaged_frames)); ctx->averaged_frames[aframe_index].image_plane_tag = frame->image_plane_tag; ctx->averaged_frames[aframe_index].ready_to_present = 1; atomic_add_u32(&ctx->averaged_frame_index, 1); + atomic_store_u64((u64 *)&ctx->latest_frame, (u64)(ctx->averaged_frames + aframe_index)); + } else { + atomic_store_u64((u64 *)&ctx->latest_frame, (u64)frame); } - frame->ready_to_present = 1; cs->processing_compute = 0; push_compute_timing_info(ctx->compute_timing_table, @@ -823,12 +811,10 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step) } BeamformerSharedMemory *sm = ctx->shared_memory.region; - BeamformerParameters *bp = &sm->parameters; - b32 averaging = bp->output_points[3] > 1; if (sm->locks[BeamformerSharedMemoryLockKind_DispatchCompute] && ctx->os.compute_worker.asleep) { if (sm->start_compute_from_main) { BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); - ImagePlaneTag tag = beamformer_get_newest_frame(ctx, averaging)->image_plane_tag; + ImagePlaneTag tag = ctx->latest_frame->image_plane_tag; if (fill_frame_compute_work(ctx, work, tag)) beamform_work_queue_push_commit(ctx->beamform_work_queue); atomic_store_u32(&sm->start_compute_from_main, 0); @@ -836,8 +822,8 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step) ctx->os.wake_waiters(&ctx->os.compute_worker.sync_variable); } - BeamformComputeFrame *frame = beamformer_get_newest_frame(ctx, averaging); - draw_ui(ctx, input, frame->ready_to_present? &frame->frame : 0, frame->image_plane_tag); + draw_ui(ctx, input, ctx->latest_frame->ready_to_present ? &ctx->latest_frame->frame : 0, + ctx->latest_frame->image_plane_tag); ctx->frame_view_render_context.updated = 0; diff --git a/beamformer.h b/beamformer.h @@ -197,7 +197,9 @@ typedef struct { b32 ui_read_params; BeamformComputeFrame beamform_frames[MAX_BEAMFORMED_SAVED_FRAMES]; + BeamformComputeFrame *latest_frame; u32 next_render_frame_index; + u32 display_frame_index; /* NOTE: this will only be used when we are averaging */ u32 averaged_frame_index; diff --git a/intrinsics.c b/intrinsics.c @@ -26,6 +26,7 @@ #define debugbreak() __debugbreak() #define unreachable() __assume(0) + #define atomic_store_u64(ptr, n) *((volatile u64 *)(ptr)) = (n) #define atomic_store_u32(ptr, n) *((volatile u32 *)(ptr)) = (n) #define atomic_load_u64(ptr) *((volatile u64 *)(ptr)) #define atomic_load_u32(ptr) *((volatile u32 *)(ptr)) @@ -54,7 +55,7 @@ #endif #define unreachable() __builtin_unreachable() - #define atomic_store_u32(ptr, n) __atomic_store_n(ptr, n, __ATOMIC_RELEASE) + #define atomic_store_u64(ptr, n) __atomic_store_n(ptr, n, __ATOMIC_RELEASE) #define atomic_load_u64(ptr) __atomic_load_n(ptr, __ATOMIC_ACQUIRE) #define atomic_add_u64(ptr, n) __atomic_fetch_add(ptr, n, __ATOMIC_ACQ_REL) #define atomic_and_u64(ptr, n) __atomic_and_fetch(ptr, n, __ATOMIC_RELEASE) @@ -64,6 +65,7 @@ #define atomic_and_u32 atomic_and_u64 #define atomic_cas_u32 atomic_cas_u64 #define atomic_load_u32 atomic_load_u64 + #define atomic_store_u32 atomic_store_u64 #define atan2_f32(y, x) __builtin_atan2f(y, x) #define ceil_f32(a) __builtin_ceilf(a) diff --git a/static.c b/static.c @@ -277,6 +277,7 @@ setup_beamformer(BeamformerCtx *ctx, BeamformerInput *input, Arena *memory) glfwMakeContextCurrent(raylib_window_handle); + ctx->latest_frame = ctx->beamform_frames; ctx->beamform_work_queue = push_struct(memory, BeamformWorkQueue); ctx->compute_shader_stats = push_struct(memory, ComputeShaderStats); ctx->compute_timing_table = push_struct(memory, ComputeTimingTable); diff --git a/ui.c b/ui.c @@ -3019,7 +3019,7 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformFrame *frame_to_draw b32 dispatch = ctx->os.shared_memory_region_lock(&ctx->shared_memory, sm->locks, BeamformerSharedMemoryLockKind_DispatchCompute, 0); - sm->start_compute_from_main |= dispatch & beamformer_get_newest_frame(ctx, 0)->ready_to_present; + sm->start_compute_from_main |= dispatch & ctx->latest_frame->ready_to_present; ctx->os.shared_memory_region_unlock(&ctx->shared_memory, sm->locks, lock); } }