ogl_beamformer_lib.c (7730B)
1 /* See LICENSE for license details. */ 2 #include "ogl_beamformer_lib.h" 3 4 typedef struct { 5 BeamformerParameters raw; 6 enum compute_shaders compute_stages[16]; 7 u32 compute_stages_count; 8 b32 upload; 9 b32 export_next_frame; 10 c8 export_pipe_name[1024]; 11 } BeamformerParametersFull; 12 13 typedef struct { 14 iptr file; 15 char *name; 16 } Pipe; 17 18 #define INVALID_FILE (-1) 19 20 static volatile BeamformerParametersFull *g_bp; 21 static Pipe g_pipe = {.file = INVALID_FILE}; 22 23 #define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a)) 24 25 #if defined(__unix__) 26 #include <fcntl.h> 27 #include <sys/mman.h> 28 #include <sys/stat.h> 29 #include <unistd.h> 30 31 #define OS_EXPORT_PIPE_NAME "/tmp/beamformer_output_pipe" 32 33 #elif defined(_WIN32) 34 35 #define OS_EXPORT_PIPE_NAME "\\\\.\\pipe\\beamformer_output_fifo" 36 37 #define OPEN_EXISTING 3 38 #define GENERIC_WRITE 0x40000000 39 #define FILE_MAP_ALL_ACCESS 0x000F001F 40 41 #define PIPE_TYPE_BYTE 0x00 42 #define PIPE_ACCESS_INBOUND 0x01 43 44 #define W32(r) __declspec(dllimport) r __stdcall 45 W32(b32) CloseHandle(iptr); 46 W32(iptr) CreateFileA(c8 *, u32, u32, void *, u32, u32, void *); 47 W32(iptr) CreateNamedPipeA(c8 *, u32, u32, u32, u32, u32, u32, void *); 48 W32(iptr) MapViewOfFile(iptr, u32, u32, u32, u64); 49 W32(iptr) OpenFileMappingA(u32, b32, c8 *); 50 W32(b32) ReadFile(iptr, u8 *, i32, i32 *, void *); 51 W32(b32) WriteFile(iptr, u8 *, i32, i32 *, void *); 52 53 #else 54 #error Unsupported Platform 55 #endif 56 57 #if defined(__unix__) 58 static Pipe 59 os_open_read_pipe(char *name) 60 { 61 mkfifo(name, 0660); 62 return (Pipe){.file = open(name, O_RDONLY|O_NONBLOCK), .name = name}; 63 } 64 65 static void 66 os_close_read_pipe(Pipe p) 67 { 68 close(p.file); 69 unlink(p.name); 70 } 71 72 static b32 73 os_read_pipe(Pipe p, void *buf, size read_size) 74 { 75 size r = 0, total_read = 0; 76 do { 77 if (r != -1) 78 total_read += r; 79 r = read(p.file, buf + total_read, read_size - total_read); 80 } while (r); 81 return total_read == read_size; 82 } 83 84 static Pipe 85 os_open_named_pipe(char *name) 86 { 87 return (Pipe){.file = open(name, O_WRONLY), .name = name}; 88 } 89 90 static size 91 os_write_to_pipe(Pipe p, void *data, size len) 92 { 93 size written = 0, w = 0; 94 do { 95 if (w != -1) 96 written += w; 97 w = write(p.file, data + written, len - written); 98 } while(written != len && w != 0); 99 return written; 100 } 101 102 static BeamformerParametersFull * 103 os_open_shared_memory_area(char *name) 104 { 105 i32 fd = shm_open(name, O_RDWR, S_IRUSR|S_IWUSR); 106 if (fd == -1) 107 return NULL; 108 109 BeamformerParametersFull *new; 110 new = mmap(NULL, sizeof(*new), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 111 close(fd); 112 113 if (new == MAP_FAILED) 114 return NULL; 115 116 return new; 117 } 118 119 #elif defined(_WIN32) 120 121 static Pipe 122 os_open_read_pipe(char *name) 123 { 124 iptr file = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE, 1, 125 0, 1024UL * 1024UL, 0, 0); 126 return (Pipe){.file = file, .name = name}; 127 } 128 129 static void 130 os_close_read_pipe(Pipe p) 131 { 132 CloseHandle(p.file); 133 } 134 135 static b32 136 os_read_pipe(Pipe p, void *buf, size read_size) 137 { 138 i32 total_read = 0; 139 ReadFile(p.file, buf, read_size, &total_read, 0); 140 return total_read == read_size; 141 } 142 143 static Pipe 144 os_open_named_pipe(char *name) 145 { 146 iptr pipe = CreateFileA(name, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); 147 return (Pipe){.file = pipe, .name = name}; 148 } 149 150 static size 151 os_write_to_pipe(Pipe p, void *data, size len) 152 { 153 i32 bytes_written; 154 WriteFile(p.file, data, len, &bytes_written, 0); 155 return bytes_written; 156 } 157 158 static BeamformerParametersFull * 159 os_open_shared_memory_area(char *name) 160 { 161 iptr h = OpenFileMappingA(FILE_MAP_ALL_ACCESS, 0, name); 162 if (h == INVALID_FILE) 163 return 0; 164 165 BeamformerParametersFull *new; 166 iptr view = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*new)); 167 new = (BeamformerParametersFull *)view; 168 CloseHandle(h); 169 170 return new; 171 } 172 #endif 173 174 #if defined(MATLAB_CONSOLE) 175 #define mexErrMsgIdAndTxt mexErrMsgIdAndTxt_800 176 #define mexWarnMsgIdAndTxt mexWarnMsgIdAndTxt_800 177 void mexErrMsgIdAndTxt(const c8 *, c8 *, ...); 178 void mexWarnMsgIdAndTxt(const c8 *, c8 *, ...); 179 #define error_tag "ogl_beamformer_lib:error" 180 #define error_msg(...) mexErrMsgIdAndTxt(error_tag, __VA_ARGS__) 181 #define warning_msg(...) mexWarnMsgIdAndTxt(error_tag, __VA_ARGS__) 182 #else 183 #define error_msg(...) 184 #define warning_msg(...) 185 #endif 186 187 static b32 188 check_shared_memory(char *name) 189 { 190 if (!g_bp) { 191 g_bp = os_open_shared_memory_area(name); 192 if (!g_bp) { 193 error_msg("failed to open shared memory area"); 194 return 0; 195 } 196 } 197 return 1; 198 } 199 200 b32 201 set_beamformer_pipeline(char *shm_name, i32 *stages, i32 stages_count) 202 { 203 if (stages_count > ARRAY_COUNT(g_bp->compute_stages)) { 204 error_msg("maximum stage count is %u", ARRAY_COUNT(g_bp->compute_stages)); 205 return 0; 206 } 207 208 if (!check_shared_memory(shm_name)) 209 return 0; 210 211 for (i32 i = 0; i < stages_count; i++) { 212 switch (stages[i]) { 213 case CS_CUDA_DECODE: 214 case CS_CUDA_HILBERT: 215 case CS_DAS: 216 case CS_DEMOD: 217 case CS_HADAMARD: 218 case CS_MIN_MAX: 219 case CS_SUM: 220 g_bp->compute_stages[i] = stages[i]; 221 break; 222 default: 223 error_msg("invalid shader stage: %d", stages[i]); 224 return 0; 225 } 226 } 227 g_bp->compute_stages_count = stages_count; 228 229 return 1; 230 } 231 232 b32 233 send_data(char *pipe_name, char *shm_name, i16 *data, uv2 data_dim) 234 { 235 if (g_pipe.file == INVALID_FILE) { 236 g_pipe = os_open_named_pipe(pipe_name); 237 if (g_pipe.file == INVALID_FILE) { 238 error_msg("failed to open pipe"); 239 return 0; 240 } 241 } 242 243 if (!check_shared_memory(shm_name)) 244 return 0; 245 246 /* TODO: this probably needs a mutex around it if we want to change it here */ 247 g_bp->raw.rf_raw_dim = data_dim; 248 size data_size = data_dim.x * data_dim.y * sizeof(i16); 249 size written = os_write_to_pipe(g_pipe, data, data_size); 250 if (written != data_size) 251 warning_msg("failed to write full data to pipe: wrote: %ld", written); 252 g_bp->upload = 1; 253 254 return 1; 255 } 256 257 b32 258 set_beamformer_parameters(char *shm_name, BeamformerParameters *new_bp) 259 { 260 if (!check_shared_memory(shm_name)) 261 return 0; 262 263 u8 *src = (u8 *)new_bp, *dest = (u8 *)&g_bp->raw; 264 for (size i = 0; i < sizeof(BeamformerParameters); i++) 265 dest[i] = src[i]; 266 g_bp->upload = 1; 267 268 return 1; 269 } 270 271 void 272 beamform_data_synchronized(char *pipe_name, char *shm_name, i16 *data, uv2 data_dim, 273 uv3 output_points, f32 *out_data) 274 { 275 if (!check_shared_memory(shm_name)) 276 return; 277 278 if (output_points.x == 0) output_points.x = 1; 279 if (output_points.y == 0) output_points.y = 1; 280 if (output_points.z == 0) output_points.z = 1; 281 282 Pipe pipe = os_open_read_pipe(OS_EXPORT_PIPE_NAME); 283 if (pipe.file == INVALID_FILE) { 284 error_msg("failed to open export pipe"); 285 return; 286 } 287 288 if (g_pipe.file == INVALID_FILE) { 289 g_pipe = os_open_named_pipe(pipe_name); 290 if (g_pipe.file == INVALID_FILE) { 291 error_msg("failed to open data pipe"); 292 return; 293 } 294 } 295 296 g_bp->raw.rf_raw_dim = data_dim; 297 g_bp->raw.output_points.x = output_points.x; 298 g_bp->raw.output_points.y = output_points.y; 299 g_bp->raw.output_points.z = output_points.z; 300 g_bp->export_next_frame = 1; 301 302 s8 export_name = s8(OS_EXPORT_PIPE_NAME); 303 if (export_name.len > ARRAY_COUNT(g_bp->export_pipe_name)) { 304 error_msg("export pipe name too long"); 305 return; 306 } 307 308 for (u32 i = 0; i < export_name.len; i++) 309 g_bp->export_pipe_name[i] = export_name.data[i]; 310 311 g_bp->upload = 1; 312 313 size data_size = data_dim.x * data_dim.y * sizeof(i16); 314 size written = os_write_to_pipe(g_pipe, data, data_size); 315 if (written != data_size) { 316 /* error */ 317 error_msg("failed to write full data to pipe: wrote: %ld", written); 318 return; 319 } 320 321 size output_size = output_points.x * output_points.y * output_points.z * 2 * sizeof(f32); 322 b32 success = os_read_pipe(pipe, out_data, output_size); 323 os_close_read_pipe(pipe); 324 325 if (!success) 326 warning_msg("failed to read full export data from pipe\n"); 327 }