ogl_beamforming

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

Commit: 65a33a6c5d05a3ea4b5b4df1fc9e3e651d9df3a1
Parent: 446eebd60d359c0a748ea69dbdd82ab67d1c4fb4
Author: Randy Palamar
Date:   Sat, 27 Sep 2025 15:17:20 -0600

core: reload only needed shader on file update

since the shaders are JIT compiled we need to do some extra work
to make sure the shader program is replaced in all active blocks
without wasting time remaking the entire pipeline

Diffstat:
Mbeamformer.c | 13++++++++++---
Mbeamformer_shared_memory.c | 1+
Mstatic.c | 17++++++++++++++---
3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -4,7 +4,8 @@ * - the check for first pass reshaping is the last non constant check * in the shader * - this will also remove the need for the channel mapping in the decode shader - * [ ]: refactor: fancier hot reloading for JIT shaders + * [ ]: refactor: ui: reload only shader which is affected by the interaction + * [x]: refactor: fancier hot reloading for JIT shaders * - loop over all active blocks - loop over shader sets per block * - when match found reload it @@ -1112,8 +1113,14 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena, iptr gl_c switch (work->kind) { case BeamformerWorkKind_ReloadShader:{ u32 reserved_blocks = sm->reserved_parameter_blocks; - for (u32 i = 0; i < reserved_blocks; i++) - mark_parameter_block_region_dirty(sm, i, BeamformerParameterBlockRegion_ComputePipeline); + for (u32 block = 0; block < reserved_blocks; block++) { + BeamformerComputePlan *cp = beamformer_compute_plan_for_block(cs, block, arena); + for (u32 slot = 0; slot < cp->pipeline.shader_count; slot++) { + i32 shader_index = beamformer_shader_reloadable_index_by_shader[cp->pipeline.shaders[slot]]; + if (beamformer_reloadable_shader_kinds[shader_index] == work->reload_shader) + load_compute_shader(ctx, cp, slot, *arena); + } + } if (ctx->latest_frame && !sm->live_imaging_parameters.active) { fill_frame_compute_work(ctx, work, ctx->latest_frame->view_plane_tag, 0, 0); diff --git a/beamformer_shared_memory.c b/beamformer_shared_memory.c @@ -73,6 +73,7 @@ typedef struct { BeamformerComputeIndirectWorkContext compute_indirect_context; BeamformerCreateFilterContext create_filter_context; BeamformerExportContext export_context; + BeamformerShaderKind reload_shader; }; } BeamformWork; diff --git a/static.c b/static.c @@ -175,12 +175,19 @@ function FILE_WATCH_CALLBACK_FN(reload_shader) return beamformer_reload_shader(os, path, ctx, arena, beamformer_shader_names[kind]); } +typedef struct { + BeamformerCtx *beamformer; + BeamformerShaderKind shader; +} BeamformerShaderReloadIndirectContext; + function FILE_WATCH_CALLBACK_FN(reload_shader_indirect) { - BeamformerCtx *ctx = (BeamformerCtx *)user_data; + BeamformerShaderReloadIndirectContext *rsi = (typeof(rsi))user_data; + BeamformerCtx *ctx = rsi->beamformer; BeamformWork *work = beamform_work_queue_push(ctx->beamform_work_queue); if (work) { work->kind = BeamformerWorkKind_ReloadShader, + work->reload_shader = rsi->shader; beamform_work_queue_push_commit(ctx->beamform_work_queue); os_wake_waiters(&os->compute_worker.sync_variable); } @@ -418,8 +425,12 @@ setup_beamformer(Arena *memory, BeamformerCtx **o_ctx, BeamformerInput **o_input Arena temp = scratch; s8 file = push_s8_from_parts(&temp, s8(OS_PATH_SEPARATOR), s8("shaders"), beamformer_reloadable_shader_files[index]); - os_add_file_watch(&ctx->os, memory, file, reload_shader_indirect, (iptr)ctx); - reload_shader_indirect(&ctx->os, file, (iptr)ctx, *memory); + + BeamformerShaderReloadIndirectContext *rsi = push_struct(memory, typeof(*rsi)); + rsi->beamformer = ctx; + rsi->shader = beamformer_reloadable_shader_kinds[index]; + os_add_file_watch(&ctx->os, memory, file, reload_shader_indirect, (iptr)rsi); + reload_shader_indirect(&ctx->os, file, (iptr)rsi, *memory); } os_wake_waiters(&worker->sync_variable);