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