ogl_beamforming

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

Commit: b2ddc221d97727c68d9812e958c6ffd93e2afb0b
Parent: b02956354378b13c98d03b384ecfa85d36cb0b3a
Author: Randy Palamar
Date:   Fri, 21 Aug 2026 19:24:31 -0700

core/gpu: move filter allocation into gpu temp arena

Diffstat:
Mbeamformer_core.c | 70+++++++++++++++++++++++++---------------------------------------------
Mbeamformer_internal.h | 4++--
2 files changed, 27 insertions(+), 47 deletions(-)

diff --git a/beamformer_core.c b/beamformer_core.c @@ -2,6 +2,7 @@ /* TODO(rnp): * [ ]: backtrace dumping on SIGSEGV * [ ]: cooperative shared memory loading in decode shader + * [ ]: refactor: save filter parameters with rest of parameters, whole slot thing is dumb * [ ]: upload previously exported data for display. maybe this is a UI thing but doing it * programatically would be nice. * [ ]: Add interface for multi frame upload. RF upload already uses an offset into SM so @@ -235,8 +236,6 @@ beamformer_compute_plan_release(BeamformerComputeContext *cc, u32 block) if (cp) { gpu_buffer_release(&cp->array_parameters); gpu_buffer_release(&cp->gpu_temp_arena); - for (u32 i = 0; i < countof(cp->filters); i++) - gpu_buffer_release(&cp->filters[i].buffer); cc->compute_plans[block] = 0; SLLPushFreelist(cp, cc->compute_plan_freelist); } @@ -364,59 +363,38 @@ beamformer_compute_plan_for_block(BeamformerComputeContext *cc, u32 block, Arena return result; } -function void -beamformer_filter_update(BeamformerFilter *f, BeamformerFilterParameters fp, u32 block, u32 slot, Arena *arena) +function BeamformerFilter * +beamformer_filter_create(Arena *arena, BeamformerFilterParameters fp) { - Temp scratch = temp_begin(arena); - Stream sb = arena_stream(arena); - stream_append_str8s(&sb, - beamformer_filter_kind_strings[fp.kind % countof(beamformer_filter_kind_strings)], - str8("Filter[")); - stream_append_u64(&sb, block); - stream_append_str8(&sb, str8("][")); - stream_append_u64(&sb, slot); - stream_append_byte(&sb, ']'); - str8 label = arena_stream_commit(arena, &sb); - - void *filter = 0; + BeamformerFilter *result = push_struct(arena, BeamformerFilter); switch (fp.kind) { case BeamformerFilterKind_Kaiser:{ /* TODO(rnp): this should also support complex */ /* TODO(rnp): implement this as an IFIR filter instead to reduce computation */ - filter = kaiser_low_pass_filter(arena, fp.kaiser.cutoff_frequency, fp.sampling_frequency, - fp.kaiser.beta, (i32)fp.kaiser.length); - f->length = (i32)fp.kaiser.length; - f->time_delay = (f32)f->length / 2.0f / fp.sampling_frequency; + result->data = kaiser_low_pass_filter(arena, fp.kaiser.cutoff_frequency, fp.sampling_frequency, + fp.kaiser.beta, (i32)fp.kaiser.length); + result->length = (i32)fp.kaiser.length; + result->time_delay = (f32)result->length / 2.0f / fp.sampling_frequency; }break; + case BeamformerFilterKind_MatchedChirp:{ typeof(fp.matched_chirp) *mc = &fp.matched_chirp; - f32 fs = fp.sampling_frequency; - f->length = (i32)(mc->duration * fs); + f32 fs = fp.sampling_frequency; + result->length = (i32)(mc->duration * fs); if (fp.complex) { - filter = baseband_chirp(arena, mc->min_frequency, mc->max_frequency, fs, f->length, 1, 0.5f); - f->time_delay = complex_filter_first_moment(filter, f->length, fs); + result->data = baseband_chirp(arena, mc->min_frequency, mc->max_frequency, fs, result->length, 1, 0.5f); + result->time_delay = complex_filter_first_moment(result->data, result->length, fs); } else { - filter = rf_chirp(arena, mc->min_frequency, mc->max_frequency, fs, f->length, 1); - f->time_delay = real_filter_first_moment(filter, f->length, fs); + result->data = rf_chirp(arena, mc->min_frequency, mc->max_frequency, fs, result->length, 1); + result->time_delay = real_filter_first_moment(result->data, result->length, fs); } }break; - InvalidDefaultCase; - } - - f->parameters = fp; - u32 byte_size = f->length * (i32)sizeof(f32) * (fp.complex? 2 : 1); - if (f->buffer.size < byte_size) { - GPUBufferAllocateInfo allocate_info = { - .size = byte_size, - .flags = VulkanUsageFlag_HostReadWrite, - .label = label, - }; - gpu_buffer_allocate(&f->buffer, allocate_info); + InvalidDefaultCase; } - gpu_buffer_range_upload(&f->buffer, filter, 0, byte_size, 0); - temp_end(scratch); + result->parameters = fp; + return result; } function iv3 @@ -849,7 +827,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A case BeamformerShaderKind_Filter: { b32 demod = node->kind == BeamformerShaderKind_Demodulate; - BeamformerFilter *f = cp->filters + sp->filter_slot; + BeamformerFilter *f = beamformer_filter_create(scratch, cp->filter_parameters[sp->filter_slot]); sd->compile_flags |= BeamformerFilterCompileFlags_Demodulate * demod; sd->compile_flags |= BeamformerFilterCompileFlags_ComplexFilter * f->parameters.complex; @@ -858,8 +836,11 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb, A BeamformerFilterBakeParameters *fb = &sd->bake.Filter; - fb->FilterCoefficients = f->buffer.gpu_pointer; - fb->FilterLength = (u32)f->length; + fb->FilterLength = (u32)f->length; + gpu_resource_push(resource_builder, f32, f->length * (f->parameters.complex ? 2 : 1), + .data = f->data, + .name = push_str8_f(scratch, "filter_%u", sp->filter_slot), + .store = &fb->FilterCoefficients); fb->SampleCount = input_sample_count; fb->DecimationRate = demod ? decimation_rate : 1; @@ -1528,12 +1509,11 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena) }break; case BeamformerWorkKind_CreateFilter:{ - /* TODO(rnp): this should probably get deleted and moved to lazy loading */ BeamformerCreateFilterContext *fctx = &work->create_filter_context; u32 block = fctx->parameter_block; u32 slot = fctx->filter_slot; BeamformerComputePlan *cp = beamformer_compute_plan_for_block(cs, block, arena); - beamformer_filter_update(cp->filters + slot, fctx->parameters, block, slot, arena); + cp->filter_parameters[slot] = fctx->parameters; }break; case BeamformerWorkKind_ComputeIndirect: diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -270,7 +270,7 @@ typedef struct { BeamformerFilterParameters parameters; f32 time_delay; i32 length; - GPUBuffer buffer; + void *data; } BeamformerFilter; typedef struct { @@ -319,7 +319,7 @@ struct BeamformerComputePlan { GPUBuffer array_parameters; GPUBuffer gpu_temp_arena; - BeamformerFilter filters[BeamformerFilterSlots]; + BeamformerFilterParameters filter_parameters[BeamformerFilterSlots]; u128 shader_hashes[BeamformerMaxComputeShaderStages]; BeamformerShaderDescriptor shader_descriptors[BeamformerMaxComputeShaderStages];