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