ogl_beamforming

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

Commit: 1ea96605d02f679311bd3e36b462a28c29de8eb5
Parent: 7d1c7212d386515488b5612e73055597a10f9b8a
Author: Randy Palamar
Date:   Tue,  9 Sep 2025 20:21:08 -0600

lib: add beamformer_beamform_data (simple API)

I haven't yet thought of how to handle the filters in a way that is
easily manageable in toy languages such as matlab so for now they
still need to be setup via a separate function call

Diffstat:
Mbeamformer.c | 24++++++++++++------------
Mbeamformer.h | 9+--------
Mbeamformer_parameters.h | 76++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mbeamformer_shared_memory.c | 2+-
Mbuild.c | 24+++++++++++++++---------
Mhelpers/ogl_beamformer_lib.c | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mhelpers/ogl_beamformer_lib_base.h | 57+++++++++++++++++++++++++++++++++++++++------------------
Mstatic.c | 2+-
Mui.c | 12++++++------
9 files changed, 186 insertions(+), 98 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -398,18 +398,18 @@ das_voxel_transform_matrix(BeamformerParameters *bp) m4 R; switch (bp->das_shader_id) { - case DASShaderKind_FORCES: - case DASShaderKind_UFORCES: - case DASShaderKind_Flash: + case BeamformerDASKind_FORCES: + case BeamformerDASKind_UFORCES: + case BeamformerDASKind_Flash: { R = m4_identity(); S.c[1].E[1] = 0; T2.c[3].E[1] = 0; }break; - case DASShaderKind_HERCULES: - case DASShaderKind_UHERCULES: - case DASShaderKind_RCA_TPW: - case DASShaderKind_RCA_VLS: + case BeamformerDASKind_HERCULES: + case BeamformerDASKind_UHERCULES: + case BeamformerDASKind_RCA_TPW: + case BeamformerDASKind_RCA_VLS: { R = m4_rotation_about_z(bp->beamform_plane ? 0.0f : 0.25f); if (!(points.x > 1 && points.y > 1 && points.z > 1)) @@ -527,7 +527,7 @@ plan_compute_pipeline(BeamformerComputePlan *cp, BeamformerParameterBlock *pb) i32 local_flags = 0; if ((bp->shader_flags & BeamformerShaderDASFlags_CoherencyWeighting) == 0) local_flags |= BeamformerShaderDASFlags_Fast; - if (bp->shader_kind == DASShaderKind_UFORCES || bp->shader_kind == DASShaderKind_UHERCULES) + if (bp->shader_kind == BeamformerDASKind_UFORCES || bp->shader_kind == BeamformerDASKind_UHERCULES) local_flags |= BeamformerShaderDASFlags_Sparse; if (pb->parameters.interpolate) local_flags |= BeamformerShaderDASFlags_Interpolate; @@ -846,8 +846,8 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame if (fast) { i32 loop_end; - if (ubo->shader_kind == DASShaderKind_RCA_VLS || - ubo->shader_kind == DASShaderKind_RCA_TPW) + if (ubo->shader_kind == BeamformerDASKind_RCA_VLS || + ubo->shader_kind == BeamformerDASKind_RCA_TPW) { /* NOTE(rnp): to avoid repeatedly sampling the whole focal vectors * texture we loop over transmits for VLS/TPW */ @@ -920,7 +920,7 @@ do_compute_shader(BeamformerCtx *ctx, BeamformerComputePlan *cp, BeamformerFrame aframe->min_coordinate = frame->min_coordinate; aframe->max_coordinate = frame->max_coordinate; aframe->compound_count = frame->compound_count; - aframe->das_shader_kind = frame->das_shader_kind; + aframe->das_kind = frame->das_kind; }break; InvalidDefaultCase; } @@ -1196,7 +1196,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena *arena, iptr gl_c frame->min_coordinate = cp->min_coordinate; frame->max_coordinate = cp->max_coordinate; - frame->das_shader_kind = cp->das_ubo_data.shader_kind; + frame->das_kind = cp->das_ubo_data.shader_kind; frame->compound_count = cp->das_ubo_data.acquisition_count; BeamformerComputeContext *cc = &ctx->compute_context; diff --git a/beamformer.h b/beamformer.h @@ -260,13 +260,6 @@ typedef struct { BeamformerRenderModel unit_cube_model; } BeamformerComputeContext; -typedef enum { - #define X(type, id, ...) DASShaderKind_##type = id, - DAS_SHADER_KIND_LIST - #undef X - DASShaderKind_Count -} DASShaderKind; - typedef struct { BeamformerComputeStatsTable table; f32 average_times[BeamformerShaderKind_Count]; @@ -324,7 +317,7 @@ struct BeamformerFrame { GLenum gl_kind; u32 id; u32 compound_count; - DASShaderKind das_shader_kind; + BeamformerDASKind das_kind; BeamformerViewPlaneTag view_plane_tag; BeamformerFrame *next; diff --git a/beamformer_parameters.h b/beamformer_parameters.h @@ -20,6 +20,7 @@ typedef struct { /* TODO(rnp): this is an absolute abuse of the preprocessor, but now is * not a good time to write a full metaprogram */ #define BEAMFORMER_FILTER_KIND_LIST(type, _) \ + X(Invalid, type unused) \ X(Kaiser, type cutoff_frequency _ type beta _ type length) \ X(MatchedChirp, type duration _ type min_frequency _ type max_frequency) @@ -55,6 +56,13 @@ typedef enum { X(EPIC_UHERCULES, 9, "EPIC-UHERCULES", 0) \ X(Flash, 10, "Flash", 0) +typedef enum { + #define X(type, id, ...) BeamformerDASKind_##type = id, + DAS_SHADER_KIND_LIST + #undef X + BeamformerDASKind_Count +} BeamformerDASKind; + #define FILTER_LOCAL_SIZE_X 64 #define FILTER_LOCAL_SIZE_Y 1 #define FILTER_LOCAL_SIZE_Z 1 @@ -84,37 +92,47 @@ typedef enum { X(MaxRawDataFramesInFlight, 3) \ X(MaxSavedFrames, 16) #define X(k, v, ...) Beamformer##k = v, -enum {BEAMFORMER_CONSTANTS_LIST}; +typedef enum {BEAMFORMER_CONSTANTS_LIST} BeamformerConstants; #undef X -/* X(name, type, size, elements, comment) */ +/* X(name, type, size, matlab_type, elements, comment) */ #define BEAMFORMER_PARAMS_HEAD \ - X(xdc_transform, float, [16], 16, "IMPORTANT: column major order") \ - X(xdc_element_pitch, float, [2], 2, "[m] Transducer Element Pitch {row, col}") \ - X(raw_data_dimensions, uint32_t, [2], 2, "Raw Data Dimensions") \ - X(sample_count, uint32_t, , 1, "") \ - X(channel_count, uint32_t, , 1, "") \ - X(acquisition_count, uint32_t, , 1, "") \ - X(das_shader_id, uint32_t, , 1, "") \ - X(time_offset, float, , 1, "pulse length correction time [s]") \ - X(decode, uint8_t, , 1, "Decode or just reshape data") \ - X(transmit_mode, uint8_t, , 1, "Method/Orientation of Transmit") \ - X(receive_mode, uint8_t, , 1, "Method/Orientation of Receive") \ - X(sampling_mode, uint8_t, , 1, "") + X(xdc_transform, float, [16], single, 16, "IMPORTANT: column major order") \ + X(xdc_element_pitch, float, [2], single, 2, "[m] Transducer Element Pitch {row, col}") \ + X(raw_data_dimensions, uint32_t, [2], uint32, 2, "Raw Data Dimensions") \ + X(sample_count, uint32_t, , uint32, 1, "") \ + X(channel_count, uint32_t, , uint32, 1, "") \ + X(acquisition_count, uint32_t, , uint32, 1, "") \ + X(das_shader_id, uint32_t, , uint32, 1, "") \ + X(time_offset, float, , single, 1, "pulse length correction time [s]") \ + X(decode, uint8_t, , uint8, 1, "Decode or just reshape data") \ + X(transmit_mode, uint8_t, , uint8, 1, "Method/Orientation of Transmit") \ + X(receive_mode, uint8_t, , uint8, 1, "Method/Orientation of Receive") \ + X(sampling_mode, uint8_t, , uint8, 1, "") #define BEAMFORMER_UI_PARAMS \ - X(output_min_coordinate, float, [3], 3, "[m] Back-Top-Left corner of output region") \ - X(output_max_coordinate, float, [3], 3, "[m] Front-Bottom-Right corner of output region") \ - X(output_points, int32_t, [4], 4, "Width * Height * Depth * (Frame Average Count)") \ - X(sampling_frequency, float, , 1, "[Hz]") \ - X(demodulation_frequency, float, , 1, "[Hz]") \ - X(speed_of_sound, float, , 1, "[m/s]") \ - X(f_number, float, , 1, "F# (set to 0 to disable)") \ - X(off_axis_pos, float, , 1, "[m] Position on screen normal to beamform in TPW/VLS/HERCULES") \ - X(interpolate, uint32_t, , 1, "Perform Cubic Interpolation of RF Samples") \ - X(coherency_weighting, uint32_t, , 1, "Apply coherency weighting to output data") \ - X(beamform_plane, uint32_t, , 1, "Plane to Beamform in TPW/VLS/HERCULES") \ - X(decimation_rate, uint32_t, , 1, "Number of times to decimate") + X(output_min_coordinate, float, [3], single, 3, "[m] Back-Top-Left corner of output region") \ + X(output_max_coordinate, float, [3], single, 3, "[m] Front-Bottom-Right corner of output region") \ + X(output_points, int32_t, [4], int32, 4, "Width * Height * Depth * (Frame Average Count)") \ + X(sampling_frequency, float, , single, 1, "[Hz]") \ + X(demodulation_frequency, float, , single, 1, "[Hz]") \ + X(speed_of_sound, float, , single, 1, "[m/s]") \ + X(f_number, float, , single, 1, "F# (set to 0 to disable)") \ + X(off_axis_pos, float, , single, 1, "[m] Position on screen normal to beamform in TPW/VLS/HERCULES") \ + X(interpolate, uint32_t, , uint32, 1, "Perform Cubic Interpolation of RF Samples") \ + X(coherency_weighting, uint32_t, , uint32, 1, "Apply coherency weighting to output data") \ + X(beamform_plane, uint32_t, , uint32, 1, "Plane to Beamform in TPW/VLS/HERCULES") \ + X(decimation_rate, uint32_t, , uint32, 1, "Number of times to decimate") + +#define BEAMFORMER_SIMPLE_PARAMS \ + X(channel_mapping, int16_t, [BeamformerMaxChannelCount], int16, BeamformerMaxChannelCount) \ + X(sparse_elements, int16_t, [BeamformerMaxChannelCount], int16, BeamformerMaxChannelCount) \ + X(steering_angles, float, [BeamformerMaxChannelCount], single, BeamformerMaxChannelCount) \ + X(focal_depths, float, [BeamformerMaxChannelCount], single, BeamformerMaxChannelCount) \ + X(compute_stages, int32_t, [BeamformerMaxComputeShaderStages], int32, BeamformerMaxComputeShaderStages) \ + X(compute_stage_parameters, int16_t, [BeamformerMaxComputeShaderStages], int16, BeamformerMaxComputeShaderStages) \ + X(compute_stages_count, uint32_t, , uint32, 1) \ + X(data_kind, int32_t, , int32, 1) #define X(name, type, size, ...) type name size; typedef struct {BEAMFORMER_PARAMS_HEAD} BeamformerParametersHead; @@ -124,6 +142,12 @@ typedef struct { BEAMFORMER_PARAMS_HEAD BEAMFORMER_UI_PARAMS } BeamformerParameters; + +typedef struct { + BEAMFORMER_PARAMS_HEAD + BEAMFORMER_UI_PARAMS + BEAMFORMER_SIMPLE_PARAMS +} BeamformerSimpleParameters; #undef X #define BEAMFORMER_LIVE_IMAGING_DIRTY_FLAG_LIST \ diff --git a/beamformer_shared_memory.c b/beamformer_shared_memory.c @@ -159,7 +159,7 @@ typedef struct { /* NOTE(rnp): not used for locking on w32 but we can use these to peek at the status of * the lock without leaving userspace. */ - i32 locks[BeamformerSharedMemoryLockKind_Count + BeamformerMaxParameterBlockSlots]; + i32 locks[(u32)BeamformerSharedMemoryLockKind_Count + (u32)BeamformerMaxParameterBlockSlots]; /* NOTE(rnp): total number of parameter block regions the client has requested. * used to calculate offset to scratch space and to track number of allocated diff --git a/build.c b/build.c @@ -792,12 +792,11 @@ meta_push_(MetaprogramContext *m, s8 *items, iz count) meta_begin_matlab_class_1)(m, __VA_ARGS__) function void -meta_push_matlab_property(MetaprogramContext *m, s8 name, i64 length) +meta_push_matlab_property(MetaprogramContext *m, s8 name, u64 length, s8 kind) { - meta_indent(m); - stream_append_s8s(&m->stream, name, s8("(1,")); - stream_append_i64(&m->stream, length); - stream_append_s8(&m->stream, s8(")\n")); + meta_begin_line(m, name, s8("(1,")); + meta_push_u64(m, (u64)length); + meta_end_line(m, s8(")"), kind.len > 0 ? s8(" ") : s8(""), kind); } function void @@ -2202,7 +2201,7 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) #undef X s8_list members = {0}; - for EachElement(filter_table, filter) { + for EachNonZeroEnumValue(BeamformerFilterKind, filter) { typeof(*filter_table) *f = filter_table + filter; members.count = 0; s8_list_from_s8(&members, &m->scratch, f->args); @@ -2210,7 +2209,7 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) meta_begin_scope(m, s8("properties")); for (iz it = 0; it < members.count; it++) - meta_push_matlab_property(m, members.data[it], 1); + meta_push_matlab_property(m, members.data[it], 1, s8("single")); meta_end_scope(m, s8("end")); meta_begin_scope(m, s8("methods")); @@ -2235,7 +2234,7 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) meta_push_line(m, s8("out(i) = fields{i};")); result &= meta_end_and_write_matlab(m, OUTPUT("matlab/+OGLBeamformerFilter/BaseFilter.m")); - #define X(name, __t, __s, elements, ...) meta_push_line(m, s8(#name "(1," #elements ")")); + #define X(name, __t, __s, kind, elements, ...) meta_push_matlab_property(m, s8(#name), (u64)elements, s8(#kind)); meta_begin_matlab_class(m, "OGLBeamformerParameters"); meta_begin_scope(m, s8("properties")); BEAMFORMER_PARAMS_HEAD @@ -2251,9 +2250,16 @@ metagen_emit_matlab_code(MetaContext *ctx, Arena arena) meta_begin_scope(m, s8("properties")); BEAMFORMER_UI_PARAMS result &= meta_end_and_write_matlab(m, OUTPUT("matlab/OGLBeamformerParametersUI.m")); + + meta_begin_matlab_class(m, "OGLBeamformerSimpleParameters"); + meta_begin_scope(m, s8("properties")); + BEAMFORMER_PARAMS_HEAD + BEAMFORMER_UI_PARAMS + BEAMFORMER_SIMPLE_PARAMS + result &= meta_end_and_write_matlab(m, OUTPUT("matlab/OGLBeamformerSimpleParameters.m")); #undef X - #define X(name, __t, __s, elements, ...) meta_push_matlab_property(m, s8(#name), elements); + #define X(name, __t, __s, elements, ...) meta_push_matlab_property(m, s8(#name), elements, s8("")); meta_begin_matlab_class(m, "OGLBeamformerLiveImagingParameters"); meta_begin_scope(m, s8("properties")); BEAMFORMER_LIVE_IMAGING_PARAMETERS_LIST diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c @@ -228,10 +228,8 @@ beamformer_reserve_parameter_blocks(uint32_t count) function b32 validate_pipeline(i32 *shaders, u32 shader_count, BeamformerDataKind data_kind) { - b32 result = 1; - if (lib_error_check(shader_count <= BeamformerMaxComputeShaderStages, - BF_LIB_ERR_KIND_COMPUTE_STAGE_OVERFLOW)) - { + b32 result = lib_error_check(shader_count <= BeamformerMaxComputeShaderStages, BF_LIB_ERR_KIND_COMPUTE_STAGE_OVERFLOW); + if (result) { for (u32 i = 0; i < shader_count; i++) result &= BETWEEN(shaders[i], BeamformerShaderKind_ComputeFirst, BeamformerShaderKind_ComputeLast); if (!result) { @@ -252,6 +250,18 @@ validate_pipeline(i32 *shaders, u32 shader_count, BeamformerDataKind data_kind) } function b32 +validate_simple_parameters(BeamformerSimpleParameters *bp) +{ + b32 result = check_shared_memory(); + if (result) { + result &= bp->channel_count <= BeamformerMaxChannelCount; + if (!result) + g_beamformer_library_context.last_error = BF_LIB_ERR_KIND_INVALID_SIMPLE_PARAMETERS; + } + return result; +} + +function b32 parameter_block_region_upload_explicit(void *data, u32 size, u32 block, BeamformerParameterBlockRegions region_id, u32 block_offset, i32 timeout_ms) { @@ -301,7 +311,7 @@ b32 beamformer_push_pipeline_at(i32 *shaders, u32 shader_count, BeamformerDataKind data_kind, u32 block) { b32 result = 0; - if (validate_pipeline(shaders, shader_count, data_kind)) { + if (check_shared_memory() && validate_pipeline(shaders, shader_count, data_kind)) { i32 lock = BeamformerSharedMemoryLockKind_Count + (i32)block; if (valid_parameter_block(block) && lib_try_lock(lock, g_beamformer_library_context.timeout_ms)) { BeamformerParameterBlock *b = beamformer_parameter_block(g_beamformer_library_context.bp, block); @@ -489,6 +499,35 @@ beamformer_push_parameters(BeamformerParameters *bp) } b32 +beamformer_push_simple_parameters_at(BeamformerSimpleParameters *bp, u32 block) +{ + b32 result = validate_simple_parameters(bp); + if (result) { + result &= beamformer_push_parameters_at((BeamformerParameters *)bp, block); + result &= beamformer_push_pipeline_at(bp->compute_stages, bp->compute_stages_count, (BeamformerDataKind)bp->data_kind, block); + result &= beamformer_push_channel_mapping_at(bp->channel_mapping, bp->channel_count, block); + if (bp->das_shader_id == BeamformerDASKind_UFORCES || bp->das_shader_id == BeamformerDASKind_UHERCULES) + result &= beamformer_push_sparse_elements_at(bp->sparse_elements, bp->acquisition_count, block); + + alignas(64) v2 focal_vectors[countof(bp->steering_angles)]; + for (u32 i = 0; i < countof(bp->steering_angles); i++) + focal_vectors[i] = (v2){{bp->steering_angles[i], bp->focal_depths[i]}}; + result &= beamformer_push_focal_vectors_at((f32 *)focal_vectors, countof(focal_vectors), block); + + for (u32 stage = 0; stage < bp->compute_stages_count; stage++) + result &= beamformer_set_pipeline_stage_parameters_at(stage, bp->compute_stage_parameters[stage], block); + } + return result; +} + +b32 +beamformer_push_simple_parameters(BeamformerSimpleParameters *bp) +{ + b32 result = beamformer_push_simple_parameters_at(bp, 0); + return result; +} + +b32 beamformer_push_parameters_ui(BeamformerUIParameters *bp) { b32 result = parameter_block_region_upload_explicit(bp, sizeof(*bp), 0, BeamformerParameterBlockRegion_Parameters, @@ -537,23 +576,28 @@ beamformer_read_output(void *out, iz size, i32 timeout_ms) } b32 -beamform_data_synchronized(void *data, u32 data_size, i32 output_points[3], f32 *out_data, i32 timeout_ms) +beamformer_beamform_data(BeamformerSimpleParameters *bp, void *data, uint32_t data_size, + void *out_data, int32_t timeout_ms) { - b32 result = 0; - if (check_shared_memory()) { - output_points[0] = MAX(1, output_points[0]); - output_points[1] = MAX(1, output_points[1]); - output_points[2] = MAX(1, output_points[2]); + b32 result = validate_simple_parameters(bp); + if (result) { + bp->output_points[0] = MAX(1, bp->output_points[0]); + bp->output_points[1] = MAX(1, bp->output_points[1]); + bp->output_points[2] = MAX(1, bp->output_points[2]); + + beamformer_push_simple_parameters(bp); - BeamformerParameterBlock *b = beamformer_parameter_block(g_beamformer_library_context.bp, 0); - b->parameters.output_points[0] = output_points[0]; - b->parameters.output_points[1] = output_points[1]; - b->parameters.output_points[2] = output_points[2]; + b32 complex = 0; + for (u32 stage = 0; stage < bp->compute_stages_count; stage++) { + BeamformerShaderKind shader = (BeamformerShaderKind)bp->compute_stages[stage]; + complex |= shader == BeamformerShaderKind_Demodulate || shader == BeamformerShaderKind_CudaHilbert; + } - iz output_size = output_points[0] * output_points[1] * output_points[2] * (i32)sizeof(f32) * 2; + iz output_size = bp->output_points[0] * bp->output_points[1] * bp->output_points[2] * (i32)sizeof(f32); + if (complex) output_size *= 2; Arena scratch = beamformer_shared_memory_scratch_arena(g_beamformer_library_context.bp); - if (lib_error_check(output_size <= arena_capacity(&scratch, u8), BF_LIB_ERR_KIND_EXPORT_SPACE_OVERFLOW) + if (result && lib_error_check(output_size <= arena_capacity(&scratch, u8), BF_LIB_ERR_KIND_EXPORT_SPACE_OVERFLOW) && beamformer_push_data_with_compute(data, data_size, 0, 0)) { BeamformerExportContext export; diff --git a/helpers/ogl_beamformer_lib_base.h b/helpers/ogl_beamformer_lib_base.h @@ -25,7 +25,8 @@ X(SYNC_VARIABLE, 14, "failed to acquire lock within timeout period") \ X(INVALID_TIMEOUT, 15, "invalid timeout value") \ X(INVALID_FILTER_KIND, 16, "invalid filter kind") \ - X(INVALID_FILTER_PARAM_COUNT, 17, "invalid parameters count passed for filter") + X(INVALID_FILTER_PARAM_COUNT, 17, "invalid parameters count passed for filter") \ + X(INVALID_SIMPLE_PARAMETERS, 18, "invalid simple parameters struct") #define X(type, num, string) BF_LIB_ERR_KIND_ ##type = num, typedef enum {BEAMFORMER_LIB_ERRORS} BeamformerLibErrorKind; @@ -37,6 +38,20 @@ LIB_FN BeamformerLibErrorKind beamformer_get_last_error(void); LIB_FN const char *beamformer_get_last_error_string(void); LIB_FN const char *beamformer_error_string(BeamformerLibErrorKind kind); +/////////////////////////// +// NOTE: Simple API +/* Usage: + * - fill out a BeamformerSimpleParameters + * - filters need to be created with beamformer_create_filter, and the slot + * needs to be assigned in compute_stage_parameters + * - allocate a buffer with enough space for all Float32 or Float32Complex output points + * - pass the buffer along with the data and parameters to beamformer_beamform_data() + * - if the function was unsuccessful you can check the error with beamformer_get_last_error() + * or beamformer_get_last_error_string() + */ +LIB_FN uint32_t beamformer_beamform_data(BeamformerSimpleParameters *bp, void *data, uint32_t data_size, + void *out_data, int32_t timeout_ms); + /* NOTE: sets timeout for all functions which may timeout but don't * take a timeout argument. The majority of such functions will not * timeout in the normal case and so passing a timeout parameter around @@ -47,10 +62,8 @@ LIB_FN const char *beamformer_error_string(BeamformerLibErrorKind kind); * IMPORTANT: timeout of -1 will block forever */ LIB_FN uint32_t beamformer_set_global_timeout(int32_t timeout_ms); -/* NOTE: sends data and waits for (complex) beamformed data to be returned. - * out_data: must be allocated by the caller as 2 floats per output point. */ -LIB_FN uint32_t beamform_data_synchronized(void *data, uint32_t data_size, int32_t output_points[3], - float *out_data, int32_t timeout_ms); +/////////////////////////// +// NOTE: Advanced API /* NOTE: downloads the last 32 frames worth of compute timings into output */ LIB_FN uint32_t beamformer_compute_timings(BeamformerComputeStatsTable *output, int32_t timeout_ms); @@ -58,38 +71,46 @@ LIB_FN uint32_t beamformer_compute_timings(BeamformerComputeStatsTable *output, /* NOTE: tells the beamformer to start beamforming */ LIB_FN uint32_t beamformer_start_compute(void); -LIB_FN uint32_t beamformer_push_data_with_compute(void *data, uint32_t size, - uint32_t image_plane_tag, - uint32_t parameter_slot); - /* NOTE: waits for previously queued beamform to start or for timeout_ms */ LIB_FN uint32_t beamformer_wait_for_compute_dispatch(int32_t timeout_ms); -/* NOTE: these functions only queue an upload; you must flush (start_compute) */ +/* NOTE: this function only queue an upload; you must flush (start_compute) */ LIB_FN uint32_t beamformer_push_data(void *data, uint32_t size); -LIB_FN uint32_t beamformer_push_channel_mapping(int16_t *mapping, uint32_t count); -LIB_FN uint32_t beamformer_push_sparse_elements(int16_t *elements, uint32_t count); -LIB_FN uint32_t beamformer_push_focal_vectors(float *vectors, uint32_t count); + +/* NOTE: pushes data and tries to immediately starts a compute */ +LIB_FN uint32_t beamformer_push_data_with_compute(void *data, uint32_t size, + uint32_t image_plane_tag, + uint32_t parameter_slot); /////////////////////////// // Parameter Configuration LIB_FN uint32_t beamformer_reserve_parameter_blocks(uint32_t count); LIB_FN uint32_t beamformer_set_pipeline_stage_parameters(uint32_t stage_index, int32_t parameter); LIB_FN uint32_t beamformer_push_pipeline(int32_t *shaders, uint32_t shader_count, BeamformerDataKind data_kind); -LIB_FN uint32_t beamformer_push_parameters(BeamformerParameters *); -LIB_FN uint32_t beamformer_push_parameters_ui(BeamformerUIParameters *); -LIB_FN uint32_t beamformer_push_parameters_head(BeamformerParametersHead *); LIB_FN uint32_t beamformer_set_pipeline_stage_parameters_at(uint32_t stage_index, int32_t parameter, uint32_t parameter_slot); LIB_FN uint32_t beamformer_push_pipeline_at(int32_t *shaders, uint32_t shader_count, BeamformerDataKind data_kind, uint32_t parameter_slot); + +LIB_FN uint32_t beamformer_push_simple_parameters(BeamformerSimpleParameters *bp); +LIB_FN uint32_t beamformer_push_simple_parameters_at(BeamformerSimpleParameters *bp, uint32_t parameter_slot); + +LIB_FN uint32_t beamformer_push_parameters(BeamformerParameters *); +LIB_FN uint32_t beamformer_push_parameters_ui(BeamformerUIParameters *); +LIB_FN uint32_t beamformer_push_parameters_head(BeamformerParametersHead *); + LIB_FN uint32_t beamformer_push_parameters_at(BeamformerParameters *, uint32_t parameter_slot); -LIB_FN uint32_t beamformer_push_channel_mapping_at(int16_t *mapping, uint32_t count, uint32_t parameter_slot); +LIB_FN uint32_t beamformer_push_channel_mapping(int16_t *mapping, uint32_t count); +LIB_FN uint32_t beamformer_push_channel_mapping_at(int16_t *mapping, uint32_t count, uint32_t parameter_slot); + +LIB_FN uint32_t beamformer_push_sparse_elements(int16_t *elements, uint32_t count); LIB_FN uint32_t beamformer_push_sparse_elements_at(int16_t *elements, uint32_t count, uint32_t parameter_slot); -LIB_FN uint32_t beamformer_push_focal_vectors_at(float *vectors, uint32_t count, uint32_t parameter_slot); + +LIB_FN uint32_t beamformer_push_focal_vectors(float *vectors, uint32_t count); +LIB_FN uint32_t beamformer_push_focal_vectors_at(float *vectors, uint32_t count, uint32_t parameter_slot); //////////////////// // Filter Creation diff --git a/static.c b/static.c @@ -365,7 +365,7 @@ setup_beamformer(Arena *memory, BeamformerCtx **o_ctx, BeamformerInput **o_input /* TODO(rnp): I'm not sure if its a good idea to pre-reserve a bunch of semaphores * on w32 but thats what we are doing for now */ - u32 lock_count = BeamformerSharedMemoryLockKind_Count + BeamformerMaxParameterBlockSlots; + u32 lock_count = (u32)BeamformerSharedMemoryLockKind_Count + (u32)BeamformerMaxParameterBlockSlots; ctx->shared_memory = os_create_shared_memory_area(memory, OS_SHARED_MEMORY_NAME, lock_count, BEAMFORMER_SHARED_MEMORY_SIZE); BeamformerSharedMemory *sm = ctx->shared_memory.region; diff --git a/ui.c b/ui.c @@ -657,20 +657,20 @@ stream_append_variable_group(Stream *s, Variable *var) } function s8 -push_das_shader_kind(Stream *s, DASShaderKind shader, u32 transmit_count) +push_das_shader_kind(Stream *s, BeamformerDASKind shader, u32 transmit_count) { #define X(__1, __2, pretty, ...) s8_comp(pretty), - read_only local_persist s8 pretty_names[DASShaderKind_Count + 1] = { + read_only local_persist s8 pretty_names[BeamformerDASKind_Count + 1] = { DAS_SHADER_KIND_LIST s8_comp("Invalid") }; #undef X #define X(__1, __2, __3, fixed_tx) fixed_tx, - read_only local_persist u8 fixed_transmits[DASShaderKind_Count + 1] = {DAS_SHADER_KIND_LIST}; + read_only local_persist u8 fixed_transmits[BeamformerDASKind_Count + 1] = {DAS_SHADER_KIND_LIST}; #undef X - stream_append_s8(s, pretty_names[MIN(shader, DASShaderKind_Count)]); - if (!fixed_transmits[MIN(shader, DASShaderKind_Count)]) { + stream_append_s8(s, pretty_names[MIN(shader, BeamformerDASKind_Count)]); + if (!fixed_transmits[MIN(shader, BeamformerDASKind_Count)]) { stream_append_byte(s, '-'); stream_append_u64(s, transmit_count); } @@ -2571,7 +2571,7 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa { Stream buf = arena_stream(a); - s8 shader = push_das_shader_kind(&buf, frame->das_shader_kind, frame->compound_count); + s8 shader = push_das_shader_kind(&buf, frame->das_kind, frame->compound_count); text_spec.font = &ui->font; text_spec.limits.size.w -= 16; v2 txt_s = measure_text(*text_spec.font, shader);