ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | LICENSE

ogl_beamformer_lib.c (4297B)


      1 #include "ogl_beamformer_lib.h"
      2 typedef struct {
      3 	BeamformerParameters raw;
      4 	enum compute_shaders compute_stages[16];
      5 	u32                  compute_stages_count;
      6 	b32                  upload;
      7 } BeamformerParametersFull;
      8 
      9 #define ARRAY_COUNT(a) (sizeof(a) / sizeof(*a))
     10 
     11 #if defined(__unix__)
     12 #include <fcntl.h>
     13 #include <sys/mman.h>
     14 #include <sys/stat.h>
     15 #include <unistd.h>
     16 
     17 #define OS_INVALID_FILE (-1)
     18 typedef i32 os_file;
     19 typedef struct {
     20 	os_file  file;
     21 	char    *name;
     22 } os_pipe;
     23 #elif defined(_WIN32)
     24 #include <windows.h>
     25 
     26 #define OS_INVALID_FILE (INVALID_HANDLE_VALUE)
     27 typedef HANDLE os_file;
     28 typedef struct {
     29 	os_file  file;
     30 	char    *name;
     31 } os_pipe;
     32 
     33 #else
     34 #error Unsupported Platform
     35 #endif
     36 
     37 static volatile BeamformerParametersFull *g_bp;
     38 static os_pipe g_pipe = {.file = OS_INVALID_FILE};
     39 
     40 #if defined(__unix__)
     41 static os_pipe
     42 os_open_named_pipe(char *name)
     43 {
     44 	return (os_pipe){.file = open(name, O_WRONLY), .name = name};
     45 }
     46 
     47 static size
     48 os_write_to_pipe(os_pipe p, void *data, size len)
     49 {
     50 	size written = 0, w = 0;
     51 	do {
     52 		written += w;
     53 		w = write(p.file, data, len);
     54 	} while(written != len && w != 0);
     55 	return written;
     56 }
     57 
     58 static void
     59 os_close_pipe(void)
     60 {
     61 	close(g_pipe.file);
     62 }
     63 
     64 static BeamformerParametersFull *
     65 os_open_shared_memory_area(char *name)
     66 {
     67 	i32 fd = shm_open(name, O_RDWR, S_IRUSR|S_IWUSR);
     68 	if (fd == -1)
     69 		return NULL;
     70 
     71 	BeamformerParametersFull *new;
     72 	new = mmap(NULL, sizeof(*new), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
     73 	close(fd);
     74 
     75 	if (new == MAP_FAILED)
     76 		return NULL;
     77 
     78 	return new;
     79 }
     80 
     81 #elif defined(_WIN32)
     82 
     83 static os_pipe
     84 os_open_named_pipe(char *name)
     85 {
     86 	HANDLE pipe = CreateFileA(name, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
     87 	return (os_pipe){.file = pipe, .name = name};
     88 }
     89 
     90 static size
     91 os_write_to_pipe(os_pipe p, void *data, size len)
     92 {
     93 	DWORD bytes_written;
     94 	WriteFile(p.file, data, len, &bytes_written, 0);
     95 	return bytes_written;
     96 }
     97 
     98 static void
     99 os_close_pipe(void)
    100 {
    101 	CloseHandle(g_pipe.file);
    102 }
    103 
    104 static BeamformerParametersFull *
    105 os_open_shared_memory_area(char *name)
    106 {
    107 	HANDLE h = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name);
    108 	if (h == OS_INVALID_FILE)
    109 		return NULL;
    110 
    111 	BeamformerParametersFull *new;
    112 	new = MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*new));
    113 	CloseHandle(h);
    114 
    115 	return new;
    116 }
    117 #endif
    118 
    119 static void
    120 check_shared_memory(char *name)
    121 {
    122 	if (g_bp)
    123 		return;
    124 	g_bp = os_open_shared_memory_area(name);
    125 	if (g_bp == NULL)
    126 		mexErrMsgIdAndTxt("ogl_beamformer:shared_memory",
    127 		                  "failed to open shared memory area");
    128 }
    129 
    130 void
    131 set_beamformer_pipeline(char *shm_name, i32 *stages, i32 stages_count)
    132 {
    133 	if (stages_count > ARRAY_COUNT(g_bp->compute_stages)) {
    134 		mexErrMsgIdAndTxt("ogl_beamformer:config", "maximum stage count is %u",
    135 		                  ARRAY_COUNT(g_bp->compute_stages));
    136 		return;
    137 	}
    138 
    139 	check_shared_memory(shm_name);
    140 
    141 	for (i32 i = 0; i < stages_count; i++) {
    142 		switch (stages[i]) {
    143 		case CS_CUDA_DECODE:
    144 		case CS_CUDA_HILBERT:
    145 		case CS_DEMOD:
    146 		case CS_HADAMARD:
    147 		case CS_HERCULES:
    148 		case CS_MIN_MAX:
    149 		case CS_UFORCES:
    150 			g_bp->compute_stages[i] = stages[i];
    151 			break;
    152 		default:
    153 			mexErrMsgIdAndTxt("ogl_beamformer:config", "invalid shader stage: %d",
    154 			                  stages[i]);
    155 			return;
    156 		}
    157 	}
    158 
    159 	g_bp->compute_stages_count = stages_count;
    160 }
    161 
    162 void
    163 send_data(char *pipe_name, char *shm_name, i16 *data, uv2 data_dim)
    164 {
    165 	if (g_pipe.file == OS_INVALID_FILE) {
    166 		g_pipe = os_open_named_pipe(pipe_name);
    167 		if (g_pipe.file == OS_INVALID_FILE) {
    168 			mexErrMsgIdAndTxt("ogl_beamformer:pipe_error", "failed to open pipe");
    169 			return;
    170 		}
    171 	}
    172 
    173 	check_shared_memory(shm_name);
    174 	/* TODO: this probably needs a mutex around it if we want to change it here */
    175 	g_bp->raw.rf_raw_dim = data_dim;
    176 	size data_size       = data_dim.x * data_dim.y * sizeof(i16);
    177 	size written         = os_write_to_pipe(g_pipe, data, data_size);
    178 	if (written != data_size)
    179 		mexWarnMsgIdAndTxt("ogl_beamformer:write_error",
    180 		                   "failed to write full data to pipe: wrote: %ld", written);
    181 	g_bp->upload = 1;
    182 }
    183 
    184 void
    185 set_beamformer_parameters(char *shm_name, BeamformerParameters *new_bp)
    186 {
    187 	check_shared_memory(shm_name);
    188 
    189 	if (!g_bp)
    190 		return;
    191 
    192 	u8 *src = (u8 *)new_bp, *dest = (u8 *)&g_bp->raw;
    193 	for (size i = 0; i < sizeof(BeamformerParameters); i++)
    194 		dest[i] = src[i];
    195 	g_bp->upload = 1;
    196 }