ogl_beamforming

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

util.c (13286B)


      1 /* See LICENSE for license details. */
      2 #define zero_struct(s) mem_clear(s, 0, sizeof(*s))
      3 function void *
      4 mem_clear(void *restrict p_, u8 c, iz size)
      5 {
      6 	u8 *p = p_;
      7 	while (size > 0) p[--size] = c;
      8 	return p;
      9 }
     10 
     11 function void
     12 mem_copy(void *restrict dest, void *restrict src, uz n)
     13 {
     14 	u8 *s = src, *d = dest;
     15 	for (; n; n--) *d++ = *s++;
     16 }
     17 
     18 function void
     19 mem_move(u8 *dest, u8 *src, uz n)
     20 {
     21 	if (dest < src) mem_copy(dest, src, n);
     22 	else            while (n) { n--; dest[n] = src[n]; }
     23 }
     24 
     25 function u8 *
     26 arena_aligned_start(Arena a, uz alignment)
     27 {
     28 	uz padding = -(uintptr_t)a.beg & (alignment - 1);
     29 	u8 *result = a.beg + padding;
     30 	return result;
     31 }
     32 
     33 #define arena_capacity(a, t) arena_capacity_(a, sizeof(t), alignof(t))
     34 function iz
     35 arena_capacity_(Arena *a, iz size, uz alignment)
     36 {
     37 	iz available = a->end - arena_aligned_start(*a, alignment);
     38 	iz result    = available / size;
     39 	return result;
     40 }
     41 
     42 function u8 *
     43 arena_commit(Arena *a, iz size)
     44 {
     45 	assert(a->end - a->beg >= size);
     46 	u8 *result = a->beg;
     47 	a->beg += size;
     48 	return result;
     49 }
     50 
     51 function void
     52 arena_pop(Arena *a, iz length)
     53 {
     54 	a->beg -= length;
     55 }
     56 
     57 #define push_array(a, t, n) (t *)arena_alloc(a, sizeof(t), _Alignof(t), n)
     58 #define push_struct(a, t)   (t *)arena_alloc(a, sizeof(t), _Alignof(t), 1)
     59 function void *
     60 arena_alloc(Arena *a, iz len, uz align, iz count)
     61 {
     62 	void *result = 0;
     63 	if (a->beg) {
     64 		u8 *start = arena_aligned_start(*a, align);
     65 		iz available = a->end - start;
     66 		assert((available >= 0 && count <= available / len));
     67 		asan_unpoison_region(start, count * len);
     68 		a->beg = start + count * len;
     69 		/* TODO: Performance? */
     70 		result = mem_clear(start, 0, count * len);
     71 	}
     72 	return result;
     73 }
     74 
     75 enum { DA_INITIAL_CAP = 4 };
     76 #define da_reserve(a, s, n) \
     77   (s)->data = da_reserve_((a), (s)->data, &(s)->capacity, (s)->count + n, \
     78                           _Alignof(typeof(*(s)->data)), sizeof(*(s)->data))
     79 
     80 #define da_push(a, s) \
     81   ((s)->count == (s)->capacity  \
     82     ? da_reserve(a, s, 1),      \
     83       (s)->data + (s)->count++  \
     84     : (s)->data + (s)->count++)
     85 
     86 function void *
     87 da_reserve_(Arena *a, void *data, iz *capacity, iz needed, uz align, iz size)
     88 {
     89 	iz cap = *capacity;
     90 
     91 	/* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started
     92 	 * on the stack or someone allocated something in the middle of the arena during usage) */
     93 	if (!data || a->beg != (u8 *)data + cap * size) {
     94 		void *copy = arena_alloc(a, size, align, cap);
     95 		if (data) mem_copy(copy, data, (uz)(cap * size));
     96 		data = copy;
     97 	}
     98 
     99 	if (!cap) cap = DA_INITIAL_CAP;
    100 	while (cap < needed) cap *= 2;
    101 	arena_alloc(a, size, align, cap - *capacity);
    102 	*capacity = cap;
    103 	return data;
    104 }
    105 
    106 function Arena
    107 sub_arena(Arena *a, iz len, uz align)
    108 {
    109 	Arena result = {0};
    110 
    111 	uz padding = -(uintptr_t)a->beg & (align - 1);
    112 	result.beg   = a->beg + padding;
    113 	result.end   = result.beg + len;
    114 	arena_commit(a, len + (iz)padding);
    115 
    116 	return result;
    117 }
    118 
    119 function TempArena
    120 begin_temp_arena(Arena *a)
    121 {
    122 	TempArena result = {.arena = a, .old_beg = a->beg};
    123 	return result;
    124 }
    125 
    126 function void
    127 end_temp_arena(TempArena ta)
    128 {
    129 	Arena *a = ta.arena;
    130 	if (a) {
    131 		assert(a->beg >= ta.old_beg);
    132 		a->beg = ta.old_beg;
    133 	}
    134 }
    135 
    136 function u32
    137 utf8_encode(u8 *out, u32 cp)
    138 {
    139 	u32 result = 1;
    140 	if (cp <= 0x7F) {
    141 		out[0] = cp & 0x7F;
    142 	} else if (cp <= 0x7FF) {
    143 		result = 2;
    144 		out[0] = ((cp >>  6) & 0x1F) | 0xC0;
    145 		out[1] = ((cp >>  0) & 0x3F) | 0x80;
    146 	} else if (cp <= 0xFFFF) {
    147 		result = 3;
    148 		out[0] = ((cp >> 12) & 0x0F) | 0xE0;
    149 		out[1] = ((cp >>  6) & 0x3F) | 0x80;
    150 		out[2] = ((cp >>  0) & 0x3F) | 0x80;
    151 	} else if (cp <= 0x10FFFF) {
    152 		result = 4;
    153 		out[0] = ((cp >> 18) & 0x07) | 0xF0;
    154 		out[1] = ((cp >> 12) & 0x3F) | 0x80;
    155 		out[2] = ((cp >>  6) & 0x3F) | 0x80;
    156 		out[3] = ((cp >>  0) & 0x3F) | 0x80;
    157 	} else {
    158 		out[0] = '?';
    159 	}
    160 	return result;
    161 }
    162 
    163 function UnicodeDecode
    164 utf16_decode(u16 *data, iz length)
    165 {
    166 	UnicodeDecode result = {.cp = U32_MAX};
    167 	if (length) {
    168 		result.consumed = 1;
    169 		result.cp = data[0];
    170 		if (length > 1 && BETWEEN(data[0], 0xD800u, 0xDBFFu)
    171 		               && BETWEEN(data[1], 0xDC00u, 0xDFFFu))
    172 		{
    173 			result.consumed = 2;
    174 			result.cp = ((data[0] - 0xD800u) << 10u) | ((data[1] - 0xDC00u) + 0x10000u);
    175 		}
    176 	}
    177 	return result;
    178 }
    179 
    180 function u32
    181 utf16_encode(u16 *out, u32 cp)
    182 {
    183 	u32 result = 1;
    184 	if (cp == U32_MAX) {
    185 		out[0] = '?';
    186 	} else if (cp < 0x10000u) {
    187 		out[0] = (u16)cp;
    188 	} else {
    189 		u32 value = cp - 0x10000u;
    190 		out[0] = (u16)(0xD800u + (value >> 10u));
    191 		out[1] = (u16)(0xDC00u + (value & 0x3FFu));
    192 		result = 2;
    193 	}
    194 	return result;
    195 }
    196 
    197 function Stream
    198 stream_alloc(Arena *a, i32 cap)
    199 {
    200 	Stream result = {.cap = cap};
    201 	result.data = push_array(a, u8, cap);
    202 	return result;
    203 }
    204 
    205 function s8
    206 stream_to_s8(Stream *s)
    207 {
    208 	s8 result = s8("");
    209 	if (!s->errors) result = (s8){.len = s->widx, .data = s->data};
    210 	return result;
    211 }
    212 
    213 function void
    214 stream_reset(Stream *s, i32 index)
    215 {
    216 	s->errors = s->cap <= index;
    217 	if (!s->errors)
    218 		s->widx = index;
    219 }
    220 
    221 function void
    222 stream_commit(Stream *s, i32 count)
    223 {
    224 	s->errors |= !BETWEEN(s->widx + count, 0, s->cap);
    225 	if (!s->errors)
    226 		s->widx += count;
    227 }
    228 
    229 function void
    230 stream_append(Stream *s, void *data, iz count)
    231 {
    232 	s->errors |= (s->cap - s->widx) < count;
    233 	if (!s->errors) {
    234 		mem_copy(s->data + s->widx, data, (uz)count);
    235 		s->widx += (i32)count;
    236 	}
    237 }
    238 
    239 function void
    240 stream_append_byte(Stream *s, u8 b)
    241 {
    242 	stream_append(s, &b, 1);
    243 }
    244 
    245 function void
    246 stream_pad(Stream *s, u8 b, i32 n)
    247 {
    248 	while (n > 0) stream_append_byte(s, b), n--;
    249 }
    250 
    251 function void
    252 stream_append_s8(Stream *s, s8 str)
    253 {
    254 	stream_append(s, str.data, str.len);
    255 }
    256 
    257 #define stream_append_s8s(s, ...) stream_append_s8s_(s, arg_list(s8, ##__VA_ARGS__))
    258 function void
    259 stream_append_s8s_(Stream *s, s8 *strs, iz count)
    260 {
    261 	for (iz i = 0; i < count; i++)
    262 		stream_append(s, strs[i].data, strs[i].len);
    263 }
    264 
    265 function void
    266 stream_append_u64_width(Stream *s, u64 n, u64 min_width)
    267 {
    268 	u8 tmp[64];
    269 	u8 *end = tmp + sizeof(tmp);
    270 	u8 *beg = end;
    271 	min_width = MIN(sizeof(tmp), min_width);
    272 
    273 	do { *--beg = (u8)('0' + (n % 10)); } while (n /= 10);
    274 	while (end - beg > 0 && (uz)(end - beg) < min_width)
    275 		*--beg = '0';
    276 
    277 	stream_append(s, beg, end - beg);
    278 }
    279 
    280 function void
    281 stream_append_u64(Stream *s, u64 n)
    282 {
    283 	stream_append_u64_width(s, n, 0);
    284 }
    285 
    286 function void
    287 stream_append_hex_u64(Stream *s, u64 n)
    288 {
    289 	if (!s->errors) {
    290 		u8  buf[16];
    291 		u8 *end = buf + sizeof(buf);
    292 		u8 *beg = end;
    293 		while (n) {
    294 			*--beg = (u8)"0123456789abcdef"[n & 0x0F];
    295 			n >>= 4;
    296 		}
    297 		while (end - beg < 2)
    298 			*--beg = '0';
    299 		stream_append(s, beg, end - beg);
    300 	}
    301 }
    302 
    303 function void
    304 stream_append_i64(Stream *s, i64 n)
    305 {
    306 	if (n < 0) {
    307 		stream_append_byte(s, '-');
    308 		n *= -1;
    309 	}
    310 	stream_append_u64(s, (u64)n);
    311 }
    312 
    313 function void
    314 stream_append_f64(Stream *s, f64 f, u64 prec)
    315 {
    316 	if (f < 0) {
    317 		stream_append_byte(s, '-');
    318 		f *= -1;
    319 	}
    320 
    321 	/* NOTE: round last digit */
    322 	f += 0.5f / (f64)prec;
    323 
    324 	if (f >= (f64)(-1UL >> 1)) {
    325 		stream_append_s8(s, s8("inf"));
    326 	} else {
    327 		u64 integral = (u64)f;
    328 		u64 fraction = (u64)((f - (f64)integral) * (f64)prec);
    329 		stream_append_u64(s, integral);
    330 		stream_append_byte(s, '.');
    331 		for (u64 i = prec / 10; i > 1; i /= 10) {
    332 			if (i > fraction)
    333 				stream_append_byte(s, '0');
    334 		}
    335 		stream_append_u64(s, fraction);
    336 	}
    337 }
    338 
    339 function void
    340 stream_append_f64_e(Stream *s, f64 f)
    341 {
    342 	/* TODO: there should be a better way of doing this */
    343 	#if 0
    344 	/* NOTE: we ignore subnormal numbers for now */
    345 	union { f64 f; u64 u; } u = {.f = f};
    346 	i32 exponent = ((u.u >> 52) & 0x7ff) - 1023;
    347 	f32 log_10_of_2 = 0.301f;
    348 	i32 scale       = (exponent * log_10_of_2);
    349 	/* NOTE: normalize f */
    350 	for (i32 i = ABS(scale); i > 0; i--)
    351 		f *= (scale > 0)? 0.1f : 10.0f;
    352 	#else
    353 	i32 scale = 0;
    354 	if (f != 0) {
    355 		while (f > 1) {
    356 			f *= 0.1f;
    357 			scale++;
    358 		}
    359 		while (f < 1) {
    360 			f *= 10.0f;
    361 			scale--;
    362 		}
    363 	}
    364 	#endif
    365 
    366 	u32 prec = 100;
    367 	stream_append_f64(s, f, prec);
    368 	stream_append_byte(s, 'e');
    369 	stream_append_byte(s, scale >= 0? '+' : '-');
    370 	for (u32 i = prec / 10; i > 1; i /= 10)
    371 		stream_append_byte(s, '0');
    372 	stream_append_u64(s, (u64)ABS(scale));
    373 }
    374 
    375 function void
    376 stream_append_v2(Stream *s, v2 v)
    377 {
    378 	stream_append_byte(s, '{');
    379 	stream_append_f64(s, v.x, 100);
    380 	stream_append_s8(s, s8(", "));
    381 	stream_append_f64(s, v.y, 100);
    382 	stream_append_byte(s, '}');
    383 }
    384 
    385 function Stream
    386 arena_stream(Arena a)
    387 {
    388 	Stream result = {0};
    389 	result.data   = a.beg;
    390 	result.cap    = (i32)(a.end - a.beg);
    391 
    392 	/* TODO(rnp): no idea what to do here if we want to maintain the ergonomics */
    393 	asan_unpoison_region(result.data, result.cap);
    394 
    395 	return result;
    396 }
    397 
    398 function s8
    399 arena_stream_commit(Arena *a, Stream *s)
    400 {
    401 	ASSERT(s->data == a->beg);
    402 	s8 result = stream_to_s8(s);
    403 	arena_commit(a, result.len);
    404 	return result;
    405 }
    406 
    407 function s8
    408 arena_stream_commit_zero(Arena *a, Stream *s)
    409 {
    410 	b32 error = s->errors || s->widx == s->cap;
    411 	if (!error)
    412 		s->data[s->widx] = 0;
    413 	s8 result = stream_to_s8(s);
    414 	arena_commit(a, result.len + 1);
    415 	return result;
    416 }
    417 
    418 /* NOTE(rnp): FNV-1a hash */
    419 function u64
    420 s8_hash(s8 v)
    421 {
    422 	u64 h = 0x3243f6a8885a308d; /* digits of pi */
    423 	for (; v.len; v.len--) {
    424 		h ^= v.data[v.len - 1] & 0xFF;
    425 		h *= 1111111111111111111; /* random prime */
    426 	}
    427 	return h;
    428 }
    429 
    430 function s8
    431 c_str_to_s8(char *cstr)
    432 {
    433 	s8 result = {.data = (u8 *)cstr};
    434 	if (cstr) { while (*cstr) { result.len++; cstr++; } }
    435 	return result;
    436 }
    437 
    438 /* NOTE(rnp): returns < 0 if byte is not found */
    439 function iz
    440 s8_scan_backwards(s8 s, u8 byte)
    441 {
    442 	iz result = s.len;
    443 	while (result && s.data[result - 1] != byte) result--;
    444 	result--;
    445 	return result;
    446 }
    447 
    448 function s8
    449 s8_cut_head(s8 s, iz cut)
    450 {
    451 	s8 result = s;
    452 	if (cut > 0) {
    453 		result.data += cut;
    454 		result.len  -= cut;
    455 	}
    456 	return result;
    457 }
    458 
    459 function s8
    460 s8_alloc(Arena *a, iz len)
    461 {
    462 	s8 result = {.data = push_array(a, u8, len), .len = len};
    463 	return result;
    464 }
    465 
    466 function s8
    467 s16_to_s8(Arena *a, s16 in)
    468 {
    469 	s8 result = s8("");
    470 	if (in.len) {
    471 		iz commit = in.len * 4;
    472 		iz length = 0;
    473 		u8 *data = arena_commit(a, commit + 1);
    474 		u16 *beg = in.data;
    475 		u16 *end = in.data + in.len;
    476 		while (beg < end) {
    477 			UnicodeDecode decode = utf16_decode(beg, end - beg);
    478 			length += utf8_encode(data + length, decode.cp);
    479 			beg    += decode.consumed;
    480 		}
    481 		data[length] = 0;
    482 		result = (s8){.len = length, .data = data};
    483 		arena_pop(a, commit - length);
    484 	}
    485 	return result;
    486 }
    487 
    488 function s16
    489 s8_to_s16(Arena *a, s8 in)
    490 {
    491 	s16 result = {0};
    492 	if (in.len) {
    493 		iz required = 2 * in.len + 1;
    494 		u16 *data   = push_array(a, u16, required);
    495 		iz length   = 0;
    496 		/* TODO(rnp): utf8_decode */
    497 		for (iz i = 0; i < in.len; i++) {
    498 			u32 cp  = in.data[i];
    499 			length += utf16_encode(data + length, cp);
    500 		}
    501 		result = (s16){.len = length, .data = data};
    502 		arena_pop(a, required - length);
    503 	}
    504 	return result;
    505 }
    506 
    507 function s8
    508 push_s8(Arena *a, s8 str)
    509 {
    510 	s8 result = s8_alloc(a, str.len);
    511 	mem_copy(result.data, str.data, (uz)result.len);
    512 	return result;
    513 }
    514 
    515 function s8
    516 push_s8_zero(Arena *a, s8 str)
    517 {
    518 	s8 result   = s8_alloc(a, str.len + 1);
    519 	result.len -= 1;
    520 	mem_copy(result.data, str.data, (uz)result.len);
    521 	return result;
    522 }
    523 
    524 function u32
    525 round_down_power_of_2(u32 a)
    526 {
    527 	u32 result = 0x80000000UL >> clz_u32(a);
    528 	return result;
    529 }
    530 
    531 function u32
    532 round_up_power_of_2(u32 a)
    533 {
    534 	u32 result = 0x80000000UL >> (clz_u32(a - 1) - 1);
    535 	return result;
    536 }
    537 
    538 function iz
    539 round_up_to(iz value, iz multiple)
    540 {
    541 	iz result = value;
    542 	if (value % multiple != 0)
    543 		result += multiple - value % multiple;
    544 	return result;
    545 }
    546 
    547 function void
    548 split_rect_horizontal(Rect rect, f32 fraction, Rect *left, Rect *right)
    549 {
    550 	if (left) {
    551 		left->pos    = rect.pos;
    552 		left->size.h = rect.size.h;
    553 		left->size.w = rect.size.w * fraction;
    554 	}
    555 	if (right) {
    556 		right->pos    = rect.pos;
    557 		right->pos.x += rect.size.w * fraction;
    558 		right->size.h = rect.size.h;
    559 		right->size.w = rect.size.w * (1.0f - fraction);
    560 	}
    561 }
    562 
    563 function void
    564 split_rect_vertical(Rect rect, f32 fraction, Rect *top, Rect *bot)
    565 {
    566 	if (top) {
    567 		top->pos    = rect.pos;
    568 		top->size.w = rect.size.w;
    569 		top->size.h = rect.size.h * fraction;
    570 	}
    571 	if (bot) {
    572 		bot->pos    = rect.pos;
    573 		bot->pos.y += rect.size.h * fraction;
    574 		bot->size.w = rect.size.w;
    575 		bot->size.h = rect.size.h * (1.0f - fraction);
    576 	}
    577 }
    578 
    579 function void
    580 cut_rect_horizontal(Rect rect, f32 at, Rect *left, Rect *right)
    581 {
    582 	at = MIN(at, rect.size.w);
    583 	if (left) {
    584 		*left = rect;
    585 		left->size.w = at;
    586 	}
    587 	if (right) {
    588 		*right = rect;
    589 		right->pos.x  += at;
    590 		right->size.w -= at;
    591 	}
    592 }
    593 
    594 function void
    595 cut_rect_vertical(Rect rect, f32 at, Rect *top, Rect *bot)
    596 {
    597 	at = MIN(at, rect.size.h);
    598 	if (top) {
    599 		*top = rect;
    600 		top->size.h = at;
    601 	}
    602 	if (bot) {
    603 		*bot = rect;
    604 		bot->pos.y  += at;
    605 		bot->size.h -= at;
    606 	}
    607 }
    608 
    609 function f64
    610 parse_f64(s8 s)
    611 {
    612 	f64 integral = 0, fractional = 0, sign = 1;
    613 
    614 	if (s.len && *s.data == '-') {
    615 		sign = -1;
    616 		s.data++;
    617 		s.len--;
    618 	}
    619 
    620 	while (s.len && *s.data != '.') {
    621 		integral *= 10;
    622 		integral += *s.data - '0';
    623 		s.data++;
    624 		s.len--;
    625 	}
    626 
    627 	if (*s.data == '.') { s.data++; s.len--; }
    628 
    629 	while (s.len) {
    630 		ASSERT(s.data[s.len - 1] != '.');
    631 		fractional /= 10;
    632 		fractional += (f64)(s.data[--s.len] - '0') / 10.0;
    633 	}
    634 	f64 result = sign * (integral + fractional);
    635 	return result;
    636 }
    637 
    638 function FileWatchDirectory *
    639 lookup_file_watch_directory(FileWatchContext *ctx, u64 hash)
    640 {
    641 	FileWatchDirectory *result = 0;
    642 	for (u32 i = 0; i < ctx->count; i++) {
    643 		FileWatchDirectory *test = ctx->data + i;
    644 		if (test->hash == hash) {
    645 			result = test;
    646 			break;
    647 		}
    648 	}
    649 	return result;
    650 }