Commit: b320ad663f99c17ad943af888f008a0b43a4c302
Parent: 4c026672a45a3742cdc02269e2939b62d930fa49
Author: Randy Palamar
Date: Sat, 12 Jul 2025 11:58:06 -0600
core/build: go all in on ubsan/asan
ubsan/asan are now always enabled in debug builds (they can still
be optionally enabled in release build).
For asan purposes freelist members are now poisoned when pushed
and unpoisoned when popped. Arenas are fully poisoned at
appropriate places but this has some drawbacks, particularly for
arena_stream(). It will catch anything in a frame up until a call
to arena_stream(). That part could be worked on later as
necessary.
This also fixes debug build with GCC (specifically with ld as the
linker) which was broken since 45daa35.
Finally, a bunch of memory was moved off the stack and pushed into
the arena to improve locality.
Diffstat:
12 files changed, 196 insertions(+), 122 deletions(-)
diff --git a/beamformer.c b/beamformer.c
@@ -141,8 +141,8 @@ alloc_shader_storage(BeamformerCtx *ctx, u32 rf_raw_size, Arena a)
}
/* NOTE(rnp): these are stubs when CUDA isn't supported */
- ctx->cuda_lib.register_buffers(cs->rf_data_ssbos, countof(cs->rf_data_ssbos), cs->raw_data_ssbo);
- ctx->cuda_lib.init(bp->rf_raw_dim, bp->dec_data_dim);
+ cs->cuda_lib.register_buffers(cs->rf_data_ssbos, countof(cs->rf_data_ssbos), cs->raw_data_ssbo);
+ cs->cuda_lib.init(bp->rf_raw_dim, bp->dec_data_dim);
i32 order = (i32)cs->dec_data_dim.z;
i32 *hadamard = make_hadamard_transpose(&a, order);
@@ -309,11 +309,11 @@ do_compute_shader(BeamformerCtx *ctx, Arena arena, BeamformerComputeFrame *frame
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
}break;
case BeamformerShaderKind_CudaDecode:{
- ctx->cuda_lib.decode(0, output_ssbo_idx, 0);
+ csctx->cuda_lib.decode(0, output_ssbo_idx, 0);
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
}break;
case BeamformerShaderKind_CudaHilbert:
- ctx->cuda_lib.hilbert(input_ssbo_idx, output_ssbo_idx);
+ csctx->cuda_lib.hilbert(input_ssbo_idx, output_ssbo_idx);
csctx->last_output_ssbo_index = !csctx->last_output_ssbo_index;
break;
case BeamformerShaderKind_Demodulate:{
@@ -581,7 +581,7 @@ complete_queue(BeamformerCtx *ctx, BeamformWorkQueue *q, Arena arena, iptr gl_co
tex_type = GL_SHORT;
tex_format = GL_RED_INTEGER;
tex_element_count = countof(sm->channel_mapping);
- ctx->cuda_lib.set_channel_mapping(sm->channel_mapping);
+ cs->cuda_lib.set_channel_mapping(sm->channel_mapping);
} break;
case BU_KIND_FOCAL_VECTORS: {
tex_1d = cs->focal_vectors_texture;
@@ -745,7 +745,7 @@ coalesce_timing_table(ComputeTimingTable *t, ComputeShaderStats *stats)
}break;
case ComputeTimingInfoKind_Shader:{
stats->table.times[stats_index][info.shader] += (f32)info.timer_count / 1.0e9f;
- seen_info_test |= (1 << info.shader);
+ seen_info_test |= (1u << info.shader);
}break;
case ComputeTimingInfoKind_RF_Data:{
stats->latest_rf_index = (stats->latest_rf_index + 1) % countof(stats->table.rf_time_deltas);
diff --git a/beamformer.h b/beamformer.h
@@ -107,6 +107,9 @@ typedef struct {
u32 focal_vectors_texture;
u32 hadamard_texture;
+ uv4 dec_data_dim;
+ u32 rf_raw_size;
+
f32 processing_progress;
b32 processing_compute;
@@ -114,10 +117,8 @@ typedef struct {
u32 shader_timer_ids[MAX_COMPUTE_SHADER_STAGES];
- uv4 dec_data_dim;
- u32 rf_raw_size;
-
BeamformerRenderModel unit_cube_model;
+ CudaLib cuda_lib;
} ComputeShaderCtx;
typedef enum {
@@ -214,24 +215,14 @@ typedef struct {
/* TODO(rnp): this is nasty and should be removed */
b32 ui_read_params;
- BeamformerComputeFrame beamform_frames[MAX_BEAMFORMED_SAVED_FRAMES];
- BeamformerComputeFrame *latest_frame;
- u32 next_render_frame_index;
- u32 display_frame_index;
-
- /* NOTE: this will only be used when we are averaging */
- u32 averaged_frame_index;
- BeamformerComputeFrame averaged_frames[2];
-
ComputeShaderCtx csctx;
/* TODO(rnp): ideally this would go in the UI but its hard to manage with the UI
* destroying itself on hot-reload */
FrameViewRenderContext frame_view_render_context;
- CudaLib cuda_lib;
- OS os;
- Stream error_stream;
+ OS os;
+ Stream error_stream;
BeamformWorkQueue *beamform_work_queue;
@@ -239,6 +230,15 @@ typedef struct {
ComputeTimingTable *compute_timing_table;
SharedMemoryRegion shared_memory;
+
+ BeamformerComputeFrame beamform_frames[MAX_BEAMFORMED_SAVED_FRAMES];
+ BeamformerComputeFrame *latest_frame;
+ u32 next_render_frame_index;
+ u32 display_frame_index;
+
+ /* NOTE: this will only be used when we are averaging */
+ u32 averaged_frame_index;
+ BeamformerComputeFrame averaged_frames[2];
} BeamformerCtx;
struct ShaderReloadContext {
@@ -265,4 +265,7 @@ typedef BEAMFORMER_COMPLETE_COMPUTE_FN(beamformer_complete_compute_fn);
ShaderReloadContext *src, Arena arena, s8 shader_name)
typedef BEAMFORMER_RELOAD_SHADER_FN(beamformer_reload_shader_fn);
+#define BEAMFORMER_DEBUG_UI_DEINIT_FN(name) void name(BeamformerCtx *ctx)
+typedef BEAMFORMER_DEBUG_UI_DEINIT_FN(beamformer_debug_ui_deinit_fn);
+
#endif /*_BEAMFORMER_H_ */
diff --git a/build.c b/build.c
@@ -417,10 +417,16 @@ cmd_base(Arena *a, Options *o)
if (o->debug && is_unix) cmd_append(a, &result, "-ggdb");
- if (o->sanitize) {
- if (!is_msvc) cmd_append(a, &result, "-fsanitize=address,undefined");
- else build_log_warning("santizers not supported with this compiler");
+ /* NOTE(rnp): need to avoid w32-gcc for ci */
+ b32 sanitize = !is_msvc && (o->debug || o->sanitize) && !(is_w32 && is_gcc);
+ if (sanitize) {
+ cmd_append(a, &result, "-fsanitize=address,undefined");
+ /* NOTE(rnp): impossible to autodetect on GCC versions < 14 (ci has 13) */
+ cmd_append(a, &result, "-DASAN_ACTIVE=1");
+ } else {
+ cmd_append(a, &result, "-DASAN_ACTIVE=0");
}
+ if (!sanitize && o->sanitize) build_log_warning("santizers not supported with this compiler");
return result;
}
@@ -778,6 +784,9 @@ main(i32 argc, char *argv[])
cmd_append(&arena, &c, OS_MAIN, OUTPUT_EXE("ogl"));
cmd_pdb(&arena, &c, "ogl");
if (options.debug) {
+ /* NOTE(rnp): (gnu) ld doesn't properly export global symbols without this */
+ if (is_gcc) cmd_append(&arena, &c, "-Wl,--export-dynamic");
+
if (!is_w32) cmd_append(&arena, &c, "-Wl,-rpath,.");
if (!is_msvc) cmd_append(&arena, &c, "-L.");
cmd_append(&arena, &c, LINK_LIB("raylib"));
diff --git a/main_linux.c b/main_linux.c
@@ -73,47 +73,37 @@ dispatch_file_watch_events(OS *os, Arena arena)
extern i32
main(void)
{
- BeamformerCtx ctx = {0};
- BeamformerInput input = {.executable_reloaded = 1};
- Arena temp_memory = os_alloc_arena(MB(16));
- ctx.error_stream = stream_alloc(&temp_memory, MB(1));
+ Arena program_memory = os_alloc_arena(MB(16));
- ctx.ui_backing_store = sub_arena(&temp_memory, MB(2), KB(4));
- ctx.os.compute_worker.arena = sub_arena(&temp_memory, MB(2), KB(4));
+ BeamformerCtx *ctx = 0;
+ BeamformerInput *input = 0;
- #define X(name) ctx.os.name = os_ ## name;
- OS_FNS
- #undef X
-
- ctx.os.file_watch_context.handle = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- ctx.os.compute_worker.asleep = 1;
- ctx.os.error_handle = STDERR_FILENO;
-
- setup_beamformer(&ctx, &input, &temp_memory);
- os_wake_waiters(&ctx.os.compute_worker.sync_variable);
+ setup_beamformer(&program_memory, &ctx, &input);
+ os_wake_waiters(&ctx->os.compute_worker.sync_variable);
struct pollfd fds[1] = {{0}};
- fds[0].fd = (i32)ctx.os.file_watch_context.handle;
+ fds[0].fd = (i32)ctx->os.file_watch_context.handle;
fds[0].events = POLLIN;
u64 last_time = os_get_timer_counter();
- while (!ctx.should_exit) {
+ while (!ctx->should_exit) {
poll(fds, countof(fds), 0);
if (fds[0].revents & POLLIN)
- dispatch_file_watch_events(&ctx.os, temp_memory);
+ dispatch_file_watch_events(&ctx->os, program_memory);
u64 now = os_get_timer_counter();
- input.last_mouse = input.mouse;
- input.mouse.rl = GetMousePosition();
- input.dt = (f32)((f64)(now - last_time) / (f64)os_get_timer_frequency());
- last_time = now;
+ input->last_mouse = input->mouse;
+ input->mouse.rl = GetMousePosition();
+ input->dt = (f32)((f64)(now - last_time) / (f64)os_get_timer_frequency());
+ last_time = now;
- beamformer_frame_step(&ctx, &input);
+ beamformer_frame_step(ctx, input);
- input.executable_reloaded = 0;
+ input->executable_reloaded = 0;
}
- beamformer_invalidate_shared_memory(&ctx);
+ beamformer_invalidate_shared_memory(ctx);
+ beamformer_debug_ui_deinit(ctx);
/* NOTE: make sure this will get cleaned up after external
* programs release their references */
diff --git a/main_w32.c b/main_w32.c
@@ -78,7 +78,7 @@ dispatch_file_watch(OS *os, FileWatchDirectory *fw_dir, u8 *buf, Arena arena)
function void
clear_io_queue(OS *os, BeamformerInput *input, Arena arena)
{
- os_w32_context *ctx = (os_w32_context *)os->context;
+ w32_context *ctx = (w32_context *)os->context;
iptr handle = ctx->io_completion_handle;
w32_overlapped *overlapped;
@@ -102,43 +102,30 @@ clear_io_queue(OS *os, BeamformerInput *input, Arena arena)
extern i32
main(void)
{
- BeamformerCtx ctx = {0};
- BeamformerInput input = {.executable_reloaded = 1};
- Arena temp_memory = os_alloc_arena(MB(16));
- ctx.error_stream = stream_alloc(&temp_memory, MB(1));
+ Arena program_memory = os_alloc_arena(MB(16));
- ctx.ui_backing_store = sub_arena(&temp_memory, MB(2), KB(4));
- ctx.os.compute_worker.arena = sub_arena(&temp_memory, MB(2), KB(4));
+ BeamformerCtx *ctx = 0;
+ BeamformerInput *input = 0;
- #define X(name) ctx.os.name = os_ ## name;
- OS_FNS
- #undef X
-
- os_w32_context w32_ctx = {0};
- w32_ctx.io_completion_handle = CreateIoCompletionPort(INVALID_FILE, 0, 0, 0);
- w32_ctx.timer_frequency = os_get_timer_frequency();
-
- ctx.os.context = (iptr)&w32_ctx;
- ctx.os.compute_worker.asleep = 1;
- ctx.os.error_handle = GetStdHandle(STD_ERROR_HANDLE);
-
- setup_beamformer(&ctx, &input, &temp_memory);
- os_wake_waiters(&ctx.os.compute_worker.sync_variable);
+ setup_beamformer(&program_memory, &ctx, &input);
+ os_wake_waiters(&ctx->os.compute_worker.sync_variable);
+ w32_context *w32_ctx = (w32_context *)ctx->os.context;
u64 last_time = os_get_timer_counter();
- while (!ctx.should_exit) {
- clear_io_queue(&ctx.os, &input, temp_memory);
+ while (!ctx->should_exit) {
+ clear_io_queue(&ctx->os, input, program_memory);
u64 now = os_get_timer_counter();
- input.last_mouse = input.mouse;
- input.mouse.rl = GetMousePosition();
- input.dt = (f32)((f64)(now - last_time) / (f64)w32_ctx.timer_frequency);
- last_time = now;
+ input->last_mouse = input->mouse;
+ input->mouse.rl = GetMousePosition();
+ input->dt = (f32)((f64)(now - last_time) / (f64)w32_ctx->timer_frequency);
+ last_time = now;
- beamformer_frame_step(&ctx, &input);
+ beamformer_frame_step(ctx, input);
- input.executable_reloaded = 0;
+ input->executable_reloaded = 0;
}
- beamformer_invalidate_shared_memory(&ctx);
+ beamformer_invalidate_shared_memory(ctx);
+ beamformer_debug_ui_deinit(ctx);
}
diff --git a/os_linux.c b/os_linux.c
@@ -97,6 +97,7 @@ function OS_ALLOC_ARENA_FN(os_alloc_arena)
if (result.beg == MAP_FAILED)
os_fatal(s8("os_alloc_arena: couldn't allocate memory\n"));
result.end = result.beg + capacity;
+ asan_poison_region(result.beg, result.end - result.beg);
return result;
}
@@ -294,3 +295,14 @@ function OS_SHARED_MEMORY_UNLOCK_REGION_FN(os_shared_memory_region_unlock)
atomic_store_u32(lock, 0);
os_wake_waiters(lock);
}
+
+function void
+os_init(OS *os, Arena *program_memory)
+{
+ #define X(name) os->name = os_ ## name;
+ OS_FNS
+ #undef X
+
+ os->file_watch_context.handle = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+ os->error_handle = STDERR_FILENO;
+}
diff --git a/os_win32.c b/os_win32.c
@@ -69,7 +69,7 @@ typedef struct {
typedef struct {
iptr io_completion_handle;
u64 timer_frequency;
-} os_w32_context;
+} w32_context;
typedef enum {
W32_IO_FILE_WATCH,
@@ -200,6 +200,7 @@ function OS_ALLOC_ARENA_FN(os_alloc_arena)
if (!result.beg)
os_fatal(s8("os_alloc_arena: couldn't allocate memory\n"));
result.end = result.beg + capacity;
+ asan_poison_region(result.beg, result.end - result.beg);
return result;
}
@@ -346,7 +347,7 @@ function OS_ADD_FILE_WATCH_FN(os_add_file_watch)
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, 0);
- os_w32_context *ctx = (os_w32_context *)os->context;
+ w32_context *ctx = (w32_context *)os->context;
w32_io_completion_event *event = push_struct(a, typeof(*event));
event->tag = W32_IO_FILE_WATCH;
event->context = (iptr)dir;
@@ -402,3 +403,18 @@ function OS_SHARED_MEMORY_UNLOCK_REGION_FN(os_shared_memory_region_unlock)
os_wake_waiters(locks + lock_index);
ReleaseSemaphore(ctx->semaphores[lock_index], 1, 0);
}
+
+function void
+os_init(OS *os, Arena *program_memory)
+{
+ #define X(name) os->name = os_ ## name;
+ OS_FNS
+ #undef X
+
+ w32_context *ctx = push_struct(program_memory, typeof(*ctx));
+ ctx->io_completion_handle = CreateIoCompletionPort(INVALID_FILE, 0, 0, 0);
+ ctx->timer_frequency = os_get_timer_frequency();
+
+ os->error_handle = GetStdHandle(STD_ERROR_HANDLE);
+ os->context = (iptr)ctx;
+}
diff --git a/static.c b/static.c
@@ -9,6 +9,7 @@
global void *debug_lib;
#define DEBUG_ENTRY_POINTS \
+ X(beamformer_debug_ui_deinit) \
X(beamformer_frame_step) \
X(beamformer_complete_compute) \
X(beamformer_compute_setup) \
@@ -268,6 +269,7 @@ function OS_THREAD_ENTRY_POINT_FN(compute_worker_thread_entry_point)
os_wait_on_value(&ctx->sync_variable, 1, (u32)-1);
atomic_store_u32(&ctx->asleep, 0);
}
+ asan_poison_region(ctx->arena.beg, ctx->arena.end - ctx->arena.beg);
beamformer_complete_compute(ctx->user_context, ctx->arena, ctx->gl_context);
}
@@ -277,11 +279,25 @@ function OS_THREAD_ENTRY_POINT_FN(compute_worker_thread_entry_point)
}
function void
-setup_beamformer(BeamformerCtx *ctx, BeamformerInput *input, Arena *memory)
+setup_beamformer(Arena *memory, BeamformerCtx **o_ctx, BeamformerInput **o_input)
{
- debug_init(&ctx->os, (iptr)input, memory);
+ Arena compute_arena = sub_arena(memory, MB(2), KB(4));
+ Stream error = stream_alloc(memory, MB(1));
+ Arena ui_arena = sub_arena(memory, MB(2), KB(4));
+
+ BeamformerCtx *ctx = *o_ctx = push_struct(memory, typeof(*ctx));
+ BeamformerInput *input = *o_input = push_struct(memory, typeof(*input));
+
+ ctx->window_size = (iv2){{1280, 840}};
+ ctx->error_stream = error;
+ ctx->ui_backing_store = ui_arena;
+ input->executable_reloaded = 1;
- ctx->window_size = (iv2){{1280, 840}};
+ os_init(&ctx->os, memory);
+ ctx->os.compute_worker.arena = compute_arena;
+ ctx->os.compute_worker.asleep = 1;
+
+ debug_init(&ctx->os, (iptr)input, memory);
SetConfigFlags(FLAG_VSYNC_HINT|FLAG_WINDOW_ALWAYS_RUN);
InitWindow(ctx->window_size.w, ctx->window_size.h, "OGL Beamformer");
@@ -328,13 +344,13 @@ setup_beamformer(BeamformerCtx *ctx, BeamformerInput *input, Arena *memory)
glfwMakeContextCurrent(raylib_window_handle);
+ ComputeShaderCtx *cs = &ctx->csctx;
if (ctx->gl.vendor_id == GL_VENDOR_NVIDIA
- && load_cuda_lib(&ctx->os, s8(OS_CUDA_LIB_NAME), (iptr)&ctx->cuda_lib, *memory))
+ && load_cuda_lib(&ctx->os, s8(OS_CUDA_LIB_NAME), (iptr)&cs->cuda_lib, *memory))
{
- os_add_file_watch(&ctx->os, memory, s8(OS_CUDA_LIB_NAME), load_cuda_lib,
- (iptr)&ctx->cuda_lib);
+ os_add_file_watch(&ctx->os, memory, s8(OS_CUDA_LIB_NAME), load_cuda_lib, (iptr)&cs->cuda_lib);
} else {
- #define X(name, symname) if (!ctx->cuda_lib.name) ctx->cuda_lib.name = cuda_ ## name ## _stub;
+ #define X(name, symname) if (!cs->cuda_lib.name) cs->cuda_lib.name = cuda_ ## name ## _stub;
CUDA_LIB_FNS
#undef X
}
@@ -358,7 +374,6 @@ setup_beamformer(BeamformerCtx *ctx, BeamformerInput *input, Arena *memory)
);
#undef X
- ComputeShaderCtx *cs = &ctx->csctx;
#define X(e, sn, f, nh, pretty_name) do if (s8(f).len > 0) { \
ShaderReloadContext *src = push_struct(memory, typeof(*src)); \
src->beamformer_context = ctx; \
diff --git a/tests/throughput.c b/tests/throughput.c
@@ -111,7 +111,7 @@ os_read_file_simp(char *fname)
#elif OS_WINDOWS
-global os_w32_context os_context;
+global w32_context os_context;
function void
os_init_timer(void)
diff --git a/ui.c b/ui.c
@@ -897,14 +897,14 @@ ui_beamformer_frame_view_release_subresources(BeamformerUI *ui, BeamformerFrameV
if (kind == BeamformerFrameViewKind_Copy && bv->frame) {
glDeleteTextures(1, &bv->frame->texture);
bv->frame->texture = 0;
- SLLPush(bv->frame, ui->frame_freelist);
+ SLLPushFreelist(bv->frame, ui->frame_freelist);
}
if (kind != BeamformerFrameViewKind_3DXPlane) {
if (bv->axial_scale_bar.scale_bar.savepoint_stack)
- SLLPush(bv->axial_scale_bar.scale_bar.savepoint_stack, ui->scale_bar_savepoint_freelist);
+ SLLPushFreelist(bv->axial_scale_bar.scale_bar.savepoint_stack, ui->scale_bar_savepoint_freelist);
if (bv->lateral_scale_bar.scale_bar.savepoint_stack)
- SLLPush(bv->lateral_scale_bar.scale_bar.savepoint_stack, ui->scale_bar_savepoint_freelist);
+ SLLPushFreelist(bv->lateral_scale_bar.scale_bar.savepoint_stack, ui->scale_bar_savepoint_freelist);
}
}
@@ -925,19 +925,19 @@ ui_variable_free(BeamformerUI *ui, Variable *var)
/* TODO(rnp): hack; use a sentinal */
if (bv == ui->views)
ui->views = bv->next;
- SLLPush(bv, ui->view_freelist);
+ SLLPushFreelist(bv, ui->view_freelist);
}
- Variable *next = var->next;
- SLLPush(var, ui->variable_freelist);
- if (next) {
- var = next;
+ Variable *dead = var;
+ if (var->next) {
+ var = var->next;
} else {
var = var->parent;
/* NOTE(rnp): when we assign parent here we have already
* released the children. Assign type so we don't loop */
if (var) var->type = VT_NULL;
}
+ SLLPushFreelist(dead, ui->variable_freelist);
}
}
}
@@ -984,7 +984,7 @@ function Variable *
add_variable(BeamformerUI *ui, Variable *group, Arena *arena, s8 name, u32 flags,
VariableType type, Font font)
{
- Variable *result = SLLPop(ui->variable_freelist);
+ Variable *result = SLLPopFreelist(ui->variable_freelist);
if (result) zero_struct(result);
else result = push_struct(arena, Variable);
return fill_variable(result, group, name, flags, type, font);
@@ -1284,7 +1284,7 @@ ui_beamformer_frame_view_convert(BeamformerUI *ui, Arena *arena, Variable *view,
function BeamformerFrameView *
ui_beamformer_frame_view_new(BeamformerUI *ui, Arena *arena)
{
- BeamformerFrameView *result = SLLPop(ui->view_freelist);
+ BeamformerFrameView *result = SLLPopFreelist(ui->view_freelist);
if (result) zero_struct(result);
else result = push_struct(arena, typeof(*result));
DLLPushDown(result, ui->views);
@@ -1408,7 +1408,7 @@ function void
ui_beamformer_frame_view_copy_frame(BeamformerUI *ui, BeamformerFrameView *new, BeamformerFrameView *old)
{
assert(old->frame);
- new->frame = SLLPop(ui->frame_freelist);
+ new->frame = SLLPopFreelist(ui->frame_freelist);
if (!new->frame) new->frame = push_struct(&ui->arena, typeof(*new->frame));
mem_copy(new->frame, old->frame, sizeof(*new->frame));
@@ -2582,9 +2582,9 @@ draw_compute_stats_bar_view(BeamformerUI *ui, Arena arena, ComputeShaderStats *s
u32 frame_index = (stats->latest_frame_index - i) % countof(stats->table.times);
u32 seen_shaders = 0;
for (u32 j = 0; j < stages_count; j++) {
- if ((seen_shaders & (1 << stages[j])) == 0)
+ if ((seen_shaders & (1u << stages[j])) == 0)
total_times[i] += stats->table.times[frame_index][stages[j]];
- seen_shaders |= (1 << stages[j]);
+ seen_shaders |= (1u << stages[j]);
}
}
@@ -2675,9 +2675,9 @@ draw_compute_stats_view(BeamformerUI *ui, Arena arena, Variable *view, Rect r, v
u32 seen_shaders = 0;
for (u32 i = 0; i < stages; i++) {
BeamformerShaderKind index = compute_stages[i];
- if ((seen_shaders & (1 << index)) == 0)
+ if ((seen_shaders & (1u << index)) == 0)
compute_time_sum += stats->average_times[index];
- seen_shaders |= (1 << index);
+ seen_shaders |= (1u << index);
}
v2 result = {0};
@@ -3287,7 +3287,7 @@ scale_bar_interaction(BeamformerUI *ui, ScaleBar *sb, v2 mouse)
f32 max = new_coord;
if (min > max) swap(min, max);
- v2_sll *savepoint = SLLPop(ui->scale_bar_savepoint_freelist);
+ v2_sll *savepoint = SLLPopFreelist(ui->scale_bar_savepoint_freelist);
if (!savepoint) savepoint = push_struct(&ui->arena, v2_sll);
savepoint->v.x = *sb->min_value;
@@ -3307,7 +3307,7 @@ scale_bar_interaction(BeamformerUI *ui, ScaleBar *sb, v2 mouse)
*sb->min_value = savepoint->v.x;
*sb->max_value = savepoint->v.y;
sb->savepoint_stack = savepoint->next;
- SLLPush(savepoint, ui->scale_bar_savepoint_freelist);
+ SLLPushFreelist(savepoint, ui->scale_bar_savepoint_freelist);
}
sb->zoom_starting_coord = F32_INFINITY;
}
@@ -3348,8 +3348,8 @@ ui_view_close(BeamformerUI *ui, Variable *view)
}
view->parent->next = view->next;
view->next->parent = view->parent;
- if (fw->close) SLLPush(fw->close, ui->variable_freelist);
- SLLPush(view, ui->variable_freelist);
+ if (fw->close) SLLPushFreelist(fw->close, ui->variable_freelist);
+ SLLPushFreelist(view, ui->variable_freelist);
}break;
case VT_UI_VIEW:{
assert(view->parent->type == VT_UI_REGION_SPLIT);
@@ -3369,7 +3369,7 @@ ui_view_close(BeamformerUI *ui, Variable *view)
}
remaining->parent = parent;
- SLLPush(region, ui->variable_freelist);
+ SLLPushFreelist(region, ui->variable_freelist);
}break;
InvalidDefaultCase;
}
@@ -3525,7 +3525,7 @@ ui_extra_actions(BeamformerUI *ui, Variable *var)
ui_beamformer_frame_view_copy_frame(ui, new, old);
DLLRemove(old);
- SLLPush(old, ui->view_freelist);
+ SLLPushFreelist(old, ui->view_freelist);
}break;
InvalidDefaultCase;
}
@@ -3547,15 +3547,17 @@ function void
ui_end_interact(BeamformerUI *ui, v2 mouse)
{
Interaction *it = &ui->interaction;
- b32 start_compute = (it->var->flags & V_CAUSES_COMPUTE) != 0;
+ Variable *parent = it->var->parent;
+ u32 flags = it->var->flags;
+
switch (it->kind) {
case InteractionKind_Nop:{}break;
case InteractionKind_Drag:{
switch (it->var->type) {
case VT_X_PLANE_SHIFT:{
- assert(it->var->parent && it->var->parent->type == VT_BEAMFORMER_FRAME_VIEW);
+ assert(parent && parent->type == VT_BEAMFORMER_FRAME_VIEW);
XPlaneShift *xp = &it->var->x_plane_shift;
- BeamformerFrameView *view = it->var->parent->generic;
+ BeamformerFrameView *view = parent->generic;
BeamformerViewPlaneTag plane = view_plane_tag_from_x_plane_shift(view, it->var);
f32 rotation = x_plane_rotation_for_view_plane(view, plane);
m4 x_rotation = m4_rotation_about_y(rotation);
@@ -3604,9 +3606,10 @@ ui_end_interact(BeamformerUI *ui, v2 mouse)
InvalidDefaultCase;
}
- if (start_compute) ui->flush_params = 1;
- if (it->var->flags & V_UPDATE_VIEW) {
- Variable *parent = it->var->parent;
+ if (flags & V_CAUSES_COMPUTE)
+ ui->flush_params = 1;
+
+ if (flags & V_UPDATE_VIEW) {
BeamformerFrameView *frame = parent->generic;
/* TODO(rnp): more straight forward way of achieving this */
if (parent->type != VT_BEAMFORMER_FRAME_VIEW) {
@@ -3617,13 +3620,13 @@ ui_end_interact(BeamformerUI *ui, v2 mouse)
frame->dirty = 1;
}
- if (it->var->flags & V_LIVE_CONTROL)
+ if (flags & V_LIVE_CONTROL)
ui_live_control_update(ui, it->var->parent);
- if (it->var->flags & V_HIDES_CURSOR)
+ if (flags & V_HIDES_CURSOR)
EnableCursor();
- if (it->var->flags & V_EXTRA_ACTION)
+ if (flags & V_EXTRA_ACTION)
ui_extra_actions(ui, it->var);
ui->interaction = (Interaction){.kind = InteractionKind_None};
@@ -3749,6 +3752,18 @@ ui_interact(BeamformerUI *ui, BeamformerInput *input, Rect window_rect)
ui->next_interaction = (Interaction){.kind = InteractionKind_None};
}
+/* NOTE(rnp): this only exists to make asan less annoying. do not waste
+ * people's time by freeing, closing, etc... */
+DEBUG_EXPORT BEAMFORMER_DEBUG_UI_DEINIT_FN(beamformer_debug_ui_deinit)
+{
+#if ASAN_ACTIVE
+ BeamformerUI *ui = ctx->ui;
+ UnloadFont(ui->font);
+ UnloadFont(ui->small_font);
+ CloseWindow();
+#endif
+}
+
function void
ui_init(BeamformerCtx *ctx, Arena store)
{
@@ -3817,6 +3832,8 @@ draw_ui(BeamformerCtx *ctx, BeamformerInput *input, BeamformerFrame *frame_to_dr
ui->latest_plane[BeamformerViewPlaneTag_Count] = frame_to_draw;
ui->latest_plane[frame_plane] = frame_to_draw;
+ asan_poison_region(ui->arena.beg, ui->arena.end - ui->arena.beg);
+
/* TODO(rnp): there should be a better way of detecting this */
if (ctx->ui_read_params) {
mem_copy(&ui->params, &sm->parameters.output_min_coordinate, sizeof(ui->params));
diff --git a/util.c b/util.c
@@ -50,6 +50,7 @@ arena_alloc(Arena *a, iz len, uz align, iz count)
iz available = a->end - a->beg - (iz)padding;
assert((available >= 0 && count <= available / len));
void *p = a->beg + padding;
+ asan_unpoison_region(p, count * len);
a->beg += (iz)padding + count * len;
/* TODO: Performance? */
return mem_clear(p, 0, count * len);
@@ -381,6 +382,10 @@ arena_stream(Arena a)
Stream result = {0};
result.data = a.beg;
result.cap = (i32)(a.end - a.beg);
+
+ /* TODO(rnp): no idea what to do here if we want to maintain the ergonomics */
+ asan_unpoison_region(result.data, result.cap);
+
return result;
}
diff --git a/util.h b/util.h
@@ -41,6 +41,16 @@
#endif
#define ASSERT assert
+#if ASAN_ACTIVE
+ void __asan_poison_memory_region(void *, ptrdiff_t);
+ void __asan_unpoison_memory_region(void *, ptrdiff_t);
+ #define asan_poison_region(region, size) __asan_poison_memory_region((region), (size))
+ #define asan_unpoison_region(region, size) __asan_unpoison_memory_region((region), (size))
+#else
+ #define asan_poison_region(...)
+ #define asan_unpoison_region(...)
+#endif
+
#define INVALID_CODE_PATH ASSERT(0)
#define INVALID_DEFAULT_CASE default: ASSERT(0); break
#define InvalidCodePath assert(0)
@@ -78,12 +88,22 @@
#define EachNonZeroEnumValue(type, it) (type it = (type)1; it < type##_Count; it = (type)(it + 1))
/* NOTE(rnp): no guarantees about actually getting an element */
-#define SLLPop(list) list; list = list ? list->next : 0
+#define SLLPop(list) list; list = list ? list->next : 0
#define SLLPush(v, list) do { \
(v)->next = (list); \
(list) = v; \
} while (0)
+#define SLLPopFreelist(list) list; do { \
+ asan_unpoison_region((list), sizeof(*(list))); \
+ (void)SLLPop((list)); \
+} while(0)
+
+#define SLLPushFreelist(v, list) do { \
+ SLLPush((v), (list)); \
+ asan_poison_region((v), sizeof(*(v))); \
+} while(0)
+
#define DLLPushDown(v, list) do { \
(v)->next = (list); \
if ((v)->next) (v)->next->prev = (v); \