ogl_beamforming

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

Commit: e5608036a5a39af2f5d24a7a3f8e9b3b0b8849f4
Parent: ba86ef9b9376f4680770a8c180235265ec1ff959
Author: Randy Palamar
Date:   Sun,  6 Apr 2025 21:21:02 -0600

core/lib: add start_compute command with image plane tag

Diffstat:
Mbeamformer.c | 23+++++++++++++++--------
Mbeamformer.h | 1+
Mbeamformer_parameters.h | 14++++++++++++++
Mbeamformer_work_queue.h | 4+++-
Mhelpers/ogl_beamformer_lib.c | 19+++++++++++++++++--
Mhelpers/ogl_beamformer_lib.h | 3++-
Mui.c | 8+++++---
7 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -178,7 +178,7 @@ alloc_shader_storage(BeamformerCtx *ctx, Arena a) } static b32 -fill_frame_compute_work(BeamformerCtx *ctx, BeamformWork *work) +fill_frame_compute_work(BeamformerCtx *ctx, BeamformWork *work, ImagePlaneTag plane) { b32 result = 0; if (work) { @@ -189,6 +189,7 @@ fill_frame_compute_work(BeamformerCtx *ctx, BeamformWork *work) work->frame = ctx->beamform_frames + frame_index; work->frame->ready_to_present = 0; work->frame->frame.id = frame_id; + work->frame->image_plane_tag = plane; } return result; } @@ -572,9 +573,11 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co } if (success) { + /* TODO(rnp): this check seems off */ if (ctx->csctx.raw_data_ssbo) { can_commit = 0; - fill_frame_compute_work(ctx, work); + ImagePlaneTag plane = ctx->beamform_frames[ctx->display_frame_index].image_plane_tag; + fill_frame_compute_work(ctx, work, plane); } /* TODO(rnp): remove this */ @@ -704,6 +707,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co if (did_sum_shader) { u32 aframe_index = (ctx->averaged_frame_index % ARRAY_COUNT(ctx->averaged_frames)); + ctx->averaged_frames[aframe_index].image_plane_tag = frame->image_plane_tag; ctx->averaged_frames[aframe_index].ready_to_present = 1; /* TODO(rnp): not really sure what to do here */ mem_copy(&ctx->averaged_frames[aframe_index].stats.times, @@ -763,11 +767,12 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step) } BeamformerParameters *bp = &ctx->shared_memory->parameters; - if (ctx->shared_memory->start_compute) { - ctx->shared_memory->start_compute = 0; + if (ctx->shared_memory->dispatch_compute_sync) { + ImagePlaneTag current_plane = ctx->shared_memory->current_image_plane; + atomic_store(&ctx->shared_memory->dispatch_compute_sync, 0); BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); if (work) { - if (fill_frame_compute_work(ctx, work)) + if (fill_frame_compute_work(ctx, work, current_plane)) beamform_work_queue_push_commit(ctx->beamform_work_queue); if (ctx->shared_memory->export_next_frame) { @@ -796,8 +801,9 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step) if (ctx->start_compute) { if (ctx->beamform_frames[ctx->display_frame_index].ready_to_present) { - BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); - if (fill_frame_compute_work(ctx, work)) { + BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); + ImagePlaneTag plane = ctx->beamform_frames[ctx->display_frame_index].image_plane_tag; + if (fill_frame_compute_work(ctx, work, plane)) { beamform_work_queue_push_commit(ctx->beamform_work_queue); ctx->os.wake_waiters(&ctx->os.compute_worker.sync_variable); ctx->start_compute = 0; @@ -827,7 +833,8 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step) frame_to_draw = ctx->beamform_frames + ctx->display_frame_index; } - draw_ui(ctx, input, frame_to_draw->ready_to_present? &frame_to_draw->frame : 0, &frame_to_draw->stats); + draw_ui(ctx, input, frame_to_draw->ready_to_present? &frame_to_draw->frame : 0, + frame_to_draw->image_plane_tag, &frame_to_draw->stats); ctx->fsctx.updated = 0; diff --git a/beamformer.h b/beamformer.h @@ -137,6 +137,7 @@ typedef struct BeamformFrame { struct BeamformComputeFrame { BeamformFrame frame; ComputeShaderStats stats; + ImagePlaneTag image_plane_tag; b32 in_flight; b32 ready_to_present; }; diff --git a/beamformer_parameters.h b/beamformer_parameters.h @@ -24,6 +24,20 @@ typedef enum { X(NONE, 0, "None") \ X(HADAMARD, 1, "Hadamard") +/* X(type, id, pretty name) */ +#define IMAGE_PLANE_TAGS \ + X(XZ, 0, "XZ Plane") \ + X(YZ, 1, "YZ Plane") \ + X(XY, 2, "XY Plane") \ + X(ARBITRARY, 3, "Arbitrary Plane") + +typedef enum { + #define X(type, id, pretty) IPT_ ##type = id, + IMAGE_PLANE_TAGS + #undef X + IPT_LAST +} ImagePlaneTag; + /* X(type, id, pretty name, fixed transmits) */ #define DAS_TYPES \ X(FORCES, 0, "FORCES", 1) \ diff --git a/beamformer_work_queue.h b/beamformer_work_queue.h @@ -65,8 +65,10 @@ typedef struct { i32 raw_data_sync; u32 raw_data_size; + i32 dispatch_compute_sync; + ImagePlaneTag current_image_plane; + /* TODO(rnp): these shouldn't be needed */ - b32 start_compute; b32 export_next_frame; i32 parameters_sync; diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c @@ -250,6 +250,20 @@ set_beamformer_pipeline(char *shm_name, i32 *stages, i32 stages_count) return 1; } +b32 +beamformer_start_compute(char *shm_name, u32 image_plane_tag) +{ + b32 result = image_plane_tag < IPT_LAST && check_shared_memory(shm_name); + if (result) { + result = !atomic_load(&g_bp->dispatch_compute_sync); + if (result) { + g_bp->current_image_plane = image_plane_tag; + atomic_store(&g_bp->dispatch_compute_sync, 1); + } + } + return result; +} + #define BEAMFORMER_UPLOAD_FNS \ X(channel_mapping, i16, CHANNEL_MAPPING) \ X(sparse_elements, i16, SPARSE_ELEMENTS) \ @@ -315,7 +329,7 @@ send_data(char *pipe_name, char *shm_name, void *data, u32 data_size) if (work) { i32 current = atomic_load(&g_bp->raw_data_sync); if (current) { - atomic_inc(&g_bp->raw_data_sync, -current); + atomic_swap(&g_bp->raw_data_sync, 0); work->type = BW_UPLOAD_RF_DATA; work->completion_barrier = offsetof(BeamformerSharedMemory, raw_data_sync); mem_copy((u8 *)g_bp + BEAMFORMER_RF_DATA_OFF, data, data_size); @@ -323,7 +337,8 @@ send_data(char *pipe_name, char *shm_name, void *data, u32 data_size) beamform_work_queue_push_commit(&g_bp->external_work_queue); - g_bp->start_compute = 1; + beamformer_start_compute(shm_name, 0); + /* TODO(rnp): set timeout on acquiring the lock instead of this */ os_wait_on_value(&g_bp->raw_data_sync, 0, -1); } else { diff --git a/helpers/ogl_beamformer_lib.h b/helpers/ogl_beamformer_lib.h @@ -31,8 +31,9 @@ LIB_FN b32 send_data(char *pipe_name, char *shm_name, void *data, u32 data_size) LIB_FN b32 beamform_data_synchronized(char *pipe_name, char *shm_name, void *data, u32 data_size, uv4 output_points, f32 *out_data, i32 timeout_ms); -/* NOTE: these functions only queue an upload; you must flush (for now via one of the data functions) */ +LIB_FN b32 beamformer_start_compute(char *shm_name, u32 image_plane_tag); +/* NOTE: these functions only queue an upload; you must flush (data functions or start_compute) */ LIB_FN b32 beamformer_push_channel_mapping(char *shm_name, i16 *mapping, u32 count, i32 timeout_ms); LIB_FN b32 beamformer_push_sparse_elements(char *shm_name, i16 *elements, u32 count, i32 timeout_ms); LIB_FN b32 beamformer_push_focal_vectors(char *shm_name, f32 *vectors, u32 count, i32 timeout_ms); diff --git a/ui.c b/ui.c @@ -300,6 +300,7 @@ struct BeamformerUI { u32 ruler_state; BeamformFrame *latest_frame; + BeamformFrame *latest_plane[IPT_LAST]; ComputeShaderStats *latest_compute_stats; BeamformerUIParameters params; @@ -2370,13 +2371,14 @@ validate_ui_parameters(BeamformerUIParameters *p) } static void -draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformFrame *frame_to_draw, +draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformFrame *frame_to_draw, ImagePlaneTag frame_plane, ComputeShaderStats *latest_compute_stats) { BeamformerUI *ui = ctx->ui; - ui->latest_frame = frame_to_draw; - ui->latest_compute_stats = latest_compute_stats; + ui->latest_frame = frame_to_draw; + ui->latest_plane[frame_plane] = frame_to_draw; + ui->latest_compute_stats = latest_compute_stats; /* TODO(rnp): there should be a better way of detecting this */ if (ctx->ui_read_params) {