ogl_beamforming

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

Commit: 0afdb85ac35a8c54946ce288f9ea7e76ae0a7e29
Parent: ae0fe93f0853be0a368a03f4d8682d23f09cf5c8
Author: Randy Palamar
Date:   Thu, 11 Jul 2024 23:15:31 -0600

add an extra flag after parameters to indicate new data

This is hidden from the helper's caller but visible in the main process.

Diffstat:
Mbeamformer.c | 81++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mbeamformer.h | 7+++++--
Mhelpers/ogl_beamformer_lib.c | 28+++++++++++++++++-----------
Mmain.c | 2+-
Mos_unix.c | 8++++----
Mos_win32.c | 8++++----
6 files changed, 74 insertions(+), 60 deletions(-)

diff --git a/beamformer.c b/beamformer.c @@ -4,10 +4,11 @@ static void alloc_shader_storage(BeamformerCtx *ctx, Arena a) { - uv4 rf_data_dim = ctx->params->rf_data_dim; - ctx->csctx.rf_data_dim = rf_data_dim; - size rf_raw_size = ctx->params->channel_data_stride * rf_data_dim.y * rf_data_dim.z * sizeof(i16); - size rf_decoded_size = rf_data_dim.x * rf_data_dim.y * rf_data_dim.z * sizeof(f32); + BeamformerParameters *bp = &ctx->params->raw; + uv4 rf_data_dim = bp->rf_data_dim; + ctx->csctx.rf_data_dim = rf_data_dim; + size rf_raw_size = bp->channel_data_stride * rf_data_dim.y * rf_data_dim.z * sizeof(i16); + size rf_decoded_size = rf_data_dim.x * rf_data_dim.y * rf_data_dim.z * sizeof(f32); glDeleteBuffers(ARRAY_COUNT(ctx->csctx.rf_data_ssbos), ctx->csctx.rf_data_ssbos); glGenBuffers(ARRAY_COUNT(ctx->csctx.rf_data_ssbos), ctx->csctx.rf_data_ssbos); @@ -27,6 +28,7 @@ alloc_shader_storage(BeamformerCtx *ctx, Arena a) ctx->csctx.hadamard_ssbo = rlLoadShaderBuffer(hadamard_elements * sizeof(i32), hadamard, GL_STATIC_DRAW); + ctx->out_data_dim = bp->output_points; /* NOTE: allocate storage for beamformed output data; * this is shared between compute and fragment shaders */ uv4 odim = ctx->out_data_dim; @@ -125,7 +127,7 @@ move_towards_v4(v4 current, v4 target, v4 delta) } static v4 -fmsub_v4(v4 a, v4 b, v4 scale) +scaled_sub_v4(v4 a, v4 b, v4 scale) { return (v4){ .x = scale.x * (a.x - b.x), @@ -138,6 +140,8 @@ fmsub_v4(v4 a, v4 b, v4 scale) static void draw_settings_ui(BeamformerCtx *ctx, Arena arena, f32 dt, Rect r, v2 mouse) { + BeamformerParameters *bp = &ctx->params->raw; + struct listing { char *prefix; char *suffix; @@ -145,22 +149,22 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, f32 dt, Rect r, v2 mouse) f32 data_scale; b32 editable; } listings[] = { - { "Sampling Rate:", " [MHz]", &ctx->params->sampling_frequency, 1e-6, 0 }, - { "Speed of Sound:", " [m/s]", &ctx->params->speed_of_sound, 1, 1 }, - { "Min X Point:", " [mm]", &ctx->params->output_min_xz.x, 1e3, 1 }, - { "Max X Point:", " [mm]", &ctx->params->output_max_xz.x, 1e3, 1 }, - { "Min Z Point:", " [mm]", &ctx->params->output_min_xz.y, 1e3, 1 }, - { "Max Z Point:", " [mm]", &ctx->params->output_max_xz.y, 1e3, 1 }, - { "Dynamic Range:", " [dB]", &ctx->fsctx.db, 1, 1 }, + { "Sampling Rate:", " [MHz]", &bp->sampling_frequency, 1e-6, 0 }, + { "Speed of Sound:", " [m/s]", &bp->speed_of_sound, 1, 1 }, + { "Min X Point:", " [mm]", &bp->output_min_xz.x, 1e3, 1 }, + { "Max X Point:", " [mm]", &bp->output_max_xz.x, 1e3, 1 }, + { "Min Z Point:", " [mm]", &bp->output_min_xz.y, 1e3, 1 }, + { "Max Z Point:", " [mm]", &bp->output_max_xz.y, 1e3, 1 }, + { "Dynamic Range:", " [dB]", &ctx->fsctx.db, 1, 1 }, }; struct { f32 min, max; } limits[] = { {0}, - {0, 1e6}, - {-1e3, ctx->params->output_max_xz.x - 1e-6}, - {ctx->params->output_min_xz.x + 1e-6, 1e3}, - {0, ctx->params->output_max_xz.y - 1e-6}, - {ctx->params->output_min_xz.y + 1e-6, 1e3}, + {0, 1e6}, + {-1e3, bp->output_max_xz.x - 1e-6}, + {bp->output_min_xz.x + 1e-6, 1e3}, + {0, bp->output_max_xz.y - 1e-6}, + {bp->output_min_xz.y + 1e-6, 1e3}, {-120, 0}, }; @@ -168,7 +172,7 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, f32 dt, Rect r, v2 mouse) static v4 colours[ARRAY_COUNT(listings)]; f32 scale = 6; v4 scaled_dt = (v4){.x = scale * dt, .y = scale * dt, .z = scale * dt, .w = scale * dt}; - v4 delta = fmsub_v4(ctx->fg, ctx->hovered_colour, scaled_dt); + v4 delta = scaled_sub_v4(ctx->fg, ctx->hovered_colour, scaled_dt); if (init) { for (i32 i = 0; i < ARRAY_COUNT(colours); i++) colours[i] = ctx->fg; @@ -210,7 +214,8 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, f32 dt, Rect r, v2 mouse) if (mouse_scroll) { *l->data += mouse_scroll / l->data_scale; CLAMP(*l->data, limits[i].min, limits[i].max); - ctx->flags |= UPLOAD_UBO|DO_COMPUTE; + ctx->flags |= DO_COMPUTE; + ctx->params->upload = 1; } } @@ -220,10 +225,8 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, f32 dt, Rect r, v2 mouse) else colours[i] = move_towards_v4(colours[i], ctx->fg, delta); - if (i == focused_idx) - tcol = colour_from_normalized(ctx->focused_colour); - else - tcol = colour_from_normalized(colours[i]); + if (i == focused_idx) tcol = colour_from_normalized(ctx->focused_colour); + else tcol = colour_from_normalized(colours[i]); DrawTextEx(ctx->font, (char *)txt.data, rpos.rl, ctx->font_size, ctx->font_spacing, tcol); @@ -242,7 +245,8 @@ draw_settings_ui(BeamformerCtx *ctx, Arena arena, f32 dt, Rect r, v2 mouse) *listings[focused_idx].data = new_val / listings[focused_idx].data_scale; CLAMP(*listings[focused_idx].data, limits[focused_idx].min, limits[focused_idx].max); - ctx->flags |= UPLOAD_UBO|DO_COMPUTE; + ctx->flags |= DO_COMPUTE; + ctx->params->upload = 1; } focused_idx = -1; focus_buf[0] = 0; @@ -344,10 +348,13 @@ do_beamformer(BeamformerCtx *ctx, Arena arena) ctx->window_size.w = GetScreenWidth(); } + BeamformerParameters *bp = &ctx->params->raw; /* NOTE: Check for and Load RF Data into GPU */ if (os_poll_pipe(ctx->data_pipe)) { - if (!uv4_equal(ctx->csctx.rf_data_dim, ctx->params->rf_data_dim)) + if (!uv4_equal(ctx->csctx.rf_data_dim, bp->rf_data_dim) || + !uv4_equal(ctx->out_data_dim, bp->output_points)) { alloc_shader_storage(ctx, arena); + } glBindBuffer(GL_SHADER_STORAGE_BUFFER, ctx->csctx.rf_data_ssbos[0]); void *rf_data_buf = glMapBuffer(GL_SHADER_STORAGE_BUFFER, GL_WRITE_ONLY); @@ -356,21 +363,19 @@ do_beamformer(BeamformerCtx *ctx, Arena arena) size rf_raw_size = rf_data_dim.x * rf_data_dim.y * rf_data_dim.z * sizeof(i16); size rlen = os_read_pipe_data(ctx->data_pipe, rf_data_buf, rf_raw_size); glUnmapBuffer(GL_SHADER_STORAGE_BUFFER); - if (rlen == rf_raw_size) { - ctx->flags |= DO_COMPUTE; - } else { - ctx->partial_transfer_count++; - } + + if (rlen == rf_raw_size) ctx->flags |= DO_COMPUTE; + else ctx->partial_transfer_count++; } if (ctx->flags & DO_COMPUTE) { - if (ctx->flags & UPLOAD_UBO) { + if (ctx->params->upload) { glBindBuffer(GL_UNIFORM_BUFFER, ctx->csctx.shared_ubo); void *ubo = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY); - mem_copy((s8){.data = (u8 *)ctx->params, .len = sizeof(BeamformerParameters)}, - (s8){.data = (u8 *)ubo, .len = sizeof(BeamformerParameters)}); + mem_copy((s8){.data = (u8 *)bp, .len = sizeof(*bp)}, + (s8){.data = (u8 *)ubo, .len = sizeof(*bp)}); glUnmapBuffer(GL_UNIFORM_BUFFER); - ctx->flags &= ~UPLOAD_UBO; + ctx->params->upload = 0; } do_compute_shader(ctx, CS_HADAMARD); do_compute_shader(ctx, CS_UFORCES); @@ -397,8 +402,8 @@ do_beamformer(BeamformerCtx *ctx, Arena arena) Texture *output = &ctx->fsctx.output.texture; v2 output_dim = { - .x = ctx->params->output_max_xz.x - ctx->params->output_min_xz.x, - .y = ctx->params->output_max_xz.y - ctx->params->output_min_xz.y, + .x = bp->output_max_xz.x - bp->output_min_xz.x, + .y = bp->output_max_xz.y - bp->output_min_xz.y, }; v2 line_step_mm = {.x = 3, .y = 5}; @@ -442,7 +447,7 @@ do_beamformer(BeamformerCtx *ctx, Arena arena) v2 start_pos = vr.pos; start_pos.y += vr.size.h; - f32 x_mm = ctx->params->output_min_xz.x * 1e3; + f32 x_mm = bp->output_min_xz.x * 1e3; f32 x_mm_inc = x_inc * output_dim.x * 1e3 / vr.size.w; v2 end_pos = start_pos; @@ -471,7 +476,7 @@ do_beamformer(BeamformerCtx *ctx, Arena arena) v2 start_pos = vr.pos; start_pos.x += vr.size.w; - f32 y_mm = ctx->params->output_min_xz.y * 1e3; + f32 y_mm = bp->output_min_xz.y * 1e3; f32 y_mm_inc = y_inc * output_dim.y * 1e3 / vr.size.h; v2 end_pos = start_pos; diff --git a/beamformer.h b/beamformer.h @@ -41,7 +41,6 @@ enum compute_shaders { enum program_flags { RELOAD_SHADERS = 1 << 0, DO_COMPUTE = 1 << 1, - UPLOAD_UBO = 1 << 2, }; typedef struct { @@ -69,6 +68,10 @@ typedef struct { } FragmentShaderCtx; #include "beamformer_parameters.h" +typedef struct { + BeamformerParameters raw; + b32 upload; +} BeamformerParametersFull; #if defined(__unix__) #define GL_GLEXT_PROTOTYPES 1 @@ -104,7 +107,7 @@ typedef struct { os_pipe data_pipe; u32 partial_transfer_count; - BeamformerParameters *params; + BeamformerParametersFull *params; } BeamformerCtx; #endif /*_BEAMFORMER_H_ */ diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c @@ -1,4 +1,8 @@ #include "ogl_beamformer_lib.h" +typedef struct { + BeamformerParameters raw; + b32 upload; +} BeamformerParametersFull; #if defined(__unix__) #include <fcntl.h> @@ -26,7 +30,7 @@ typedef struct { #error Unsupported Platform #endif -static volatile BeamformerParameters *g_bp; +static volatile BeamformerParametersFull *g_bp; static os_pipe g_pipe = {.file = OS_INVALID_FILE}; #if defined(__unix__) @@ -53,15 +57,15 @@ os_close_pipe(void) close(g_pipe.file); } -static BeamformerParameters * +static BeamformerParametersFull * os_open_shared_memory_area(char *name) { i32 fd = shm_open(name, O_RDWR, S_IRUSR|S_IWUSR); if (fd == -1) return NULL; - BeamformerParameters *new; - new = mmap(NULL, sizeof(BeamformerParameters), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + BeamformerParametersFull *new; + new = mmap(NULL, sizeof(*new), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (new == MAP_FAILED) @@ -93,15 +97,15 @@ os_close_pipe(void) CloseHandle(g_pipe.file); } -static BeamformerParameters * +static BeamformerParametersFull * os_open_shared_memory_area(char *name) { HANDLE h = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name); if (h == OS_INVALID_FILE) return NULL; - BeamformerParameters *new; - new = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(BeamformerParameters)); + BeamformerParametersFull *new; + new = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*new)); CloseHandle(h); return new; @@ -132,12 +136,13 @@ send_data(char *pipe_name, char *shm_name, i16 *data, uv4 data_dim) check_shared_memory(shm_name); /* TODO: this probably needs a mutex around it if we want to change it here */ - g_bp->rf_data_dim = data_dim; - size data_size = data_dim.x * data_dim.y * data_dim.z * sizeof(i16); - size written = os_write_to_pipe(g_pipe, data, data_size); + g_bp->raw.rf_data_dim = data_dim; + size data_size = data_dim.x * data_dim.y * data_dim.z * sizeof(i16); + size written = os_write_to_pipe(g_pipe, data, data_size); if (written != data_size) mexWarnMsgIdAndTxt("ogl_beamformer:write_error", "failed to write full data to pipe: wrote: %ld", written); + g_bp->upload = 1; } void @@ -148,7 +153,8 @@ set_beamformer_parameters(char *shm_name, BeamformerParameters *new_bp) if (!g_bp) return; - u8 *src = (u8 *)new_bp, *dest = (u8 *)g_bp; + u8 *src = (u8 *)new_bp, *dest = (u8 *)&g_bp->raw; for (size i = 0; i < sizeof(BeamformerParameters); i++) dest[i] = src[i]; + g_bp->upload = 1; } diff --git a/main.c b/main.c @@ -165,7 +165,7 @@ main(void) ASSERT(ctx.data_pipe.file != OS_INVALID_FILE); ASSERT(ctx.params); - ctx.params->output_points = ctx.out_data_dim; + ctx.params->raw.output_points = ctx.out_data_dim; /* NOTE: allocate space for Uniform Buffer Object but don't send anything yet */ glGenBuffers(1, &ctx.csctx.shared_ubo); diff --git a/os_unix.c b/os_unix.c @@ -102,20 +102,20 @@ os_read_pipe_data(os_pipe p, void *buf, size len) return total_read; } -static BeamformerParameters * +static BeamformerParametersFull * os_open_shared_memory_area(char *name) { i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (fd == -1) return NULL; - if (ftruncate(fd, sizeof(BeamformerParameters)) == -1) { + if (ftruncate(fd, sizeof(BeamformerParametersFull)) == -1) { close(fd); return NULL; } - BeamformerParameters *new; - new = mmap(NULL, sizeof(BeamformerParameters), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + BeamformerParametersFull *new; + new = mmap(NULL, sizeof(*new), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); if (new == MAP_FAILED) diff --git a/os_win32.c b/os_win32.c @@ -117,16 +117,16 @@ os_read_pipe_data(os_pipe p, void *buf, size len) return total_read; } -static BeamformerParameters * +static BeamformerParametersFull * os_open_shared_memory_area(char *name) { HANDLE h = CreateFileMappingA(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, - sizeof(BeamformerParameters), name); + sizeof(BeamformerParametersFull), name); if (h == INVALID_HANDLE_VALUE) return NULL; - BeamformerParameters *new; - new = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(BeamformerParameters)); + BeamformerParametersFull *new; + new = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*new)); return new; }