ogl_beamforming

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

Commit: 69799d54a9fddad0670eb6b776f79926282775c6
Parent: 8de9e21b0bb2d2af9962987b5b9b89a31eb040ed
Author: Randy Palamar
Date:   Sat,  8 Aug 2026 07:19:47 -0700

core: merge {Compute,DAS} array parameter structs

This stuff doesn't need to be defined in two separate places.

Diffstat:
Mbeamformer.meta | 24++++++++++++++++++------
Mbeamformer_core.c | 44++++++++++++++++----------------------------
Mbeamformer_internal.h | 20--------------------
Mgenerated/beamformer.c | 40++++++++++++++++++++++++++++++++++------
Mmath.c | 2+-
Mshaders/das.glsl | 12++++++------
6 files changed, 75 insertions(+), 67 deletions(-)

diff --git a/beamformer.meta b/beamformer.meta @@ -267,16 +267,28 @@ @Library @Struct LiveImagingParameters @MATLAB @Struct LiveImagingParameters -@Struct DASArrayParameters +@Table([name_upper name_lower type elements]) ComputeArrayParametersTable { - [focal_vectors V2 MaxChannelCount] - [sparse_elements S16 MaxChannelCount] - [transmit_receive_orientations U16 MaxChannelCount] - [hadamard_matrix F16 MaxHadamardElements] + [FocalVectors focal_vectors V2 MaxChannelCount] + [SparseElements sparse_elements S16 MaxChannelCount] + [TransmitReceiveOrientations transmit_receive_orientations U16 MaxChannelCount] + [DASHadamard das_hadamard F16 MaxHadamardElements] + [DecodeHadamard decode_hadamard F16 MaxHadamardElements] } +@Expand(ComputeArrayParametersTable) @Enumeration(`$(name_upper)`) ComputeArrayParametersField +@Expand(ComputeArrayParametersTable) @Struct([`$(name_lower)` `$(type)` `$(elements)`]) ComputeArrayParameters + @Emit { + `read_only global u32 beamformer_compute_array_parameter_sizes[] = {` + @Expand(ComputeArrayParametersTable) ` sizeof($(%type))$(|)* Beamformer$(elements),` + `};` + `` + `read_only global u32 beamformer_compute_array_parameter_offsets[] = {` + @Expand(ComputeArrayParametersTable) ` offsetof(BeamformerComputeArrayParameters, $(name_lower)),` + `};` + `` `read_only global u8 beamformer_data_kind_element_size[] = {` @Expand(DataKindTable) ` $(size),` `};` @@ -416,7 +428,7 @@ @Enumeration ShaderBufferSlot @Enumeration ShaderResourceKind - @Struct DASArrayParameters + @Struct ComputeArrayParameters @Flags { diff --git a/beamformer_core.c b/beamformer_core.c @@ -56,18 +56,6 @@ typedef struct { u64 count; } BeamformerComputeGraph; -read_only global u32 beamformer_compute_array_parameter_sizes[] = { - #define X(k, type, elements) sizeof(type) * elements, - BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST - #undef X -}; - -read_only global u32 beamformer_compute_array_parameter_offsets[] = { - #define X(k, ...) offsetof(BeamformerComputeArrayParameters, k), - BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST - #undef X -}; - read_only global BeamformerFrame beamformer_nil_frame; read_only global BeamformerComputePlan beamformer_nil_compute_plan; @@ -195,7 +183,6 @@ beamformer_compute_plan_for_block(BeamformerComputeContext *cc, u32 block, Arena stream_append_str8(&label, str8("ComputeParameterArray[")); stream_append_u64(&label, block); stream_append_str8(&label, str8("]")); - stream_append_byte(&label, 0); GPUBufferAllocateInfo allocate_info = { .size = sizeof(BeamformerComputeArrayParameters), @@ -274,17 +261,15 @@ das_valid_points(iv3 points) } function void -beamformer_update_hadamard(BeamformerComputePlan *cp, i32 order, b32 row_major, b32 das_matrix, Arena *arena) +beamformer_update_hadamard(BeamformerComputePlan *cp, BeamformerComputeArrayParametersField output_field, + i32 order, b32 row_major, Arena *arena) { f16 *hadamard = make_hadamard_transpose(arena, order, row_major); if (hadamard) { - u64 offset = das_matrix ? offsetof(BeamformerComputeArrayParameters, DasHadamard) - : offsetof(BeamformerComputeArrayParameters, DecodeHadamard); - u64 size = das_matrix ? sizeof(*((BeamformerComputeArrayParameters *)0)->DasHadamard) - : sizeof(*((BeamformerComputeArrayParameters *)0)->DecodeHadamard); + u64 offset = beamformer_compute_array_parameter_offsets[output_field]; + u64 size = beamformer_compute_array_parameter_sizes[output_field] / BeamformerMaxHadamardElements; size *= order * order; vk_buffer_range_upload(&cp->array_parameters, hadamard, offset, size, 0); - if(!das_matrix) cp->hadamard_order = order; } } @@ -1072,9 +1057,12 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp, if (pb->parameters.decode_mode != BeamformerDecodeMode_None && cp->hadamard_order != (i32)cp->acquisition_count) { - beamformer_update_hadamard(cp, (i32)cp->acquisition_count, vk_gpu_info()->cooperative_matrix, 0, scratch); + beamformer_update_hadamard(cp, BeamformerComputeArrayParametersField_DecodeHadamard, + cp->acquisition_count, vk_gpu_info()->cooperative_matrix, scratch); if (pb->parameters.readi_group_count > 1) - beamformer_update_hadamard(cp, (i32)pb->parameters.readi_group_count, 0, 1, scratch); + beamformer_update_hadamard(cp, BeamformerComputeArrayParametersField_DASHadamard, + pb->parameters.readi_group_count, 0, scratch); + cp->hadamard_order = cp->acquisition_count; } }break; @@ -1083,7 +1071,7 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp, }break; case BeamformerParameterRegionFlag_TransmitReceiveOrientations:{ GPUBuffer *b = &cp->array_parameters; - u32 kind = BeamformerComputeArrayParameterKind_TransmitReceiveOrientations; + u32 kind = BeamformerComputeArrayParametersField_TransmitReceiveOrientations; u64 offset = beamformer_compute_array_parameter_offsets[kind]; u64 size = beamformer_compute_array_parameter_sizes[kind]; { @@ -1097,18 +1085,18 @@ beamformer_commit_parameter_block(BeamformerCtx *ctx, BeamformerComputePlan *cp, case BeamformerParameterRegionFlag_FocalVectors: case BeamformerParameterRegionFlag_SparseElements: { - u32 kind = BeamformerComputeArrayParameterKind_Count; + u32 kind = BeamformerComputeArrayParametersField_Count; switch (region) { case BeamformerParameterBlockRegion_FocalVectors:{ - kind = BeamformerComputeArrayParameterKind_FocalVectors; + kind = BeamformerComputeArrayParametersField_FocalVectors; }break; case BeamformerParameterBlockRegion_SparseElements:{ - kind = BeamformerComputeArrayParameterKind_SparseElements; + kind = BeamformerComputeArrayParametersField_SparseElements; }break; InvalidDefaultCase; } - if (kind != BeamformerComputeArrayParameterKind_Count) { + if (kind != BeamformerComputeArrayParametersField_Count) { GPUBuffer *b = &cp->array_parameters; u64 offset = beamformer_compute_array_parameter_offsets[kind]; u64 size = beamformer_compute_array_parameter_sizes[kind]; @@ -1144,7 +1132,7 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c case BeamformerShaderKind_Decode:{ BeamformerDecodePushConstants pc = { - .hadamard_buffer = cp->array_parameters.gpu_pointer + offsetof(BeamformerComputeArrayParameters, DecodeHadamard), + .hadamard_buffer = cp->array_parameters.gpu_pointer + offsetof(BeamformerComputeArrayParameters, decode_hadamard), .rf_buffer = pp_input_pointer, }; @@ -1252,7 +1240,7 @@ do_compute_shader(BeamformerCtx *ctx, VulkanHandle cmd, BeamformerComputePlan *c .cycle_t = das_cycle_t++, .channel_offset = channel_offset, .readi_group = cp->readi_group, - .array_parameters = cp->array_parameters.gpu_pointer + offsetof(BeamformerComputeArrayParameters, FocalVectors), + .array_parameters = cp->array_parameters.gpu_pointer, }; memory_copy(pc.voxel_transform.E, cp->das_voxel_transform.E, sizeof(pc.voxel_transform)); memory_copy(pc.xdc_transform.E, cp->xdc_transform.E, sizeof(pc.xdc_transform)); diff --git a/beamformer_internal.h b/beamformer_internal.h @@ -264,26 +264,6 @@ typedef struct { GPUBuffer buffer; } BeamformerFilter; -// X(kind, format, elements) -#define BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST \ - X(DecodeHadamard, f16, BeamformerMaxChannelCount * BeamformerMaxChannelCount) \ - X(FocalVectors, v2, BeamformerMaxChannelCount) \ - X(SparseElements, i16, BeamformerMaxChannelCount) \ - X(TransmitReceiveOrientations, u16, BeamformerMaxChannelCount) \ - X(DasHadamard, f16, BeamformerMaxChannelCount * BeamformerMaxChannelCount) \ - -typedef enum { - #define X(k, ...) BeamformerComputeArrayParameterKind_##k, - BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST - #undef X - BeamformerComputeArrayParameterKind_Count -} BeamformerComputeArrayParameterKind; - -// NOTE(rnp): only used to calculate offsets, never used directly -#define X(name, type, elements) alignas(64) type name[elements]; -typedef struct {BEAMFORMER_COMPUTE_ARRAY_PARAMETERS_LIST} BeamformerComputeArrayParameters; -#undef X - typedef struct { uv3 layout; uv3 dispatch; diff --git a/generated/beamformer.c b/generated/beamformer.c @@ -115,6 +115,15 @@ typedef enum { } BeamformerLiveFeedbackFlags; typedef enum { + BeamformerComputeArrayParametersField_FocalVectors = 0, + BeamformerComputeArrayParametersField_SparseElements = 1, + BeamformerComputeArrayParametersField_TransmitReceiveOrientations = 2, + BeamformerComputeArrayParametersField_DASHadamard = 3, + BeamformerComputeArrayParametersField_DecodeHadamard = 4, + BeamformerComputeArrayParametersField_Count, +} BeamformerComputeArrayParametersField; + +typedef enum { BeamformerLiveImagingDirtyFlags_ImagePlaneOffsets = 1 << 0, BeamformerLiveImagingDirtyFlags_TransmitPower = 1 << 1, BeamformerLiveImagingDirtyFlags_TGCControlPoints = 1 << 2, @@ -457,8 +466,9 @@ typedef struct { v2 focal_vectors[BeamformerMaxChannelCount]; i16 sparse_elements[BeamformerMaxChannelCount]; u16 transmit_receive_orientations[BeamformerMaxChannelCount]; - f16 hadamard_matrix[BeamformerMaxHadamardElements]; -} BeamformerDASArrayParameters; + f16 das_hadamard[BeamformerMaxHadamardElements]; + f16 decode_hadamard[BeamformerMaxHadamardElements]; +} BeamformerComputeArrayParameters; typedef union { BeamformerDecodeBakeParameters Decode; @@ -467,6 +477,22 @@ typedef union { BeamformerReshapeBakeParameters Reshape; } BeamformerShaderBakeParameters; +read_only global u32 beamformer_compute_array_parameter_sizes[] = { + sizeof(v2) * BeamformerMaxChannelCount, + sizeof(i16) * BeamformerMaxChannelCount, + sizeof(u16) * BeamformerMaxChannelCount, + sizeof(f16) * BeamformerMaxHadamardElements, + sizeof(f16) * BeamformerMaxHadamardElements, +}; + +read_only global u32 beamformer_compute_array_parameter_offsets[] = { + offsetof(BeamformerComputeArrayParameters, focal_vectors), + offsetof(BeamformerComputeArrayParameters, sparse_elements), + offsetof(BeamformerComputeArrayParameters, transmit_receive_orientations), + offsetof(BeamformerComputeArrayParameters, das_hadamard), + offsetof(BeamformerComputeArrayParameters, decode_hadamard), +}; + read_only global u8 beamformer_data_kind_element_size[] = { 2, 2, @@ -848,17 +874,19 @@ read_only global str8 beamformer_shader_global_header_strings[] = { "#define RCAOrientation_Columns 2\n" "\n"), str8_comp("" - "struct DASArrayParameters {\n" + "struct ComputeArrayParameters {\n" " f32vec2 focal_vectors[MaxChannelCount];\n" " int16_t sparse_elements[MaxChannelCount];\n" " uint16_t transmit_receive_orientations[MaxChannelCount];\n" - " float16_t hadamard_matrix[MaxHadamardElements];\n" + " float16_t das_hadamard[MaxHadamardElements];\n" + " float16_t decode_hadamard[MaxHadamardElements];\n" "};\n" - "layout(std430, buffer_reference) buffer DASArrayParametersReference {\n" + "layout(std430, buffer_reference) buffer ComputeArrayParametersReference {\n" " f32vec2 focal_vectors[MaxChannelCount];\n" " int16_t sparse_elements[MaxChannelCount];\n" " uint16_t transmit_receive_orientations[MaxChannelCount];\n" - " float16_t hadamard_matrix[MaxHadamardElements];\n" + " float16_t das_hadamard[MaxHadamardElements];\n" + " float16_t decode_hadamard[MaxHadamardElements];\n" "};\n" "\n"), str8_comp("" diff --git a/math.c b/math.c @@ -124,7 +124,7 @@ make_hadamard_transpose(Arena *arena, i32 dim, b32 row_major) temp_end(scratch); } - if (row_major) { + if (result && row_major) { for (i32 r = 0; r < order; r++) for (i32 c = 0; c < order; c++) swap(result[r * order + c], result[c * order + r]); diff --git a/shaders/das.glsl b/shaders/das.glsl @@ -170,14 +170,14 @@ float cylindrical_wave_transmit_distance(const vec3 point, const float focal_dep u16 tx_rx_orientation_for_acquisition(const s16 acquisition) { u16 result = u16(TransmitReceiveOrientation); - DASArrayParametersReference dp = DASArrayParametersReference(array_parameters); + ComputeArrayParametersReference dp = ComputeArrayParametersReference(array_parameters); if (!SingleOrientation) result = dp.transmit_receive_orientations[acquisition]; return result; } f32vec2 focal_vector_for_acquisition(const s16 acquisition) { - DASArrayParametersReference dp = DASArrayParametersReference(array_parameters); + ComputeArrayParametersReference dp = ComputeArrayParametersReference(array_parameters); f32vec2 result = SingleFocus ? f32vec2(TransmitAngle, FocusDepth) : dp.focal_vectors[acquisition]; return result; } @@ -230,7 +230,7 @@ RESULT_TYPE RCA(const vec3 world_point) RESULT_TYPE HERCULES(const vec3 world_point) { - DASArrayParametersReference dp = DASArrayParametersReference(array_parameters); + ComputeArrayParametersReference dp = ComputeArrayParametersReference(array_parameters); const uint16_t tx_rx_orientation = tx_rx_orientation_for_acquisition(int16_t(0)); const bool rx_cols = RX_ORIENTATION(tx_rx_orientation) == RCAOrientation_Columns; @@ -287,7 +287,7 @@ RESULT_TYPE FORCES(const vec3 xdc_world_point) { RESULT_TYPE result = RESULT_TYPE(0); - DASArrayParametersReference dp = DASArrayParametersReference(array_parameters); + ComputeArrayParametersReference dp = ComputeArrayParametersReference(array_parameters); float z_delta_squared = xdc_world_point.z * xdc_world_point.z; float transmit_y_delta = xdc_world_point.y - xdc_element_pitch.y * ChannelCount / 2; @@ -322,7 +322,7 @@ RESULT_TYPE READI_FORCES(const vec3 xdc_world_point) { RESULT_TYPE result = RESULT_TYPE(0); - DASArrayParametersReference dp = DASArrayParametersReference(array_parameters); + ComputeArrayParametersReference dp = ComputeArrayParametersReference(array_parameters); float z_delta_squared = xdc_world_point.z * xdc_world_point.z; float transmit_y_delta = xdc_world_point.y - xdc_element_pitch.y * ChannelCount / 2; @@ -347,7 +347,7 @@ RESULT_TYPE READI_FORCES(const vec3 xdc_world_point) // sequential elements. The first element in each group is beamformed using the first // acquisition, the second element in each group is beamformed using the second acquisition, etc. for (s32 tx_group = 0; tx_group < s32(ReadiGroupCount); tx_group++) { - f32 group_apodization = apodization * dp.hadamard_matrix[hadamard_offset + tx_group]; + f32 group_apodization = apodization * dp.das_hadamard[hadamard_offset + tx_group]; s32 rf_offset = channel_rf_offset; for (s32 tx_event = 0; tx_event < AcquisitionCount; tx_event++) {