Commit: 7878beab76e8e83d59f6cd2655186dc5fda0144f
Parent: e8e91267bc6f03da7de75be806398303b151eff5
Author: Randy Palamar
Date: Thu, 23 Jan 2025 21:26:38 -0700
core: delete all multi transducer handling code
This will be reintroduced later by using a seperate UBO for each
transducer. Not only will this be more general, but it also
significantly simplifies the code. The only thing necessary
besides providing an api for submitting multiple UBOs is adding a
UBO field to the beamform compute work items.
The code is now limited to handling a maximum of 256 transmit
events for a single transducer. This should be more than
suffiecent for any arrays we manufacture in the lab.
Diffstat:
6 files changed, 73 insertions(+), 103 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -12,14 +12,13 @@ decoded_data_size(ComputeShaderCtx *cs)
return result;
}
-static uv4
-make_valid_test_dim(uv4 in)
+static uv3
+make_valid_test_dim(uv3 in)
{
- uv4 result;
+ uv3 result;
result.x = MAX(in.x, 1);
result.y = MAX(in.y, 1);
result.z = MAX(in.z, 1);
- result.w = 1;
return result;
}
@@ -47,47 +46,40 @@ frame_next(BeamformFrameIterator *bfi)
}
static void
-alloc_beamform_frame(GLParams *gp, BeamformFrame *out, uv4 out_dim, u32 frame_index, s8 name)
+alloc_beamform_frame(GLParams *gp, BeamformFrame *out, uv3 out_dim, u32 frame_index, s8 name)
{
- glDeleteTextures(out->dim.w, out->textures);
+ glDeleteTextures(1, &out->texture);
out->dim.x = CLAMP(round_down_power_of_2(ORONE(out_dim.x)), 1, gp->max_3d_texture_dim);
out->dim.y = CLAMP(round_down_power_of_2(ORONE(out_dim.y)), 1, gp->max_3d_texture_dim);
out->dim.z = CLAMP(round_down_power_of_2(ORONE(out_dim.z)), 1, gp->max_3d_texture_dim);
- out->dim.w = CLAMP(out_dim.w, 0, MAX_MULTI_XDC_COUNT);
/* NOTE: allocate storage for beamformed output data;
* this is shared between compute and fragment shaders */
u32 max_dim = MAX(out->dim.x, MAX(out->dim.y, out->dim.z));
out->mips = ctz_u32(max_dim) + 1;
+ /* TODO(rnp): arena?? */
u8 buf[256];
Stream label = {.data = buf, .cap = ARRAY_COUNT(buf)};
stream_append_s8(&label, name);
stream_append_byte(&label, '[');
stream_append_u64(&label, frame_index);
- stream_append_s8(&label, s8("]["));
- u32 sidx = label.widx;
+ stream_append_s8(&label, s8("]"));
- glCreateTextures(GL_TEXTURE_3D, out->dim.w, out->textures);
- for (u32 i = 0; i < out->dim.w; i++) {
- glTextureStorage3D(out->textures[i], out->mips, GL_RG32F,
- out->dim.x, out->dim.y, out->dim.z);
- stream_append_u64(&label, i);
- stream_append_byte(&label, ']');
- LABEL_GL_OBJECT(GL_TEXTURE, out->textures[i], stream_to_s8(&label));
- label.widx = sidx;
- }
+ glCreateTextures(GL_TEXTURE_3D, 1, &out->texture);
+ glTextureStorage3D(out->texture, out->mips, GL_RG32F, out->dim.x, out->dim.y, out->dim.z);
+ LABEL_GL_OBJECT(GL_TEXTURE, out->texture, stream_to_s8(&label));
}
static void
-alloc_output_image(BeamformerCtx *ctx, uv4 output_dim)
+alloc_output_image(BeamformerCtx *ctx, uv3 output_dim)
{
- uv4 try_dim = make_valid_test_dim(output_dim);
- if (!uv4_equal(try_dim, ctx->averaged_frame.dim)) {
+ uv3 try_dim = make_valid_test_dim(output_dim);
+ if (!uv3_equal(try_dim, ctx->averaged_frame.dim)) {
alloc_beamform_frame(&ctx->gl, &ctx->averaged_frame, try_dim, 0,
s8("Beamformed_Averaged_Data"));
- uv4 odim = ctx->averaged_frame.dim;
+ uv3 odim = ctx->averaged_frame.dim;
UnloadRenderTexture(ctx->fsctx.output);
/* TODO: select odim.x vs odim.y */
@@ -264,9 +256,8 @@ beamform_work_queue_push(BeamformerCtx *ctx, Arena *a, enum beamform_work work_t
BeamformFrameIterator bfi = beamform_frame_iterator(ctx);
for (BeamformFrame *frame = frame_next(&bfi); frame; frame = frame_next(&bfi)) {
- uv4 try_dim = ctx->params->raw.output_points;
- try_dim.w = ctx->params->raw.xdc_count;
- if (!uv4_equal(frame->dim, try_dim)) {
+ uv3 try_dim = ctx->params->raw.output_points.xyz;
+ if (!uv3_equal(frame->dim, try_dim)) {
u32 index = (bfi.offset - bfi.cursor) % bfi.capacity;
alloc_beamform_frame(&ctx->gl, frame, try_dim, index,
s8("Beamformed_Data"));
@@ -293,11 +284,10 @@ beamform_work_queue_push(BeamformerCtx *ctx, Arena *a, enum beamform_work work_t
static void
export_frame(BeamformerCtx *ctx, iptr handle, BeamformFrame *frame)
{
- uv3 dim = frame->dim.xyz;
+ uv3 dim = frame->dim;
size out_size = dim.x * dim.y * dim.z * 2 * sizeof(f32);
ctx->export_buffer = ctx->platform.alloc_arena(ctx->export_buffer, out_size);
- u32 texture = frame->textures[frame->dim.w - 1];
- glGetTextureImage(texture, 0, GL_RG, GL_FLOAT, out_size, ctx->export_buffer.beg);
+ glGetTextureImage(frame->texture, 0, GL_RG, GL_FLOAT, out_size, ctx->export_buffer.beg);
s8 raw = {.len = out_size, .data = ctx->export_buffer.beg};
if (!ctx->platform.write_file(handle, raw))
TraceLog(LOG_WARNING, "failed to export frame\n");
@@ -306,7 +296,7 @@ export_frame(BeamformerCtx *ctx, iptr handle, BeamformFrame *frame)
static void
do_sum_shader(ComputeShaderCtx *cs, u32 *in_textures, u32 in_texture_count, f32 in_scale,
- u32 out_texture, uv4 out_data_dim)
+ u32 out_texture, uv3 out_data_dim)
{
/* NOTE: zero output before summing */
glClearTexImage(out_texture, 0, GL_RED, GL_FLOAT, 0);
@@ -330,14 +320,10 @@ do_beamform_shader(ComputeShaderCtx *cs, BeamformerParameters *bp, BeamformFrame
glUniform3iv(cs->volume_export_dim_offset_id, 1, compute_dim_offset.E);
glUniform1i(cs->volume_export_pass_id, compute_pass);
- for (u32 i = 0; i < frame->dim.w; i++) {
- u32 texture = frame->textures[i];
- glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RG32F);
- glUniform1i(cs->xdc_index_id, i);
- glDispatchCompute(ORONE(dispatch_dim.x / 32),
- ORONE(dispatch_dim.y),
- ORONE(dispatch_dim.z / 32));
- }
+ glBindImageTexture(0, frame->texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RG32F);
+ glDispatchCompute(ORONE(dispatch_dim.x / 32),
+ ORONE(dispatch_dim.y),
+ ORONE(dispatch_dim.z / 32));
}
static b32
@@ -427,7 +413,7 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformFrame *frame, u32 raw
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
break;
case CS_MIN_MAX: {
- u32 texture = frame->textures[frame->dim.w - 1];
+ u32 texture = frame->texture;
for (u32 i = 1; i < frame->mips; i++) {
glBindImageTexture(0, texture, i - 1, GL_TRUE, 0, GL_READ_ONLY, GL_RG32F);
glBindImageTexture(1, texture, i - 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RG32F);
@@ -444,24 +430,15 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformFrame *frame, u32 raw
u32 rf_ssbo = csctx->rf_data_ssbos[input_ssbo_idx];
iv3 dispatch_dim = {.x = frame->dim.x, .y = frame->dim.y, .z = frame->dim.z};
do_beamform_shader(csctx, &ctx->params->raw, frame, rf_ssbo, dispatch_dim, (iv3){0}, 0);
- if (frame->dim.w > 1) {
- glUseProgram(csctx->programs[CS_SUM]);
- u32 input_texture_count = frame->dim.w - 1;
- do_sum_shader(csctx, frame->textures, input_texture_count,
- 1 / (f32)input_texture_count, frame->textures[frame->dim.w - 1],
- frame->dim);
- }
} break;
case CS_SUM: {
u32 frame_count = 0;
u32 *in_textures = alloc(&arena, u32, MAX_BEAMFORMED_SAVED_FRAMES);
BeamformFrameIterator bfi = beamform_frame_iterator(ctx);
- for (BeamformFrame *frame = frame_next(&bfi); frame; frame = frame_next(&bfi)) {
- ASSERT(frame->dim.w);
- in_textures[frame_count++] = frame->textures[frame->dim.w - 1];
- }
+ for (BeamformFrame *frame = frame_next(&bfi); frame; frame = frame_next(&bfi))
+ in_textures[frame_count++] = frame->texture;
do_sum_shader(csctx, in_textures, frame_count, 1 / (f32)frame_count,
- ctx->averaged_frame.textures[0], ctx->averaged_frame.dim);
+ ctx->averaged_frame.texture, ctx->averaged_frame.dim);
} break;
default: ASSERT(0);
}
@@ -542,7 +519,7 @@ do_beamform_work(BeamformerCtx *ctx, Arena *a)
work->compute_ctx.export_handle = INVALID_FILE;
/* NOTE: do not waste a bunch of GPU space holding onto the volume
* texture if it was just for export */
- glDeleteTextures(frame->dim.w, frame->textures);
+ glDeleteTextures(1, &frame->texture);
mem_clear(frame, 0, sizeof(*frame));
}
} break;
@@ -671,8 +648,7 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
if (output_3d) {
work->type = BW_PARTIAL_COMPUTE;
BeamformFrame *frame = &ctx->partial_compute_ctx.frame;
- uv4 out_dim = ctx->params->raw.output_points;
- out_dim.w = ctx->params->raw.xdc_count;
+ uv3 out_dim = ctx->params->raw.output_points.xyz;
alloc_beamform_frame(&ctx->gl, frame, out_dim, 0, s8("Beamformed_Volume"));
work->compute_ctx.frame = frame;
}
@@ -682,7 +658,7 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
size rf_raw_size = rf_raw_dim.x * rf_raw_dim.y * sizeof(i16);
void *rf_data_buf = cs->raw_data_arena.beg + raw_index * rf_raw_size;
- alloc_output_image(ctx, bp->output_points);
+ alloc_output_image(ctx, bp->output_points.xyz);
size rlen = ctx->platform.read_pipe(input->pipe_handle, rf_data_buf, rf_raw_size);
if (rlen != rf_raw_size) {
@@ -720,12 +696,10 @@ DEBUG_EXPORT BEAMFORMER_FRAME_STEP_FN(beamformer_frame_step)
u32 out_texture = 0;
if (bp->output_points.w > 1) {
frame_to_draw = &ctx->averaged_frame;
- out_texture = ctx->averaged_frame.textures[0];
+ out_texture = ctx->averaged_frame.texture;
} else {
frame_to_draw = ctx->beamform_frames + ctx->displayed_frame_index;
- /* NOTE: verify we have actually beamformed something yet */
- if (frame_to_draw->dim.w)
- out_texture = frame_to_draw->textures[frame_to_draw->dim.w - 1];
+ out_texture = frame_to_draw->texture;
}
glBindTextureUnit(0, out_texture);
glUniform1f(fs->db_cutoff_id, fs->db);
diff --git a/beamformer.h b/beamformer.h
@@ -169,7 +169,6 @@ typedef struct {
#define CS_UNIFORMS \
X(CS_DAS, volume_export_dim_offset) \
X(CS_DAS, volume_export_pass) \
- X(CS_DAS, xdc_index) \
X(CS_DAS, cycle_t) \
X(CS_MIN_MAX, mips_level) \
X(CS_SUM, sum_prescale)
@@ -223,10 +222,8 @@ typedef struct {
} FragmentShaderCtx;
typedef struct {
- /* NOTE: we always have one extra texture to sum into; thus the final output data
- * is always found in textures[dim.w - 1] */
- u32 textures[MAX_MULTI_XDC_COUNT + 1];
- uv4 dim;
+ uv3 dim;
+ u32 texture;
/* NOTE: for use when displaying either prebeamformed frames or on the current frame
* when we intend to recompute on the next frame */
diff --git a/beamformer_parameters.h b/beamformer_parameters.h
@@ -22,23 +22,22 @@ enum compute_shaders {
#define DAS_ID_RCA 2
#define MAX_BEAMFORMED_SAVED_FRAMES 16
-#define MAX_MULTI_XDC_COUNT 4
/* NOTE: This struct follows the OpenGL std140 layout. DO NOT modify unless you have
* read and understood the rules, particulary with regards to _member alignment_ */
typedef struct {
- u16 channel_mapping[512]; /* Transducer Channel to Verasonics Channel */
+ u16 channel_mapping[256]; /* Transducer Channel to Verasonics Channel */
u32 uforces_channels[128]; /* Channels used for virtual UFORCES elements */
- f32 focal_depths[128]; /* [m] Focal Depths for each transmit of a RCA imaging scheme*/
- f32 transmit_angles[128]; /* [radians] Transmit Angles for each transmit of a RCA imaging scheme*/
- f32 xdc_transforms[16 * MAX_MULTI_XDC_COUNT]; /* IMPORTANT: column major order */
+ f32 focal_depths[256]; /* [m] Focal Depths for each transmit of a RCA imaging scheme*/
+ f32 transmit_angles[256]; /* [radians] Transmit Angles for each transmit of a RCA imaging scheme*/
+ f32 xdc_transform[16]; /* IMPORTANT: column major order */
uv4 dec_data_dim; /* Samples * Channels * Acquisitions; last element ignored */
uv4 output_points; /* Width * Height * Depth * (Frame Average Count) */
v4 output_min_coordinate; /* [m] Back-Top-Left corner of output region (w ignored) */
v4 output_max_coordinate; /* [m] Front-Bottom-Right corner of output region (w ignored)*/
- v2 xdc_element_pitch; /* [m] Transducer Element Pitch */
+ f32 xdc_element_pitch[2]; /* [m] Transducer Element Pitch {row, col} */
uv2 rf_raw_dim; /* Raw Data Dimensions */
+ u32 transmit_mode; /* Method/Orientation of Transmit */
u32 decode; /* Decode or just reshape data */
- u32 xdc_count; /* Number of Transducer Arrays (4 max) */
u32 channel_offset; /* Offset into channel_mapping: 0 or 128 (rows or columns) */
f32 speed_of_sound; /* [m/s] */
f32 sampling_frequency; /* [Hz] */
@@ -59,19 +58,19 @@ typedef struct {
#version 460 core\n\
\n\
layout(std140, binding = 0) uniform parameters {\n\
- uvec4 channel_mapping[64]; /* Transducer Channel to Verasonics Channel */\n\
+ uvec4 channel_mapping[32]; /* Transducer Channel to Verasonics Channel */\n\
uvec4 uforces_channels[32]; /* Channels used for virtual UFORCES elements */\n\
- vec4 focal_depths[32]; /* [m] Focal Depths for each transmit of a RCA imaging scheme*/\n\
- vec4 transmit_angles[32]; /* [radians] Transmit Angles for each transmit of a RCA imaging scheme*/\n\
- mat4 xdc_transforms[" str(MAX_MULTI_XDC_COUNT) "]; /* IMPORTANT: column major order */\n\
+ vec4 focal_depths[64]; /* [m] Focal Depths for each transmit of a RCA imaging scheme*/\n\
+ vec4 transmit_angles[64]; /* [radians] Transmit Angles for each transmit of a RCA imaging scheme*/\n\
+ mat4 xdc_transform; /* IMPORTANT: column major order */\n\
uvec4 dec_data_dim; /* Samples * Channels * Acquisitions; last element ignored */\n\
uvec4 output_points; /* Width * Height * Depth * (Frame Average Count) */\n\
vec4 output_min_coord; /* [m] Top left corner of output region */\n\
vec4 output_max_coord; /* [m] Bottom right corner of output region */\n\
- vec2 xdc_element_pitch; /* [m] Transducer Element Pitch */\n\
+ vec2 xdc_element_pitch; /* [m] Transducer Element Pitch {row, col} */\n\
uvec2 rf_raw_dim; /* Raw Data Dimensions */\n\
+ uint transmit_mode; /* Method/Orientation of Transmit */\n\
uint decode; /* Decode or just reshape data */\n\
- uint xdc_count; /* Number of Transducer Arrays (4 max) */\n\
uint channel_offset; /* Offset into channel_mapping: 0 or 128 (rows or columns) */\n\
float speed_of_sound; /* [m/s] */\n\
float sampling_frequency; /* [Hz] */\n\
diff --git a/shaders/das.glsl b/shaders/das.glsl
@@ -9,8 +9,7 @@ layout(rg32f, binding = 0) writeonly uniform image3D u_out_data_tex;
layout(location = 2) uniform int u_volume_export_pass;
layout(location = 3) uniform ivec3 u_volume_export_dim_offset;
-layout(location = 4) uniform int u_xdc_index;
-layout(location = 5) uniform float u_cycle_t;
+layout(location = 4) uniform float u_cycle_t;
#define C_SPLINE 0.5
@@ -84,7 +83,7 @@ vec3 orientation_projection(bool tx_rows)
vec3 world_space_to_rca_space(vec3 image_point, int transmit_orientation)
{
- vec3 result = (xdc_transforms[u_xdc_index] * vec4(image_point, 1)).xyz;
+ vec3 result = (xdc_transform * vec4(image_point, 1)).xyz;
result *= orientation_projection(transmit_orientation != TX_ROWS);
return result;
}
@@ -107,11 +106,11 @@ float cylindricalwave_transmit_distance(vec3 point, float focal_depth, float tra
return length((point - f) * orientation_projection(transmit_orientation == TX_ROWS));
}
-vec2 RCA(vec3 image_point, vec3 delta, uint starting_offset, float apodization_arg)
+vec2 RCA(vec3 image_point, vec3 delta, float apodization_arg)
{
/* TODO: pass this in (there is a problem in that it depends on the orientation
* of the array relative to the target/subject). */
- uint ridx = starting_offset;
+ uint ridx = 0;
int direction = beamform_plane * (u_volume_export_pass ^ 1);
if (direction == TX_ROWS) image_point = image_point.yxz;
@@ -152,9 +151,9 @@ vec2 RCA(vec3 image_point, vec3 delta, uint starting_offset, float apodization_a
return sum;
}
-vec2 HERCULES(vec3 image_point, vec3 delta, uint starting_offset, float apodization_arg)
+vec2 HERCULES(vec3 image_point, vec3 delta, float apodization_arg)
{
- uint ridx = starting_offset;
+ uint ridx = 0;
int direction = beamform_plane * (u_volume_export_pass ^ 1);
if (direction != TX_ROWS) image_point = image_point.yxz;
@@ -163,7 +162,7 @@ vec2 HERCULES(vec3 image_point, vec3 delta, uint starting_offset, float apodizat
float focal_depth = focal_depths[0][0];
float transmit_angle = transmit_angles[0][0];
- vec3 recieve_point = (xdc_transforms[u_xdc_index] * vec4(image_point, 1)).xyz;
+ vec3 recieve_point = (xdc_transform * vec4(image_point, 1)).xyz;
if (transmit_orientation == TX_ROWS)
delta = delta.yxz;
@@ -200,13 +199,13 @@ vec2 HERCULES(vec3 image_point, vec3 delta, uint starting_offset, float apodizat
return sum;
}
-vec2 uFORCES(vec3 image_point, vec3 delta, uint starting_offset, float apodization_arg)
+vec2 uFORCES(vec3 image_point, vec3 delta, float apodization_arg)
{
/* NOTE: skip first acquisition in uforces since its garbage */
uint uforces = uint(dec_data_dim.y != dec_data_dim.z);
- uint ridx = starting_offset + dec_data_dim.y * dec_data_dim.x * uforces;
+ uint ridx = dec_data_dim.y * dec_data_dim.x * uforces;
- image_point = (xdc_transforms[u_xdc_index] * vec4(image_point, 1)).xyz;
+ image_point = (xdc_transform * vec4(image_point, 1)).xyz;
int transmit_orientation = TX_ROWS;
//int transmit_orientation = int(transmit_orientations[0][0]);
@@ -254,18 +253,16 @@ void main()
float apod_arg = f_number * radians(180) / abs(image_point.z);
/* NOTE: skip over channels corresponding to other arrays */
- uint starting_offset = u_xdc_index * (dec_data_dim.y / xdc_count) * dec_data_dim.x * dec_data_dim.z;
-
vec2 sum;
switch (das_shader_id) {
case DAS_ID_UFORCES:
- sum = uFORCES(image_point, vec3(xdc_element_pitch, 0), starting_offset, apod_arg);
+ sum = uFORCES(image_point, vec3(xdc_element_pitch, 0), apod_arg);
break;
case DAS_ID_HERCULES:
- sum = HERCULES(image_point, vec3(xdc_element_pitch, 0), starting_offset, apod_arg);
+ sum = HERCULES(image_point, vec3(xdc_element_pitch, 0), apod_arg);
break;
case DAS_ID_RCA:
- sum = RCA(image_point, vec3(xdc_element_pitch, 0), starting_offset, apod_arg);
+ sum = RCA(image_point, vec3(xdc_element_pitch, 0), apod_arg);
break;
}
diff --git a/ui.c b/ui.c
@@ -867,11 +867,8 @@ ui_start_compute(BeamformerCtx *ctx)
if (ui_can_start_compute(ctx)) {
beamform_work_queue_push(ctx, &a, BW_RECOMPUTE);
BeamformFrameIterator bfi = beamform_frame_iterator(ctx);
- for (BeamformFrame *frame = frame_next(&bfi); frame; frame = frame_next(&bfi)) {
- if (frame->dim.w && frame->textures[frame->dim.w - 1])
- glClearTexImage(frame->textures[frame->dim.w - 1], 0,
- GL_RED, GL_FLOAT, 0);
- }
+ for (BeamformFrame *frame = frame_next(&bfi); frame; frame = frame_next(&bfi))
+ glClearTexImage(frame->texture, 0, GL_RED, GL_FLOAT, 0);
}
ctx->params->upload = 1;
}
diff --git a/util.c b/util.c
@@ -311,12 +311,6 @@ push_s8(Arena *a, s8 str)
return result;
}
-static b32
-uv4_equal(uv4 a, uv4 b)
-{
- return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
-}
-
static u32
round_down_power_of_2(u32 a)
{
@@ -324,6 +318,12 @@ round_down_power_of_2(u32 a)
return result;
}
+static b32
+uv3_equal(uv3 a, uv3 b)
+{
+ return a.x == b.x && a.y == b.y && a.z == b.z;
+}
+
static v3
cross(v3 a, v3 b)
{
@@ -398,6 +398,12 @@ magnitude_v2(v2 a)
return result;
}
+static b32
+uv4_equal(uv4 a, uv4 b)
+{
+ return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
+}
+
static v4
sub_v4(v4 a, v4 b)
{