das.glsl (8727B)
1 /* See LICENSE for license details. */ 2 layout(std430, binding = 1) readonly restrict buffer buffer_1 { 3 vec2 rf_data[]; 4 }; 5 6 layout(rg32f, binding = 0) writeonly restrict uniform image3D u_out_data_tex; 7 layout(r16i, binding = 1) readonly restrict uniform iimage1D sparse_elements; 8 layout(rg32f, binding = 2) readonly restrict uniform image1D focal_vectors; 9 10 #define C_SPLINE 0.5 11 12 #define TX_ROWS 0 13 #define TX_COLS 1 14 15 #define TX_MODE_TX_COLS(a) (((a) & 2) != 0) 16 #define TX_MODE_RX_COLS(a) (((a) & 1) != 0) 17 18 /* NOTE: See: https://cubic.org/docs/hermite.htm */ 19 vec2 cubic(int ridx, float x) 20 { 21 mat4 h = mat4( 22 2, -3, 0, 1, 23 -2, 3, 0, 0, 24 1, -2, 1, 0, 25 1, -1, 0, 0 26 ); 27 28 int xk = int(floor(x)); 29 float t = (x - float(xk)); 30 vec4 S = vec4(t * t * t, t * t, t, 1); 31 32 vec2 P1 = rf_data[ridx + xk]; 33 vec2 P2 = rf_data[ridx + xk + 1]; 34 vec2 T1 = C_SPLINE * (P2 - rf_data[ridx + xk - 1]); 35 vec2 T2 = C_SPLINE * (rf_data[ridx + xk + 2] - P1); 36 37 vec4 C1 = vec4(P1.x, P2.x, T1.x, T2.x); 38 vec4 C2 = vec4(P1.y, P2.y, T1.y, T2.y); 39 return vec2(dot(S, h * C1), dot(S, h * C2)); 40 } 41 42 vec2 sample_rf(int ridx, float t) 43 { 44 vec2 result; 45 if (interpolate) result = cubic(ridx, t); 46 else result = rf_data[ridx + int(floor(t))]; 47 return result; 48 } 49 50 vec3 calc_image_point(vec3 voxel) 51 { 52 vec3 out_data_dim = vec3(imageSize(u_out_data_tex)); 53 vec4 output_size = abs(output_max_coordinate - output_min_coordinate); 54 vec3 image_point = output_min_coordinate.xyz + voxel * output_size.xyz / out_data_dim; 55 56 switch (das_shader_id) { 57 case DAS_ID_FLASH: 58 case DAS_ID_FORCES: 59 case DAS_ID_UFORCES: 60 /* TODO: fix the math so that the image plane can be aritrary */ 61 image_point.y = 0; 62 break; 63 case DAS_ID_HERCULES: 64 case DAS_ID_RCA_TPW: 65 case DAS_ID_RCA_VLS: 66 /* TODO(rnp): this can be removed when we use an abitrary plane transform */ 67 if (!all(greaterThan(out_data_dim, vec3(1, 1, 1)))) 68 image_point.y = off_axis_pos; 69 break; 70 } 71 72 return image_point; 73 } 74 75 vec2 apodize(vec2 value, float apodization_arg, float distance) 76 { 77 /* NOTE: apodization value for this transducer element */ 78 float a = cos(clamp(abs(apodization_arg * distance), 0, 0.25 * radians(360))); 79 return value * a * a; 80 } 81 82 vec3 orientation_projection(vec3 point, bool rows) 83 { 84 return point * vec3(!rows, rows, 1); 85 } 86 87 vec3 world_space_to_rca_space(vec3 image_point, bool rx_rows) 88 { 89 return orientation_projection((xdc_transform * vec4(image_point, 1)).xyz, rx_rows); 90 } 91 92 float sample_index(float distance) 93 { 94 float time = distance / speed_of_sound + time_offset; 95 return time * sampling_frequency; 96 } 97 98 float planewave_transmit_distance(vec3 point, float transmit_angle, bool tx_rows) 99 { 100 return dot(orientation_projection(point, tx_rows), 101 vec3(sin(transmit_angle), sin(transmit_angle), cos(transmit_angle))); 102 } 103 104 float cylindricalwave_transmit_distance(vec3 point, float focal_depth, float transmit_angle, bool tx_rows) 105 { 106 vec3 f = focal_depth * vec3(sin(transmit_angle), sin(transmit_angle), cos(transmit_angle)); 107 return length(orientation_projection(point - f, tx_rows)); 108 } 109 110 vec2 RCA(vec3 image_point, vec3 delta, float apodization_arg) 111 { 112 int ridx = 0; 113 int direction = beamform_plane; 114 if (direction != TX_ROWS) image_point = image_point.yxz; 115 116 bool tx_col = TX_MODE_TX_COLS(transmit_mode); 117 bool rx_col = TX_MODE_RX_COLS(transmit_mode); 118 119 vec3 receive_point = world_space_to_rca_space(image_point, !rx_col); 120 delta = orientation_projection(delta, !rx_col); 121 122 vec2 sum = vec2(0); 123 /* NOTE: For Each Acquistion in Raw Data */ 124 // uint i = (dec_data_dim.z - 1) * uint(clamp(u_cycle_t, 0, 1)); { 125 for (int i = 0; i < dec_data_dim.z; i++) { 126 float transmit_angle = radians(imageLoad(focal_vectors, i).x); 127 float focal_depth = imageLoad(focal_vectors, i).y; 128 129 float transmit_distance; 130 if (isinf(focal_depth)) { 131 transmit_distance = planewave_transmit_distance(image_point, transmit_angle, 132 !tx_col); 133 } else { 134 transmit_distance = cylindricalwave_transmit_distance(image_point, focal_depth, 135 transmit_angle, 136 !tx_col); 137 } 138 139 vec3 receive_distance = receive_point; 140 /* NOTE: For Each Receiver */ 141 // uint j = (dec_data_dim.z - 1) * uint(clamp(u_cycle_t, 0, 1)); { 142 for (uint j = 0; j < dec_data_dim.y; j++) { 143 float sidx = sample_index(transmit_distance + length(receive_distance)); 144 vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x); 145 sum += apodize(sample_rf(ridx, sidx), apodization_arg, length(receive_distance.xy)) * valid; 146 receive_distance -= delta; 147 ridx += int(dec_data_dim.x); 148 } 149 } 150 return sum; 151 } 152 153 vec2 HERCULES(vec3 image_point, vec3 delta, float apodization_arg) 154 { 155 int uhercules = int(das_shader_id == DAS_ID_UHERCULES); 156 int ridx = int(dec_data_dim.y * dec_data_dim.x * uhercules); 157 int direction = beamform_plane; 158 if (direction != TX_ROWS) image_point = image_point.yxz; 159 160 bool tx_col = TX_MODE_TX_COLS(transmit_mode); 161 bool rx_col = TX_MODE_RX_COLS(transmit_mode); 162 float transmit_angle = radians(imageLoad(focal_vectors, 0).x); 163 float focal_depth = imageLoad(focal_vectors, 0).y; 164 165 vec3 receive_point = (xdc_transform * vec4(image_point, 1)).xyz; 166 167 float transmit_distance; 168 if (isinf(focal_depth)) { 169 transmit_distance = planewave_transmit_distance(image_point, transmit_angle, 170 !tx_col); 171 } else { 172 transmit_distance = cylindricalwave_transmit_distance(image_point, focal_depth, 173 transmit_angle, 174 !tx_col); 175 } 176 177 vec2 sum = vec2(0); 178 /* NOTE: For Each Acquistion in Raw Data */ 179 for (int i = uhercules; i < dec_data_dim.z; i++) { 180 int channel = imageLoad(sparse_elements, i - uhercules).x; 181 /* NOTE: For Each Virtual Source */ 182 for (uint j = 0; j < dec_data_dim.y; j++) { 183 vec3 element_position; 184 if (rx_col) element_position = vec3(j, channel, 0) * delta; 185 else element_position = vec3(channel, j, 0) * delta; 186 vec3 receive_distance = receive_point - element_position; 187 float sidx = sample_index(transmit_distance + length(receive_distance)); 188 vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x); 189 190 /* NOTE: tribal knowledge */ 191 if (i == 0) valid *= inversesqrt(dec_data_dim.z); 192 193 sum += apodize(sample_rf(ridx, sidx), apodization_arg, 194 length(receive_distance.xy)) * valid; 195 ridx += int(dec_data_dim.x); 196 } 197 } 198 return sum; 199 } 200 201 vec2 uFORCES(vec3 image_point, vec3 delta, float apodization_arg) 202 { 203 /* NOTE: skip first acquisition in uforces since its garbage */ 204 int uforces = int(das_shader_id == DAS_ID_UFORCES); 205 int ridx = int(dec_data_dim.y * dec_data_dim.x * uforces); 206 207 image_point = (xdc_transform * vec4(image_point, 1)).xyz; 208 209 vec2 sum = vec2(0); 210 for (int i = uforces; i < dec_data_dim.z; i++) { 211 int channel = imageLoad(sparse_elements, i - uforces).x; 212 vec2 recieve_point = image_point.xz; 213 vec3 element_center = delta * vec3(channel, floor(dec_data_dim.y / 2), 0); 214 float transmit_dist = distance(image_point, element_center); 215 216 for (uint j = 0; j < dec_data_dim.y; j++) { 217 float sidx = sample_index(transmit_dist + length(recieve_point)); 218 vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x); 219 sum += valid * apodize(sample_rf(ridx, sidx), apodization_arg, 220 recieve_point.x); 221 ridx += int(dec_data_dim.x); 222 recieve_point.x -= delta.x; 223 } 224 } 225 return sum; 226 } 227 228 void main() 229 { 230 /* NOTE: Convert voxel to physical coordinates */ 231 ivec3 out_coord = ivec3(gl_GlobalInvocationID) + u_voxel_offset; 232 vec3 image_point = calc_image_point(vec3(out_coord)); 233 234 /* NOTE: used for constant F# dynamic receive apodization. This is implemented as: 235 * 236 * / |x_e - x_i|\ 237 * a(x, z) = cos(F# * π * ----------- ) ^ 2 238 * \ |z_e - z_i|/ 239 * 240 * where x,z_e are transducer element positions and x,z_i are image positions. */ 241 float apod_arg = f_number * radians(180) / abs(image_point.z); 242 243 /* NOTE: skip over channels corresponding to other arrays */ 244 vec2 sum; 245 switch (das_shader_id) { 246 case DAS_ID_FORCES: 247 case DAS_ID_UFORCES: 248 sum = uFORCES(image_point, vec3(xdc_element_pitch, 0), apod_arg); 249 break; 250 case DAS_ID_HERCULES: 251 case DAS_ID_UHERCULES: 252 sum = HERCULES(image_point, vec3(xdc_element_pitch, 0), apod_arg); 253 break; 254 case DAS_ID_FLASH: 255 case DAS_ID_RCA_TPW: 256 case DAS_ID_RCA_VLS: 257 sum = RCA(image_point, vec3(xdc_element_pitch, 0), apod_arg); 258 break; 259 } 260 261 imageStore(u_out_data_tex, out_coord, vec4(sum, 0, 0)); 262 }