ogl_beamforming

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

hadamard.glsl (3930B)


      1 /* See LICENSE for license details. */
      2 #version 460 core
      3 layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
      4 
      5 layout(std430, binding = 1) readonly restrict buffer buffer_1 {
      6 	int rf_data[];
      7 };
      8 
      9 layout(std430, binding = 2) writeonly restrict buffer buffer_2 {
     10 	vec2 out_data[];
     11 };
     12 
     13 layout(std430, binding = 3) readonly restrict buffer buffer_3 {
     14 	int hadamard[];
     15 };
     16 
     17 layout(std140, binding = 0) uniform parameters {
     18 	uvec4 channel_mapping[64];    /* Transducer Channel to Verasonics Channel */
     19 	uvec4 uforces_channels[32];   /* Channels used for virtual UFORCES elements */
     20 	vec4  lpf_coefficients[16];   /* Low Pass Filter Cofficients */
     21 	vec4  xdc_origin;             /* [m] Corner of transducer being treated as origin */
     22 	vec4  xdc_corner1;            /* [m] Corner of transducer along first axis (arbitrary) */
     23 	vec4  xdc_corner2;            /* [m] Corner of transducer along second axis (arbitrary) */
     24 	uvec4 dec_data_dim;           /* Samples * Channels * Acquisitions; last element ignored */
     25 	uvec4 output_points;          /* Width * Height * Depth; last element ignored */
     26 	vec4  output_min_coord;       /* [m] Top left corner of output region */
     27 	vec4  output_max_coord;       /* [m] Bottom right corner of output region */
     28 	uvec2 rf_raw_dim;             /* Raw Data Dimensions */
     29 	uint  channel_offset;         /* Offset into channel_mapping: 0 or 128 (rows or columns) */
     30 	uint  lpf_order;              /* Order of Low Pass Filter */
     31 	float speed_of_sound;         /* [m/s] */
     32 	float sampling_frequency;     /* [Hz]  */
     33 	float center_frequency;       /* [Hz]  */
     34 	float focal_depth;            /* [m]   */
     35 	float time_offset;            /* pulse length correction time [s]   */
     36 	uint  uforces;                /* mode is UFORCES (1) or FORCES (0) */
     37 	float off_axis_pos;           /* [m] Position on screen normal to beamform in 2D HERCULES */
     38 	int   beamform_plane;         /* Plane to Beamform in 2D HERCULES */
     39 };
     40 
     41 void main()
     42 {
     43 	/* NOTE: each invocation takes a time sample and a receive channel.
     44 	 * It first maps the column to the correct column in the rf data then
     45 	 * does the dot product with the equivalent row of the hadamard matrix.
     46 	 * The result is stored to the equivalent row, column index of the output.
     47 	 */
     48 	uint time_sample = gl_GlobalInvocationID.x;
     49 	uint channel     = gl_GlobalInvocationID.y;
     50 	uint acq         = gl_GlobalInvocationID.z;
     51 
     52 	/* NOTE: offset to get the correct column in hadamard matrix */
     53 	uint hoff = dec_data_dim.z * acq;
     54 
     55 	/* NOTE: offsets for storing the results in the output data */
     56 	uint out_off = dec_data_dim.x * dec_data_dim.y * acq + dec_data_dim.x * channel + time_sample;
     57 
     58 	/* NOTE: channel mapping is stored as u16s so we must do this to extract the final value */
     59 	uint ch_array_idx = ((channel + channel_offset) / 8);
     60 	uint ch_vec_idx   = ((channel + channel_offset) % 8) / 2;
     61 	uint ch_elem_lfs  = ((channel + channel_offset) & 1u) * 16;
     62 	uint rf_channel   = (channel_mapping[ch_array_idx][ch_vec_idx] << ch_elem_lfs) >> 16;
     63 
     64 	/* NOTE: stride is the number of samples between acquistions; off is the
     65 	 * index of the first acquisition for this channel and time sample  */
     66 	uint rf_stride = dec_data_dim.x;
     67 	uint rf_off    = rf_raw_dim.x * rf_channel + time_sample;
     68 
     69 	/* NOTE: rf_data index and stride considering the data is i16 not i32 */
     70 	uint ridx       = rf_off / 2;
     71 	uint ridx_delta = rf_stride / 2;
     72 
     73 	/* NOTE: rf_data is i16 so each access grabs two time samples at time.
     74 	 * We need to shift arithmetically (maintaining the sign) to get the
     75 	 * desired element. If the time sample is even we take the upper half
     76 	 * and if its odd we take the lower half. */
     77 	uint lfs = ((~time_sample) & 1u) * 16;
     78 
     79 	/* NOTE: Compute N-D dot product */
     80 	int sum = 0;
     81 	for (int i = 0; i < dec_data_dim.z; i++) {
     82 		int data = (rf_data[ridx] << lfs) >> 16;
     83 		sum  += hadamard[hoff + i] * data;
     84 		ridx += ridx_delta;
     85 	}
     86 	out_data[out_off] = vec2(float(sum), 0);
     87 }