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 }