Commit: aa57cf8ebd7c9fae917350ccc850dc57030ddf34
Parent: 004752ed6527fcbbec1a09443e69c35aa71c9f23
Author: Randy Palamar
Date: Tue, 9 Jul 2024 15:59:06 -0600
allow rf_data_dim to be changed at runtime
Diffstat:
7 files changed, 125 insertions(+), 94 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -2,6 +2,49 @@
#include "beamformer.h"
static void
+alloc_shader_storage(BeamformerCtx *ctx, Arena a)
+{
+ uv3 rf_data_dim = ctx->params->rf_data_dim;
+ ctx->csctx.rf_data_dim = rf_data_dim;
+ size rf_raw_size = rf_data_dim.w * rf_data_dim.h * rf_data_dim.d * sizeof(i16);
+ size rf_decoded_size = rf_data_dim.w * rf_data_dim.h * rf_data_dim.d * 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);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ctx->csctx.rf_data_ssbos[0]);
+ glBufferStorage(GL_SHADER_STORAGE_BUFFER, rf_raw_size, 0,
+ GL_DYNAMIC_STORAGE_BIT|GL_MAP_WRITE_BIT);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ctx->csctx.rf_data_ssbos[1]);
+ glBufferStorage(GL_SHADER_STORAGE_BUFFER, rf_decoded_size, 0, GL_DYNAMIC_STORAGE_BIT);
+
+ /* NOTE: store hadamard in GPU once; it won't change for a particular imaging session */
+ ctx->csctx.hadamard_dim = (uv2){ .x = rf_data_dim.d, .y = rf_data_dim.d };
+ size hadamard_elements = ctx->csctx.hadamard_dim.x * ctx->csctx.hadamard_dim.y;
+ i32 *hadamard = alloc(&a, i32, hadamard_elements);
+ fill_hadamard(hadamard, ctx->csctx.hadamard_dim.x);
+
+ rlUnloadShaderBuffer(ctx->csctx.hadamard_ssbo);
+ ctx->csctx.hadamard_ssbo = rlLoadShaderBuffer(hadamard_elements * sizeof(i32), hadamard,
+ GL_STATIC_DRAW);
+
+ /* NOTE: allocate storage for beamformed output data;
+ * this is shared between compute and fragment shaders */
+ uv3 odim = ctx->out_data_dim;
+ u32 max_dim = MAX(odim.x, MAX(odim.y, odim.z));
+ /* TODO: does this actually matter or is 0 fine? */
+ ctx->out_texture_unit = 0;
+ ctx->out_texture_mips = _tzcnt_u32(max_dim) + 1;
+ glActiveTexture(GL_TEXTURE0 + ctx->out_texture_unit);
+ glDeleteTextures(1, &ctx->out_texture);
+ glGenTextures(1, &ctx->out_texture);
+ glBindTexture(GL_TEXTURE_3D, ctx->out_texture);
+ glTexStorage3D(GL_TEXTURE_3D, ctx->out_texture_mips, GL_RG32F, odim.x, odim.y, odim.z);
+
+ UnloadRenderTexture(ctx->fsctx.output);
+ ctx->fsctx.output = LoadRenderTexture(odim.w, odim.h);
+}
+
+static void
do_compute_shader(BeamformerCtx *ctx, enum compute_shaders shader)
{
ComputeShaderCtx *csctx = &ctx->csctx;
@@ -120,6 +163,9 @@ do_beamformer(BeamformerCtx *ctx, Arena arena)
/* NOTE: Check for and Load RF Data into GPU */
if (os_poll_pipe(ctx->data_pipe)) {
+ if (!uv3_equal(ctx->csctx.rf_data_dim, ctx->params->rf_data_dim))
+ 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);
ASSERT(rf_data_buf);
@@ -128,15 +174,19 @@ do_beamformer(BeamformerCtx *ctx, Arena arena)
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) {
- /* NOTE: this will skip partially read data */
- do_compute_shader(ctx, CS_HADAMARD);
- do_compute_shader(ctx, CS_UFORCES);
- do_compute_shader(ctx, CS_MIN_MAX);
+ ctx->flags |= DO_COMPUTE;
} else {
ctx->partial_transfer_count++;
}
}
+ if (ctx->flags & DO_COMPUTE) {
+ do_compute_shader(ctx, CS_HADAMARD);
+ do_compute_shader(ctx, CS_UFORCES);
+ do_compute_shader(ctx, CS_MIN_MAX);
+ ctx->flags &= ~DO_COMPUTE;
+ }
+
/* NOTE: check mouse wheel for adjusting dynamic range of image */
ctx->fsctx.db += GetMouseWheelMove();
CLAMP(ctx->fsctx.db, -120, 0);
diff --git a/beamformer.h b/beamformer.h
@@ -11,18 +11,6 @@
#include "util.h"
typedef union {
- struct { u32 x, y; };
- struct { u32 w, h; };
- u32 E[2];
-} uv2;
-
-typedef union {
- struct { u32 x, y, z; };
- struct { u32 w, h, d; };
- u32 E[3];
-} uv3;
-
-typedef union {
struct { f32 x, y; };
f32 E[2];
Vector2 rl;
@@ -46,6 +34,7 @@ enum compute_shaders {
enum program_flags {
RELOAD_SHADERS = 1 << 0,
+ DO_COMPUTE = 1 << 1,
};
typedef struct {
@@ -72,12 +61,13 @@ typedef struct {
} FragmentShaderCtx;
typedef struct {
- i16 channel_row_mapping[128];
- i16 channel_column_mapping[128];
- i16 uforces_channels[128];
+ u32 channel_row_mapping[128];
+ u32 channel_column_mapping[128];
+ u32 uforces_channels[128];
u32 channel_data_stride;
f32 speed_of_sound;
f32 sampling_frequency;
+ uv3 rf_data_dim;
uv3 output_points;
} BeamformerParameters;
diff --git a/helpers/ogl_beamformer_lib.c b/helpers/ogl_beamformer_lib.c
@@ -26,7 +26,7 @@ typedef struct {
#error Unsupported Platform
#endif
-static BeamformerParameters *bp;
+static volatile BeamformerParameters *g_bp;
static char *shm_name = "/ogl_beamformer_parameters";
static os_pipe g_pipe = {.file = OS_INVALID_FILE};
@@ -95,6 +95,17 @@ os_close_pipe(void)
}
#endif
+static void
+check_shared_memory(void)
+{
+ if (g_bp)
+ return;
+ g_bp = os_open_shared_memory_area(shm_name);
+ if (g_bp == NULL)
+ mexErrMsgIdAndTxt("ogl_beamformer:shared_memory",
+ "failed to open shared memory area");
+}
+
void
send_data(char *pipe_name, i16 *data, uv3 data_dim)
{
@@ -106,8 +117,11 @@ send_data(char *pipe_name, i16 *data, uv3 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);
+ check_shared_memory();
+ /* 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);
if (written != data_size)
mexWarnMsgIdAndTxt("ogl_beamformer:write_error",
"failed to write full data to pipe: wrote: %ld", written);
@@ -116,16 +130,8 @@ send_data(char *pipe_name, i16 *data, uv3 data_dim)
void
set_beamformer_parameters(BeamformerParameters *new_bp)
{
- if (bp == NULL) {
- bp = os_open_shared_memory_area(shm_name);
- if (bp == NULL) {
- mexErrMsgIdAndTxt("ogl_beamformer:shared_memory",
- "failed to open shared memory area");
- return;
- }
- }
-
- u8 *src = (u8 *)new_bp, *dest = (u8 *)bp;
+ check_shared_memory();
+ u8 *src = (u8 *)new_bp, *dest = (u8 *)g_bp;
for (size i = 0; i < sizeof(BeamformerParameters); i++)
dest[i] = src[i];
}
diff --git a/helpers/ogl_beamformer_lib.h b/helpers/ogl_beamformer_lib.h
@@ -23,12 +23,13 @@ typedef struct { u32 x, y, z; } uv3;
typedef struct { f32 x, y, z; } v3;
typedef struct {
- i16 channel_row_mapping[128];
- i16 channel_column_mapping[128];
- i16 uforces_channels[128];
+ u32 channel_row_mapping[128];
+ u32 channel_column_mapping[128];
+ u32 uforces_channels[128];
u32 channel_data_stride;
f32 speed_of_sound;
f32 sampling_frequency;
+ uv3 rf_data_dim;
uv3 output_points;
} BeamformerParameters;
diff --git a/main.c b/main.c
@@ -65,26 +65,6 @@ do_debug(void)
#endif /* _DEBUG */
-static void
-fill_hadamard(i32 *m, u32 dim)
-{
- ASSERT(dim && ISPOWEROF2(dim));
-
- #define IND(i, j) ((i) * dim + (j))
- m[0] = 1;
- for (u32 k = 1; k < dim; k *= 2) {
- for (u32 i = 0; i < k; i++) {
- for (u32 j = 0; j < k; j++) {
- i32 val = m[IND(i, j)];
- m[IND(i + k, j)] = val;
- m[IND(i, j + k)] = val;
- m[IND(i + k, j + k)] = -val;
- }
- }
- }
- #undef IND
-}
-
static u32
compile_shader(Arena a, u32 type, s8 shader)
{
@@ -117,28 +97,6 @@ compile_shader(Arena a, u32 type, s8 shader)
}
static void
-init_compute_shader_ctx(ComputeShaderCtx *ctx, Arena a, uv3 rf_data_dim)
-{
- ctx->rf_data_dim = rf_data_dim;
- size rf_raw_size = rf_data_dim.w * rf_data_dim.h * rf_data_dim.d * sizeof(i16);
- size rf_decoded_size = rf_data_dim.w * rf_data_dim.h * rf_data_dim.d * sizeof(i32);
-
- glGenBuffers(ARRAY_COUNT(ctx->rf_data_ssbos), ctx->rf_data_ssbos);
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, ctx->rf_data_ssbos[0]);
- glBufferStorage(GL_SHADER_STORAGE_BUFFER, rf_raw_size, 0,
- GL_DYNAMIC_STORAGE_BIT|GL_MAP_WRITE_BIT);
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, ctx->rf_data_ssbos[1]);
- glBufferStorage(GL_SHADER_STORAGE_BUFFER, rf_decoded_size, 0, GL_DYNAMIC_STORAGE_BIT);
-
- /* NOTE: store hadamard in GPU once; it won't change for a particular imaging session */
- ctx->hadamard_dim = (uv2){ .x = rf_data_dim.d, .y = rf_data_dim.d };
- size hadamard_elements = ctx->hadamard_dim.x * ctx->hadamard_dim.y;
- i32 *hadamard = alloc(&a, i32, hadamard_elements);
- fill_hadamard(hadamard, ctx->hadamard_dim.x);
- ctx->hadamard_ssbo = rlLoadShaderBuffer(hadamard_elements * sizeof(i32), hadamard, GL_STATIC_DRAW);
-}
-
-static void
init_fragment_shader_ctx(FragmentShaderCtx *ctx, uv3 out_data_dim)
{
ctx->output = LoadRenderTexture(out_data_dim.w, out_data_dim.h);
@@ -158,6 +116,7 @@ reload_shaders(BeamformerCtx *ctx, Arena a)
if (shader_id) {
glDeleteProgram(csctx->programs[i]);
csctx->programs[i] = rlLoadComputeShaderProgram(shader_id);
+ ctx->flags |= DO_COMPUTE;
}
glDeleteShader(shader_id);
@@ -184,8 +143,8 @@ main(void)
Arena temp_memory = os_new_arena(256 * MEGABYTE);
- ctx.window_size = (uv2){.w = 2048, .h = 2048};
- ctx.out_data_dim = (uv3){.w = 2048, .h = 2048, .d = 1};
+ ctx.window_size = (uv2){.w = 1024, .h = 1024};
+ ctx.out_data_dim = (uv3){.w = 256, .h = 1024, .d = 1};
ctx.bg = PINK;
ctx.fg = (Color){ .r = 0xea, .g = 0xe1, .b = 0xb4, .a = 0xff };
@@ -195,21 +154,6 @@ main(void)
ctx.font = GetFontDefault();
- /* NOTE: allocate storage for beamformed output data;
- * this is shared between compute and fragment shaders */
- {
- uv3 odim = ctx.out_data_dim;
- u32 max_dim = MAX(odim.x, MAX(odim.y, odim.z));
- /* TODO: does this actually matter or is 0 fine? */
- ctx.out_texture_unit = 0;
- ctx.out_texture_mips = _tzcnt_u32(max_dim) + 1;
- glActiveTexture(GL_TEXTURE0 + ctx.out_texture_unit);
- glGenTextures(1, &ctx.out_texture);
- glBindTexture(GL_TEXTURE_3D, ctx.out_texture);
- glTexStorage3D(GL_TEXTURE_3D, ctx.out_texture_mips, GL_RG32F, odim.x, odim.y, odim.z);
- }
-
- init_compute_shader_ctx(&ctx.csctx, temp_memory, (uv3){.w = 3456, .h = 128, .d = 8});
init_fragment_shader_ctx(&ctx.fsctx, ctx.out_data_dim);
ctx.data_pipe = os_open_named_pipe("/tmp/beamformer_data_fifo");
@@ -218,6 +162,8 @@ main(void)
ASSERT(ctx.data_pipe.file != OS_INVALID_FILE);
ASSERT(ctx.params);
+ ctx.params->output_points = ctx.out_data_dim;
+
ctx.flags |= RELOAD_SHADERS;
while(!WindowShouldClose()) {
diff --git a/util.c b/util.c
@@ -44,3 +44,29 @@ s8alloc(Arena *a, size len)
{
return (s8){ .data = alloc(a, u8, len), .len = len };
}
+
+static b32
+uv3_equal(uv3 a, uv3 b)
+{
+ return a.x == b.x && a.y == b.y && a.z == b.z;
+}
+
+static void
+fill_hadamard(i32 *m, u32 dim)
+{
+ ASSERT(dim && ISPOWEROF2(dim));
+
+ #define IND(i, j) ((i) * dim + (j))
+ m[0] = 1;
+ for (u32 k = 1; k < dim; k *= 2) {
+ for (u32 i = 0; i < k; i++) {
+ for (u32 j = 0; j < k; j++) {
+ i32 val = m[IND(i, j)];
+ m[IND(i + k, j)] = val;
+ m[IND(i, j + k)] = val;
+ m[IND(i + k, j + k)] = -val;
+ }
+ }
+ }
+ #undef IND
+}
diff --git a/util.h b/util.h
@@ -37,6 +37,18 @@ typedef struct { u8 *beg, *end; } Arena;
typedef struct { size len; u8 *data; } s8;
+typedef union {
+ struct { u32 x, y; };
+ struct { u32 w, h; };
+ u32 E[2];
+} uv2;
+
+typedef union {
+ struct { u32 x, y, z; };
+ struct { u32 w, h, d; };
+ u32 E[3];
+} uv3;
+
#include "util.c"
#endif /* _UTIL_H_ */