das.glsl (12137B)
1 /* See LICENSE for license details. */ 2 layout(std430, binding = 1) readonly restrict buffer buffer_1 { 3 vec2 rf_data[]; 4 }; 5 6 #if DAS_FAST 7 layout(rg32f, binding = 0) restrict uniform image3D u_out_data_tex; 8 #else 9 layout(rg32f, binding = 0) writeonly restrict uniform image3D u_out_data_tex; 10 #endif 11 12 layout(r16i, binding = 1) readonly restrict uniform iimage1D sparse_elements; 13 layout(rg32f, binding = 2) readonly restrict uniform image1D focal_vectors; 14 15 #define C_SPLINE 0.5 16 17 #define TX_ROWS 0 18 #define TX_COLS 1 19 20 #define TX_MODE_TX_COLS(a) (((a) & 2) != 0) 21 #define TX_MODE_RX_COLS(a) (((a) & 1) != 0) 22 23 vec2 rotate_iq(vec2 iq, float time) 24 { 25 vec2 result = iq; 26 if (center_frequency > 0) { 27 float arg = radians(360) * center_frequency * time; 28 mat2 phasor = mat2( cos(arg), sin(arg), 29 -sin(arg), cos(arg)); 30 result = phasor * iq; 31 } 32 return result; 33 } 34 35 /* NOTE: See: https://cubic.org/docs/hermite.htm */ 36 vec2 cubic(int base_index, float index) 37 { 38 mat4 h = mat4( 39 2, -3, 0, 1, 40 -2, 3, 0, 0, 41 1, -2, 1, 0, 42 1, -1, 0, 0 43 ); 44 45 float tk, t = modf(index, tk); 46 vec2 samples[4] = { 47 rf_data[base_index + int(tk) - 1], 48 rf_data[base_index + int(tk) + 0], 49 rf_data[base_index + int(tk) + 1], 50 rf_data[base_index + int(tk) + 2], 51 }; 52 53 vec4 S = vec4(t * t * t, t * t, t, 1); 54 vec2 P1 = samples[1]; 55 vec2 P2 = samples[2]; 56 vec2 T1 = C_SPLINE * (P2 - samples[0]); 57 vec2 T2 = C_SPLINE * (samples[3] - P1); 58 59 mat2x4 C = mat2x4(vec4(P1.x, P2.x, T1.x, T2.x), vec4(P1.y, P2.y, T1.y, T2.y)); 60 vec2 result = S * h * C; 61 return result; 62 } 63 64 vec2 sample_rf(int channel, int transmit, float index) 65 { 66 vec2 result = vec2(index >= 0.0f) * vec2((int(index) + 1 + int(interpolate)) < dec_data_dim.x); 67 int base_index = channel * dec_data_dim.x * dec_data_dim.z + transmit * dec_data_dim.x; 68 if (interpolate) result *= cubic(base_index, index); 69 else result *= rf_data[base_index + int(round(index))]; 70 result = rotate_iq(result, index / sampling_frequency); 71 return result; 72 } 73 74 float sample_index(float distance) 75 { 76 float time = distance / speed_of_sound + time_offset; 77 return time * sampling_frequency; 78 } 79 80 float apodize(float arg) 81 { 82 /* NOTE: used for constant F# dynamic receive apodization. This is implemented as: 83 * 84 * / |x_e - x_i|\ 85 * a(x, z) = cos(F# * π * ----------- ) ^ 2 86 * \ |z_e - z_i|/ 87 * 88 * where x,z_e are transducer element positions and x,z_i are image positions. */ 89 float a = cos(clamp(abs(arg), 0, 0.25 * radians(360))); 90 return a * a; 91 } 92 93 vec2 rca_plane_projection(vec3 point, bool rows) 94 { 95 vec2 result = vec2(point[int(rows)], point[2]); 96 return result; 97 } 98 99 float plane_wave_transmit_distance(vec3 point, float transmit_angle, bool tx_rows) 100 { 101 return dot(rca_plane_projection(point, tx_rows), vec2(sin(transmit_angle), cos(transmit_angle))); 102 } 103 104 float cylindrical_wave_transmit_distance(vec3 point, float focal_depth, float transmit_angle, bool tx_rows) 105 { 106 vec2 f = focal_depth * vec2(sin(transmit_angle), cos(transmit_angle)); 107 return distance(rca_plane_projection(point, tx_rows), f); 108 } 109 110 #if DAS_FAST 111 vec3 RCA(vec3 world_point) 112 { 113 bool tx_rows = !TX_MODE_TX_COLS(transmit_mode); 114 bool rx_rows = !TX_MODE_RX_COLS(transmit_mode); 115 vec2 xdc_world_point = rca_plane_projection((xdc_transform * vec4(world_point, 1)).xyz, rx_rows); 116 vec2 focal_vector = imageLoad(focal_vectors, u_channel).xy; 117 float transmit_angle = radians(focal_vector.x); 118 float focal_depth = focal_vector.y; 119 120 float transmit_distance; 121 if (isinf(focal_depth)) { 122 transmit_distance = plane_wave_transmit_distance(world_point, transmit_angle, tx_rows); 123 } else { 124 transmit_distance = cylindrical_wave_transmit_distance(world_point, focal_depth, 125 transmit_angle, tx_rows); 126 } 127 128 vec2 result = vec2(0); 129 for (int channel = 0; channel < dec_data_dim.y; channel++) { 130 vec2 receive_vector = xdc_world_point - rca_plane_projection(vec3(channel * xdc_element_pitch, 0), rx_rows); 131 float receive_distance = length(receive_vector); 132 float apodization = apodize(f_number * radians(180) / abs(xdc_world_point.y) * receive_vector.x); 133 134 if (apodization > 0) { 135 float sidx = sample_index(transmit_distance + receive_distance); 136 result += apodization * sample_rf(channel, u_channel, sidx); 137 } 138 } 139 return vec3(result, 0); 140 } 141 #else 142 vec3 RCA(vec3 world_point) 143 { 144 bool tx_rows = !TX_MODE_TX_COLS(transmit_mode); 145 bool rx_rows = !TX_MODE_RX_COLS(transmit_mode); 146 vec2 xdc_world_point = rca_plane_projection((xdc_transform * vec4(world_point, 1)).xyz, rx_rows); 147 148 vec3 sum = vec3(0); 149 for (int transmit = 0; transmit < dec_data_dim.z; transmit++) { 150 vec2 focal_vector = imageLoad(focal_vectors, transmit).xy; 151 float transmit_angle = radians(focal_vector.x); 152 float focal_depth = focal_vector.y; 153 154 float transmit_distance; 155 if (isinf(focal_depth)) { 156 transmit_distance = plane_wave_transmit_distance(world_point, transmit_angle, tx_rows); 157 } else { 158 transmit_distance = cylindrical_wave_transmit_distance(world_point, focal_depth, 159 transmit_angle, tx_rows); 160 } 161 162 for (int rx_channel = 0; rx_channel < dec_data_dim.y; rx_channel++) { 163 vec3 rx_center = vec3(rx_channel * xdc_element_pitch, 0); 164 vec2 receive_vector = xdc_world_point - rca_plane_projection(rx_center, rx_rows); 165 float apodization = apodize(f_number * radians(180) / abs(xdc_world_point.y) * receive_vector.x); 166 167 if (apodization > 0) { 168 float sidx = sample_index(transmit_distance + length(receive_vector)); 169 vec2 value = apodization * sample_rf(rx_channel, transmit, sidx); 170 sum += vec3(value, length(value)); 171 } 172 } 173 } 174 return sum; 175 } 176 #endif 177 178 #if DAS_FAST 179 vec3 HERCULES(vec3 world_point) 180 { 181 bool uhercules = das_shader_id == DAS_ID_UHERCULES; 182 vec3 xdc_world_point = (xdc_transform * vec4(world_point, 1)).xyz; 183 bool tx_rows = !TX_MODE_TX_COLS(transmit_mode); 184 bool rx_cols = TX_MODE_RX_COLS(transmit_mode); 185 vec2 focal_vector = imageLoad(focal_vectors, 0).xy; 186 float transmit_angle = radians(focal_vector.x); 187 float focal_depth = focal_vector.y; 188 189 float transmit_distance; 190 if (isinf(focal_depth)) { 191 transmit_distance = plane_wave_transmit_distance(world_point, transmit_angle, tx_rows); 192 } else { 193 transmit_distance = cylindrical_wave_transmit_distance(world_point, focal_depth, 194 transmit_angle, tx_rows); 195 } 196 197 vec2 result = vec2(0); 198 for (int transmit = int(uhercules); transmit < dec_data_dim.z; transmit++) { 199 int tx_channel = uhercules ? imageLoad(sparse_elements, transmit - int(uhercules)).x : transmit; 200 vec3 element_position; 201 if (rx_cols) element_position = vec3(u_channel, tx_channel, 0) * vec3(xdc_element_pitch, 0); 202 else element_position = vec3(tx_channel, u_channel, 0) * vec3(xdc_element_pitch, 0); 203 204 float apodization = apodize(f_number * radians(180) / abs(xdc_world_point.z) * 205 distance(xdc_world_point.xy, element_position.xy)); 206 if (apodization > 0) { 207 /* NOTE: tribal knowledge */ 208 if (transmit == 0) apodization *= inversesqrt(dec_data_dim.z); 209 210 float sidx = sample_index(transmit_distance + distance(xdc_world_point, element_position)); 211 result += apodization * sample_rf(u_channel, transmit, sidx); 212 } 213 } 214 return vec3(result, 0); 215 } 216 #else 217 vec3 HERCULES(vec3 world_point) 218 { 219 bool uhercules = das_shader_id == DAS_ID_UHERCULES; 220 vec3 xdc_world_point = (xdc_transform * vec4(world_point, 1)).xyz; 221 bool tx_rows = !TX_MODE_TX_COLS(transmit_mode); 222 bool rx_cols = TX_MODE_RX_COLS(transmit_mode); 223 vec2 focal_vector = imageLoad(focal_vectors, 0).xy; 224 float transmit_angle = radians(focal_vector.x); 225 float focal_depth = focal_vector.y; 226 227 float transmit_distance; 228 if (isinf(focal_depth)) { 229 transmit_distance = plane_wave_transmit_distance(world_point, transmit_angle, tx_rows); 230 } else { 231 transmit_distance = cylindrical_wave_transmit_distance(world_point, focal_depth, 232 transmit_angle, tx_rows); 233 } 234 235 vec3 result = vec3(0); 236 for (int transmit = int(uhercules); transmit < dec_data_dim.z; transmit++) { 237 int tx_channel = uhercules ? imageLoad(sparse_elements, transmit - int(uhercules)).x : transmit; 238 for (int rx_channel = 0; rx_channel < dec_data_dim.y; rx_channel++) { 239 vec3 element_position; 240 if (rx_cols) element_position = vec3(rx_channel, tx_channel, 0) * vec3(xdc_element_pitch, 0); 241 else element_position = vec3(tx_channel, rx_channel, 0) * vec3(xdc_element_pitch, 0); 242 243 float apodization = apodize(f_number * radians(180) / abs(xdc_world_point.z) * 244 distance(xdc_world_point.xy, element_position.xy)); 245 if (apodization > 0) { 246 /* NOTE: tribal knowledge */ 247 if (transmit == 0) apodization *= inversesqrt(dec_data_dim.z); 248 249 float sidx = sample_index(transmit_distance + distance(xdc_world_point, element_position)); 250 vec2 value = apodization * sample_rf(rx_channel, transmit, sidx); 251 result += vec3(value, length(value)); 252 } 253 } 254 } 255 return result; 256 } 257 #endif 258 259 #if DAS_FAST 260 vec3 FORCES(vec3 world_point) 261 { 262 bool uforces = das_shader_id == DAS_ID_UFORCES; 263 vec3 xdc_world_point = (xdc_transform * vec4(world_point, 1)).xyz; 264 float receive_distance = distance(xdc_world_point.xz, vec2(u_channel * xdc_element_pitch.x, 0)); 265 float apodization = apodize(f_number * radians(180) / abs(xdc_world_point.z) * 266 (xdc_world_point.x - u_channel * xdc_element_pitch.x)); 267 268 vec2 result = vec2(0); 269 if (apodization > 0) { 270 for (int transmit = int(uforces); transmit < dec_data_dim.z; transmit++) { 271 int tx_channel = uforces ? imageLoad(sparse_elements, transmit - int(uforces)).x : transmit; 272 vec3 transmit_center = vec3(xdc_element_pitch * vec2(tx_channel, floor(dec_data_dim.y / 2)), 0); 273 274 float sidx = sample_index(distance(xdc_world_point, transmit_center) + receive_distance); 275 result += apodization * sample_rf(u_channel, transmit, sidx); 276 } 277 } 278 return vec3(result, 0); 279 } 280 #else 281 vec3 FORCES(vec3 world_point) 282 { 283 bool uforces = das_shader_id == DAS_ID_UFORCES; 284 vec3 xdc_world_point = (xdc_transform * vec4(world_point, 1)).xyz; 285 286 vec3 result = vec3(0); 287 for (int rx_channel = 0; rx_channel < dec_data_dim.y; rx_channel++) { 288 float receive_distance = distance(xdc_world_point.xz, vec2(rx_channel * xdc_element_pitch.x, 0)); 289 float apodization = apodize(f_number * radians(180) / abs(xdc_world_point.z) * 290 (xdc_world_point.x - rx_channel * xdc_element_pitch.x)); 291 if (apodization > 0) { 292 for (int transmit = int(uforces); transmit < dec_data_dim.z; transmit++) { 293 int tx_channel = uforces ? imageLoad(sparse_elements, transmit - int(uforces)).x : transmit; 294 vec3 transmit_center = vec3(xdc_element_pitch * vec2(tx_channel, floor(dec_data_dim.y / 2)), 0); 295 296 float sidx = sample_index(distance(xdc_world_point, transmit_center) + receive_distance); 297 vec2 value = apodization * sample_rf(rx_channel, tx_channel, sidx); 298 result += vec3(value, length(value)); 299 } 300 } 301 } 302 return result; 303 } 304 #endif 305 306 void main() 307 { 308 ivec3 out_voxel = ivec3(gl_GlobalInvocationID); 309 #if DAS_FAST 310 vec3 sum = vec3(imageLoad(u_out_data_tex, out_voxel).xy, 0); 311 #else 312 vec3 sum = vec3(0); 313 out_voxel += u_voxel_offset; 314 #endif 315 316 vec3 world_point = (u_voxel_transform * vec4(out_voxel, 1)).xyz; 317 318 switch (das_shader_id) { 319 case DAS_ID_FORCES: 320 case DAS_ID_UFORCES: 321 { 322 sum += FORCES(world_point); 323 }break; 324 case DAS_ID_HERCULES: 325 case DAS_ID_UHERCULES: 326 { 327 sum += HERCULES(world_point); 328 }break; 329 case DAS_ID_FLASH: 330 case DAS_ID_RCA_TPW: 331 case DAS_ID_RCA_VLS: 332 { 333 sum += RCA(world_point); 334 }break; 335 } 336 337 /* TODO(rnp): scale such that brightness remains ~constant */ 338 if (coherency_weighting) sum.xy *= sum.xy / (sum.z + float(sum.z == 0)); 339 340 imageStore(u_out_data_tex, out_voxel, vec4(sum.xy, 0, 0)); 341 }