ogl_beamforming

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

throughput.c (6401B)


      1 /* See LICENSE for license details. */
      2 /* TODO(rnp):
      3  * [ ]: for finer grained evaluation of throughput latency just queue a data upload
      4  *      without replacing the data.
      5  * [ ]: bug: we aren't inserting rf data between each frame
      6  */
      7 
      8 #include "test_common.c"
      9 
     10 global iv3 g_output_points    = {{512, 1, 1024}};
     11 global v2  g_axial_extent     = {{ 10e-3f, 165e-3f}};
     12 global v2  g_lateral_extent   = {{-60e-3f,  60e-3f}};
     13 global f32 g_f_number         = 0.5f;
     14 
     15 typedef struct {
     16 	b32 loop;
     17 	u32 frame_number;
     18 
     19 	char **remaining;
     20 	i32    remaining_count;
     21 } Options;
     22 
     23 global b32 g_should_exit;
     24 
     25 function void
     26 usage(char *argv0)
     27 {
     28 	die("%s [--loop] [--frame n] parameters_file\n"
     29 	    "    --loop:    reupload data forever\n"
     30 	    "    --frame n: use frame n of the data for display\n",
     31 	    argv0);
     32 }
     33 
     34 function Options
     35 parse_argv(i32 argc, char *argv[])
     36 {
     37 	Options result = {0};
     38 
     39 	char *argv0 = argv[0];
     40 	shift(argv, argc);
     41 
     42 	while (argc > 0) {
     43 		str8 arg = str8_from_c_str(*argv);
     44 
     45 		if (str8_equal(arg, str8("--loop"))) {
     46 			shift(argv, argc);
     47 			result.loop = 1;
     48 		} else if (str8_equal(arg, str8("--frame"))) {
     49 			shift(argv, argc);
     50 			if (argc) {
     51 				result.frame_number = (u32)atoi(*argv);
     52 				shift(argv, argc);
     53 			}
     54 		} else if (arg.length > 0 && arg.data[0] == '-') {
     55 			usage(argv0);
     56 		} else {
     57 			break;
     58 		}
     59 	}
     60 
     61 	result.remaining       = argv;
     62 	result.remaining_count = argc;
     63 
     64 	return result;
     65 }
     66 
     67 function b32
     68 send_frame(void *restrict data, BeamformerSimpleParameters *restrict bp, BeamformerViewPlaneTag tag, u32 slot)
     69 {
     70 	u32 data_size = bp->raw_data_dimensions.E[0] * bp->raw_data_dimensions.E[1]
     71 	                * beamformer_data_kind_byte_size[bp->data_kind];
     72 	b32 result    = beamformer_push_data_with_compute(data, data_size, tag, slot);
     73 	if (!result && !g_should_exit) printf("lib error: %s\n", beamformer_get_last_error_string());
     74 
     75 	return result;
     76 }
     77 
     78 function void
     79 execute_study(Arena *arena, Stream path, Options *options)
     80 {
     81 	i32 path_work_index = path.widx;
     82 	stream_ensure_termination(&path, 0);
     83 
     84 	ZBP_Data raw_data = {0};
     85 	BeamformerSimpleParameters bp = {0};
     86 	if (!beamformer_simple_parameters_from_zbp_file(arena, &bp, (char *)path.data, &raw_data, 0))
     87 		die("failed to load parameters file: %s\n", (char *)path.data);
     88 	stream_reset(&path, path_work_index);
     89 
     90 	v2 min_coordinate = (v2){{g_lateral_extent.x, g_axial_extent.x}};
     91 	v2 max_coordinate = (v2){{g_lateral_extent.y, g_axial_extent.y}};
     92 	if (RXOrientation(bp.transmit_receive_orientation) == ZBP_RCAOrientation_Rows)
     93 		bp.das_voxel_transform = das_transform_2d_yz(min_coordinate, max_coordinate, 0);
     94 	else
     95 		bp.das_voxel_transform = das_transform_2d_xz(min_coordinate, max_coordinate, 0);
     96 
     97 	bp.output_points.x = g_output_points.x;
     98 	bp.output_points.y = g_output_points.z;
     99 	bp.output_points.z = 1;
    100 	bp.output_points.w = 1;
    101 
    102 	bp.f_number           = g_f_number;
    103 	bp.interpolation_mode = BeamformerInterpolationMode_Cubic;
    104 
    105 	bp.decimation_rate = 1;
    106 
    107 	if (bp.data_kind != BeamformerDataKind_Float32Complex &&
    108 	    bp.data_kind != BeamformerDataKind_Int16Complex)
    109 	{
    110 		bp.compute_stages[bp.compute_stages_count++] = BeamformerShaderKind_Demodulate;
    111 	}
    112 	bp.compute_stages[bp.compute_stages_count++] = BeamformerShaderKind_Decode;
    113 	bp.compute_stages[bp.compute_stages_count++] = BeamformerShaderKind_DAS;
    114 
    115 	BeamformerFilterParameters filter = {.sampling_frequency = bp.sampling_frequency / 2};
    116 	{
    117 		BeamformerEmissionParameters *ep = &bp.emission_parameters;
    118 		switch (bp.emission_parameters.kind) {
    119 
    120 		case BeamformerEmissionKind_Sine:{
    121 			filter.kind                    = BeamformerFilterKind_Kaiser;
    122 			filter.kaiser.beta             = 5.65f;
    123 			filter.kaiser.cutoff_frequency = 0.5f * ep->sine.frequency;
    124 			filter.kaiser.length           = 36;
    125 		}break;
    126 
    127 		case BeamformerEmissionKind_Chirp:{
    128 			filter.kind                        = BeamformerFilterKind_MatchedChirp;
    129 			filter.matched_chirp.duration      = ep->chirp.duration;
    130 			filter.matched_chirp.min_frequency = ep->chirp.min_frequency - bp.demodulation_frequency;
    131 			filter.matched_chirp.max_frequency = ep->chirp.max_frequency - bp.demodulation_frequency;
    132 			filter.complex                     = 1;
    133 
    134 			//bp.time_offset += ep->chirp.duration / 2;
    135 		}break;
    136 
    137 		InvalidDefaultCase;
    138 		}
    139 
    140 		beamformer_create_filter(&filter, 0, 0);
    141 
    142 		bp.compute_stage_parameters[0] = 0;
    143 	}
    144 
    145 	beamformer_push_simple_parameters(&bp);
    146 
    147 	beamformer_set_global_timeout(1000);
    148 
    149 	void *data = zbp_data_pointer(arena, &raw_data, path, options->frame_number);
    150 
    151 	if (options->loop) {
    152 		BeamformerLiveImagingParameters lip = {
    153 			.active = 1,
    154 			.acquisition_kind = bp.acquisition_kind,
    155 			.save_enabled = 1,
    156 			.acquisition_kind_enabled_flags = 1 << bp.acquisition_kind,
    157 		};
    158 
    159 		str8 short_name = str8("Throughput");
    160 		memory_copy(lip.save_name_tag, short_name.data, (u64)short_name.length);
    161 		lip.save_name_tag_length = (i32)short_name.length;
    162 		beamformer_set_live_parameters(&lip);
    163 
    164 		u32 frame = 0;
    165 		f32 times[32] = {0};
    166 		f32 data_size = (f32)(bp.raw_data_dimensions.E[0] * bp.raw_data_dimensions.E[1]
    167 		                      * beamformer_data_kind_byte_size[bp.data_kind]);
    168 		u64 start = os_timer_count();
    169 		f64 frequency = os_timer_frequency();
    170 		for (;!g_should_exit;) {
    171 			if (send_frame(data, &bp, BeamformerViewPlaneTag_XZ, 0)) {
    172 				u64 now   = os_timer_count();
    173 				f64 delta = (now - start) / frequency;
    174 				start = now;
    175 
    176 				if ((frame % 16) == 0) {
    177 					f32 sum = 0;
    178 					for (u32 i = 0; i < countof(times); i++)
    179 						sum += times[i] / countof(times);
    180 					printf("Frame Time: %8.3f [ms] | 32-Frame Average: %8.3f [ms] | %8.3f GB/s\n",
    181 					       delta * 1e3, sum * 1e3, data_size / (sum * (GB(1))));
    182 				}
    183 
    184 				times[frame % countof(times)] = delta;
    185 				frame++;
    186 			}
    187 			i32 flag = beamformer_live_parameters_get_dirty_flag();
    188 			if (flag != -1 && (1 << flag) == BeamformerLiveImagingDirtyFlags_StopImaging)
    189 				break;
    190 		}
    191 
    192 		lip.active = 0;
    193 		beamformer_set_live_parameters(&lip);
    194 	} else {
    195 		send_frame(data, &bp, BeamformerViewPlaneTag_XZ, 0);
    196 	}
    197 }
    198 
    199 function void
    200 sigint(i32 _signo)
    201 {
    202 	g_should_exit = 1;
    203 }
    204 
    205 BASE_IMPORT void
    206 entry_point(i32 argc, char *argv[])
    207 {
    208 	Options options = parse_argv(argc, argv);
    209 
    210 	if (options.remaining_count != 1)
    211 		usage(argv[0]);
    212 
    213 	signal(SIGINT, sigint);
    214 
    215 	Arena  *arena = arena_create();
    216 	Stream  path  = stream_alloc(arena, KB(4));
    217 	stream_append_str8(&path, str8_from_c_str(options.remaining[0]));
    218 
    219 	execute_study(arena, path, &options);
    220 }