Commit: bb06bbeb3f69a70b1d7d59da62a9dbefd31f0ece
Parent: 7fc08ca46a917eaf6fb3cb77b97ed36b0514bcf3
Author: Randy Palamar
Date: Tue, 2 Jul 2024 13:34:46 -0600
read rf data from a pipe; only compute on new data
Diffstat:
M | beamformer.c | | | 63 | +++++++++++++++++++++++++++++++++------------------------------ |
M | build.sh | | | 2 | +- |
M | main.c | | | 24 | +++++++++++++++--------- |
M | os_unix.c | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
M | util.h | | | 46 | ++++++++++++++++++++-------------------------- |
5 files changed, 111 insertions(+), 66 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -7,7 +7,7 @@
#include "util.h"
static void
-do_compute_shader(BeamformerCtx *ctx, u32 rf_ssbo_idx, enum compute_shaders shader)
+do_compute_shader(BeamformerCtx *ctx, enum compute_shaders shader)
{
ComputeShaderCtx *csctx = &ctx->csctx;
glUseProgram(csctx->programs[shader]);
@@ -17,7 +17,8 @@ do_compute_shader(BeamformerCtx *ctx, u32 rf_ssbo_idx, enum compute_shaders shad
GL_WRITE_ONLY, GL_RG32F);
glUniform1i(csctx->out_data_tex_id, ctx->out_texture_unit);
- u32 decoded_ssbo_idx = 2;
+ u32 rf_ssbo_idx = 0;
+ u32 decoded_ssbo_idx = 1;
switch (shader) {
case CS_HADAMARD:
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, csctx->rf_data_ssbos[rf_ssbo_idx]);
@@ -61,29 +62,29 @@ draw_debug_overlay(BeamformerCtx *ctx, Arena arena, f32 dt)
u32 fontsize = 32;
u32 fontspace = 1;
+ s8 partial_txt = s8alloc(&arena, 64);
s8 db_txt = s8alloc(&arena, 64);
- s8 compute_txt = s8alloc(&arena, 64);
+ snprintf((char *)partial_txt.data, partial_txt.len, "Partial Transfers: %u", ctx->partial_transfer_count);
snprintf((char *)db_txt.data, db_txt.len, "Dynamic Range: %0.01f [db]", ctx->fsctx.db);
- snprintf((char *)compute_txt.data, compute_txt.len, "Compute: %d", !!(ctx->flags & DO_COMPUTE));
+ v2 partial_fs = {.rl = MeasureTextEx(ctx->font, (char *)partial_txt.data, fontsize, fontspace)};
v2 db_fs = {.rl = MeasureTextEx(ctx->font, (char *)db_txt.data, fontsize, fontspace)};
- v2 compute_fs = {.rl = MeasureTextEx(ctx->font, (char *)compute_txt.data, fontsize, fontspace)};
- v2 scale = {.x = 90, .y = 20 };
+ v2 scale = {.x = 90, .y = 20};
+ v2 pos = {.x = 20, .y = ws.h - db_fs.y - partial_fs.y - 20};
/* NOTE: Dynamic Range */
{
- v2 dpos = {.x = 20, .y = ws.h - db_fs.y - compute_fs.y - 20};
- v2 dposa = {.x = dpos.x + db_fs.x / scale.x, .y = dpos.y + db_fs.y / scale.y };
+ v2 dposa = {.x = pos.x + db_fs.x / scale.x, .y = pos.y + db_fs.y / scale.y };
DrawTextEx(ctx->font, (char *)db_txt.data, dposa.rl, fontsize, fontspace, Fade(BLACK, 0.8));
- DrawTextEx(ctx->font, (char *)db_txt.data, dpos.rl, fontsize, fontspace, RED);
+ DrawTextEx(ctx->font, (char *)db_txt.data, pos.rl, fontsize, fontspace, RED);
+ pos.y += db_fs.y;
}
-
- /* NOTE: Compute Status */
+ /* NOTE: Partial Tranfers */
{
- v2 dpos = {.x = 20, .y = ws.h - compute_fs.y - 20};
- v2 dposa = {.x = dpos.x + compute_fs.x / scale.x, .y = dpos.y + compute_fs.y / scale.y };
- DrawTextEx(ctx->font, (char *)compute_txt.data, dposa.rl, fontsize, fontspace, Fade(BLACK, 0.8));
- DrawTextEx(ctx->font, (char *)compute_txt.data, dpos.rl, fontsize, fontspace, RED);
+ v2 dposa = {.x = pos.x + partial_fs.x / scale.x, .y = pos.y + partial_fs.y / scale.y };
+ DrawTextEx(ctx->font, (char *)partial_txt.data, dposa.rl, fontsize, fontspace, Fade(BLACK, 0.8));
+ DrawTextEx(ctx->font, (char *)partial_txt.data, pos.rl, fontsize, fontspace, RED);
+ pos.y += partial_fs.y;
}
{
@@ -122,19 +123,23 @@ do_beamformer(BeamformerCtx *ctx, Arena arena, s8 rf_data)
{
f32 dt = GetFrameTime();
- /* NOTE: grab operating idx and swap it; other buffer can now be used for storage */
- u32 rf_ssbo_idx = atomic_fetch_xor_explicit(&ctx->csctx.rf_data_idx, 1, memory_order_relaxed);
- ASSERT(rf_ssbo_idx == 0 || rf_ssbo_idx == 1);
-
- /* NOTE: Load RF Data into GPU */
- /* TODO: This should be done in a separate thread */
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, ctx->csctx.rf_data_ssbos[!rf_ssbo_idx]);
- glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, rf_data.len, rf_data.data);
-
- if (ctx->flags & DO_COMPUTE) {
- do_compute_shader(ctx, rf_ssbo_idx, CS_HADAMARD);
- do_compute_shader(ctx, rf_ssbo_idx, CS_UFORCES);
- do_compute_shader(ctx, rf_ssbo_idx, CS_MIN_MAX);
+ /* NOTE: Check for and Load RF Data into GPU */
+ if (os_poll_pipe(ctx->data_pipe)) {
+ 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);
+ uv3 rf_data_dim = ctx->csctx.rf_data_dim;
+ size rf_raw_size = rf_data_dim.w * rf_data_dim.h * rf_data_dim.d * sizeof(i32);
+ 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);
+ } else {
+ ctx->partial_transfer_count++;
+ }
}
/* NOTE: check mouse wheel for adjusting dynamic range of image */
@@ -167,6 +172,4 @@ do_beamformer(BeamformerCtx *ctx, Arena arena, s8 rf_data)
if (IsKeyPressed(KEY_R))
ctx->flags |= RELOAD_SHADERS;
- if (IsKeyPressed(KEY_SPACE))
- ctx->flags ^= DO_COMPUTE;
}
diff --git a/build.sh b/build.sh
@@ -11,7 +11,7 @@ case "$1" in
ldflags="$ldflags -lGL"
# Hot Reloading/Debugging
- cflags="$cflags -D_DEBUG"
+ cflags="$cflags -D_DEBUG -Wno-unused-function"
libcflags="$cflags -fPIC -flto -Wno-unused-function"
libldflags="$ldflags -shared"
diff --git a/main.c b/main.c
@@ -125,17 +125,16 @@ static void
init_compute_shader_ctx(ComputeShaderCtx *ctx, Arena a, uv3 rf_data_dim)
{
ctx->rf_data_dim = rf_data_dim;
- size rf_data_size = rf_data_dim.w * rf_data_dim.h * rf_data_dim.d * sizeof(i32);
+ /* TODO: send i16 data and convert to i32 on GPU */
+ size rf_raw_size = rf_data_dim.w * rf_data_dim.h * rf_data_dim.d * sizeof(i32);
+ 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);
- for (u32 i = 0; i < ARRAY_COUNT(ctx->rf_data_ssbos); i++) {
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, ctx->rf_data_ssbos[i]);
- glBufferData(GL_SHADER_STORAGE_BUFFER, rf_data_size, 0, GL_DYNAMIC_COPY);
- /* TODO: This doesn't actually work; need to use
- * a texture to store i16 data and load i32 data */
- glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R32I, GL_R16I, GL_SHORT, 0);
- }
- ctx->rf_data_idx = 0;
+ 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 };
@@ -223,6 +222,10 @@ main(void)
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");
+ /* TODO: properly handle this? */
+ ASSERT(ctx.data_pipe.file != OS_INVALID_FILE);
+
ctx.flags |= RELOAD_SHADERS;
while(!WindowShouldClose()) {
@@ -235,4 +238,7 @@ main(void)
do_beamformer(&ctx, temp_memory, raw_rf_data);
}
+
+ /* NOTE: garbage code needed for Linux */
+ os_close_named_pipe(ctx.data_pipe);
}
diff --git a/os_unix.c b/os_unix.c
@@ -1,8 +1,16 @@
#include <fcntl.h>
+#include <poll.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
+#define OS_INVALID_FILE (-1)
+typedef i32 os_file;
+typedef struct {
+ os_file file;
+ char *name;
+} os_pipe;
+
typedef struct timespec os_filetime;
typedef struct {
@@ -59,3 +67,37 @@ os_get_file_stats(char *fname)
.timestamp = st.st_mtim,
};
}
+
+static os_pipe
+os_open_named_pipe(char *name)
+{
+ mkfifo(name, 0660);
+ return (os_pipe){.file = open(name, O_RDONLY|O_NONBLOCK), .name = name};
+}
+
+static void
+os_close_named_pipe(os_pipe p)
+{
+ close(p.file);
+ unlink(p.name);
+}
+
+static b32
+os_poll_pipe(os_pipe p)
+{
+ struct pollfd pfd = {.fd = p.file, .events = POLLIN};
+ poll(&pfd, 1, 0);
+ return !!(pfd.revents & POLLIN);
+}
+
+static size
+os_read_pipe_data(os_pipe p, void *buf, size len)
+{
+ size r = 0, total_read = 0;
+ do {
+ if (r != -1)
+ total_read += r;
+ r = read(p.file, buf + total_read, len - total_read);
+ } while (r);
+ return total_read;
+}
diff --git a/util.h b/util.h
@@ -2,7 +2,6 @@
#ifndef _UTIL_H_
#define _UTIL_H_
-#include <stdatomic.h>
#include <stddef.h>
#include <stdint.h>
@@ -63,22 +62,28 @@ enum compute_shaders {
enum program_flags {
RELOAD_SHADERS = 1 << 0,
- DO_COMPUTE = 1 << 1,
};
+#include "util.c"
+#if defined(__unix__)
+#define GL_GLEXT_PROTOTYPES 1
+#include <GL/glcorearb.h>
+#include <GL/glext.h>
+#include "os_unix.c"
+#elif defined(_WIN32)
+#include <glad.h>
+#include "os_win32.c"
+#else
+#error Unsupported Platform!
+#endif
+
typedef struct {
u32 programs[CS_LAST];
- /* NOTE: need 3 storage buffers: incoming rf, currently decoding rf, decoded.
- * last buffer will always be for decoded data. other two will swap everytime there
- * is new data. current operating idx is stored in rf_data_idx (0 or 1) which needs
- * to be accessed atomically
- */
- u32 rf_data_ssbos[3];
- _Atomic u32 rf_data_idx;
-
- u32 hadamard_ssbo;
- uv2 hadamard_dim;
+ /* NOTE: One SSBO for raw data and one for decoded data */
+ u32 rf_data_ssbos[2];
+ u32 hadamard_ssbo;
+ uv2 hadamard_dim;
uv3 rf_data_dim;
i32 rf_data_dim_id;
@@ -110,6 +115,9 @@ typedef struct {
ComputeShaderCtx csctx;
FragmentShaderCtx fsctx;
+
+ os_pipe data_pipe;
+ u32 partial_transfer_count;
} BeamformerCtx;
#define MEGABYTE (1024ULL * 1024ULL)
@@ -123,18 +131,4 @@ typedef struct {
#define CLAMP(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x))
#define ISPOWEROF2(a) (((a) & ((a) - 1)) == 0)
-#include "util.c"
-
-#if defined(__unix__)
-#define GL_GLEXT_PROTOTYPES 1
-#include <GL/glcorearb.h>
-#include <GL/glext.h>
-#include "os_unix.c"
-#elif defined(_WIN32)
-#include <glad.h>
-#include "os_win32.c"
-#else
-#error Unsupported Platform!
-#endif
-
#endif /*_UTIL_H_ */