ogl_beamforming

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

Commit: 00d479ed264a3adc3a2de2297b13f3df200c191b
Parent: 7e351ca34f89675e39ee52a4d516a87c1bb17e15
Author: Randy Palamar
Date:   Sun,  6 Apr 2025 14:03:02 -0600

core/lib: upload focal vectors as a 1D RG32F texture

Diffstat:
Mbeamformer.c | 13+++++++++++++
Mbeamformer.h | 1+
Mbeamformer_parameters.h | 4+---
Mbeamformer_work_queue.h | 10++++++----
Mhelpers/ogl_beamformer_lib.c | 24+++++++++++++++++++++++-
Mhelpers/ogl_beamformer_lib.h | 1+
Mshaders/das.glsl | 14++++++--------
Mstatic.c | 1+
8 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -348,6 +348,7 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformComputeFrame *frame, glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, csctx->rf_data_ssbos[input_ssbo_idx]); glBindImageTexture(0, frame->frame.texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RG32F); glBindImageTexture(1, csctx->sparse_elements_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R16I); + glBindImageTexture(2, csctx->focal_vectors_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RG32F); #if 1 /* TODO(rnp): compute max_points_per_dispatch based on something like a @@ -594,6 +595,18 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co ARRAY_COUNT(sm->channel_mapping), GL_RED_INTEGER, GL_SHORT, sm->channel_mapping); } break; + case BW_UPLOAD_FOCAL_VECTORS: { + ASSERT(!atomic_load(&ctx->shared_memory->focal_vectors_sync)); + if (!cs->focal_vectors_texture) { + glCreateTextures(GL_TEXTURE_1D, 1, &cs->focal_vectors_texture); + glTextureStorage1D(cs->focal_vectors_texture, 1, GL_RG32F, + ARRAY_COUNT(sm->focal_vectors)); + LABEL_GL_OBJECT(GL_TEXTURE, cs->focal_vectors_texture, s8("Focal_Vectors")); + } + glTextureSubImage1D(cs->focal_vectors_texture, 0, 0, + ARRAY_COUNT(sm->focal_vectors), GL_RG, + GL_FLOAT, sm->focal_vectors); + } break; case BW_UPLOAD_RF_DATA: { ASSERT(!atomic_load(&ctx->shared_memory->raw_data_sync)); diff --git a/beamformer.h b/beamformer.h @@ -88,6 +88,7 @@ typedef struct { u32 channel_mapping_texture; u32 sparse_elements_texture; + u32 focal_vectors_texture; f32 processing_progress; b32 processing_compute; diff --git a/beamformer_parameters.h b/beamformer_parameters.h @@ -58,7 +58,7 @@ typedef enum { X(channel_mapping, u16, [256], uvec4, [32], "/* Transducer Channel to Verasonics Channel */") \ X(uforces_channels, u16, [256], uvec4, [32], "/* Channels used for virtual UFORCES elements */") \ X(focal_depths, f32, [256], vec4, [64], "/* [m] Focal Depths for each transmit of a RCA imaging scheme*/") \ - X(transmit_angles, f32, [256], vec4, [64], "/* [radians] Transmit Angles for each transmit of a RCA imaging scheme*/") \ + X(transmit_angles, f32, [256], vec4, [64], "/* [degrees] Transmit Angles for each transmit of a RCA imaging scheme*/") \ X(xdc_transform, f32, [16] , mat4, , "/* IMPORTANT: column major order */") \ X(dec_data_dim, uv4, , uvec4, , "/* Samples * Channels * Acquisitions; last element ignored */") \ X(xdc_element_pitch, f32, [2] , vec2, , "/* [m] Transducer Element Pitch {row, col} */") \ @@ -69,8 +69,6 @@ typedef enum { X(time_offset, f32, , float, , "/* pulse length correction time [s] */") #define BEAMFORMER_PARAMS_HEAD \ - X(focal_depths, f32, [256], vec4, [64], "/* [m] Focal Depths for each transmit of a RCA imaging scheme*/") \ - X(transmit_angles, f32, [256], vec4, [64], "/* [radians] Transmit Angles for each transmit of a RCA imaging scheme*/") \ X(xdc_transform, f32, [16] , mat4, , "/* IMPORTANT: column major order */") \ X(dec_data_dim, uv4, , uvec4, , "/* Samples * Channels * Acquisitions; last element ignored */") \ X(xdc_element_pitch, f32, [2] , vec2, , "/* [m] Transducer Element Pitch {row, col} */") \ diff --git a/beamformer_work_queue.h b/beamformer_work_queue.h @@ -70,15 +70,17 @@ typedef struct { b32 start_compute; b32 export_next_frame; - /* TODO(rnp): probably remove this */ - c8 export_pipe_name[256]; - i32 channel_mapping_sync; i32 sparse_elements_sync; + i32 focal_vectors_sync; + + /* TODO(rnp): probably remove this */ + c8 export_pipe_name[256]; i16 channel_mapping[256]; i16 sparse_elements[256]; - v2 transmit_angles_focal_depths[256]; + /* NOTE(rnp): interleaved transmit angle, focal depth pairs */ + v2 focal_vectors[256]; BeamformWorkQueue external_work_queue; } BeamformerSharedMemory; diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c @@ -305,6 +305,23 @@ beamformer_push_sparse_elements(char *shm_name, i16 *elements, u32 count, i32 ti } b32 +beamformer_push_focal_vectors(char *shm_name, f32 *vectors, u32 count, i32 timeout_ms) +{ + b32 result = check_shared_memory(shm_name) && count <= ARRAY_COUNT(g_bp->focal_vectors); + if (result) { + BeamformWork *work = beamform_work_queue_push(&g_bp->external_work_queue); + result = work && try_wait_sync(&g_bp->focal_vectors_sync, timeout_ms); + if (result) { + work->type = BW_UPLOAD_FOCAL_VECTORS; + work->completion_barrier = offsetof(BeamformerSharedMemory, focal_vectors_sync); + mem_copy(g_bp->focal_vectors, vectors, count * sizeof(*g_bp->focal_vectors)); + beamform_work_queue_push_commit(&g_bp->external_work_queue); + } + } + return result; +} + +b32 set_beamformer_parameters(char *shm_name, BeamformerParametersV0 *new_bp) { b32 result = 0; @@ -312,8 +329,13 @@ set_beamformer_parameters(char *shm_name, BeamformerParametersV0 *new_bp) ARRAY_COUNT(new_bp->channel_mapping), 0); result |= beamformer_push_sparse_elements(shm_name, (i16 *)new_bp->uforces_channels, ARRAY_COUNT(new_bp->uforces_channels), 0); + v2 focal_vectors[256]; + for (u32 i = 0; i < ARRAY_COUNT(focal_vectors); i++) + focal_vectors[i] = (v2){{new_bp->transmit_angles[i], new_bp->focal_depths[i]}}; + result |= beamformer_push_focal_vectors(shm_name, (f32 *)focal_vectors, ARRAY_COUNT(focal_vectors), 0); + if (result) { - mem_copy(&g_bp->raw, &new_bp->focal_depths, sizeof(g_bp->raw)); + mem_copy(&g_bp->raw, &new_bp->xdc_transform, sizeof(g_bp->raw)); g_bp->upload = 1; } diff --git a/helpers/ogl_beamformer_lib.h b/helpers/ogl_beamformer_lib.h @@ -35,3 +35,4 @@ LIB_FN b32 beamform_data_synchronized(char *pipe_name, char *shm_name, void *dat 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/shaders/das.glsl b/shaders/das.glsl @@ -5,6 +5,7 @@ layout(std430, binding = 1) readonly restrict buffer buffer_1 { layout(rg32f, binding = 0) writeonly restrict uniform image3D u_out_data_tex; layout(r16i, binding = 1) readonly restrict uniform iimage1D sparse_elements; +layout(rg32f, binding = 2) readonly restrict uniform image1D focal_vectors; layout(location = 2) uniform ivec3 u_voxel_offset; layout(location = 3) uniform uint u_cycle_t; @@ -123,12 +124,9 @@ vec2 RCA(vec3 image_point, vec3 delta, float apodization_arg) vec2 sum = vec2(0); /* NOTE: For Each Acquistion in Raw Data */ // uint i = (dec_data_dim.z - 1) * uint(clamp(u_cycle_t, 0, 1)); { - for (uint i = 0; i < dec_data_dim.z; i++) { - uint base_idx = i / 4; - uint sub_idx = i % 4; - - float focal_depth = focal_depths[base_idx][sub_idx]; - float transmit_angle = radians(transmit_angles[base_idx][sub_idx]); + for (int i = 0; i < dec_data_dim.z; i++) { + float transmit_angle = radians(imageLoad(focal_vectors, i).x); + float focal_depth = imageLoad(focal_vectors, i).y; float transmit_distance; if (isinf(focal_depth)) { @@ -163,8 +161,8 @@ vec2 HERCULES(vec3 image_point, vec3 delta, float apodization_arg) bool tx_col = TX_MODE_TX_COLS(transmit_mode); bool rx_col = TX_MODE_RX_COLS(transmit_mode); - float focal_depth = focal_depths[0][0]; - float transmit_angle = radians(transmit_angles[0][0]); + float transmit_angle = radians(imageLoad(focal_vectors, 0).x); + float focal_depth = imageLoad(focal_vectors, 0).y; vec3 receive_point = (xdc_transform * vec4(image_point, 1)).xyz; diff --git a/static.c b/static.c @@ -309,6 +309,7 @@ setup_beamformer(BeamformerCtx *ctx, Arena *memory) ctx->shared_memory->raw_data_sync = 1; ctx->shared_memory->channel_mapping_sync = 1; ctx->shared_memory->sparse_elements_sync = 1; + ctx->shared_memory->focal_vectors_sync = 1; /* NOTE: default compute shader pipeline */ ctx->shared_memory->compute_stages[0] = CS_DECODE;