das.glsl (8953B)
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 uniform image3D u_out_data_tex; 7 8 layout(location = 2) uniform ivec3 u_voxel_offset; 9 layout(location = 3) uniform uint u_cycle_t; 10 11 #define C_SPLINE 0.5 12 13 #define TX_ROWS 0 14 #define TX_COLS 1 15 16 #define TX_MODE_TX_COLS(a) (((a) & 2) != 0) 17 #define TX_MODE_RX_COLS(a) (((a) & 1) != 0) 18 19 /* NOTE: See: https://cubic.org/docs/hermite.htm */ 20 vec2 cubic(uint ridx, float x) 21 { 22 mat4 h = mat4( 23 2, -3, 0, 1, 24 -2, 3, 0, 0, 25 1, -2, 1, 0, 26 1, -1, 0, 0 27 ); 28 29 uint xk = uint(floor(x)); 30 float t = (x - float(xk)); 31 vec4 S = vec4(t * t * t, t * t, t, 1); 32 33 vec2 P1 = rf_data[ridx + xk]; 34 vec2 P2 = rf_data[ridx + xk + 1]; 35 vec2 T1 = C_SPLINE * (P2 - rf_data[ridx + xk - 1]); 36 vec2 T2 = C_SPLINE * (rf_data[ridx + xk + 2] - P1); 37 38 vec4 C1 = vec4(P1.x, P2.x, T1.x, T2.x); 39 vec4 C2 = vec4(P1.y, P2.y, T1.y, T2.y); 40 return vec2(dot(S, h * C1), dot(S, h * C2)); 41 } 42 43 vec2 sample_rf(uint ridx, float t) 44 { 45 vec2 result; 46 if (interpolate) result = cubic(ridx, t); 47 else result = rf_data[ridx + uint(floor(t))]; 48 return result; 49 } 50 51 vec3 calc_image_point(vec3 voxel) 52 { 53 ivec3 out_data_dim = imageSize(u_out_data_tex); 54 vec4 output_size = abs(output_max_coordinate - output_min_coordinate); 55 vec3 image_point = output_min_coordinate.xyz + voxel * output_size.xyz / out_data_dim; 56 57 switch (das_shader_id) { 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 uint 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 (uint i = 0; i < dec_data_dim.z; i++) { 126 uint base_idx = i / 4; 127 uint sub_idx = i % 4; 128 129 float focal_depth = focal_depths[base_idx][sub_idx]; 130 float transmit_angle = radians(transmit_angles[base_idx][sub_idx]); 131 132 float transmit_distance; 133 if (isinf(focal_depth)) { 134 transmit_distance = planewave_transmit_distance(image_point, transmit_angle, 135 !tx_col); 136 } else { 137 transmit_distance = cylindricalwave_transmit_distance(image_point, focal_depth, 138 transmit_angle, 139 !tx_col); 140 } 141 142 vec3 receive_distance = receive_point; 143 /* NOTE: For Each Receiver */ 144 // uint j = (dec_data_dim.z - 1) * uint(clamp(u_cycle_t, 0, 1)); { 145 for (uint j = 0; j < dec_data_dim.y; j++) { 146 float sidx = sample_index(transmit_distance + length(receive_distance)); 147 vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x); 148 sum += apodize(sample_rf(ridx, sidx), apodization_arg, length(receive_distance.xy)) * valid; 149 receive_distance -= delta; 150 ridx += dec_data_dim.x; 151 } 152 } 153 return sum; 154 } 155 156 vec2 HERCULES(vec3 image_point, vec3 delta, float apodization_arg) 157 { 158 uint uhercules = uint(das_shader_id == DAS_ID_UHERCULES); 159 uint ridx = dec_data_dim.y * dec_data_dim.x * uhercules; 160 int direction = beamform_plane; 161 if (direction != TX_ROWS) image_point = image_point.yxz; 162 163 bool tx_col = TX_MODE_TX_COLS(transmit_mode); 164 bool rx_col = TX_MODE_RX_COLS(transmit_mode); 165 float focal_depth = focal_depths[0][0]; 166 float transmit_angle = radians(transmit_angles[0][0]); 167 168 vec3 receive_point = (xdc_transform * vec4(image_point, 1)).xyz; 169 170 float transmit_distance; 171 if (isinf(focal_depth)) { 172 transmit_distance = planewave_transmit_distance(image_point, transmit_angle, 173 !tx_col); 174 } else { 175 transmit_distance = cylindricalwave_transmit_distance(image_point, focal_depth, 176 transmit_angle, 177 !tx_col); 178 } 179 180 vec2 sum = vec2(0); 181 /* NOTE: For Each Acquistion in Raw Data */ 182 for (uint i = uhercules; i < dec_data_dim.z; i++) { 183 uint base_idx = ((i - uhercules) / 8); 184 uint sub_idx = ((i - uhercules) % 8) / 2; 185 uint shift = (~(i - uhercules) & 1u) * 16u; 186 uint channel = (uforces_channels[base_idx][sub_idx] << shift) >> 16u; 187 188 /* NOTE: For Each Virtual Source */ 189 for (uint j = 0; j < dec_data_dim.y; j++) { 190 vec3 element_position; 191 if (rx_col) element_position = vec3(j, channel, 0) * delta; 192 else element_position = vec3(channel, j, 0) * delta; 193 vec3 receive_distance = receive_point - element_position; 194 float sidx = sample_index(transmit_distance + length(receive_distance)); 195 vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x); 196 197 /* NOTE: tribal knowledge */ 198 if (i == 0) valid *= inversesqrt(dec_data_dim.z); 199 200 sum += apodize(sample_rf(ridx, sidx), apodization_arg, 201 length(receive_distance.xy)) * valid; 202 ridx += dec_data_dim.x; 203 } 204 } 205 return sum; 206 } 207 208 vec2 uFORCES(vec3 image_point, vec3 delta, float apodization_arg) 209 { 210 /* NOTE: skip first acquisition in uforces since its garbage */ 211 uint uforces = uint(das_shader_id == DAS_ID_UFORCES); 212 uint ridx = dec_data_dim.y * dec_data_dim.x * uforces; 213 214 image_point = (xdc_transform * vec4(image_point, 1)).xyz; 215 216 vec3 focal_point_offset = vec3(0, delta.y * floor(dec_data_dim.y / 2), 0); 217 delta.y = 0; 218 219 vec2 sum = vec2(0); 220 for (uint i = uforces; i < dec_data_dim.z; i++) { 221 uint base_idx = ((i - uforces) / 8); 222 uint sub_idx = ((i - uforces) % 8) / 2; 223 uint shift = (~(i - uforces) & 1u) * 16u; 224 uint channel = (uforces_channels[base_idx][sub_idx] << shift) >> 16u; 225 226 vec2 rdist = vec2(image_point.x, image_point.z); 227 vec3 focal_point = channel * delta + focal_point_offset; 228 float transmit_dist = distance(image_point, focal_point); 229 230 for (uint j = 0; j < dec_data_dim.y; j++) { 231 float sidx = sample_index(transmit_dist + length(rdist)); 232 vec2 valid = vec2(sidx >= 0) * vec2(sidx < dec_data_dim.x); 233 sum += apodize(sample_rf(ridx, sidx), apodization_arg, rdist.x) * valid; 234 rdist.x -= delta.x; 235 ridx += dec_data_dim.x; 236 } 237 } 238 return sum; 239 } 240 241 void main() 242 { 243 /* NOTE: Convert voxel to physical coordinates */ 244 ivec3 out_coord = ivec3(gl_GlobalInvocationID) + u_voxel_offset; 245 vec3 image_point = calc_image_point(vec3(out_coord)); 246 247 /* NOTE: used for constant F# dynamic receive apodization. This is implemented as: 248 * 249 * / |x_e - x_i|\ 250 * a(x, z) = cos(F# * π * ----------- ) ^ 2 251 * \ |z_e - z_i|/ 252 * 253 * where x,z_e are transducer element positions and x,z_i are image positions. */ 254 float apod_arg = f_number * radians(180) / abs(image_point.z); 255 256 /* NOTE: skip over channels corresponding to other arrays */ 257 vec2 sum; 258 switch (das_shader_id) { 259 case DAS_ID_FORCES: 260 case DAS_ID_UFORCES: 261 sum = uFORCES(image_point, vec3(xdc_element_pitch, 0), apod_arg); 262 break; 263 case DAS_ID_HERCULES: 264 case DAS_ID_UHERCULES: 265 sum = HERCULES(image_point, vec3(xdc_element_pitch, 0), apod_arg); 266 break; 267 case DAS_ID_RCA_TPW: 268 case DAS_ID_RCA_VLS: 269 sum = RCA(image_point, vec3(xdc_element_pitch, 0), apod_arg); 270 break; 271 } 272 273 imageStore(u_out_data_tex, out_coord, vec4(sum, 0, 0)); 274 }